All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V5 0/4] Consolidated KVM vPMU support for x86
@ 2015-06-12  5:34 Wei Huang
  2015-06-12  5:34 ` [PATCH V5 1/4] KVM: x86/vPMU: Define kvm_pmu_ops to support vPMU function dispatch Wei Huang
                   ` (5 more replies)
  0 siblings, 6 replies; 13+ messages in thread
From: Wei Huang @ 2015-06-12  5:34 UTC (permalink / raw)
  To: kvm, x86, pbonzini, gleb, rkrcmar, joro

Currently KVM only supports vPMU for Intel CPUs. This patchset enables
KVM vPMU support for AMD platform by creating a common PMU interface
for x86. By refractoring, PMU related MSR accesses from guest VMs
are dispatched to corresponding functions defined in arch specific
files.

This patchset is directlyh applicable on kvm.git/queue.

V5:
  * Remove the get_pmu_ops from sub_arch; instead define pmu dispatcher
    in kvm_x86_ops->pmu_ops. The dispatcher is initialized in sub-arch.
    The PMU interface functions are changed accordingly (suggested by 
    Joerg Rodel).

V4:
  * Change vPMU API function names to further clarify their functionality
  * Small fix for switch statement index in EVNTSELn and PERFCTRn
    (patch 4)
  * Add Tested-by and Reviewed-by

V3:
  * Rebase the code to the latest of KVM tree (queue branch);
  * Branch out the Intel specific code from pmu.c to pmu_intel.c, in 
    order to reflect the change history more accurately;
  * Name the parameters/variables more consistently (use msr, idx,
    pmc_idx) across files;
  * Fix issues (whitespaces, macro names, ...) based on Radim's V2
    comments;
  * Fix the MSR_K7_PERFCTRn and MSR_K7_EVNTSELn access code (in patch 4);

V2:
  * Create a generic pmu.c file which is shared by Intel and AMD CPUs;
  * pmu.c code becomes part of kvm.ko module. Similarly pmu_intel.c and
    pmu_amd.c are linked to kvm-intel.ko and kvm-amd.ko respectively;
  * Re-define kvm_pmu_ops function pointers. Per Radim Krcmar's comments,
    a large portion of Intel vPMU code are now consolidated and moved to
    pmu.c;
  * Polish pmu_amd.c code to comply with new definition of kvm_pmu_ops;

V1:
  * Adopt the file layout suggested by Radim Krcmar
  * Link arch module with its specific PMU file

RFC:
  * Initial version for RFC

Wei Huang (4):
  KVM: x86/vPMU: Define kvm_pmu_ops to support vPMU function dispatch
  KVM: x86/vPMU: Create vPMU interface for VMX and SVM
  KVM: x86/vPMU: Implement AMD vPMU code for KVM
  KVM: x86/vPMU: Enable PMU handling for AMD PERFCTRn and EVNTSELn MSRs

 arch/x86/include/asm/kvm_host.h |  48 ++--
 arch/x86/kvm/Makefile           |   4 +-
 arch/x86/kvm/cpuid.c            |   3 +-
 arch/x86/kvm/pmu.c              | 550 ++++++++++------------------------------
 arch/x86/kvm/pmu.h              |  96 +++++++
 arch/x86/kvm/pmu_amd.c          | 207 +++++++++++++++
 arch/x86/kvm/pmu_intel.c        | 360 ++++++++++++++++++++++++++
 arch/x86/kvm/svm.c              |   3 +
 arch/x86/kvm/vmx.c              |   3 +
 arch/x86/kvm/x86.c              |  70 ++---
 10 files changed, 863 insertions(+), 481 deletions(-)
 create mode 100644 arch/x86/kvm/pmu.h
 create mode 100644 arch/x86/kvm/pmu_amd.c
 create mode 100644 arch/x86/kvm/pmu_intel.c

-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH V5 1/4] KVM: x86/vPMU: Define kvm_pmu_ops to support vPMU function dispatch
  2015-06-12  5:34 [PATCH V5 0/4] Consolidated KVM vPMU support for x86 Wei Huang
@ 2015-06-12  5:34 ` Wei Huang
  2015-06-19 11:30   ` Paolo Bonzini
  2015-06-12  5:34 ` [PATCH V5 2/4] KVM: x86/vPMU: Create vPMU interface for VMX and SVM Wei Huang
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 13+ messages in thread
From: Wei Huang @ 2015-06-12  5:34 UTC (permalink / raw)
  To: kvm, x86, pbonzini, gleb, rkrcmar, joro

This patch defines a new function pointer struct (kvm_pmu_ops) to
support vPMU for both Intel and AMD. The functions pointers defined in
this new struct will be linked with Intel and AMD functions later. In the
meanwhile the struct that maps from event_sel bits to PERF_TYPE_HARDWARE
events is renamed and moved from Intel specific code to kvm_host.h as a
common struct.

Reviewed-by: Joerg Roedel <jroedel@suse.de>
Tested-by: Joerg Roedel <jroedel@suse.de>
Signed-off-by: Wei Huang <wei@redhat.com>
---
 arch/x86/include/asm/kvm_host.h | 34 ++++++++++++++++++++++++++++------
 arch/x86/kvm/pmu.c              | 21 ++++++++-------------
 2 files changed, 36 insertions(+), 19 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 8ca32cf..82dc7cc 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -304,6 +304,12 @@ struct kvm_mmu {
 	u64 pdptrs[4]; /* pae */
 };
 
+struct msr_data {
+	bool host_initiated;
+	u32 index;
+	u64 data;
+};
+
 enum pmc_type {
 	KVM_PMC_GP = 0,
 	KVM_PMC_FIXED,
@@ -318,6 +324,12 @@ struct kvm_pmc {
 	struct kvm_vcpu *vcpu;
 };
 
+struct kvm_event_hw_type_mapping {
+	u8 eventsel;
+	u8 unit_mask;
+	unsigned event_type;
+};
+
 struct kvm_pmu {
 	unsigned nr_arch_gp_counters;
 	unsigned nr_arch_fixed_counters;
@@ -336,6 +348,22 @@ struct kvm_pmu {
 	u64 reprogram_pmi;
 };
 
+struct kvm_pmu_ops {
+	unsigned (*find_arch_event)(struct kvm_pmu *pmu, u8 event_select,
+				    u8 unit_mask);
+	unsigned (*find_fixed_event)(int idx);
+	bool (*pmc_enabled)(struct kvm_pmc *pmc);
+	struct kvm_pmc *(*pmc_idx_to_pmc)(struct kvm_pmu *pmu, int pmc_idx);
+	struct kvm_pmc *(*msr_idx_to_pmc)(struct kvm_vcpu *vcpu, unsigned idx);
+	int (*is_valid_msr_idx)(struct kvm_vcpu *vcpu, unsigned idx);
+	bool (*is_valid_msr)(struct kvm_vcpu *vcpu, u32 msr);
+	int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr, u64 *data);
+	int (*set_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
+	void (*refresh)(struct kvm_vcpu *vcpu);
+	void (*init)(struct kvm_vcpu *vcpu);
+	void (*reset)(struct kvm_vcpu *vcpu);
+};
+
 enum {
 	KVM_DEBUGREG_BP_ENABLED = 1,
 	KVM_DEBUGREG_WONT_EXIT = 2,
@@ -683,12 +711,6 @@ struct kvm_vcpu_stat {
 
 struct x86_instruction_info;
 
-struct msr_data {
-	bool host_initiated;
-	u32 index;
-	u64 data;
-};
-
 struct kvm_lapic_irq {
 	u32 vector;
 	u16 delivery_mode;
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index 29fbf9d..3af3404 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -20,12 +20,7 @@
 #include "cpuid.h"
 #include "lapic.h"
 
-static struct kvm_arch_event_perf_mapping {
-	u8 eventsel;
-	u8 unit_mask;
-	unsigned event_type;
-	bool inexact;
-} arch_events[] = {
+static struct kvm_event_hw_type_mapping intel_arch_events[] = {
 	/* Index must match CPUID 0x0A.EBX bit vector */
 	[0] = { 0x3c, 0x00, PERF_COUNT_HW_CPU_CYCLES },
 	[1] = { 0xc0, 0x00, PERF_COUNT_HW_INSTRUCTIONS },
@@ -37,7 +32,7 @@ static struct kvm_arch_event_perf_mapping {
 	[7] = { 0x00, 0x30, PERF_COUNT_HW_REF_CPU_CYCLES },
 };
 
-/* mapping between fixed pmc index and arch_events array */
+/* mapping between fixed pmc index and intel_arch_events array */
 static int fixed_pmc_events[] = {1, 0, 7};
 
 static bool pmc_is_gp(struct kvm_pmc *pmc)
@@ -202,16 +197,16 @@ static unsigned find_arch_event(struct kvm_pmu *pmu, u8 event_select,
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(arch_events); i++)
-		if (arch_events[i].eventsel == event_select
-				&& arch_events[i].unit_mask == unit_mask
+	for (i = 0; i < ARRAY_SIZE(intel_arch_events); i++)
+		if (intel_arch_events[i].eventsel == event_select
+				&& intel_arch_events[i].unit_mask == unit_mask
 				&& (pmu->available_event_types & (1 << i)))
 			break;
 
-	if (i == ARRAY_SIZE(arch_events))
+	if (i == ARRAY_SIZE(intel_arch_events))
 		return PERF_COUNT_HW_MAX;
 
-	return arch_events[i].event_type;
+	return intel_arch_events[i].event_type;
 }
 
 static void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel)
@@ -265,7 +260,7 @@ static void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 en_pmi, int idx)
 		return;
 
 	reprogram_counter(pmc, PERF_TYPE_HARDWARE,
-			arch_events[fixed_pmc_events[idx]].event_type,
+			intel_arch_events[fixed_pmc_events[idx]].event_type,
 			!(en & 0x2), /* exclude user */
 			!(en & 0x1), /* exclude kernel */
 			pmi, false, false);
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH V5 2/4] KVM: x86/vPMU: Create vPMU interface for VMX and SVM
  2015-06-12  5:34 [PATCH V5 0/4] Consolidated KVM vPMU support for x86 Wei Huang
  2015-06-12  5:34 ` [PATCH V5 1/4] KVM: x86/vPMU: Define kvm_pmu_ops to support vPMU function dispatch Wei Huang
@ 2015-06-12  5:34 ` Wei Huang
  2015-06-16 15:40   ` Joerg Roedel
  2015-06-19 11:31   ` Paolo Bonzini
  2015-06-12  5:34 ` [PATCH V5 3/4] KVM: x86/vPMU: Implement AMD vPMU code for KVM Wei Huang
                   ` (3 subsequent siblings)
  5 siblings, 2 replies; 13+ messages in thread
From: Wei Huang @ 2015-06-12  5:34 UTC (permalink / raw)
  To: kvm, x86, pbonzini, gleb, rkrcmar, joro

This patch splits existing vPMU code into a common vPMU interface (pmc.c)
and Intel specific vPMU code (pmu_intel.c) using the following steps:

- Part of arechitectural vPMU code is extracted and moved to pmu_intel.c
  file. They are hooked up with the newly-defined intel_pmu_ops, which will
  be called from pmu interface;
- Create a dummy pmu_amd.c file for AMD SVM with empty functions;

All architectural vPMU functions are now called via PMU function dispatcher.
This function dispatcher is defined in kvm_x86_ops->pmu_ops, which is
initialized by sub-arch. Also note that Intel and AMD modules are now
generated by combinig their corresponding arch files (vmx.c/svm.c) and pmu
files (pmu_intel.c/pmu_amd.c).

Tested-by: Radim Krčmář <rkrcmar@redhat.com>
Signed-off-by: Wei Huang <wei@redhat.com>
---
 arch/x86/include/asm/kvm_host.h |  14 +-
 arch/x86/kvm/Makefile           |   4 +-
 arch/x86/kvm/cpuid.c            |   3 +-
 arch/x86/kvm/pmu.c              | 545 +++++++++++-----------------------------
 arch/x86/kvm/pmu.h              |  96 +++++++
 arch/x86/kvm/pmu_amd.c          |  97 +++++++
 arch/x86/kvm/pmu_intel.c        | 360 ++++++++++++++++++++++++++
 arch/x86/kvm/svm.c              |   3 +
 arch/x86/kvm/vmx.c              |   3 +
 arch/x86/kvm/x86.c              |  19 +-
 10 files changed, 716 insertions(+), 428 deletions(-)
 create mode 100644 arch/x86/kvm/pmu.h
 create mode 100644 arch/x86/kvm/pmu_amd.c
 create mode 100644 arch/x86/kvm/pmu_intel.c

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 82dc7cc..dc8e33a 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -862,6 +862,8 @@ struct kvm_x86_ops {
 	void (*enable_log_dirty_pt_masked)(struct kvm *kvm,
 					   struct kvm_memory_slot *slot,
 					   gfn_t offset, unsigned long mask);
+	/* pmu operations of sub-arch */
+	const struct kvm_pmu_ops *pmu_ops;
 };
 
 struct kvm_arch_async_pf {
@@ -1204,18 +1206,6 @@ void kvm_complete_insn_gp(struct kvm_vcpu *vcpu, int err);
 
 int kvm_is_in_guest(void);
 
-void kvm_pmu_init(struct kvm_vcpu *vcpu);
-void kvm_pmu_destroy(struct kvm_vcpu *vcpu);
-void kvm_pmu_reset(struct kvm_vcpu *vcpu);
-void kvm_pmu_cpuid_update(struct kvm_vcpu *vcpu);
-bool kvm_pmu_msr(struct kvm_vcpu *vcpu, u32 msr);
-int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *data);
-int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
-int kvm_pmu_check_pmc(struct kvm_vcpu *vcpu, unsigned pmc);
-int kvm_pmu_read_pmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data);
-void kvm_handle_pmu_event(struct kvm_vcpu *vcpu);
-void kvm_deliver_pmi(struct kvm_vcpu *vcpu);
-
 int __x86_set_memory_region(struct kvm *kvm,
 			    const struct kvm_userspace_memory_region *mem);
 int x86_set_memory_region(struct kvm *kvm,
diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile
index 16e8f96..c1c99d7 100644
--- a/arch/x86/kvm/Makefile
+++ b/arch/x86/kvm/Makefile
@@ -14,8 +14,8 @@ kvm-$(CONFIG_KVM_ASYNC_PF)	+= $(KVM)/async_pf.o
 kvm-y			+= x86.o mmu.o emulate.o i8259.o irq.o lapic.o \
 			   i8254.o ioapic.o irq_comm.o cpuid.o pmu.o
 kvm-$(CONFIG_KVM_DEVICE_ASSIGNMENT)	+= assigned-dev.o iommu.o
-kvm-intel-y		+= vmx.o
-kvm-amd-y		+= svm.o
+kvm-intel-y		+= vmx.o pmu_intel.o
+kvm-amd-y		+= svm.o pmu_amd.o
 
 obj-$(CONFIG_KVM)	+= kvm.o
 obj-$(CONFIG_KVM_INTEL)	+= kvm-intel.o
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 9dadf8d..a64cc76 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -24,6 +24,7 @@
 #include "lapic.h"
 #include "mmu.h"
 #include "trace.h"
+#include "pmu.h"
 
 static u32 xstate_required_size(u64 xstate_bv, bool compacted)
 {
@@ -111,7 +112,7 @@ int kvm_update_cpuid(struct kvm_vcpu *vcpu)
 	/* Update physical-address width */
 	vcpu->arch.maxphyaddr = cpuid_query_maxphyaddr(vcpu);
 
-	kvm_pmu_cpuid_update(vcpu);
+	kvm_pmu_refresh(vcpu);
 	return 0;
 }
 
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index 3af3404..ebb5888 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -1,17 +1,16 @@
 /*
  * Kernel-based Virtual Machine -- Performance Monitoring Unit support
  *
- * Copyright 2011 Red Hat, Inc. and/or its affiliates.
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
  *
  * Authors:
  *   Avi Kivity   <avi@redhat.com>
  *   Gleb Natapov <gleb@redhat.com>
+ *   Wei Huang    <wei@redhat.com>
  *
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
- *
  */
-
 #include <linux/types.h>
 #include <linux/kvm_host.h>
 #include <linux/perf_event.h>
@@ -19,83 +18,39 @@
 #include "x86.h"
 #include "cpuid.h"
 #include "lapic.h"
+#include "pmu.h"
+
+/* NOTE:
+ * - Each perf counter is defined as "struct kvm_pmc";
+ * - There are two types of perf counters: general purpose (gp) and fixed.
+ *   gp counters are stored in gp_counters[] and fixed counters are stored
+ *   in fixed_counters[] respectively. Both of them are part of "struct
+ *   kvm_pmu";
+ * - pmu.c understands the difference between gp counters and fixed counters.
+ *   However AMD doesn't support fixed-counters;
+ * - There are three types of index to access perf counters (PMC):
+ *     1. MSR (named msr): For example Intel has MSR_IA32_PERFCTRn and AMD
+ *        has MSR_K7_PERFCTRn.
+ *     2. MSR Index (named idx): This normally is used by RDPMC instruction.
+ *        For instance AMD RDPMC instruction uses 0000_0003h in ECX to access
+ *        C001_0007h (MSR_K7_PERCTR3). Intel has a similar mechanism, except
+ *        that it also supports fixed counters. idx can be used to as index to
+ *        gp and fixed counters.
+ *     3. Global PMC Index (named pmc): pmc is an index specific to PMU
+ *        code. Each pmc, stored in kvm_pmc.idx field, is unique across
+ *        all perf counters (both gp and fixed). The mapping relationship
+ *        between pmc and perf counters is as the following:
+ *        * Intel: [0 .. INTEL_PMC_MAX_GENERIC-1] <=> gp counters
+ *                 [INTEL_PMC_IDX_FIXED .. INTEL_PMC_IDX_FIXED + 2] <=> fixed
+ *        * AMD:   [0 .. AMD64_NUM_COUNTERS-1] <=> gp counters
+ */
 
-static struct kvm_event_hw_type_mapping intel_arch_events[] = {
-	/* Index must match CPUID 0x0A.EBX bit vector */
-	[0] = { 0x3c, 0x00, PERF_COUNT_HW_CPU_CYCLES },
-	[1] = { 0xc0, 0x00, PERF_COUNT_HW_INSTRUCTIONS },
-	[2] = { 0x3c, 0x01, PERF_COUNT_HW_BUS_CYCLES  },
-	[3] = { 0x2e, 0x4f, PERF_COUNT_HW_CACHE_REFERENCES },
-	[4] = { 0x2e, 0x41, PERF_COUNT_HW_CACHE_MISSES },
-	[5] = { 0xc4, 0x00, PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
-	[6] = { 0xc5, 0x00, PERF_COUNT_HW_BRANCH_MISSES },
-	[7] = { 0x00, 0x30, PERF_COUNT_HW_REF_CPU_CYCLES },
-};
-
-/* mapping between fixed pmc index and intel_arch_events array */
-static int fixed_pmc_events[] = {1, 0, 7};
-
-static bool pmc_is_gp(struct kvm_pmc *pmc)
-{
-	return pmc->type == KVM_PMC_GP;
-}
-
-static inline u64 pmc_bitmask(struct kvm_pmc *pmc)
-{
-	struct kvm_pmu *pmu = &pmc->vcpu->arch.pmu;
-
-	return pmu->counter_bitmask[pmc->type];
-}
-
-static inline bool pmc_enabled(struct kvm_pmc *pmc)
-{
-	struct kvm_pmu *pmu = &pmc->vcpu->arch.pmu;
-	return test_bit(pmc->idx, (unsigned long *)&pmu->global_ctrl);
-}
-
-static inline struct kvm_pmc *get_gp_pmc(struct kvm_pmu *pmu, u32 msr,
-					 u32 base)
-{
-	if (msr >= base && msr < base + pmu->nr_arch_gp_counters)
-		return &pmu->gp_counters[msr - base];
-	return NULL;
-}
-
-static inline struct kvm_pmc *get_fixed_pmc(struct kvm_pmu *pmu, u32 msr)
-{
-	int base = MSR_CORE_PERF_FIXED_CTR0;
-	if (msr >= base && msr < base + pmu->nr_arch_fixed_counters)
-		return &pmu->fixed_counters[msr - base];
-	return NULL;
-}
-
-static inline struct kvm_pmc *get_fixed_pmc_idx(struct kvm_pmu *pmu, int idx)
-{
-	return get_fixed_pmc(pmu, MSR_CORE_PERF_FIXED_CTR0 + idx);
-}
-
-static struct kvm_pmc *global_idx_to_pmc(struct kvm_pmu *pmu, int idx)
-{
-	if (idx < INTEL_PMC_IDX_FIXED)
-		return get_gp_pmc(pmu, MSR_P6_EVNTSEL0 + idx, MSR_P6_EVNTSEL0);
-	else
-		return get_fixed_pmc_idx(pmu, idx - INTEL_PMC_IDX_FIXED);
-}
-
-void kvm_deliver_pmi(struct kvm_vcpu *vcpu)
-{
-	if (vcpu->arch.apic)
-		kvm_apic_local_deliver(vcpu->arch.apic, APIC_LVTPC);
-}
-
-static void trigger_pmi(struct irq_work *irq_work)
+static void kvm_pmi_trigger_fn(struct irq_work *irq_work)
 {
-	struct kvm_pmu *pmu = container_of(irq_work, struct kvm_pmu,
-			irq_work);
-	struct kvm_vcpu *vcpu = container_of(pmu, struct kvm_vcpu,
-			arch.pmu);
+	struct kvm_pmu *pmu = container_of(irq_work, struct kvm_pmu, irq_work);
+	struct kvm_vcpu *vcpu = pmu_to_vcpu(pmu);
 
-	kvm_deliver_pmi(vcpu);
+	kvm_pmu_deliver_pmi(vcpu);
 }
 
 static void kvm_perf_overflow(struct perf_event *perf_event,
@@ -103,26 +58,32 @@ static void kvm_perf_overflow(struct perf_event *perf_event,
 			      struct pt_regs *regs)
 {
 	struct kvm_pmc *pmc = perf_event->overflow_handler_context;
-	struct kvm_pmu *pmu = &pmc->vcpu->arch.pmu;
-	if (!test_and_set_bit(pmc->idx, (unsigned long *)&pmu->reprogram_pmi)) {
+	struct kvm_pmu *pmu = pmc_to_pmu(pmc);
+
+	if (!test_and_set_bit(pmc->idx,
+			      (unsigned long *)&pmu->reprogram_pmi)) {
 		__set_bit(pmc->idx, (unsigned long *)&pmu->global_status);
 		kvm_make_request(KVM_REQ_PMU, pmc->vcpu);
 	}
 }
 
 static void kvm_perf_overflow_intr(struct perf_event *perf_event,
-		struct perf_sample_data *data, struct pt_regs *regs)
+				   struct perf_sample_data *data,
+				   struct pt_regs *regs)
 {
 	struct kvm_pmc *pmc = perf_event->overflow_handler_context;
-	struct kvm_pmu *pmu = &pmc->vcpu->arch.pmu;
-	if (!test_and_set_bit(pmc->idx, (unsigned long *)&pmu->reprogram_pmi)) {
+	struct kvm_pmu *pmu = pmc_to_pmu(pmc);
+
+	if (!test_and_set_bit(pmc->idx,
+			      (unsigned long *)&pmu->reprogram_pmi)) {
 		__set_bit(pmc->idx, (unsigned long *)&pmu->global_status);
 		kvm_make_request(KVM_REQ_PMU, pmc->vcpu);
+
 		/*
 		 * Inject PMI. If vcpu was in a guest mode during NMI PMI
 		 * can be ejected on a guest mode re-entry. Otherwise we can't
 		 * be sure that vcpu wasn't executing hlt instruction at the
-		 * time of vmexit and is not going to re-enter guest mode until,
+		 * time of vmexit and is not going to re-enter guest mode until
 		 * woken up. So we should wake it, but this is impossible from
 		 * NMI context. Do it from irq work instead.
 		 */
@@ -133,33 +94,10 @@ static void kvm_perf_overflow_intr(struct perf_event *perf_event,
 	}
 }
 
-static u64 read_pmc(struct kvm_pmc *pmc)
-{
-	u64 counter, enabled, running;
-
-	counter = pmc->counter;
-
-	if (pmc->perf_event)
-		counter += perf_event_read_value(pmc->perf_event,
-						 &enabled, &running);
-
-	/* FIXME: Scaling needed? */
-
-	return counter & pmc_bitmask(pmc);
-}
-
-static void stop_counter(struct kvm_pmc *pmc)
-{
-	if (pmc->perf_event) {
-		pmc->counter = read_pmc(pmc);
-		perf_event_release_kernel(pmc->perf_event);
-		pmc->perf_event = NULL;
-	}
-}
-
-static void reprogram_counter(struct kvm_pmc *pmc, u32 type,
-		unsigned config, bool exclude_user, bool exclude_kernel,
-		bool intr, bool in_tx, bool in_tx_cp)
+static void pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type,
+				  unsigned config, bool exclude_user,
+				  bool exclude_kernel, bool intr,
+				  bool in_tx, bool in_tx_cp)
 {
 	struct perf_event *event;
 	struct perf_event_attr attr = {
@@ -172,6 +110,7 @@ static void reprogram_counter(struct kvm_pmc *pmc, u32 type,
 		.exclude_kernel = exclude_kernel,
 		.config = config,
 	};
+
 	if (in_tx)
 		attr.config |= HSW_IN_TX;
 	if (in_tx_cp)
@@ -183,8 +122,8 @@ static void reprogram_counter(struct kvm_pmc *pmc, u32 type,
 						 intr ? kvm_perf_overflow_intr :
 						 kvm_perf_overflow, pmc);
 	if (IS_ERR(event)) {
-		printk_once("kvm: pmu event creation failed %ld\n",
-				PTR_ERR(event));
+		printk_once("kvm_pmu: event creation failed %ld\n",
+			    PTR_ERR(event));
 		return;
 	}
 
@@ -192,24 +131,7 @@ static void reprogram_counter(struct kvm_pmc *pmc, u32 type,
 	clear_bit(pmc->idx, (unsigned long*)&pmc->vcpu->arch.pmu.reprogram_pmi);
 }
 
-static unsigned find_arch_event(struct kvm_pmu *pmu, u8 event_select,
-		u8 unit_mask)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(intel_arch_events); i++)
-		if (intel_arch_events[i].eventsel == event_select
-				&& intel_arch_events[i].unit_mask == unit_mask
-				&& (pmu->available_event_types & (1 << i)))
-			break;
-
-	if (i == ARRAY_SIZE(intel_arch_events))
-		return PERF_COUNT_HW_MAX;
-
-	return intel_arch_events[i].event_type;
-}
-
-static void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel)
+void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel)
 {
 	unsigned config, type = PERF_TYPE_RAW;
 	u8 event_select, unit_mask;
@@ -219,21 +141,22 @@ static void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel)
 
 	pmc->eventsel = eventsel;
 
-	stop_counter(pmc);
+	pmc_stop_counter(pmc);
 
-	if (!(eventsel & ARCH_PERFMON_EVENTSEL_ENABLE) || !pmc_enabled(pmc))
+	if (!(eventsel & ARCH_PERFMON_EVENTSEL_ENABLE) || !pmc_is_enabled(pmc))
 		return;
 
 	event_select = eventsel & ARCH_PERFMON_EVENTSEL_EVENT;
 	unit_mask = (eventsel & ARCH_PERFMON_EVENTSEL_UMASK) >> 8;
 
 	if (!(eventsel & (ARCH_PERFMON_EVENTSEL_EDGE |
-				ARCH_PERFMON_EVENTSEL_INV |
-				ARCH_PERFMON_EVENTSEL_CMASK |
-				HSW_IN_TX |
-				HSW_IN_TX_CHECKPOINTED))) {
-		config = find_arch_event(&pmc->vcpu->arch.pmu, event_select,
-				unit_mask);
+			  ARCH_PERFMON_EVENTSEL_INV |
+			  ARCH_PERFMON_EVENTSEL_CMASK |
+			  HSW_IN_TX |
+			  HSW_IN_TX_CHECKPOINTED))) {
+		config = kvm_x86_ops->pmu_ops->find_arch_event(&pmc->vcpu->arch.pmu,
+						      event_select,
+						      unit_mask);
 		if (config != PERF_COUNT_HW_MAX)
 			type = PERF_TYPE_HARDWARE;
 	}
@@ -241,56 +164,36 @@ static void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel)
 	if (type == PERF_TYPE_RAW)
 		config = eventsel & X86_RAW_EVENT_MASK;
 
-	reprogram_counter(pmc, type, config,
-			!(eventsel & ARCH_PERFMON_EVENTSEL_USR),
-			!(eventsel & ARCH_PERFMON_EVENTSEL_OS),
-			eventsel & ARCH_PERFMON_EVENTSEL_INT,
-			(eventsel & HSW_IN_TX),
-			(eventsel & HSW_IN_TX_CHECKPOINTED));
+	pmc_reprogram_counter(pmc, type, config,
+			      !(eventsel & ARCH_PERFMON_EVENTSEL_USR),
+			      !(eventsel & ARCH_PERFMON_EVENTSEL_OS),
+			      eventsel & ARCH_PERFMON_EVENTSEL_INT,
+			      (eventsel & HSW_IN_TX),
+			      (eventsel & HSW_IN_TX_CHECKPOINTED));
 }
+EXPORT_SYMBOL_GPL(reprogram_gp_counter);
 
-static void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 en_pmi, int idx)
+void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 ctrl, int idx)
 {
-	unsigned en = en_pmi & 0x3;
-	bool pmi = en_pmi & 0x8;
+	unsigned en_field = ctrl & 0x3;
+	bool pmi = ctrl & 0x8;
 
-	stop_counter(pmc);
+	pmc_stop_counter(pmc);
 
-	if (!en || !pmc_enabled(pmc))
+	if (!en_field || !pmc_is_enabled(pmc))
 		return;
 
-	reprogram_counter(pmc, PERF_TYPE_HARDWARE,
-			intel_arch_events[fixed_pmc_events[idx]].event_type,
-			!(en & 0x2), /* exclude user */
-			!(en & 0x1), /* exclude kernel */
-			pmi, false, false);
-}
-
-static inline u8 fixed_en_pmi(u64 ctrl, int idx)
-{
-	return (ctrl >> (idx * 4)) & 0xf;
-}
-
-static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data)
-{
-	int i;
-
-	for (i = 0; i < pmu->nr_arch_fixed_counters; i++) {
-		u8 en_pmi = fixed_en_pmi(data, i);
-		struct kvm_pmc *pmc = get_fixed_pmc_idx(pmu, i);
-
-		if (fixed_en_pmi(pmu->fixed_ctr_ctrl, i) == en_pmi)
-			continue;
-
-		reprogram_fixed_counter(pmc, en_pmi, i);
-	}
-
-	pmu->fixed_ctr_ctrl = data;
+	pmc_reprogram_counter(pmc, PERF_TYPE_HARDWARE,
+			      kvm_x86_ops->pmu_ops->find_fixed_event(idx),
+			      !(en_field & 0x2), /* exclude user */
+			      !(en_field & 0x1), /* exclude kernel */
+			      pmi, false, false);
 }
+EXPORT_SYMBOL_GPL(reprogram_fixed_counter);
 
-static void reprogram_idx(struct kvm_pmu *pmu, int idx)
+void reprogram_counter(struct kvm_pmu *pmu, int pmc_idx)
 {
-	struct kvm_pmc *pmc = global_idx_to_pmc(pmu, idx);
+	struct kvm_pmc *pmc = kvm_x86_ops->pmu_ops->pmc_idx_to_pmc(pmu, pmc_idx);
 
 	if (!pmc)
 		return;
@@ -298,251 +201,104 @@ static void reprogram_idx(struct kvm_pmu *pmu, int idx)
 	if (pmc_is_gp(pmc))
 		reprogram_gp_counter(pmc, pmc->eventsel);
 	else {
-		int fidx = idx - INTEL_PMC_IDX_FIXED;
-		reprogram_fixed_counter(pmc,
-				fixed_en_pmi(pmu->fixed_ctr_ctrl, fidx), fidx);
+		int idx = pmc_idx - INTEL_PMC_IDX_FIXED;
+		u8 ctrl = fixed_ctrl_field(pmu->fixed_ctr_ctrl, idx);
+
+		reprogram_fixed_counter(pmc, ctrl, idx);
 	}
 }
+EXPORT_SYMBOL_GPL(reprogram_counter);
 
-static void global_ctrl_changed(struct kvm_pmu *pmu, u64 data)
+void kvm_pmu_handle_event(struct kvm_vcpu *vcpu)
 {
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+	u64 bitmask;
 	int bit;
-	u64 diff = pmu->global_ctrl ^ data;
-
-	pmu->global_ctrl = data;
 
-	for_each_set_bit(bit, (unsigned long *)&diff, X86_PMC_IDX_MAX)
-		reprogram_idx(pmu, bit);
-}
-
-bool kvm_pmu_msr(struct kvm_vcpu *vcpu, u32 msr)
-{
-	struct kvm_pmu *pmu = &vcpu->arch.pmu;
-	int ret;
-
-	switch (msr) {
-	case MSR_CORE_PERF_FIXED_CTR_CTRL:
-	case MSR_CORE_PERF_GLOBAL_STATUS:
-	case MSR_CORE_PERF_GLOBAL_CTRL:
-	case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
-		ret = pmu->version > 1;
-		break;
-	default:
-		ret = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0)
-			|| get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0)
-			|| get_fixed_pmc(pmu, msr);
-		break;
-	}
-	return ret;
-}
+	bitmask = pmu->reprogram_pmi;
 
-int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data)
-{
-	struct kvm_pmu *pmu = &vcpu->arch.pmu;
-	struct kvm_pmc *pmc;
+	for_each_set_bit(bit, (unsigned long *)&bitmask, X86_PMC_IDX_MAX) {
+		struct kvm_pmc *pmc = kvm_x86_ops->pmu_ops->pmc_idx_to_pmc(pmu, bit);
 
-	switch (index) {
-	case MSR_CORE_PERF_FIXED_CTR_CTRL:
-		*data = pmu->fixed_ctr_ctrl;
-		return 0;
-	case MSR_CORE_PERF_GLOBAL_STATUS:
-		*data = pmu->global_status;
-		return 0;
-	case MSR_CORE_PERF_GLOBAL_CTRL:
-		*data = pmu->global_ctrl;
-		return 0;
-	case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
-		*data = pmu->global_ovf_ctrl;
-		return 0;
-	default:
-		if ((pmc = get_gp_pmc(pmu, index, MSR_IA32_PERFCTR0)) ||
-				(pmc = get_fixed_pmc(pmu, index))) {
-			*data = read_pmc(pmc);
-			return 0;
-		} else if ((pmc = get_gp_pmc(pmu, index, MSR_P6_EVNTSEL0))) {
-			*data = pmc->eventsel;
-			return 0;
+		if (unlikely(!pmc || !pmc->perf_event)) {
+			clear_bit(bit, (unsigned long *)&pmu->reprogram_pmi);
+			continue;
 		}
-	}
-	return 1;
-}
 
-int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
-{
-	struct kvm_pmu *pmu = &vcpu->arch.pmu;
-	struct kvm_pmc *pmc;
-	u32 index = msr_info->index;
-	u64 data = msr_info->data;
-
-	switch (index) {
-	case MSR_CORE_PERF_FIXED_CTR_CTRL:
-		if (pmu->fixed_ctr_ctrl == data)
-			return 0;
-		if (!(data & 0xfffffffffffff444ull)) {
-			reprogram_fixed_counters(pmu, data);
-			return 0;
-		}
-		break;
-	case MSR_CORE_PERF_GLOBAL_STATUS:
-		if (msr_info->host_initiated) {
-			pmu->global_status = data;
-			return 0;
-		}
-		break; /* RO MSR */
-	case MSR_CORE_PERF_GLOBAL_CTRL:
-		if (pmu->global_ctrl == data)
-			return 0;
-		if (!(data & pmu->global_ctrl_mask)) {
-			global_ctrl_changed(pmu, data);
-			return 0;
-		}
-		break;
-	case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
-		if (!(data & (pmu->global_ctrl_mask & ~(3ull<<62)))) {
-			if (!msr_info->host_initiated)
-				pmu->global_status &= ~data;
-			pmu->global_ovf_ctrl = data;
-			return 0;
-		}
-		break;
-	default:
-		if ((pmc = get_gp_pmc(pmu, index, MSR_IA32_PERFCTR0)) ||
-				(pmc = get_fixed_pmc(pmu, index))) {
-			if (!msr_info->host_initiated)
-				data = (s64)(s32)data;
-			pmc->counter += data - read_pmc(pmc);
-			return 0;
-		} else if ((pmc = get_gp_pmc(pmu, index, MSR_P6_EVNTSEL0))) {
-			if (data == pmc->eventsel)
-				return 0;
-			if (!(data & pmu->reserved_bits)) {
-				reprogram_gp_counter(pmc, data);
-				return 0;
-			}
-		}
+		reprogram_counter(pmu, bit);
 	}
-	return 1;
 }
 
-int kvm_pmu_check_pmc(struct kvm_vcpu *vcpu, unsigned pmc)
+/* check if idx is a valid index to access PMU */
+int kvm_pmu_is_valid_msr_idx(struct kvm_vcpu *vcpu, unsigned idx)
 {
-	struct kvm_pmu *pmu = &vcpu->arch.pmu;
-	bool fixed = pmc & (1u << 30);
-	pmc &= ~(3u << 30);
-	return (!fixed && pmc >= pmu->nr_arch_gp_counters) ||
-		(fixed && pmc >= pmu->nr_arch_fixed_counters);
+	return kvm_x86_ops->pmu_ops->is_valid_msr_idx(vcpu, idx);
 }
 
-int kvm_pmu_read_pmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data)
+int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned idx, u64 *data)
 {
-	struct kvm_pmu *pmu = &vcpu->arch.pmu;
-	bool fast_mode = pmc & (1u << 31);
-	bool fixed = pmc & (1u << 30);
-	struct kvm_pmc *counters;
-	u64 ctr;
-
-	pmc &= ~(3u << 30);
-	if (!fixed && pmc >= pmu->nr_arch_gp_counters)
-		return 1;
-	if (fixed && pmc >= pmu->nr_arch_fixed_counters)
+	bool fast_mode = idx & (1u << 31);
+	struct kvm_pmc *pmc;
+	u64 ctr_val;
+
+	pmc = kvm_x86_ops->pmu_ops->msr_idx_to_pmc(vcpu, idx);
+	if (!pmc)
 		return 1;
-	counters = fixed ? pmu->fixed_counters : pmu->gp_counters;
-	ctr = read_pmc(&counters[pmc]);
+
+	ctr_val = pmc_read_counter(pmc);
 	if (fast_mode)
-		ctr = (u32)ctr;
-	*data = ctr;
+		ctr_val = (u32)ctr_val;
 
+	*data = ctr_val;
 	return 0;
 }
 
-void kvm_pmu_cpuid_update(struct kvm_vcpu *vcpu)
+void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu)
 {
-	struct kvm_pmu *pmu = &vcpu->arch.pmu;
-	struct kvm_cpuid_entry2 *entry;
-	union cpuid10_eax eax;
-	union cpuid10_edx edx;
-
-	pmu->nr_arch_gp_counters = 0;
-	pmu->nr_arch_fixed_counters = 0;
-	pmu->counter_bitmask[KVM_PMC_GP] = 0;
-	pmu->counter_bitmask[KVM_PMC_FIXED] = 0;
-	pmu->version = 0;
-	pmu->reserved_bits = 0xffffffff00200000ull;
-
-	entry = kvm_find_cpuid_entry(vcpu, 0xa, 0);
-	if (!entry)
-		return;
-	eax.full = entry->eax;
-	edx.full = entry->edx;
-
-	pmu->version = eax.split.version_id;
-	if (!pmu->version)
-		return;
-
-	pmu->nr_arch_gp_counters = min_t(int, eax.split.num_counters,
-					INTEL_PMC_MAX_GENERIC);
-	pmu->counter_bitmask[KVM_PMC_GP] = ((u64)1 << eax.split.bit_width) - 1;
-	pmu->available_event_types = ~entry->ebx &
-					((1ull << eax.split.mask_length) - 1);
-
-	if (pmu->version == 1) {
-		pmu->nr_arch_fixed_counters = 0;
-	} else {
-		pmu->nr_arch_fixed_counters =
-			min_t(int, edx.split.num_counters_fixed,
-				INTEL_PMC_MAX_FIXED);
-		pmu->counter_bitmask[KVM_PMC_FIXED] =
-			((u64)1 << edx.split.bit_width_fixed) - 1;
-	}
+	if (vcpu->arch.apic)
+		kvm_apic_local_deliver(vcpu->arch.apic, APIC_LVTPC);
+}
 
-	pmu->global_ctrl = ((1 << pmu->nr_arch_gp_counters) - 1) |
-		(((1ull << pmu->nr_arch_fixed_counters) - 1) << INTEL_PMC_IDX_FIXED);
-	pmu->global_ctrl_mask = ~pmu->global_ctrl;
+bool kvm_pmu_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
+{
+	return kvm_x86_ops->pmu_ops->is_valid_msr(vcpu, msr);
+}
 
-	entry = kvm_find_cpuid_entry(vcpu, 7, 0);
-	if (entry &&
-	    (boot_cpu_has(X86_FEATURE_HLE) || boot_cpu_has(X86_FEATURE_RTM)) &&
-	    (entry->ebx & (X86_FEATURE_HLE|X86_FEATURE_RTM)))
-		pmu->reserved_bits ^= HSW_IN_TX|HSW_IN_TX_CHECKPOINTED;
+int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *data)
+{
+	return kvm_x86_ops->pmu_ops->get_msr(vcpu, msr, data);
 }
 
-void kvm_pmu_init(struct kvm_vcpu *vcpu)
+int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 {
-	int i;
-	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+	return kvm_x86_ops->pmu_ops->set_msr(vcpu, msr_info);
+}
 
-	memset(pmu, 0, sizeof(*pmu));
-	for (i = 0; i < INTEL_PMC_MAX_GENERIC; i++) {
-		pmu->gp_counters[i].type = KVM_PMC_GP;
-		pmu->gp_counters[i].vcpu = vcpu;
-		pmu->gp_counters[i].idx = i;
-	}
-	for (i = 0; i < INTEL_PMC_MAX_FIXED; i++) {
-		pmu->fixed_counters[i].type = KVM_PMC_FIXED;
-		pmu->fixed_counters[i].vcpu = vcpu;
-		pmu->fixed_counters[i].idx = i + INTEL_PMC_IDX_FIXED;
-	}
-	init_irq_work(&pmu->irq_work, trigger_pmi);
-	kvm_pmu_cpuid_update(vcpu);
+/* refresh PMU settings. This function generally is called when underlying
+ * settings are changed (such as changes of PMU CPUID by guest VMs), which
+ * should rarely happen.
+ */
+void kvm_pmu_refresh(struct kvm_vcpu *vcpu)
+{
+	kvm_x86_ops->pmu_ops->refresh(vcpu);
 }
 
 void kvm_pmu_reset(struct kvm_vcpu *vcpu)
 {
-	struct kvm_pmu *pmu = &vcpu->arch.pmu;
-	int i;
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
 
 	irq_work_sync(&pmu->irq_work);
-	for (i = 0; i < INTEL_PMC_MAX_GENERIC; i++) {
-		struct kvm_pmc *pmc = &pmu->gp_counters[i];
-		stop_counter(pmc);
-		pmc->counter = pmc->eventsel = 0;
-	}
+	kvm_x86_ops->pmu_ops->reset(vcpu);
+}
 
-	for (i = 0; i < INTEL_PMC_MAX_FIXED; i++)
-		stop_counter(&pmu->fixed_counters[i]);
+void kvm_pmu_init(struct kvm_vcpu *vcpu)
+{
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
 
-	pmu->fixed_ctr_ctrl = pmu->global_ctrl = pmu->global_status =
-		pmu->global_ovf_ctrl = 0;
+	memset(pmu, 0, sizeof(*pmu));
+	kvm_x86_ops->pmu_ops->init(vcpu);
+	init_irq_work(&pmu->irq_work, kvm_pmi_trigger_fn);
+	kvm_pmu_refresh(vcpu);
 }
 
 void kvm_pmu_destroy(struct kvm_vcpu *vcpu)
@@ -550,22 +306,3 @@ void kvm_pmu_destroy(struct kvm_vcpu *vcpu)
 	kvm_pmu_reset(vcpu);
 }
 
-void kvm_handle_pmu_event(struct kvm_vcpu *vcpu)
-{
-	struct kvm_pmu *pmu = &vcpu->arch.pmu;
-	u64 bitmask;
-	int bit;
-
-	bitmask = pmu->reprogram_pmi;
-
-	for_each_set_bit(bit, (unsigned long *)&bitmask, X86_PMC_IDX_MAX) {
-		struct kvm_pmc *pmc = global_idx_to_pmc(pmu, bit);
-
-		if (unlikely(!pmc || !pmc->perf_event)) {
-			clear_bit(bit, (unsigned long *)&pmu->reprogram_pmi);
-			continue;
-		}
-
-		reprogram_idx(pmu, bit);
-	}
-}
diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
new file mode 100644
index 0000000..a19a0d5
--- /dev/null
+++ b/arch/x86/kvm/pmu.h
@@ -0,0 +1,96 @@
+#ifndef __KVM_X86_PMU_H
+#define __KVM_X86_PMU_H
+
+#define vcpu_to_pmu(vcpu) (&(vcpu)->arch.pmu)
+#define pmu_to_vcpu(pmu)  (container_of((pmu), struct kvm_vcpu, arch.pmu))
+#define pmc_to_pmu(pmc)   (&(pmc)->vcpu->arch.pmu)
+
+/* retrieve the control fields of IA32_FIXED_CTR_CTRL */
+#define fixed_ctrl_field(ctrl_reg, idx) (((ctrl_reg) >> ((idx)*4)) & 0xf)
+
+static inline u64 pmc_bitmask(struct kvm_pmc *pmc)
+{
+	struct kvm_pmu *pmu = pmc_to_pmu(pmc);
+
+	return pmu->counter_bitmask[pmc->type];
+}
+
+static inline u64 pmc_read_counter(struct kvm_pmc *pmc)
+{
+	u64 counter, enabled, running;
+
+	counter = pmc->counter;
+	if (pmc->perf_event)
+		counter += perf_event_read_value(pmc->perf_event,
+						 &enabled, &running);
+	/* FIXME: Scaling needed? */
+	return counter & pmc_bitmask(pmc);
+}
+
+static inline void pmc_stop_counter(struct kvm_pmc *pmc)
+{
+	if (pmc->perf_event) {
+		pmc->counter = pmc_read_counter(pmc);
+		perf_event_release_kernel(pmc->perf_event);
+		pmc->perf_event = NULL;
+	}
+}
+
+static inline bool pmc_is_gp(struct kvm_pmc *pmc)
+{
+	return pmc->type == KVM_PMC_GP;
+}
+
+static inline bool pmc_is_fixed(struct kvm_pmc *pmc)
+{
+	return pmc->type == KVM_PMC_FIXED;
+}
+
+static inline bool pmc_is_enabled(struct kvm_pmc *pmc)
+{
+	return kvm_x86_ops->pmu_ops->pmc_enabled(pmc);
+}
+
+/* returns general purpose PMC with the specified MSR. Note that it can be
+ * used for both PERFCTRn and EVNTSELn; that is why it accepts base as a
+ * paramenter to tell them apart.
+ */
+static inline struct kvm_pmc *get_gp_pmc(struct kvm_pmu *pmu, u32 msr,
+					 u32 base)
+{
+	if (msr >= base && msr < base + pmu->nr_arch_gp_counters)
+		return &pmu->gp_counters[msr - base];
+
+	return NULL;
+}
+
+/* returns fixed PMC with the specified MSR */
+static inline struct kvm_pmc *get_fixed_pmc(struct kvm_pmu *pmu, u32 msr)
+{
+	int base = MSR_CORE_PERF_FIXED_CTR0;
+
+	if (msr >= base && msr < base + pmu->nr_arch_fixed_counters)
+		return &pmu->fixed_counters[msr - base];
+
+	return NULL;
+}
+
+void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel);
+void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 ctrl, int fixed_idx);
+void reprogram_counter(struct kvm_pmu *pmu, int pmc_idx);
+
+void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu);
+void kvm_pmu_handle_event(struct kvm_vcpu *vcpu);
+int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data);
+int kvm_pmu_is_valid_msr_idx(struct kvm_vcpu *vcpu, unsigned idx);
+bool kvm_pmu_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr);
+int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *data);
+int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
+void kvm_pmu_refresh(struct kvm_vcpu *vcpu);
+void kvm_pmu_reset(struct kvm_vcpu *vcpu);
+void kvm_pmu_init(struct kvm_vcpu *vcpu);
+void kvm_pmu_destroy(struct kvm_vcpu *vcpu);
+
+extern struct kvm_pmu_ops intel_pmu_ops;
+extern struct kvm_pmu_ops amd_pmu_ops;
+#endif /* __KVM_X86_PMU_H */
diff --git a/arch/x86/kvm/pmu_amd.c b/arch/x86/kvm/pmu_amd.c
new file mode 100644
index 0000000..388f637
--- /dev/null
+++ b/arch/x86/kvm/pmu_amd.c
@@ -0,0 +1,97 @@
+/*
+ * KVM PMU support for AMD
+ *
+ * Copyright 2015, Red Hat, Inc. and/or its affiliates.
+ *
+ * Author:
+ *   Wei Huang <wei@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ * Implementation is based on pmu_intel.c file
+ */
+#include <linux/types.h>
+#include <linux/kvm_host.h>
+#include <linux/perf_event.h>
+#include "x86.h"
+#include "cpuid.h"
+#include "lapic.h"
+#include "pmu.h"
+
+static unsigned amd_find_arch_event(struct kvm_pmu *pmu,
+				    u8 event_select,
+				    u8 unit_mask)
+{
+	return PERF_COUNT_HW_MAX;
+}
+
+/* return PERF_COUNT_HW_MAX as AMD doesn't have fixed events */
+static unsigned amd_find_fixed_event(int idx)
+{
+	return PERF_COUNT_HW_MAX;
+}
+
+static bool amd_pmc_enabled(struct kvm_pmc *pmc)
+{
+	return false;
+}
+
+static struct kvm_pmc *amd_pmc_idx_to_pmc(struct kvm_pmu *pmu, int pmc_idx)
+{
+	return NULL;
+}
+
+/* returns 0 if idx's corresponding MSR exists; otherwise returns 1. */
+static int amd_is_valid_msr_idx(struct kvm_vcpu *vcpu, unsigned idx)
+{
+	return 1;
+}
+
+/* idx is the ECX register of RDPMC instruction */
+static struct kvm_pmc *amd_msr_idx_to_pmc(struct kvm_vcpu *vcpu, unsigned idx)
+{
+	return NULL;
+}
+
+static bool amd_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
+{
+	return false;
+}
+
+static int amd_pmu_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *data)
+{
+	return 1;
+}
+
+static int amd_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
+{
+	return 1;
+}
+
+static void amd_pmu_refresh(struct kvm_vcpu *vcpu)
+{
+}
+
+static void amd_pmu_init(struct kvm_vcpu *vcpu)
+{
+}
+
+static void amd_pmu_reset(struct kvm_vcpu *vcpu)
+{
+}
+
+struct kvm_pmu_ops amd_pmu_ops = {
+	.find_arch_event = amd_find_arch_event,
+	.find_fixed_event = amd_find_fixed_event,
+	.pmc_enabled = amd_pmc_enabled,
+	.pmc_idx_to_pmc = amd_pmc_idx_to_pmc,
+	.msr_idx_to_pmc = amd_msr_idx_to_pmc,
+	.is_valid_msr_idx = amd_is_valid_msr_idx,
+	.is_valid_msr = amd_is_valid_msr,
+	.get_msr = amd_pmu_get_msr,
+	.set_msr = amd_pmu_set_msr,
+	.refresh = amd_pmu_refresh,
+	.init = amd_pmu_init,
+	.reset = amd_pmu_reset,
+};
diff --git a/arch/x86/kvm/pmu_intel.c b/arch/x86/kvm/pmu_intel.c
new file mode 100644
index 0000000..51b4729
--- /dev/null
+++ b/arch/x86/kvm/pmu_intel.c
@@ -0,0 +1,360 @@
+/*
+ * KVM PMU support for Intel CPUs
+ *
+ * Copyright 2011 Red Hat, Inc. and/or its affiliates.
+ *
+ * Authors:
+ *   Avi Kivity   <avi@redhat.com>
+ *   Gleb Natapov <gleb@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#include <linux/types.h>
+#include <linux/kvm_host.h>
+#include <linux/perf_event.h>
+#include <asm/perf_event.h>
+#include "x86.h"
+#include "cpuid.h"
+#include "lapic.h"
+#include "pmu.h"
+
+static struct kvm_event_hw_type_mapping intel_arch_events[] = {
+	/* Index must match CPUID 0x0A.EBX bit vector */
+	[0] = { 0x3c, 0x00, PERF_COUNT_HW_CPU_CYCLES },
+	[1] = { 0xc0, 0x00, PERF_COUNT_HW_INSTRUCTIONS },
+	[2] = { 0x3c, 0x01, PERF_COUNT_HW_BUS_CYCLES  },
+	[3] = { 0x2e, 0x4f, PERF_COUNT_HW_CACHE_REFERENCES },
+	[4] = { 0x2e, 0x41, PERF_COUNT_HW_CACHE_MISSES },
+	[5] = { 0xc4, 0x00, PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
+	[6] = { 0xc5, 0x00, PERF_COUNT_HW_BRANCH_MISSES },
+	[7] = { 0x00, 0x30, PERF_COUNT_HW_REF_CPU_CYCLES },
+};
+
+/* mapping between fixed pmc index and intel_arch_events array */
+static int fixed_pmc_events[] = {1, 0, 7};
+
+static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data)
+{
+	int i;
+
+	for (i = 0; i < pmu->nr_arch_fixed_counters; i++) {
+		u8 new_ctrl = fixed_ctrl_field(data, i);
+		u8 old_ctrl = fixed_ctrl_field(pmu->fixed_ctr_ctrl, i);
+		struct kvm_pmc *pmc;
+
+		pmc = get_fixed_pmc(pmu, MSR_CORE_PERF_FIXED_CTR0 + i);
+
+		if (old_ctrl == new_ctrl)
+			continue;
+
+		reprogram_fixed_counter(pmc, new_ctrl, i);
+	}
+
+	pmu->fixed_ctr_ctrl = data;
+}
+
+/* function is called when global control register has been updated. */
+static void global_ctrl_changed(struct kvm_pmu *pmu, u64 data)
+{
+	int bit;
+	u64 diff = pmu->global_ctrl ^ data;
+
+	pmu->global_ctrl = data;
+
+	for_each_set_bit(bit, (unsigned long *)&diff, X86_PMC_IDX_MAX) {
+		reprogram_counter(pmu, bit);
+	}
+}
+
+static unsigned intel_find_arch_event(struct kvm_pmu *pmu,
+				      u8 event_select,
+				      u8 unit_mask)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(intel_arch_events); i++)
+		if (intel_arch_events[i].eventsel == event_select
+		    && intel_arch_events[i].unit_mask == unit_mask
+		    && (pmu->available_event_types & (1 << i)))
+			break;
+
+	if (i == ARRAY_SIZE(intel_arch_events))
+		return PERF_COUNT_HW_MAX;
+
+	return intel_arch_events[i].event_type;
+}
+
+static unsigned intel_find_fixed_event(int idx)
+{
+
+	if (idx >= ARRAY_SIZE(fixed_pmc_events))
+		return PERF_COUNT_HW_MAX;
+
+	return intel_arch_events[fixed_pmc_events[idx]].event_type;
+}
+
+/* check if a PMC is enabled by comparising it with globl_ctrl bits. */
+static bool intel_pmc_enabled(struct kvm_pmc *pmc)
+{
+	struct kvm_pmu *pmu = pmc_to_pmu(pmc);
+
+	return test_bit(pmc->idx, (unsigned long *)&pmu->global_ctrl);
+}
+
+static struct kvm_pmc *intel_pmc_idx_to_pmc(struct kvm_pmu *pmu, int pmc_idx)
+{
+	if (pmc_idx < INTEL_PMC_IDX_FIXED)
+		return get_gp_pmc(pmu, MSR_P6_EVNTSEL0 + pmc_idx,
+				  MSR_P6_EVNTSEL0);
+	else {
+		u32 idx = pmc_idx - INTEL_PMC_IDX_FIXED;
+
+		return get_fixed_pmc(pmu, idx + MSR_CORE_PERF_FIXED_CTR0);
+	}
+}
+
+/* returns 0 if idx's corresponding MSR exists; otherwise returns 1. */
+static int intel_is_valid_msr_idx(struct kvm_vcpu *vcpu, unsigned idx)
+{
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+	bool fixed = idx & (1u << 30);
+
+	idx &= ~(3u << 30);
+
+	return (!fixed && idx >= pmu->nr_arch_gp_counters) ||
+		(fixed && idx >= pmu->nr_arch_fixed_counters);
+}
+
+static struct kvm_pmc *intel_msr_idx_to_pmc(struct kvm_vcpu *vcpu,
+					    unsigned idx)
+{
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+	bool fixed = idx & (1u << 30);
+	struct kvm_pmc *counters;
+
+	idx &= ~(3u << 30);
+	if (!fixed && idx >= pmu->nr_arch_gp_counters)
+		return NULL;
+	if (fixed && idx >= pmu->nr_arch_fixed_counters)
+		return NULL;
+	counters = fixed ? pmu->fixed_counters : pmu->gp_counters;
+
+	return &counters[idx];
+}
+
+static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
+{
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+	int ret;
+
+	switch (msr) {
+	case MSR_CORE_PERF_FIXED_CTR_CTRL:
+	case MSR_CORE_PERF_GLOBAL_STATUS:
+	case MSR_CORE_PERF_GLOBAL_CTRL:
+	case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
+		ret = pmu->version > 1;
+		break;
+	default:
+		ret = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0) ||
+			get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0) ||
+			get_fixed_pmc(pmu, msr);
+		break;
+	}
+
+	return ret;
+}
+
+static int intel_pmu_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *data)
+{
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+	struct kvm_pmc *pmc;
+
+	switch (msr) {
+	case MSR_CORE_PERF_FIXED_CTR_CTRL:
+		*data = pmu->fixed_ctr_ctrl;
+		return 0;
+	case MSR_CORE_PERF_GLOBAL_STATUS:
+		*data = pmu->global_status;
+		return 0;
+	case MSR_CORE_PERF_GLOBAL_CTRL:
+		*data = pmu->global_ctrl;
+		return 0;
+	case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
+		*data = pmu->global_ovf_ctrl;
+		return 0;
+	default:
+		if ((pmc = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0)) ||
+		    (pmc = get_fixed_pmc(pmu, msr))) {
+			*data = pmc_read_counter(pmc);
+			return 0;
+		} else if ((pmc = get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0))) {
+			*data = pmc->eventsel;
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
+{
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+	struct kvm_pmc *pmc;
+	u32 msr = msr_info->index;
+	u64 data = msr_info->data;
+
+	switch (msr) {
+	case MSR_CORE_PERF_FIXED_CTR_CTRL:
+		if (pmu->fixed_ctr_ctrl == data)
+			return 0;
+		if (!(data & 0xfffffffffffff444ull)) {
+			reprogram_fixed_counters(pmu, data);
+			return 0;
+		}
+		break;
+	case MSR_CORE_PERF_GLOBAL_STATUS:
+		if (msr_info->host_initiated) {
+			pmu->global_status = data;
+			return 0;
+		}
+		break; /* RO MSR */
+	case MSR_CORE_PERF_GLOBAL_CTRL:
+		if (pmu->global_ctrl == data)
+			return 0;
+		if (!(data & pmu->global_ctrl_mask)) {
+			global_ctrl_changed(pmu, data);
+			return 0;
+		}
+		break;
+	case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
+		if (!(data & (pmu->global_ctrl_mask & ~(3ull<<62)))) {
+			if (!msr_info->host_initiated)
+				pmu->global_status &= ~data;
+			pmu->global_ovf_ctrl = data;
+			return 0;
+		}
+		break;
+	default:
+		if ((pmc = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0)) ||
+		    (pmc = get_fixed_pmc(pmu, msr))) {
+			if (!msr_info->host_initiated)
+				data = (s64)(s32)data;
+			pmc->counter += data - pmc_read_counter(pmc);
+			return 0;
+		} else if ((pmc = get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0))) {
+			if (data == pmc->eventsel)
+				return 0;
+			if (!(data & pmu->reserved_bits)) {
+				reprogram_gp_counter(pmc, data);
+				return 0;
+			}
+		}
+	}
+
+	return 1;
+}
+
+static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
+{
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+	struct kvm_cpuid_entry2 *entry;
+	union cpuid10_eax eax;
+	union cpuid10_edx edx;
+
+	pmu->nr_arch_gp_counters = 0;
+	pmu->nr_arch_fixed_counters = 0;
+	pmu->counter_bitmask[KVM_PMC_GP] = 0;
+	pmu->counter_bitmask[KVM_PMC_FIXED] = 0;
+	pmu->version = 0;
+	pmu->reserved_bits = 0xffffffff00200000ull;
+
+	entry = kvm_find_cpuid_entry(vcpu, 0xa, 0);
+	if (!entry)
+		return;
+	eax.full = entry->eax;
+	edx.full = entry->edx;
+
+	pmu->version = eax.split.version_id;
+	if (!pmu->version)
+		return;
+
+	pmu->nr_arch_gp_counters = min_t(int, eax.split.num_counters,
+					INTEL_PMC_MAX_GENERIC);
+	pmu->counter_bitmask[KVM_PMC_GP] = ((u64)1 << eax.split.bit_width) - 1;
+	pmu->available_event_types = ~entry->ebx &
+					((1ull << eax.split.mask_length) - 1);
+
+	if (pmu->version == 1) {
+		pmu->nr_arch_fixed_counters = 0;
+	} else {
+		pmu->nr_arch_fixed_counters =
+			min_t(int, edx.split.num_counters_fixed,
+				INTEL_PMC_MAX_FIXED);
+		pmu->counter_bitmask[KVM_PMC_FIXED] =
+			((u64)1 << edx.split.bit_width_fixed) - 1;
+	}
+
+	pmu->global_ctrl = ((1 << pmu->nr_arch_gp_counters) - 1) |
+		(((1ull << pmu->nr_arch_fixed_counters) - 1) << INTEL_PMC_IDX_FIXED);
+	pmu->global_ctrl_mask = ~pmu->global_ctrl;
+
+	entry = kvm_find_cpuid_entry(vcpu, 7, 0);
+	if (entry &&
+	    (boot_cpu_has(X86_FEATURE_HLE) || boot_cpu_has(X86_FEATURE_RTM)) &&
+	    (entry->ebx & (X86_FEATURE_HLE|X86_FEATURE_RTM)))
+		pmu->reserved_bits ^= HSW_IN_TX|HSW_IN_TX_CHECKPOINTED;
+}
+
+static void intel_pmu_init(struct kvm_vcpu *vcpu)
+{
+	int i;
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+
+	for (i = 0; i < INTEL_PMC_MAX_GENERIC; i++) {
+		pmu->gp_counters[i].type = KVM_PMC_GP;
+		pmu->gp_counters[i].vcpu = vcpu;
+		pmu->gp_counters[i].idx = i;
+	}
+
+	for (i = 0; i < INTEL_PMC_MAX_FIXED; i++) {
+		pmu->fixed_counters[i].type = KVM_PMC_FIXED;
+		pmu->fixed_counters[i].vcpu = vcpu;
+		pmu->fixed_counters[i].idx = i + INTEL_PMC_IDX_FIXED;
+	}
+}
+
+static void intel_pmu_reset(struct kvm_vcpu *vcpu)
+{
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+	int i;
+
+	for (i = 0; i < INTEL_PMC_MAX_GENERIC; i++) {
+		struct kvm_pmc *pmc = &pmu->gp_counters[i];
+
+		pmc_stop_counter(pmc);
+		pmc->counter = pmc->eventsel = 0;
+	}
+
+	for (i = 0; i < INTEL_PMC_MAX_FIXED; i++)
+		pmc_stop_counter(&pmu->fixed_counters[i]);
+
+	pmu->fixed_ctr_ctrl = pmu->global_ctrl = pmu->global_status =
+		pmu->global_ovf_ctrl = 0;
+}
+
+struct kvm_pmu_ops intel_pmu_ops = {
+	.find_arch_event = intel_find_arch_event,
+	.find_fixed_event = intel_find_fixed_event,
+	.pmc_enabled = intel_pmc_enabled,
+	.pmc_idx_to_pmc = intel_pmc_idx_to_pmc,
+	.msr_idx_to_pmc = intel_msr_idx_to_pmc,
+	.is_valid_msr_idx = intel_is_valid_msr_idx,
+	.is_valid_msr = intel_is_valid_msr,
+	.get_msr = intel_pmu_get_msr,
+	.set_msr = intel_pmu_set_msr,
+	.refresh = intel_pmu_refresh,
+	.init = intel_pmu_init,
+	.reset = intel_pmu_reset,
+};
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 6807531..c8e9e67 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -21,6 +21,7 @@
 #include "kvm_cache_regs.h"
 #include "x86.h"
 #include "cpuid.h"
+#include "pmu.h"
 
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
@@ -4453,6 +4454,8 @@ static struct kvm_x86_ops svm_x86_ops = {
 	.handle_external_intr = svm_handle_external_intr,
 
 	.sched_in = svm_sched_in,
+
+	.pmu_ops = &amd_pmu_ops,
 };
 
 static int __init svm_init(void)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 06a186b..e5ca9eb 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -48,6 +48,7 @@
 #include <asm/apic.h>
 
 #include "trace.h"
+#include "pmu.h"
 
 #define __ex(x) __kvm_handle_fault_on_reboot(x)
 #define __ex_clear(x, reg) \
@@ -10407,6 +10408,8 @@ static struct kvm_x86_ops vmx_x86_ops = {
 	.slot_disable_log_dirty = vmx_slot_disable_log_dirty,
 	.flush_log_dirty = vmx_flush_log_dirty,
 	.enable_log_dirty_pt_masked = vmx_enable_log_dirty_pt_masked,
+
+	.pmu_ops = &intel_pmu_ops,
 };
 
 static int __init vmx_init(void)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 43f0df7..a2a3356 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -28,6 +28,7 @@
 #include "x86.h"
 #include "cpuid.h"
 #include "assigned-dev.h"
+#include "pmu.h"
 
 #include <linux/clocksource.h>
 #include <linux/interrupt.h>
@@ -910,7 +911,7 @@ bool kvm_rdpmc(struct kvm_vcpu *vcpu)
 	u64 data;
 	int err;
 
-	err = kvm_pmu_read_pmc(vcpu, ecx, &data);
+	err = kvm_pmu_rdpmc(vcpu, ecx, &data);
 	if (err)
 		return err;
 	kvm_register_write(vcpu, VCPU_REGS_RAX, (u32)data);
@@ -2401,7 +2402,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 		pr = true;
 	case MSR_P6_EVNTSEL0:
 	case MSR_P6_EVNTSEL1:
-		if (kvm_pmu_msr(vcpu, msr))
+		if (kvm_pmu_is_valid_msr(vcpu, msr))
 			return kvm_pmu_set_msr(vcpu, msr_info);
 
 		if (pr || data != 0)
@@ -2447,7 +2448,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 	default:
 		if (msr && (msr == vcpu->kvm->arch.xen_hvm_config.msr))
 			return xen_hvm_config(vcpu, data);
-		if (kvm_pmu_msr(vcpu, msr))
+		if (kvm_pmu_is_valid_msr(vcpu, msr))
 			return kvm_pmu_set_msr(vcpu, msr_info);
 		if (!ignore_msrs) {
 			vcpu_unimpl(vcpu, "unhandled wrmsr: 0x%x data %llx\n",
@@ -2641,7 +2642,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 	case MSR_P6_PERFCTR1:
 	case MSR_P6_EVNTSEL0:
 	case MSR_P6_EVNTSEL1:
-		if (kvm_pmu_msr(vcpu, msr_info->index))
+		if (kvm_pmu_is_valid_msr(vcpu, msr_info->index))
 			return kvm_pmu_get_msr(vcpu, msr_info->index, &msr_info->data);
 		msr_info->data = 0;
 		break;
@@ -2769,7 +2770,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 		msr_info->data = vcpu->arch.osvw.status;
 		break;
 	default:
-		if (kvm_pmu_msr(vcpu, msr_info->index))
+		if (kvm_pmu_is_valid_msr(vcpu, msr_info->index))
 			return kvm_pmu_get_msr(vcpu, msr_info->index, &msr_info->data);
 		if (!ignore_msrs) {
 			vcpu_unimpl(vcpu, "unhandled rdmsr: 0x%x\n", msr_info->index);
@@ -5174,13 +5175,13 @@ static void emulator_set_smbase(struct x86_emulate_ctxt *ctxt, u64 smbase)
 static int emulator_check_pmc(struct x86_emulate_ctxt *ctxt,
 			      u32 pmc)
 {
-	return kvm_pmu_check_pmc(emul_to_vcpu(ctxt), pmc);
+	return kvm_pmu_is_valid_msr_idx(emul_to_vcpu(ctxt), pmc);
 }
 
 static int emulator_read_pmc(struct x86_emulate_ctxt *ctxt,
 			     u32 pmc, u64 *pdata)
 {
-	return kvm_pmu_read_pmc(emul_to_vcpu(ctxt), pmc, pdata);
+	return kvm_pmu_rdpmc(emul_to_vcpu(ctxt), pmc, pdata);
 }
 
 static void emulator_halt(struct x86_emulate_ctxt *ctxt)
@@ -6750,9 +6751,9 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 		if (kvm_check_request(KVM_REQ_NMI, vcpu))
 			process_nmi(vcpu);
 		if (kvm_check_request(KVM_REQ_PMU, vcpu))
-			kvm_handle_pmu_event(vcpu);
+			kvm_pmu_handle_event(vcpu);
 		if (kvm_check_request(KVM_REQ_PMI, vcpu))
-			kvm_deliver_pmi(vcpu);
+			kvm_pmu_deliver_pmi(vcpu);
 		if (kvm_check_request(KVM_REQ_SCAN_IOAPIC, vcpu))
 			vcpu_scan_ioapic(vcpu);
 		if (kvm_check_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu))
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH V5 3/4] KVM: x86/vPMU: Implement AMD vPMU code for KVM
  2015-06-12  5:34 [PATCH V5 0/4] Consolidated KVM vPMU support for x86 Wei Huang
  2015-06-12  5:34 ` [PATCH V5 1/4] KVM: x86/vPMU: Define kvm_pmu_ops to support vPMU function dispatch Wei Huang
  2015-06-12  5:34 ` [PATCH V5 2/4] KVM: x86/vPMU: Create vPMU interface for VMX and SVM Wei Huang
@ 2015-06-12  5:34 ` Wei Huang
  2015-06-12  5:34 ` [PATCH V5 4/4] KVM: x86/vPMU: Enable PMU handling for AMD PERFCTRn and EVNTSELn MSRs Wei Huang
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: Wei Huang @ 2015-06-12  5:34 UTC (permalink / raw)
  To: kvm, x86, pbonzini, gleb, rkrcmar, joro

This patch replaces the empty AMD vPMU functions (in pmu_amd.c) with real
implementation.

Reviewed-by: Joerg Roedel <jroedel@suse.de>
Tested-by: Joerg Roedel <jroedel@suse.de>
Signed-off-by: Wei Huang <wei@redhat.com>
---
 arch/x86/kvm/pmu_amd.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 116 insertions(+), 6 deletions(-)

diff --git a/arch/x86/kvm/pmu_amd.c b/arch/x86/kvm/pmu_amd.c
index 388f637..ff5cea7 100644
--- a/arch/x86/kvm/pmu_amd.c
+++ b/arch/x86/kvm/pmu_amd.c
@@ -19,11 +19,33 @@
 #include "lapic.h"
 #include "pmu.h"
 
+/* duplicated from amd_perfmon_event_map, K7 and above should work. */
+static struct kvm_event_hw_type_mapping amd_event_mapping[] = {
+	[0] = { 0x76, 0x00, PERF_COUNT_HW_CPU_CYCLES },
+	[1] = { 0xc0, 0x00, PERF_COUNT_HW_INSTRUCTIONS },
+	[2] = { 0x80, 0x00, PERF_COUNT_HW_CACHE_REFERENCES },
+	[3] = { 0x81, 0x00, PERF_COUNT_HW_CACHE_MISSES },
+	[4] = { 0xc2, 0x00, PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
+	[5] = { 0xc3, 0x00, PERF_COUNT_HW_BRANCH_MISSES },
+	[6] = { 0xd0, 0x00, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND },
+	[7] = { 0xd1, 0x00, PERF_COUNT_HW_STALLED_CYCLES_BACKEND },
+};
+
 static unsigned amd_find_arch_event(struct kvm_pmu *pmu,
 				    u8 event_select,
 				    u8 unit_mask)
 {
-	return PERF_COUNT_HW_MAX;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(amd_event_mapping); i++)
+		if (amd_event_mapping[i].eventsel == event_select
+		    && amd_event_mapping[i].unit_mask == unit_mask)
+			break;
+
+	if (i == ARRAY_SIZE(amd_event_mapping))
+		return PERF_COUNT_HW_MAX;
+
+	return amd_event_mapping[i].event_type;
 }
 
 /* return PERF_COUNT_HW_MAX as AMD doesn't have fixed events */
@@ -32,53 +54,141 @@ static unsigned amd_find_fixed_event(int idx)
 	return PERF_COUNT_HW_MAX;
 }
 
+/* check if a PMC is enabled by comparing it against global_ctrl bits. Because
+ * AMD CPU doesn't have global_ctrl MSR, all PMCs are enabled (return TRUE).
+ */
 static bool amd_pmc_enabled(struct kvm_pmc *pmc)
 {
-	return false;
+	return true;
 }
 
 static struct kvm_pmc *amd_pmc_idx_to_pmc(struct kvm_pmu *pmu, int pmc_idx)
 {
-	return NULL;
+	return get_gp_pmc(pmu, MSR_K7_EVNTSEL0 + pmc_idx, MSR_K7_EVNTSEL0);
 }
 
 /* returns 0 if idx's corresponding MSR exists; otherwise returns 1. */
 static int amd_is_valid_msr_idx(struct kvm_vcpu *vcpu, unsigned idx)
 {
-	return 1;
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+
+	idx &= ~(3u << 30);
+
+	return (idx >= pmu->nr_arch_gp_counters);
 }
 
 /* idx is the ECX register of RDPMC instruction */
 static struct kvm_pmc *amd_msr_idx_to_pmc(struct kvm_vcpu *vcpu, unsigned idx)
 {
-	return NULL;
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+	struct kvm_pmc *counters;
+
+	idx &= ~(3u << 30);
+	if (idx >= pmu->nr_arch_gp_counters)
+		return NULL;
+	counters = pmu->gp_counters;
+
+	return &counters[idx];
 }
 
 static bool amd_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
 {
-	return false;
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+	int ret = false;
+
+	ret = get_gp_pmc(pmu, msr, MSR_K7_PERFCTR0) ||
+		get_gp_pmc(pmu, msr, MSR_K7_EVNTSEL0);
+
+	return ret;
 }
 
 static int amd_pmu_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *data)
 {
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+	struct kvm_pmc *pmc;
+
+	/* MSR_K7_PERFCTRn */
+	pmc = get_gp_pmc(pmu, msr, MSR_K7_PERFCTR0);
+	if (pmc) {
+		*data = pmc_read_counter(pmc);
+		return 0;
+	}
+	/* MSR_K7_EVNTSELn */
+	pmc = get_gp_pmc(pmu, msr, MSR_K7_EVNTSEL0);
+	if (pmc) {
+		*data = pmc->eventsel;
+		return 0;
+	}
+
 	return 1;
 }
 
 static int amd_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 {
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+	struct kvm_pmc *pmc;
+	u32 msr = msr_info->index;
+	u64 data = msr_info->data;
+
+	/* MSR_K7_PERFCTRn */
+	pmc = get_gp_pmc(pmu, msr, MSR_K7_PERFCTR0);
+	if (pmc) {
+		if (!msr_info->host_initiated)
+			data = (s64)data;
+		pmc->counter += data - pmc_read_counter(pmc);
+		return 0;
+	}
+	/* MSR_K7_EVNTSELn */
+	pmc = get_gp_pmc(pmu, msr, MSR_K7_EVNTSEL0);
+	if (pmc) {
+		if (data == pmc->eventsel)
+			return 0;
+		if (!(data & pmu->reserved_bits)) {
+			reprogram_gp_counter(pmc, data);
+			return 0;
+		}
+	}
+
 	return 1;
 }
 
 static void amd_pmu_refresh(struct kvm_vcpu *vcpu)
 {
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+
+	pmu->nr_arch_gp_counters = AMD64_NUM_COUNTERS;
+	pmu->counter_bitmask[KVM_PMC_GP] = ((u64)1 << 48) - 1;
+	pmu->reserved_bits = 0xffffffff00200000ull;
+	/* not applicable to AMD; but clean them to prevent any fall out */
+	pmu->counter_bitmask[KVM_PMC_FIXED] = 0;
+	pmu->nr_arch_fixed_counters = 0;
+	pmu->version = 0;
+	pmu->global_status = 0;
 }
 
 static void amd_pmu_init(struct kvm_vcpu *vcpu)
 {
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+	int i;
+
+	for (i = 0; i < AMD64_NUM_COUNTERS ; i++) {
+		pmu->gp_counters[i].type = KVM_PMC_GP;
+		pmu->gp_counters[i].vcpu = vcpu;
+		pmu->gp_counters[i].idx = i;
+	}
 }
 
 static void amd_pmu_reset(struct kvm_vcpu *vcpu)
 {
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+	int i;
+
+	for (i = 0; i < AMD64_NUM_COUNTERS; i++) {
+		struct kvm_pmc *pmc = &pmu->gp_counters[i];
+
+		pmc_stop_counter(pmc);
+		pmc->counter = pmc->eventsel = 0;
+	}
 }
 
 struct kvm_pmu_ops amd_pmu_ops = {
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH V5 4/4] KVM: x86/vPMU: Enable PMU handling for AMD PERFCTRn and EVNTSELn MSRs
  2015-06-12  5:34 [PATCH V5 0/4] Consolidated KVM vPMU support for x86 Wei Huang
                   ` (2 preceding siblings ...)
  2015-06-12  5:34 ` [PATCH V5 3/4] KVM: x86/vPMU: Implement AMD vPMU code for KVM Wei Huang
@ 2015-06-12  5:34 ` Wei Huang
  2015-06-16 15:41 ` [PATCH V5 0/4] Consolidated KVM vPMU support for x86 Joerg Roedel
  2015-06-19 15:14 ` Paolo Bonzini
  5 siblings, 0 replies; 13+ messages in thread
From: Wei Huang @ 2015-06-12  5:34 UTC (permalink / raw)
  To: kvm, x86, pbonzini, gleb, rkrcmar, joro

This patch enables AMD guest VM to access (R/W) PMU related MSRs, which
include PERFCTR[0..3] and EVNTSEL[0..3].

Reviewed-by: Joerg Roedel <jroedel@suse.de>
Tested-by: Joerg Roedel <jroedel@suse.de>
Reviewed-by: Radim Krčmář <rkrcmar@redhat.com>
Signed-off-by: Wei Huang <wei@redhat.com>
---
 arch/x86/kvm/x86.c | 51 +++++++++------------------------------------------
 1 file changed, 9 insertions(+), 42 deletions(-)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index a2a3356..597db31 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2372,36 +2372,11 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 	case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_CTL(KVM_MAX_MCE_BANKS) - 1:
 		return set_msr_mce(vcpu, msr, data);
 
-	/* Performance counters are not protected by a CPUID bit,
-	 * so we should check all of them in the generic path for the sake of
-	 * cross vendor migration.
-	 * Writing a zero into the event select MSRs disables them,
-	 * which we perfectly emulate ;-). Any other value should be at least
-	 * reported, some guests depend on them.
-	 */
-	case MSR_K7_EVNTSEL0:
-	case MSR_K7_EVNTSEL1:
-	case MSR_K7_EVNTSEL2:
-	case MSR_K7_EVNTSEL3:
-		if (data != 0)
-			vcpu_unimpl(vcpu, "unimplemented perfctr wrmsr: "
-				    "0x%x data 0x%llx\n", msr, data);
-		break;
-	/* at least RHEL 4 unconditionally writes to the perfctr registers,
-	 * so we ignore writes to make it happy.
-	 */
-	case MSR_K7_PERFCTR0:
-	case MSR_K7_PERFCTR1:
-	case MSR_K7_PERFCTR2:
-	case MSR_K7_PERFCTR3:
-		vcpu_unimpl(vcpu, "unimplemented perfctr wrmsr: "
-			    "0x%x data 0x%llx\n", msr, data);
-		break;
-	case MSR_P6_PERFCTR0:
-	case MSR_P6_PERFCTR1:
-		pr = true;
-	case MSR_P6_EVNTSEL0:
-	case MSR_P6_EVNTSEL1:
+	case MSR_K7_PERFCTR0 ... MSR_K7_PERFCTR3:
+	case MSR_P6_PERFCTR0 ... MSR_P6_PERFCTR1:
+		pr = true; /* fall through */
+	case MSR_K7_EVNTSEL0 ... MSR_K7_EVNTSEL3:
+	case MSR_P6_EVNTSEL0 ... MSR_P6_EVNTSEL1:
 		if (kvm_pmu_is_valid_msr(vcpu, msr))
 			return kvm_pmu_set_msr(vcpu, msr_info);
 
@@ -2624,24 +2599,16 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 	case MSR_K8_SYSCFG:
 	case MSR_K7_HWCR:
 	case MSR_VM_HSAVE_PA:
-	case MSR_K7_EVNTSEL0:
-	case MSR_K7_EVNTSEL1:
-	case MSR_K7_EVNTSEL2:
-	case MSR_K7_EVNTSEL3:
-	case MSR_K7_PERFCTR0:
-	case MSR_K7_PERFCTR1:
-	case MSR_K7_PERFCTR2:
-	case MSR_K7_PERFCTR3:
 	case MSR_K8_INT_PENDING_MSG:
 	case MSR_AMD64_NB_CFG:
 	case MSR_FAM10H_MMIO_CONF_BASE:
 	case MSR_AMD64_BU_CFG2:
 		msr_info->data = 0;
 		break;
-	case MSR_P6_PERFCTR0:
-	case MSR_P6_PERFCTR1:
-	case MSR_P6_EVNTSEL0:
-	case MSR_P6_EVNTSEL1:
+	case MSR_K7_EVNTSEL0 ... MSR_K7_EVNTSEL3:
+	case MSR_K7_PERFCTR0 ... MSR_K7_PERFCTR3:
+	case MSR_P6_PERFCTR0 ... MSR_P6_PERFCTR1:
+	case MSR_P6_EVNTSEL0 ... MSR_P6_EVNTSEL1:
 		if (kvm_pmu_is_valid_msr(vcpu, msr_info->index))
 			return kvm_pmu_get_msr(vcpu, msr_info->index, &msr_info->data);
 		msr_info->data = 0;
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH V5 2/4] KVM: x86/vPMU: Create vPMU interface for VMX and SVM
  2015-06-12  5:34 ` [PATCH V5 2/4] KVM: x86/vPMU: Create vPMU interface for VMX and SVM Wei Huang
@ 2015-06-16 15:40   ` Joerg Roedel
  2015-06-19 11:31   ` Paolo Bonzini
  1 sibling, 0 replies; 13+ messages in thread
From: Joerg Roedel @ 2015-06-16 15:40 UTC (permalink / raw)
  To: Wei Huang; +Cc: kvm, x86, pbonzini, gleb, rkrcmar

On Fri, Jun 12, 2015 at 01:34:54AM -0400, Wei Huang wrote:
> This patch splits existing vPMU code into a common vPMU interface (pmc.c)
> and Intel specific vPMU code (pmu_intel.c) using the following steps:
> 
> - Part of arechitectural vPMU code is extracted and moved to pmu_intel.c
>   file. They are hooked up with the newly-defined intel_pmu_ops, which will
>   be called from pmu interface;
> - Create a dummy pmu_amd.c file for AMD SVM with empty functions;
> 
> All architectural vPMU functions are now called via PMU function dispatcher.
> This function dispatcher is defined in kvm_x86_ops->pmu_ops, which is
> initialized by sub-arch. Also note that Intel and AMD modules are now
> generated by combinig their corresponding arch files (vmx.c/svm.c) and pmu
> files (pmu_intel.c/pmu_amd.c).
> 
> Tested-by: Radim Krčmář <rkrcmar@redhat.com>
> Signed-off-by: Wei Huang <wei@redhat.com>

Reviewed-by: Joerg Roedel <jroedel@suse.de>


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH V5 0/4] Consolidated KVM vPMU support for x86
  2015-06-12  5:34 [PATCH V5 0/4] Consolidated KVM vPMU support for x86 Wei Huang
                   ` (3 preceding siblings ...)
  2015-06-12  5:34 ` [PATCH V5 4/4] KVM: x86/vPMU: Enable PMU handling for AMD PERFCTRn and EVNTSELn MSRs Wei Huang
@ 2015-06-16 15:41 ` Joerg Roedel
  2015-06-19 15:14 ` Paolo Bonzini
  5 siblings, 0 replies; 13+ messages in thread
From: Joerg Roedel @ 2015-06-16 15:41 UTC (permalink / raw)
  To: Wei Huang; +Cc: kvm, x86, pbonzini, gleb, rkrcmar

On Fri, Jun 12, 2015 at 01:34:52AM -0400, Wei Huang wrote:
> This patchset is directlyh applicable on kvm.git/queue.
> 
> V5:
>   * Remove the get_pmu_ops from sub_arch; instead define pmu dispatcher
>     in kvm_x86_ops->pmu_ops. The dispatcher is initialized in sub-arch.
>     The PMU interface functions are changed accordingly (suggested by 
>     Joerg Rodel).

Tested it again, works like a charm on my AMD system :) So for all patches
again:

	Tested-by: Joerg Roedel <jroedel@suse.de>


Thanks,

	Joerg


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH V5 1/4] KVM: x86/vPMU: Define kvm_pmu_ops to support vPMU function dispatch
  2015-06-12  5:34 ` [PATCH V5 1/4] KVM: x86/vPMU: Define kvm_pmu_ops to support vPMU function dispatch Wei Huang
@ 2015-06-19 11:30   ` Paolo Bonzini
  2015-06-19 14:34     ` Wei Huang
  0 siblings, 1 reply; 13+ messages in thread
From: Paolo Bonzini @ 2015-06-19 11:30 UTC (permalink / raw)
  To: Wei Huang, kvm, x86, gleb, rkrcmar, joro



On 12/06/2015 07:34, Wei Huang wrote:
> This patch defines a new function pointer struct (kvm_pmu_ops) to
> support vPMU for both Intel and AMD. The functions pointers defined in
> this new struct will be linked with Intel and AMD functions later. In the
> meanwhile the struct that maps from event_sel bits to PERF_TYPE_HARDWARE
> events is renamed and moved from Intel specific code to kvm_host.h as a
> common struct.
> 
> Reviewed-by: Joerg Roedel <jroedel@suse.de>
> Tested-by: Joerg Roedel <jroedel@suse.de>
> Signed-off-by: Wei Huang <wei@redhat.com>

The kvm_pmu_ops are unused and would belong in patch 2... the code is
good anyway, and I'm not going to be fussy about it because there's no
semantic change anyway in this patch.

Paolo

> ---
>  arch/x86/include/asm/kvm_host.h | 34 ++++++++++++++++++++++++++++------
>  arch/x86/kvm/pmu.c              | 21 ++++++++-------------
>  2 files changed, 36 insertions(+), 19 deletions(-)
> 
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index 8ca32cf..82dc7cc 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -304,6 +304,12 @@ struct kvm_mmu {
>  	u64 pdptrs[4]; /* pae */
>  };
>  
> +struct msr_data {
> +	bool host_initiated;
> +	u32 index;
> +	u64 data;
> +};
> +
>  enum pmc_type {
>  	KVM_PMC_GP = 0,
>  	KVM_PMC_FIXED,
> @@ -318,6 +324,12 @@ struct kvm_pmc {
>  	struct kvm_vcpu *vcpu;
>  };
>  
> +struct kvm_event_hw_type_mapping {
> +	u8 eventsel;
> +	u8 unit_mask;
> +	unsigned event_type;
> +};
> +
>  struct kvm_pmu {
>  	unsigned nr_arch_gp_counters;
>  	unsigned nr_arch_fixed_counters;
> @@ -336,6 +348,22 @@ struct kvm_pmu {
>  	u64 reprogram_pmi;
>  };
>  
> +struct kvm_pmu_ops {
> +	unsigned (*find_arch_event)(struct kvm_pmu *pmu, u8 event_select,
> +				    u8 unit_mask);
> +	unsigned (*find_fixed_event)(int idx);
> +	bool (*pmc_enabled)(struct kvm_pmc *pmc);
> +	struct kvm_pmc *(*pmc_idx_to_pmc)(struct kvm_pmu *pmu, int pmc_idx);
> +	struct kvm_pmc *(*msr_idx_to_pmc)(struct kvm_vcpu *vcpu, unsigned idx);
> +	int (*is_valid_msr_idx)(struct kvm_vcpu *vcpu, unsigned idx);
> +	bool (*is_valid_msr)(struct kvm_vcpu *vcpu, u32 msr);
> +	int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr, u64 *data);
> +	int (*set_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
> +	void (*refresh)(struct kvm_vcpu *vcpu);
> +	void (*init)(struct kvm_vcpu *vcpu);
> +	void (*reset)(struct kvm_vcpu *vcpu);
> +};
> +
>  enum {
>  	KVM_DEBUGREG_BP_ENABLED = 1,
>  	KVM_DEBUGREG_WONT_EXIT = 2,
> @@ -683,12 +711,6 @@ struct kvm_vcpu_stat {
>  
>  struct x86_instruction_info;
>  
> -struct msr_data {
> -	bool host_initiated;
> -	u32 index;
> -	u64 data;
> -};
> -
>  struct kvm_lapic_irq {
>  	u32 vector;
>  	u16 delivery_mode;
> diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
> index 29fbf9d..3af3404 100644
> --- a/arch/x86/kvm/pmu.c
> +++ b/arch/x86/kvm/pmu.c
> @@ -20,12 +20,7 @@
>  #include "cpuid.h"
>  #include "lapic.h"
>  
> -static struct kvm_arch_event_perf_mapping {
> -	u8 eventsel;
> -	u8 unit_mask;
> -	unsigned event_type;
> -	bool inexact;
> -} arch_events[] = {
> +static struct kvm_event_hw_type_mapping intel_arch_events[] = {
>  	/* Index must match CPUID 0x0A.EBX bit vector */
>  	[0] = { 0x3c, 0x00, PERF_COUNT_HW_CPU_CYCLES },
>  	[1] = { 0xc0, 0x00, PERF_COUNT_HW_INSTRUCTIONS },
> @@ -37,7 +32,7 @@ static struct kvm_arch_event_perf_mapping {
>  	[7] = { 0x00, 0x30, PERF_COUNT_HW_REF_CPU_CYCLES },
>  };
>  
> -/* mapping between fixed pmc index and arch_events array */
> +/* mapping between fixed pmc index and intel_arch_events array */
>  static int fixed_pmc_events[] = {1, 0, 7};
>  
>  static bool pmc_is_gp(struct kvm_pmc *pmc)
> @@ -202,16 +197,16 @@ static unsigned find_arch_event(struct kvm_pmu *pmu, u8 event_select,
>  {
>  	int i;
>  
> -	for (i = 0; i < ARRAY_SIZE(arch_events); i++)
> -		if (arch_events[i].eventsel == event_select
> -				&& arch_events[i].unit_mask == unit_mask
> +	for (i = 0; i < ARRAY_SIZE(intel_arch_events); i++)
> +		if (intel_arch_events[i].eventsel == event_select
> +				&& intel_arch_events[i].unit_mask == unit_mask
>  				&& (pmu->available_event_types & (1 << i)))
>  			break;
>  
> -	if (i == ARRAY_SIZE(arch_events))
> +	if (i == ARRAY_SIZE(intel_arch_events))
>  		return PERF_COUNT_HW_MAX;
>  
> -	return arch_events[i].event_type;
> +	return intel_arch_events[i].event_type;
>  }
>  
>  static void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel)
> @@ -265,7 +260,7 @@ static void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 en_pmi, int idx)
>  		return;
>  
>  	reprogram_counter(pmc, PERF_TYPE_HARDWARE,
> -			arch_events[fixed_pmc_events[idx]].event_type,
> +			intel_arch_events[fixed_pmc_events[idx]].event_type,
>  			!(en & 0x2), /* exclude user */
>  			!(en & 0x1), /* exclude kernel */
>  			pmi, false, false);
> 
--
To unsubscribe from this list: send the line "unsubscribe kvm" in

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH V5 2/4] KVM: x86/vPMU: Create vPMU interface for VMX and SVM
  2015-06-12  5:34 ` [PATCH V5 2/4] KVM: x86/vPMU: Create vPMU interface for VMX and SVM Wei Huang
  2015-06-16 15:40   ` Joerg Roedel
@ 2015-06-19 11:31   ` Paolo Bonzini
  2015-06-19 14:36     ` Wei Huang
  1 sibling, 1 reply; 13+ messages in thread
From: Paolo Bonzini @ 2015-06-19 11:31 UTC (permalink / raw)
  To: Wei Huang, kvm, x86, gleb, rkrcmar, joro



On 12/06/2015 07:34, Wei Huang wrote:
> -static void trigger_pmi(struct irq_work *irq_work)
> +static void kvm_pmi_trigger_fn(struct irq_work *irq_work)
>  {
> -	struct kvm_pmu *pmu = container_of(irq_work, struct kvm_pmu,
> -			irq_work);
> -	struct kvm_vcpu *vcpu = container_of(pmu, struct kvm_vcpu,
> -			arch.pmu);
> +	struct kvm_pmu *pmu = container_of(irq_work, struct kvm_pmu, irq_work);
> +	struct kvm_vcpu *vcpu = pmu_to_vcpu(pmu);
>  
> -	kvm_deliver_pmi(vcpu);
> +	kvm_pmu_deliver_pmi(vcpu);
>  }
>  

On the other hand, this patch really should have been split further.

For example, just looking at this snippet you can see that the
introduction of pmu_to_vcpu and the function renames should have been
separate from the creation of the vPMU interface.

Paolo
--
To unsubscribe from this list: send the line "unsubscribe kvm" in

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH V5 1/4] KVM: x86/vPMU: Define kvm_pmu_ops to support vPMU function dispatch
  2015-06-19 11:30   ` Paolo Bonzini
@ 2015-06-19 14:34     ` Wei Huang
  0 siblings, 0 replies; 13+ messages in thread
From: Wei Huang @ 2015-06-19 14:34 UTC (permalink / raw)
  To: Paolo Bonzini, kvm, x86, gleb, rkrcmar, joro



On 06/19/2015 06:30 AM, Paolo Bonzini wrote:
> 
> 
> On 12/06/2015 07:34, Wei Huang wrote:
>> This patch defines a new function pointer struct (kvm_pmu_ops) to
>> support vPMU for both Intel and AMD. The functions pointers defined in
>> this new struct will be linked with Intel and AMD functions later. In the
>> meanwhile the struct that maps from event_sel bits to PERF_TYPE_HARDWARE
>> events is renamed and moved from Intel specific code to kvm_host.h as a
>> common struct.
>>
>> Reviewed-by: Joerg Roedel <jroedel@suse.de>
>> Tested-by: Joerg Roedel <jroedel@suse.de>
>> Signed-off-by: Wei Huang <wei@redhat.com>
> 
> The kvm_pmu_ops are unused and would belong in patch 2... the code is
> good anyway, and I'm not going to be fussy about it because there's no
> semantic change anyway in this patch.
OK. This is should be relatively easy.

-Wei
> 
> Paolo
> 
>> ---
>>  arch/x86/include/asm/kvm_host.h | 34 ++++++++++++++++++++++++++++------
>>  arch/x86/kvm/pmu.c              | 21 ++++++++-------------
>>  2 files changed, 36 insertions(+), 19 deletions(-)
>>
>> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
>> index 8ca32cf..82dc7cc 100644
>> --- a/arch/x86/include/asm/kvm_host.h
>> +++ b/arch/x86/include/asm/kvm_host.h
>> @@ -304,6 +304,12 @@ struct kvm_mmu {
>>  	u64 pdptrs[4]; /* pae */
>>  };
>>  
>> +struct msr_data {
>> +	bool host_initiated;
>> +	u32 index;
>> +	u64 data;
>> +};
>> +
>>  enum pmc_type {
>>  	KVM_PMC_GP = 0,
>>  	KVM_PMC_FIXED,
>> @@ -318,6 +324,12 @@ struct kvm_pmc {
>>  	struct kvm_vcpu *vcpu;
>>  };
>>  
>> +struct kvm_event_hw_type_mapping {
>> +	u8 eventsel;
>> +	u8 unit_mask;
>> +	unsigned event_type;
>> +};
>> +
>>  struct kvm_pmu {
>>  	unsigned nr_arch_gp_counters;
>>  	unsigned nr_arch_fixed_counters;
>> @@ -336,6 +348,22 @@ struct kvm_pmu {
>>  	u64 reprogram_pmi;
>>  };
>>  
>> +struct kvm_pmu_ops {
>> +	unsigned (*find_arch_event)(struct kvm_pmu *pmu, u8 event_select,
>> +				    u8 unit_mask);
>> +	unsigned (*find_fixed_event)(int idx);
>> +	bool (*pmc_enabled)(struct kvm_pmc *pmc);
>> +	struct kvm_pmc *(*pmc_idx_to_pmc)(struct kvm_pmu *pmu, int pmc_idx);
>> +	struct kvm_pmc *(*msr_idx_to_pmc)(struct kvm_vcpu *vcpu, unsigned idx);
>> +	int (*is_valid_msr_idx)(struct kvm_vcpu *vcpu, unsigned idx);
>> +	bool (*is_valid_msr)(struct kvm_vcpu *vcpu, u32 msr);
>> +	int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr, u64 *data);
>> +	int (*set_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
>> +	void (*refresh)(struct kvm_vcpu *vcpu);
>> +	void (*init)(struct kvm_vcpu *vcpu);
>> +	void (*reset)(struct kvm_vcpu *vcpu);
>> +};
>> +
>>  enum {
>>  	KVM_DEBUGREG_BP_ENABLED = 1,
>>  	KVM_DEBUGREG_WONT_EXIT = 2,
>> @@ -683,12 +711,6 @@ struct kvm_vcpu_stat {
>>  
>>  struct x86_instruction_info;
>>  
>> -struct msr_data {
>> -	bool host_initiated;
>> -	u32 index;
>> -	u64 data;
>> -};
>> -
>>  struct kvm_lapic_irq {
>>  	u32 vector;
>>  	u16 delivery_mode;
>> diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
>> index 29fbf9d..3af3404 100644
>> --- a/arch/x86/kvm/pmu.c
>> +++ b/arch/x86/kvm/pmu.c
>> @@ -20,12 +20,7 @@
>>  #include "cpuid.h"
>>  #include "lapic.h"
>>  
>> -static struct kvm_arch_event_perf_mapping {
>> -	u8 eventsel;
>> -	u8 unit_mask;
>> -	unsigned event_type;
>> -	bool inexact;
>> -} arch_events[] = {
>> +static struct kvm_event_hw_type_mapping intel_arch_events[] = {
>>  	/* Index must match CPUID 0x0A.EBX bit vector */
>>  	[0] = { 0x3c, 0x00, PERF_COUNT_HW_CPU_CYCLES },
>>  	[1] = { 0xc0, 0x00, PERF_COUNT_HW_INSTRUCTIONS },
>> @@ -37,7 +32,7 @@ static struct kvm_arch_event_perf_mapping {
>>  	[7] = { 0x00, 0x30, PERF_COUNT_HW_REF_CPU_CYCLES },
>>  };
>>  
>> -/* mapping between fixed pmc index and arch_events array */
>> +/* mapping between fixed pmc index and intel_arch_events array */
>>  static int fixed_pmc_events[] = {1, 0, 7};
>>  
>>  static bool pmc_is_gp(struct kvm_pmc *pmc)
>> @@ -202,16 +197,16 @@ static unsigned find_arch_event(struct kvm_pmu *pmu, u8 event_select,
>>  {
>>  	int i;
>>  
>> -	for (i = 0; i < ARRAY_SIZE(arch_events); i++)
>> -		if (arch_events[i].eventsel == event_select
>> -				&& arch_events[i].unit_mask == unit_mask
>> +	for (i = 0; i < ARRAY_SIZE(intel_arch_events); i++)
>> +		if (intel_arch_events[i].eventsel == event_select
>> +				&& intel_arch_events[i].unit_mask == unit_mask
>>  				&& (pmu->available_event_types & (1 << i)))
>>  			break;
>>  
>> -	if (i == ARRAY_SIZE(arch_events))
>> +	if (i == ARRAY_SIZE(intel_arch_events))
>>  		return PERF_COUNT_HW_MAX;
>>  
>> -	return arch_events[i].event_type;
>> +	return intel_arch_events[i].event_type;
>>  }
>>  
>>  static void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel)
>> @@ -265,7 +260,7 @@ static void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 en_pmi, int idx)
>>  		return;
>>  
>>  	reprogram_counter(pmc, PERF_TYPE_HARDWARE,
>> -			arch_events[fixed_pmc_events[idx]].event_type,
>> +			intel_arch_events[fixed_pmc_events[idx]].event_type,
>>  			!(en & 0x2), /* exclude user */
>>  			!(en & 0x1), /* exclude kernel */
>>  			pmi, false, false);
>>
--
To unsubscribe from this list: send the line "unsubscribe kvm" in

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH V5 2/4] KVM: x86/vPMU: Create vPMU interface for VMX and SVM
  2015-06-19 11:31   ` Paolo Bonzini
@ 2015-06-19 14:36     ` Wei Huang
  0 siblings, 0 replies; 13+ messages in thread
From: Wei Huang @ 2015-06-19 14:36 UTC (permalink / raw)
  To: Paolo Bonzini, kvm, x86, gleb, rkrcmar, joro



On 06/19/2015 06:31 AM, Paolo Bonzini wrote:
> 
> 
> On 12/06/2015 07:34, Wei Huang wrote:
>> -static void trigger_pmi(struct irq_work *irq_work)
>> +static void kvm_pmi_trigger_fn(struct irq_work *irq_work)
>>  {
>> -	struct kvm_pmu *pmu = container_of(irq_work, struct kvm_pmu,
>> -			irq_work);
>> -	struct kvm_vcpu *vcpu = container_of(pmu, struct kvm_vcpu,
>> -			arch.pmu);
>> +	struct kvm_pmu *pmu = container_of(irq_work, struct kvm_pmu, irq_work);
>> +	struct kvm_vcpu *vcpu = pmu_to_vcpu(pmu);
>>  
>> -	kvm_deliver_pmi(vcpu);
>> +	kvm_pmu_deliver_pmi(vcpu);
>>  }
>>  
> 
> On the other hand, this patch really should have been split further.
> 
> For example, just looking at this snippet you can see that the
> introduction of pmu_to_vcpu and the function renames should have been
> separate from the creation of the vPMU interface.
Drew Jones brought up in a separate email. I will split it into a
smaller pieces, less intrusive in each step.

Thanks,
-Wei

> 
> Paolo
> 
--
To unsubscribe from this list: send the line "unsubscribe kvm" in

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH V5 0/4] Consolidated KVM vPMU support for x86
  2015-06-12  5:34 [PATCH V5 0/4] Consolidated KVM vPMU support for x86 Wei Huang
                   ` (4 preceding siblings ...)
  2015-06-16 15:41 ` [PATCH V5 0/4] Consolidated KVM vPMU support for x86 Joerg Roedel
@ 2015-06-19 15:14 ` Paolo Bonzini
  2015-06-19 15:40   ` Wei Huang
  5 siblings, 1 reply; 13+ messages in thread
From: Paolo Bonzini @ 2015-06-19 15:14 UTC (permalink / raw)
  To: Wei Huang, kvm, x86, gleb, rkrcmar, joro

While the code looks great, the splitting of patches 1 and 2
left something to be desired.  I've redone the split altogether
and I'll place it soon in kvm/queue because I needed to do it myself
to figure out some suggestions; and after 4 hours it would have been
pointless for you to do the work again. :)  Nevertheless, do take some
time to review the single patches in order to understand the point of
splitting the patches this way.

Here is the new structuring of the patch series:

* KVM: x86/vPMU: rename a few PMU functions
* KVM: x86/vPMU: introduce pmu.h header
* KVM: x86/vPMU: use the new macros to go between PMC, PMU and VCPU
* KVM: x86/vPMU: whitespace and stylistic adjustments in PMU code
* KVM: x86/vPMU: reorder PMU functions
* KVM: x86/vPMU: introduce kvm_pmu_msr_idx_to_pmc
* KVM: x86/vPMU: Define kvm_pmu_ops to support vPMU function dispatch
* KVM: x86/vPMU: Implement AMD vPMU code for KVM
* KVM: x86/vPMU: Enable PMU handling for AMD PERFCTRn and EVNTSELn MSRs

The code changes compared to your patches are very minor, mostly
undoing parts of patch 1:

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index b68b9ac847c4..5a2b4508be44 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -304,12 +304,6 @@ struct kvm_mmu {
 	u64 pdptrs[4]; /* pae */
 };
 
-struct msr_data {
-	bool host_initiated;
-	u32 index;
-	u64 data;
-};
-
 enum pmc_type {
 	KVM_PMC_GP = 0,
 	KVM_PMC_FIXED,
@@ -324,12 +318,6 @@ struct kvm_pmc {
 	struct kvm_vcpu *vcpu;
 };
 
-struct kvm_event_hw_type_mapping {
-	u8 eventsel;
-	u8 unit_mask;
-	unsigned event_type;
-};
-
 struct kvm_pmu {
 	unsigned nr_arch_gp_counters;
 	unsigned nr_arch_fixed_counters;
@@ -348,21 +336,7 @@ struct kvm_pmu {
 	u64 reprogram_pmi;
 };
 
-struct kvm_pmu_ops {
-	unsigned (*find_arch_event)(struct kvm_pmu *pmu, u8 event_select,
-				    u8 unit_mask);
-	unsigned (*find_fixed_event)(int idx);
-	bool (*pmc_enabled)(struct kvm_pmc *pmc);
-	struct kvm_pmc *(*pmc_idx_to_pmc)(struct kvm_pmu *pmu, int pmc_idx);
-	struct kvm_pmc *(*msr_idx_to_pmc)(struct kvm_vcpu *vcpu, unsigned idx);
-	int (*is_valid_msr_idx)(struct kvm_vcpu *vcpu, unsigned idx);
-	bool (*is_valid_msr)(struct kvm_vcpu *vcpu, u32 msr);
-	int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr, u64 *data);
-	int (*set_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
-	void (*refresh)(struct kvm_vcpu *vcpu);
-	void (*init)(struct kvm_vcpu *vcpu);
-	void (*reset)(struct kvm_vcpu *vcpu);
-};
+struct kvm_pmu_ops;
 
 enum {
 	KVM_DEBUGREG_BP_ENABLED = 1,
@@ -725,6 +699,12 @@ struct kvm_vcpu_stat {
 
 struct x86_instruction_info;
 
+struct msr_data {
+	bool host_initiated;
+	u32 index;
+	u64 data;
+};
+
 struct kvm_lapic_irq {
 	u32 vector;
 	u16 delivery_mode;
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index ebb5888e9d10..31aa2c85dc97 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -10,7 +10,9 @@
  *
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
+ *
  */
+
 #include <linux/types.h>
 #include <linux/kvm_host.h>
 #include <linux/perf_event.h>
@@ -88,7 +90,7 @@ static void kvm_perf_overflow_intr(struct perf_event *perf_event,
 		 * NMI context. Do it from irq work instead.
 		 */
 		if (!kvm_is_in_guest())
-			irq_work_queue(&pmc->vcpu->arch.pmu.irq_work);
+			irq_work_queue(&pmc_to_pmu(pmc)->irq_work);
 		else
 			kvm_make_request(KVM_REQ_PMI, pmc->vcpu);
 	}
@@ -128,7 +130,7 @@ static void pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type,
 	}
 
 	pmc->perf_event = event;
-	clear_bit(pmc->idx, (unsigned long*)&pmc->vcpu->arch.pmu.reprogram_pmi);
+	clear_bit(pmc->idx, (unsigned long*)&pmc_to_pmu(pmc)->reprogram_pmi);
 }
 
 void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel)
@@ -154,7 +156,7 @@ void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel)
 			  ARCH_PERFMON_EVENTSEL_CMASK |
 			  HSW_IN_TX |
 			  HSW_IN_TX_CHECKPOINTED))) {
-		config = kvm_x86_ops->pmu_ops->find_arch_event(&pmc->vcpu->arch.pmu,
+		config = kvm_x86_ops->pmu_ops->find_arch_event(pmc_to_pmu(pmc),
 						      event_select,
 						      unit_mask);
 		if (config != PERF_COUNT_HW_MAX)
@@ -305,4 +307,3 @@ void kvm_pmu_destroy(struct kvm_vcpu *vcpu)
 {
 	kvm_pmu_reset(vcpu);
 }
-
diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
index a19a0d5fdb07..f96e1f962587 100644
--- a/arch/x86/kvm/pmu.h
+++ b/arch/x86/kvm/pmu.h
@@ -5,9 +5,31 @@
 #define pmu_to_vcpu(pmu)  (container_of((pmu), struct kvm_vcpu, arch.pmu))
 #define pmc_to_pmu(pmc)   (&(pmc)->vcpu->arch.pmu)
 
-/* retrieve the control fields of IA32_FIXED_CTR_CTRL */
+/* retrieve the 4 bits for EN and PMI out of IA32_FIXED_CTR_CTRL */
 #define fixed_ctrl_field(ctrl_reg, idx) (((ctrl_reg) >> ((idx)*4)) & 0xf)
 
+struct kvm_event_hw_type_mapping {
+	u8 eventsel;
+	u8 unit_mask;
+	unsigned event_type;
+};
+
+struct kvm_pmu_ops {
+	unsigned (*find_arch_event)(struct kvm_pmu *pmu, u8 event_select,
+				    u8 unit_mask);
+	unsigned (*find_fixed_event)(int idx);
+	bool (*pmc_is_enabled)(struct kvm_pmc *pmc);
+	struct kvm_pmc *(*pmc_idx_to_pmc)(struct kvm_pmu *pmu, int pmc_idx);
+	struct kvm_pmc *(*msr_idx_to_pmc)(struct kvm_vcpu *vcpu, unsigned idx);
+	int (*is_valid_msr_idx)(struct kvm_vcpu *vcpu, unsigned idx);
+	bool (*is_valid_msr)(struct kvm_vcpu *vcpu, u32 msr);
+	int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr, u64 *data);
+	int (*set_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
+	void (*refresh)(struct kvm_vcpu *vcpu);
+	void (*init)(struct kvm_vcpu *vcpu);
+	void (*reset)(struct kvm_vcpu *vcpu);
+};
+
 static inline u64 pmc_bitmask(struct kvm_pmc *pmc)
 {
 	struct kvm_pmu *pmu = pmc_to_pmu(pmc);
@@ -48,7 +70,7 @@ static inline bool pmc_is_fixed(struct kvm_pmc *pmc)
 
 static inline bool pmc_is_enabled(struct kvm_pmc *pmc)
 {
-	return kvm_x86_ops->pmu_ops->pmc_enabled(pmc);
+	return kvm_x86_ops->pmu_ops->pmc_is_enabled(pmc);
 }
 
 /* returns general purpose PMC with the specified MSR. Note that it can be
diff --git a/arch/x86/kvm/pmu_amd.c b/arch/x86/kvm/pmu_amd.c
index ff5cea79a104..886aa25a7131 100644
--- a/arch/x86/kvm/pmu_amd.c
+++ b/arch/x86/kvm/pmu_amd.c
@@ -57,7 +57,7 @@ static unsigned amd_find_fixed_event(int idx)
 /* check if a PMC is enabled by comparing it against global_ctrl bits. Because
  * AMD CPU doesn't have global_ctrl MSR, all PMCs are enabled (return TRUE).
  */
-static bool amd_pmc_enabled(struct kvm_pmc *pmc)
+static bool amd_pmc_is_enabled(struct kvm_pmc *pmc)
 {
 	return true;
 }
@@ -194,7 +194,7 @@ static void amd_pmu_reset(struct kvm_vcpu *vcpu)
 struct kvm_pmu_ops amd_pmu_ops = {
 	.find_arch_event = amd_find_arch_event,
 	.find_fixed_event = amd_find_fixed_event,
-	.pmc_enabled = amd_pmc_enabled,
+	.pmc_is_enabled = amd_pmc_is_enabled,
 	.pmc_idx_to_pmc = amd_pmc_idx_to_pmc,
 	.msr_idx_to_pmc = amd_msr_idx_to_pmc,
 	.is_valid_msr_idx = amd_is_valid_msr_idx,
diff --git a/arch/x86/kvm/pmu_intel.c b/arch/x86/kvm/pmu_intel.c
index 51b4729493db..ab38af4f4947 100644
--- a/arch/x86/kvm/pmu_intel.c
+++ b/arch/x86/kvm/pmu_intel.c
@@ -63,9 +63,8 @@ static void global_ctrl_changed(struct kvm_pmu *pmu, u64 data)
 
 	pmu->global_ctrl = data;
 
-	for_each_set_bit(bit, (unsigned long *)&diff, X86_PMC_IDX_MAX) {
+	for_each_set_bit(bit, (unsigned long *)&diff, X86_PMC_IDX_MAX)
 		reprogram_counter(pmu, bit);
-	}
 }
 
 static unsigned intel_find_arch_event(struct kvm_pmu *pmu,
@@ -88,7 +87,6 @@ static unsigned intel_find_arch_event(struct kvm_pmu *pmu,
 
 static unsigned intel_find_fixed_event(int idx)
 {
-
 	if (idx >= ARRAY_SIZE(fixed_pmc_events))
 		return PERF_COUNT_HW_MAX;
 
@@ -96,7 +94,7 @@ static unsigned intel_find_fixed_event(int idx)
 }
 
 /* check if a PMC is enabled by comparising it with globl_ctrl bits. */
-static bool intel_pmc_enabled(struct kvm_pmc *pmc)
+static bool intel_pmc_is_enabled(struct kvm_pmc *pmc)
 {
 	struct kvm_pmu *pmu = pmc_to_pmu(pmc);
 
@@ -347,7 +345,7 @@ static void intel_pmu_reset(struct kvm_vcpu *vcpu)
 struct kvm_pmu_ops intel_pmu_ops = {
 	.find_arch_event = intel_find_arch_event,
 	.find_fixed_event = intel_find_fixed_event,
-	.pmc_enabled = intel_pmc_enabled,
+	.pmc_is_enabled = intel_pmc_is_enabled,
 	.pmc_idx_to_pmc = intel_pmc_idx_to_pmc,
 	.msr_idx_to_pmc = intel_msr_idx_to_pmc,
 	.is_valid_msr_idx = intel_is_valid_msr_idx,


Note how, by splitting patches, I was able to find:

* some coding style violations (global_ctrl_changed, intel_find_fixed_event)

* a function naming inconsistency (pmc_is_enabled calls pmu_ops->pmc_enabled)

* some missed conversions to pmc_to_pmu

* the unnecessary changes in patch 1 I already mentioned

Interestingly, after the split git does not show anymore
the "big" patch as rewriting pmu.c; the diffstat for that file
is a pretty tame

 1 file changed, 47 insertions(+), 336 deletions(-)

where most of the insertions are the nice new header comment.

The trick is to treat these kind of style changes/refactorings as
a warning sign that you should be committing something soon.  You
can develop a git workflow, based for example on "git add -p" and
possibly "git stash", that lets you commit them quickly without
getting out of your previous line of thoughts.  Just get them
out of the way, you can later group them or otherwise reorder
them as you see fit.

For other examples of splitting patches, check out my SMM series
and Xiao's patches in kvm/next.

Paolo
--
To unsubscribe from this list: send the line "unsubscribe kvm" in

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH V5 0/4] Consolidated KVM vPMU support for x86
  2015-06-19 15:14 ` Paolo Bonzini
@ 2015-06-19 15:40   ` Wei Huang
  0 siblings, 0 replies; 13+ messages in thread
From: Wei Huang @ 2015-06-19 15:40 UTC (permalink / raw)
  To: Paolo Bonzini, kvm, x86, gleb, rkrcmar, joro

I understand that the original patch2 was huge. Thanks for taking care
of it (and the tips). I reviewed the diff below and they are reasonable.

-Wei

On 06/19/2015 10:14 AM, Paolo Bonzini wrote:
> While the code looks great, the splitting of patches 1 and 2
> left something to be desired.  I've redone the split altogether
> and I'll place it soon in kvm/queue because I needed to do it myself
> to figure out some suggestions; and after 4 hours it would have been
> pointless for you to do the work again. :)  Nevertheless, do take some
> time to review the single patches in order to understand the point of
> splitting the patches this way.
> 
> Here is the new structuring of the patch series:
> 
> * KVM: x86/vPMU: rename a few PMU functions
> * KVM: x86/vPMU: introduce pmu.h header
> * KVM: x86/vPMU: use the new macros to go between PMC, PMU and VCPU
> * KVM: x86/vPMU: whitespace and stylistic adjustments in PMU code
> * KVM: x86/vPMU: reorder PMU functions
> * KVM: x86/vPMU: introduce kvm_pmu_msr_idx_to_pmc
> * KVM: x86/vPMU: Define kvm_pmu_ops to support vPMU function dispatch
> * KVM: x86/vPMU: Implement AMD vPMU code for KVM
> * KVM: x86/vPMU: Enable PMU handling for AMD PERFCTRn and EVNTSELn MSRs
> 
> The code changes compared to your patches are very minor, mostly
> undoing parts of patch 1:
> 
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index b68b9ac847c4..5a2b4508be44 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -304,12 +304,6 @@ struct kvm_mmu {
>  	u64 pdptrs[4]; /* pae */
>  };
>  
> -struct msr_data {
> -	bool host_initiated;
> -	u32 index;
> -	u64 data;
> -};
> -
>  enum pmc_type {
>  	KVM_PMC_GP = 0,
>  	KVM_PMC_FIXED,
> @@ -324,12 +318,6 @@ struct kvm_pmc {
>  	struct kvm_vcpu *vcpu;
>  };
>  
> -struct kvm_event_hw_type_mapping {
> -	u8 eventsel;
> -	u8 unit_mask;
> -	unsigned event_type;
> -};
> -
>  struct kvm_pmu {
>  	unsigned nr_arch_gp_counters;
>  	unsigned nr_arch_fixed_counters;
> @@ -348,21 +336,7 @@ struct kvm_pmu {
>  	u64 reprogram_pmi;
>  };
>  
> -struct kvm_pmu_ops {
> -	unsigned (*find_arch_event)(struct kvm_pmu *pmu, u8 event_select,
> -				    u8 unit_mask);
> -	unsigned (*find_fixed_event)(int idx);
> -	bool (*pmc_enabled)(struct kvm_pmc *pmc);
> -	struct kvm_pmc *(*pmc_idx_to_pmc)(struct kvm_pmu *pmu, int pmc_idx);
> -	struct kvm_pmc *(*msr_idx_to_pmc)(struct kvm_vcpu *vcpu, unsigned idx);
> -	int (*is_valid_msr_idx)(struct kvm_vcpu *vcpu, unsigned idx);
> -	bool (*is_valid_msr)(struct kvm_vcpu *vcpu, u32 msr);
> -	int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr, u64 *data);
> -	int (*set_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
> -	void (*refresh)(struct kvm_vcpu *vcpu);
> -	void (*init)(struct kvm_vcpu *vcpu);
> -	void (*reset)(struct kvm_vcpu *vcpu);
> -};
> +struct kvm_pmu_ops;
>  
>  enum {
>  	KVM_DEBUGREG_BP_ENABLED = 1,
> @@ -725,6 +699,12 @@ struct kvm_vcpu_stat {
>  
>  struct x86_instruction_info;
>  
> +struct msr_data {
> +	bool host_initiated;
> +	u32 index;
> +	u64 data;
> +};
> +
>  struct kvm_lapic_irq {
>  	u32 vector;
>  	u16 delivery_mode;
> diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
> index ebb5888e9d10..31aa2c85dc97 100644
> --- a/arch/x86/kvm/pmu.c
> +++ b/arch/x86/kvm/pmu.c
> @@ -10,7 +10,9 @@
>   *
>   * This work is licensed under the terms of the GNU GPL, version 2.  See
>   * the COPYING file in the top-level directory.
> + *
>   */
> +
>  #include <linux/types.h>
>  #include <linux/kvm_host.h>
>  #include <linux/perf_event.h>
> @@ -88,7 +90,7 @@ static void kvm_perf_overflow_intr(struct perf_event *perf_event,
>  		 * NMI context. Do it from irq work instead.
>  		 */
>  		if (!kvm_is_in_guest())
> -			irq_work_queue(&pmc->vcpu->arch.pmu.irq_work);
> +			irq_work_queue(&pmc_to_pmu(pmc)->irq_work);
>  		else
>  			kvm_make_request(KVM_REQ_PMI, pmc->vcpu);
>  	}
> @@ -128,7 +130,7 @@ static void pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type,
>  	}
>  
>  	pmc->perf_event = event;
> -	clear_bit(pmc->idx, (unsigned long*)&pmc->vcpu->arch.pmu.reprogram_pmi);
> +	clear_bit(pmc->idx, (unsigned long*)&pmc_to_pmu(pmc)->reprogram_pmi);
>  }
>  
>  void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel)
> @@ -154,7 +156,7 @@ void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel)
>  			  ARCH_PERFMON_EVENTSEL_CMASK |
>  			  HSW_IN_TX |
>  			  HSW_IN_TX_CHECKPOINTED))) {
> -		config = kvm_x86_ops->pmu_ops->find_arch_event(&pmc->vcpu->arch.pmu,
> +		config = kvm_x86_ops->pmu_ops->find_arch_event(pmc_to_pmu(pmc),
>  						      event_select,
>  						      unit_mask);
>  		if (config != PERF_COUNT_HW_MAX)
> @@ -305,4 +307,3 @@ void kvm_pmu_destroy(struct kvm_vcpu *vcpu)
>  {
>  	kvm_pmu_reset(vcpu);
>  }
> -
> diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
> index a19a0d5fdb07..f96e1f962587 100644
> --- a/arch/x86/kvm/pmu.h
> +++ b/arch/x86/kvm/pmu.h
> @@ -5,9 +5,31 @@
>  #define pmu_to_vcpu(pmu)  (container_of((pmu), struct kvm_vcpu, arch.pmu))
>  #define pmc_to_pmu(pmc)   (&(pmc)->vcpu->arch.pmu)
>  
> -/* retrieve the control fields of IA32_FIXED_CTR_CTRL */
> +/* retrieve the 4 bits for EN and PMI out of IA32_FIXED_CTR_CTRL */
>  #define fixed_ctrl_field(ctrl_reg, idx) (((ctrl_reg) >> ((idx)*4)) & 0xf)
>  
> +struct kvm_event_hw_type_mapping {
> +	u8 eventsel;
> +	u8 unit_mask;
> +	unsigned event_type;
> +};
> +
> +struct kvm_pmu_ops {
> +	unsigned (*find_arch_event)(struct kvm_pmu *pmu, u8 event_select,
> +				    u8 unit_mask);
> +	unsigned (*find_fixed_event)(int idx);
> +	bool (*pmc_is_enabled)(struct kvm_pmc *pmc);
> +	struct kvm_pmc *(*pmc_idx_to_pmc)(struct kvm_pmu *pmu, int pmc_idx);
> +	struct kvm_pmc *(*msr_idx_to_pmc)(struct kvm_vcpu *vcpu, unsigned idx);
> +	int (*is_valid_msr_idx)(struct kvm_vcpu *vcpu, unsigned idx);
> +	bool (*is_valid_msr)(struct kvm_vcpu *vcpu, u32 msr);
> +	int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr, u64 *data);
> +	int (*set_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
> +	void (*refresh)(struct kvm_vcpu *vcpu);
> +	void (*init)(struct kvm_vcpu *vcpu);
> +	void (*reset)(struct kvm_vcpu *vcpu);
> +};
> +
>  static inline u64 pmc_bitmask(struct kvm_pmc *pmc)
>  {
>  	struct kvm_pmu *pmu = pmc_to_pmu(pmc);
> @@ -48,7 +70,7 @@ static inline bool pmc_is_fixed(struct kvm_pmc *pmc)
>  
>  static inline bool pmc_is_enabled(struct kvm_pmc *pmc)
>  {
> -	return kvm_x86_ops->pmu_ops->pmc_enabled(pmc);
> +	return kvm_x86_ops->pmu_ops->pmc_is_enabled(pmc);
>  }
>  
>  /* returns general purpose PMC with the specified MSR. Note that it can be
> diff --git a/arch/x86/kvm/pmu_amd.c b/arch/x86/kvm/pmu_amd.c
> index ff5cea79a104..886aa25a7131 100644
> --- a/arch/x86/kvm/pmu_amd.c
> +++ b/arch/x86/kvm/pmu_amd.c
> @@ -57,7 +57,7 @@ static unsigned amd_find_fixed_event(int idx)
>  /* check if a PMC is enabled by comparing it against global_ctrl bits. Because
>   * AMD CPU doesn't have global_ctrl MSR, all PMCs are enabled (return TRUE).
>   */
> -static bool amd_pmc_enabled(struct kvm_pmc *pmc)
> +static bool amd_pmc_is_enabled(struct kvm_pmc *pmc)
>  {
>  	return true;
>  }
> @@ -194,7 +194,7 @@ static void amd_pmu_reset(struct kvm_vcpu *vcpu)
>  struct kvm_pmu_ops amd_pmu_ops = {
>  	.find_arch_event = amd_find_arch_event,
>  	.find_fixed_event = amd_find_fixed_event,
> -	.pmc_enabled = amd_pmc_enabled,
> +	.pmc_is_enabled = amd_pmc_is_enabled,
>  	.pmc_idx_to_pmc = amd_pmc_idx_to_pmc,
>  	.msr_idx_to_pmc = amd_msr_idx_to_pmc,
>  	.is_valid_msr_idx = amd_is_valid_msr_idx,
> diff --git a/arch/x86/kvm/pmu_intel.c b/arch/x86/kvm/pmu_intel.c
> index 51b4729493db..ab38af4f4947 100644
> --- a/arch/x86/kvm/pmu_intel.c
> +++ b/arch/x86/kvm/pmu_intel.c
> @@ -63,9 +63,8 @@ static void global_ctrl_changed(struct kvm_pmu *pmu, u64 data)
>  
>  	pmu->global_ctrl = data;
>  
> -	for_each_set_bit(bit, (unsigned long *)&diff, X86_PMC_IDX_MAX) {
> +	for_each_set_bit(bit, (unsigned long *)&diff, X86_PMC_IDX_MAX)
>  		reprogram_counter(pmu, bit);
> -	}
>  }
>  
>  static unsigned intel_find_arch_event(struct kvm_pmu *pmu,
> @@ -88,7 +87,6 @@ static unsigned intel_find_arch_event(struct kvm_pmu *pmu,
>  
>  static unsigned intel_find_fixed_event(int idx)
>  {
> -
>  	if (idx >= ARRAY_SIZE(fixed_pmc_events))
>  		return PERF_COUNT_HW_MAX;
>  
> @@ -96,7 +94,7 @@ static unsigned intel_find_fixed_event(int idx)
>  }
>  
>  /* check if a PMC is enabled by comparising it with globl_ctrl bits. */
> -static bool intel_pmc_enabled(struct kvm_pmc *pmc)
> +static bool intel_pmc_is_enabled(struct kvm_pmc *pmc)
>  {
>  	struct kvm_pmu *pmu = pmc_to_pmu(pmc);
>  
> @@ -347,7 +345,7 @@ static void intel_pmu_reset(struct kvm_vcpu *vcpu)
>  struct kvm_pmu_ops intel_pmu_ops = {
>  	.find_arch_event = intel_find_arch_event,
>  	.find_fixed_event = intel_find_fixed_event,
> -	.pmc_enabled = intel_pmc_enabled,
> +	.pmc_is_enabled = intel_pmc_is_enabled,
>  	.pmc_idx_to_pmc = intel_pmc_idx_to_pmc,
>  	.msr_idx_to_pmc = intel_msr_idx_to_pmc,
>  	.is_valid_msr_idx = intel_is_valid_msr_idx,
> 
> 
> Note how, by splitting patches, I was able to find:
> 
> * some coding style violations (global_ctrl_changed, intel_find_fixed_event)
> 
> * a function naming inconsistency (pmc_is_enabled calls pmu_ops->pmc_enabled)
> 
> * some missed conversions to pmc_to_pmu
> 
> * the unnecessary changes in patch 1 I already mentioned
> 
> Interestingly, after the split git does not show anymore
> the "big" patch as rewriting pmu.c; the diffstat for that file
> is a pretty tame
> 
>  1 file changed, 47 insertions(+), 336 deletions(-)
> 
> where most of the insertions are the nice new header comment.
> 
> The trick is to treat these kind of style changes/refactorings as
> a warning sign that you should be committing something soon.  You
> can develop a git workflow, based for example on "git add -p" and
> possibly "git stash", that lets you commit them quickly without
> getting out of your previous line of thoughts.  Just get them
> out of the way, you can later group them or otherwise reorder
> them as you see fit.
> 
> For other examples of splitting patches, check out my SMM series
> and Xiao's patches in kvm/next.
> 
> Paolo
> 
--
To unsubscribe from this list: send the line "unsubscribe kvm" in

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2015-06-19 15:40 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-12  5:34 [PATCH V5 0/4] Consolidated KVM vPMU support for x86 Wei Huang
2015-06-12  5:34 ` [PATCH V5 1/4] KVM: x86/vPMU: Define kvm_pmu_ops to support vPMU function dispatch Wei Huang
2015-06-19 11:30   ` Paolo Bonzini
2015-06-19 14:34     ` Wei Huang
2015-06-12  5:34 ` [PATCH V5 2/4] KVM: x86/vPMU: Create vPMU interface for VMX and SVM Wei Huang
2015-06-16 15:40   ` Joerg Roedel
2015-06-19 11:31   ` Paolo Bonzini
2015-06-19 14:36     ` Wei Huang
2015-06-12  5:34 ` [PATCH V5 3/4] KVM: x86/vPMU: Implement AMD vPMU code for KVM Wei Huang
2015-06-12  5:34 ` [PATCH V5 4/4] KVM: x86/vPMU: Enable PMU handling for AMD PERFCTRn and EVNTSELn MSRs Wei Huang
2015-06-16 15:41 ` [PATCH V5 0/4] Consolidated KVM vPMU support for x86 Joerg Roedel
2015-06-19 15:14 ` Paolo Bonzini
2015-06-19 15:40   ` Wei Huang

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.