summaryrefslogtreecommitdiff
path: root/arch/x86/machine/pmu_amd.c
diff options
context:
space:
mode:
authorRemy Noel <mocramis@gmail.com>2018-04-21 11:29:09 +0200
committerRemy Noel <mocramis@gmail.com>2018-04-21 11:29:09 +0200
commitee443edc22d4113e57ddb9671f0ff6e2fe14a19a (patch)
tree2d5e365dbaeca7de2fd00d8ad1bae5443a81e707 /arch/x86/machine/pmu_amd.c
parent7fa079430524d77eeec1e3e3097aba8f3c42b173 (diff)
pmu_amd: Add AMD overflow handling (untested).
Diffstat (limited to 'arch/x86/machine/pmu_amd.c')
-rw-r--r--arch/x86/machine/pmu_amd.c46
1 files changed, 46 insertions, 0 deletions
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);
}