diff options
author | Remy Noel <mocramis@gmail.com> | 2018-04-20 20:18:48 +0200 |
---|---|---|
committer | Remy Noel <mocramis@gmail.com> | 2018-04-21 00:04:20 +0200 |
commit | 0971db08230932057141990462f32c17ae088d82 (patch) | |
tree | e22734bb22239ed987e0624cd1556ed400e441d1 /arch/x86/machine | |
parent | 1b86674fcbefb0c860c02ade0463db469f4df1bb (diff) |
pmu_intel: Add Overflow V2 support.
Also adds cpu_set_msr64 helper.
Diffstat (limited to 'arch/x86/machine')
-rw-r--r-- | arch/x86/machine/cpu.h | 13 | ||||
-rw-r--r-- | arch/x86/machine/pmu_intel.c | 77 |
2 files changed, 83 insertions, 7 deletions
diff --git a/arch/x86/machine/cpu.h b/arch/x86/machine/cpu.h index d40760c..eebacc6 100644 --- a/arch/x86/machine/cpu.h +++ b/arch/x86/machine/cpu.h @@ -574,6 +574,19 @@ cpu_set_msr(uint32_t msr, uint32_t high, uint32_t low) { asm volatile("wrmsr" : : "c" (msr), "a" (low), "d" (high) : "memory"); } +/* + * uint64 version of cpu_set_msr. + */ +static inline void +cpu_set_msr64(uint32_t msr, uint64_t value) +{ + uint32_t low, high; + + low = value & 0xffffffff; + high = value >> 32; + + cpu_set_msr(msr, high, low); +} static __always_inline uint64_t cpu_get_tsc(void) diff --git a/arch/x86/machine/pmu_intel.c b/arch/x86/machine/pmu_intel.c index 40e1450..bc7405c 100644 --- a/arch/x86/machine/pmu_intel.c +++ b/arch/x86/machine/pmu_intel.c @@ -45,6 +45,17 @@ #define PMU_INTEL_MSR_EVTSEL0 0x186 /* + * V2 MSR addresses + */ +#define PMU_INTEL_MSR_FIXED_CTR0 0x0309 +#define PMU_INTEL_MSR_FIXED_CTR1 0x030a +#define PMU_INTEL_MSR_FIXED_CTR2 0x030b +#define PMU_INTEL_MSR_FIXED_CTR_CTRL 0x038d +#define PMU_INTEL_MSR_GLOBAL_STATUS 0x038e +#define PMU_INTEL_MSR_GLOBAL_CTRL 0x038f +#define PMU_INTEL_MSR_GLOBAL_OVF_CTRL 0x0390 + +/* * Event Select Register addresses */ #define PMU_INTEL_EVTSEL_USR 0x00010000 @@ -117,6 +128,18 @@ pmu_intel_get(void) return &pmu_intel; } +static uint64_t +pmu_intel_get_status(void) +{ + return cpu_get_msr64(PMU_INTEL_MSR_GLOBAL_STATUS); +} + +static void +pmu_intel_ack_status(uint64_t status) +{ + return cpu_set_msr64(PMU_INTEL_MSR_GLOBAL_OVF_CTRL, status); +} + static unsigned int pmu_popcount(unsigned int bits) { @@ -236,12 +259,7 @@ pmu_intel_read(unsigned int pmc_id) static void pmu_intel_write(unsigned int pmc_id, uint64_t value) { - uint32_t low, high; - - low = value & 0xffffffff; - high = value >> 32; - - cpu_set_msr(PMU_INTEL_MSR_PMC0 + pmc_id, low, high); + cpu_set_msr64(PMU_INTEL_MSR_PMC0 + pmc_id, value); } #endif /* CONFIG_PERFMON_TEST */ @@ -276,6 +294,47 @@ pmu_intel_handle_of_intr_v1(struct trap_frame *frame) } } +static int +pmu_intel_consume_bits(uint64_t *bits) +{ + int bit; + + bit = __builtin_ffsll(*bits) - 1; + if (bit < 0) { + return bit; + } + *bits &= ~(1U << bit); + + return bit; +} + +static void +pmu_intel_handle_of_intr_v2(struct trap_frame *frame) +{ + struct pmu_intel *pmu; + uint64_t status; + int pmc_id; + + (void)frame; + + status = pmu_intel_get_status(); + if (status == 0) { + return; + } + pmu_intel_ack_status(status); + pmu = pmu_intel_get(); + + /* XXX: Mask on all PMCs (we do not check FIXED counters status */ + status &= ((1U << pmu->pmc_width) - 1); + for(;;) { + pmc_id = pmu_intel_consume_bits(&status); + if (pmc_id < 0) { + break; + } + perfmon_cpu_pmc_inc_of(pmc_id); + } +} + static uint8_t pmu_intel_get_pmc_width(void) { @@ -332,7 +391,11 @@ pmu_intel_setup(void) pmu_driver.stop = pmu_intel_stop; pmu_driver.read = pmu_intel_read; pmu_driver.get_pmc_width = pmu_intel_get_pmc_width; - pmu_driver.handle_of_intr = pmu_intel_handle_of_intr_v1; + if (pmu->version > 2) { + pmu_driver.handle_of_intr = pmu_intel_handle_of_intr_v1; + } else { + pmu_driver.handle_of_intr = pmu_intel_handle_of_intr_v2; + } #ifdef CONFIG_PERFMON_TEST pmu_driver.write = pmu_intel_write; #endif |