From ee443edc22d4113e57ddb9671f0ff6e2fe14a19a Mon Sep 17 00:00:00 2001 From: Remy Noel Date: Sat, 21 Apr 2018 11:29:09 +0200 Subject: pmu_amd: Add AMD overflow handling (untested). --- arch/x86/machine/pmu_amd.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/arch/x86/machine/pmu_amd.c b/arch/x86/machine/pmu_amd.c index 2fe6019..4d2a4f8 100644 --- a/arch/x86/machine/pmu_amd.c +++ b/arch/x86/machine/pmu_amd.c @@ -53,6 +53,7 @@ */ #define PMU_AMD_EVTSEL_USR 0x00010000 #define PMU_AMD_EVTSEL_OS 0x00020000 +#define PMU_AMD_EVTSEL_INT 0x00100000 #define PMU_AMD_EVTSEL_EN 0x00400000 /* @@ -175,6 +176,7 @@ pmu_amd_start(unsigned int pmc_id, unsigned int raw_event_id) /* TODO Handle PERFMON_EF_KERN/PERFMON_EF_USER */ high = code->event_select >> 8; low = PMU_AMD_EVTSEL_EN + | PMU_AMD_EVTSEL_INT | PMU_AMD_EVTSEL_OS | PMU_AMD_EVTSEL_USR | (code->umask << 8) @@ -198,6 +200,46 @@ pmu_amd_read(unsigned int pmc_id) return cpu_get_msr64(PMU_AMD_MSR_PERCTR0 + pmc_id); } +#ifdef CONFIG_PERFMON_TEST + +static void +pmu_amd_write(unsigned int pmc_id, uint64_t value) +{ + cpu_set_msr64(PMU_AMD_MSR_PERCTR0 + pmc_id, value); +} + +#endif /* CONFIG_PERFMON_TEST */ + +static void +pmu_amd_handle_of_intr_v1(struct trap_frame *frame) +{ + struct pmu_amd *pmu; + unsigned int mask; + uint64_t value; + uint64_t prev; + + (void)frame; + + pmu = pmu_amd_get(); + + for (unsigned int pmc_id = 0; pmc_id != PMU_AMD_NR_PMCS; pmc_id++) { + mask = (1U << pmc_id); + if (pmu->pmc_bm & mask) { + /* counter not enabled: can't overflow. */ + continue; + } + + value = pmu_amd_read(pmc_id); + prev = perfmon_cpu_pmc_get_prev(pmc_id); + if (prev > value) { + /* Overflow */ + perfmon_cpu_pmc_inc_of(pmc_id); + /* Prevents us from overflowing twice */ + perfmon_cpu_pmc_set_prev(pmc_id, value); + } + } +} + static uint8_t pmu_amd_get_pmc_width(void) { @@ -233,6 +275,10 @@ pmu_amd_setup(void) pmu_driver.stop = pmu_amd_stop; pmu_driver.read = pmu_amd_read; pmu_driver.get_pmc_width = pmu_amd_get_pmc_width; + pmu_driver.handle_of_intr = pmu_amd_handle_of_intr_v1; +#ifdef CONFIG_PERFMON_TEST + pmu_driver.write = pmu_amd_write; +#endif return perfmon_pmu_register(&pmu_driver); } -- cgit v1.2.3