summaryrefslogtreecommitdiff
path: root/arch/x86/machine/pmu_intel.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/machine/pmu_intel.c')
-rw-r--r--arch/x86/machine/pmu_intel.c49
1 files changed, 12 insertions, 37 deletions
diff --git a/arch/x86/machine/pmu_intel.c b/arch/x86/machine/pmu_intel.c
index ccc2294..e5d9ef7 100644
--- a/arch/x86/machine/pmu_intel.c
+++ b/arch/x86/machine/pmu_intel.c
@@ -21,6 +21,7 @@
#include <stdint.h>
#include <kern/init.h>
+#include <kern/clock.h>
#include <kern/log.h>
#include <kern/perfmon.h>
#include <machine/cpu.h>
@@ -174,7 +175,7 @@ pmu_intel_info(void)
pmu = pmu_intel_get();
nr_events = pmu_popcount(pmu->events);
- log_info("pmu: driver: intel, architectural v%d\n"
+ log_info("pmu: driver: intel, architectural v%d "
"pmu: nr_pmcs: %u, pmc_width: %u, events: %#x, nr_events: %u\n",
pmu->version, pmu->nr_pmcs, pmu->pmc_width, pmu->events,
nr_events);
@@ -233,19 +234,23 @@ static void
pmu_intel_start(unsigned int pmc_id, unsigned int raw_event_id)
{
const struct pmu_intel_event_code *code;
+ struct pmu_intel *pmu;
uint32_t evtsel;
assert(raw_event_id < ARRAY_SIZE(pmu_intel_event_codes));
code = &pmu_intel_event_codes[raw_event_id];
+ pmu = pmu_intel_get();
/* TODO Handle PERFMON_EF_KERN/PERFMON_EF_USER */
evtsel = PMU_INTEL_EVTSEL_EN
| PMU_INTEL_EVTSEL_OS
| PMU_INTEL_EVTSEL_USR
- | PMU_INTEL_EVTSEL_INT
| (code->umask << 8)
| code->event_select;
+ if (pmu->version >= 2) {
+ evtsel |= PMU_INTEL_EVTSEL_INT;
+ }
cpu_set_msr(PMU_INTEL_MSR_EVTSEL0 + pmc_id, 0, evtsel);
}
@@ -267,38 +272,6 @@ pmu_intel_write(unsigned int pmc_id, uint64_t value)
cpu_set_msr64(PMU_INTEL_MSR_PMC0 + pmc_id, value);
}
-/*
- * TODO Make the perfmon module handle basic overflow handling by polling
- * counters.
- */
-static void
-pmu_intel_handle_of_intr_v1(void)
-{
- struct pmu_intel *pmu;
- unsigned int mask;
- uint64_t value;
- uint64_t prev;
-
- 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 int
pmu_intel_consume_bits(uint64_t *bits)
{
@@ -330,7 +303,7 @@ pmu_intel_handle_of_intr_v2(void)
pmu_intel_ack_status(status);
pmu = pmu_intel_get();
- status &= ((1U << pmu->pmc_width) - 1);
+ status &= ((1ULL << pmu->pmc_width) - 1);
for (;;) {
pmc_id = pmu_intel_consume_bits(&status);
@@ -366,7 +339,6 @@ pmu_intel_setup(void)
cpu_cpuid(&eax, &ebx, &ecx, &edx);
pmu->version = eax & PMU_INTEL_ID_VERSION_MASK;
- /* TODO Check this */
if (pmu->version == 0) {
return ENODEV;
}
@@ -396,7 +368,10 @@ pmu_intel_setup(void)
pmu_driver.ops.handle_of_intr = pmu_intel_handle_of_intr_v2;
pmu_driver.of_max_ticks = 0;
} else {
- pmu_driver.of_max_ticks = 1UL << (pmu_driver.pmc_width - 1);
+ /* Set max_tick to half the number of instruction per seconds. */
+ pmu_driver.ops.handle_of_intr = NULL;
+ pmu_driver.of_max_ticks =
+ (1ULL << (pmu_driver.pmc_width - 1)) / (cpu_get_freq() / CLOCK_FREQ);
}
return perfmon_pmu_register(&pmu_driver);