summaryrefslogtreecommitdiff
path: root/arch/x86/machine
diff options
context:
space:
mode:
authorRemy Noel <mocramis@gmail.com>2018-04-18 19:21:42 +0200
committerRemy Noel <mocramis@gmail.com>2018-04-21 00:04:20 +0200
commit75924457863e9dc90475b5cbd9bcabfff87cfc0d (patch)
tree8c23f70d8c41a5cb17e370735f5026f7c2c94656 /arch/x86/machine
parentb6ee3f35eb82e826e800cdc4ba483c1428a6e6d6 (diff)
perfmon: Add overflow handling.
Only architectural version 1 handled so far.
Diffstat (limited to 'arch/x86/machine')
-rw-r--r--arch/x86/machine/pmu_intel.c36
-rw-r--r--arch/x86/machine/trap.c2
2 files changed, 37 insertions, 1 deletions
diff --git a/arch/x86/machine/pmu_intel.c b/arch/x86/machine/pmu_intel.c
index fcebb06..6439282 100644
--- a/arch/x86/machine/pmu_intel.c
+++ b/arch/x86/machine/pmu_intel.c
@@ -49,7 +49,11 @@
*/
#define PMU_INTEL_EVTSEL_USR 0x00010000
#define PMU_INTEL_EVTSEL_OS 0x00020000
+#define PMU_INTEL_EVTSEL_EDGE 0x00040000
+#define PMU_INTEL_EVTSEL_PC 0x00080000
+#define PMU_INTEL_EVTSEL_INT 0x00100000
#define PMU_INTEL_EVTSEL_EN 0x00400000
+#define PMU_INTEL_EVTSEL_INV 0x00800000
#define PMU_INTEL_ID_VERSION_MASK 0x000000ff
#define PMU_INTEL_ID_NR_PMCS_MASK 0x0000ff00
@@ -209,6 +213,7 @@ pmu_intel_start(unsigned int pmc_id, unsigned int raw_event_id)
evtsel = PMU_INTEL_EVTSEL_EN
| PMU_INTEL_EVTSEL_OS
| PMU_INTEL_EVTSEL_USR
+ | PMU_INTEL_EVTSEL_INT
| (code->umask << 8)
| code->event_select;
cpu_set_msr(PMU_INTEL_MSR_EVTSEL0 + pmc_id, 0, evtsel);
@@ -226,6 +231,36 @@ pmu_intel_read(unsigned int pmc_id)
return cpu_get_msr64(PMU_INTEL_MSR_PMC0 + pmc_id);
}
+static void
+pmu_intel_handle_of_intr_v1(struct trap_frame *frame)
+{
+ struct pmu_intel *pmu;
+ unsigned int mask;
+ uint64_t value;
+ uint64_t prev;
+
+ (void)frame;
+
+ pmu = pmu_intel_get();
+
+ for (unsigned int pmc_id = 0; pmc_id != pmu->nr_pmcs; pmc_id++) {
+ mask = (1U << pmc_id);
+ if (pmu->pmc_bm & mask) {
+ /* counter not enabled: can't overflow. */
+ continue;
+ }
+
+ value = pmu_intel_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_intel_get_pmc_width(void)
{
@@ -282,6 +317,7 @@ 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;
return perfmon_pmu_register(&pmu_driver);
}
diff --git a/arch/x86/machine/trap.c b/arch/x86/machine/trap.c
index 0e98015..101adf8 100644
--- a/arch/x86/machine/trap.c
+++ b/arch/x86/machine/trap.c
@@ -210,7 +210,7 @@ trap_setup(void)
trap_install(TRAP_XCALL, TRAP_HF_INTR, cpu_xcall_intr);
trap_install(TRAP_THREAD_SCHEDULE, TRAP_HF_INTR, cpu_thread_schedule_intr);
trap_install(TRAP_CPU_HALT, TRAP_HF_INTR, cpu_halt_intr);
- trap_install(TRAP_LAPIC_PMC_OF, TRAP_HF_INTR, lapic_pmc_of_intr);
+ trap_install(TRAP_LAPIC_PMC_OF, TRAP_HF_INTR, trap_default);
trap_install(TRAP_LAPIC_TIMER, TRAP_HF_INTR, lapic_timer_intr);
trap_install(TRAP_LAPIC_ERROR, TRAP_HF_INTR, lapic_error_intr);
trap_install(TRAP_LAPIC_SPURIOUS, TRAP_HF_INTR, lapic_spurious_intr);