diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2010-01-29 07:25:31 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-02-04 03:59:49 -0500 |
commit | 8c48e444191de0ff84e85d41180d7bc3e74f14ef (patch) | |
tree | 73d8f6eec69b43568d942f8a75ef4cd9666e1d7e | |
parent | 9717e6cd3db22eade7dbae0fc9235c66325a7132 (diff) |
perf_events, x86: Implement intel core solo/duo support
Implement Intel Core Solo/Duo, aka.
Intel Architectural Performance Monitoring Version 1.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | arch/x86/kernel/cpu/perf_event.c | 133 |
1 files changed, 61 insertions, 72 deletions
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 1846ead0576b..5b91992b6b25 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c | |||
@@ -228,6 +228,17 @@ static const u64 intel_perfmon_event_map[] = | |||
228 | 228 | ||
229 | static struct event_constraint intel_core_event_constraints[] = | 229 | static struct event_constraint intel_core_event_constraints[] = |
230 | { | 230 | { |
231 | INTEL_EVENT_CONSTRAINT(0x11, 0x2), /* FP_ASSIST */ | ||
232 | INTEL_EVENT_CONSTRAINT(0x12, 0x2), /* MUL */ | ||
233 | INTEL_EVENT_CONSTRAINT(0x13, 0x2), /* DIV */ | ||
234 | INTEL_EVENT_CONSTRAINT(0x14, 0x1), /* CYCLES_DIV_BUSY */ | ||
235 | INTEL_EVENT_CONSTRAINT(0x19, 0x2), /* DELAYED_BYPASS */ | ||
236 | INTEL_EVENT_CONSTRAINT(0xc1, 0x1), /* FP_COMP_INSTR_RET */ | ||
237 | EVENT_CONSTRAINT_END | ||
238 | }; | ||
239 | |||
240 | static struct event_constraint intel_core2_event_constraints[] = | ||
241 | { | ||
231 | FIXED_EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32))), /* INSTRUCTIONS_RETIRED */ | 242 | FIXED_EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32))), /* INSTRUCTIONS_RETIRED */ |
232 | FIXED_EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33))), /* UNHALTED_CORE_CYCLES */ | 243 | FIXED_EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33))), /* UNHALTED_CORE_CYCLES */ |
233 | INTEL_EVENT_CONSTRAINT(0x10, 0x1), /* FP_COMP_OPS_EXE */ | 244 | INTEL_EVENT_CONSTRAINT(0x10, 0x1), /* FP_COMP_OPS_EXE */ |
@@ -1216,7 +1227,7 @@ static void intel_pmu_disable_all(void) | |||
1216 | intel_pmu_disable_bts(); | 1227 | intel_pmu_disable_bts(); |
1217 | } | 1228 | } |
1218 | 1229 | ||
1219 | static void amd_pmu_disable_all(void) | 1230 | static void x86_pmu_disable_all(void) |
1220 | { | 1231 | { |
1221 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | 1232 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); |
1222 | int idx; | 1233 | int idx; |
@@ -1226,11 +1237,11 @@ static void amd_pmu_disable_all(void) | |||
1226 | 1237 | ||
1227 | if (!test_bit(idx, cpuc->active_mask)) | 1238 | if (!test_bit(idx, cpuc->active_mask)) |
1228 | continue; | 1239 | continue; |
1229 | rdmsrl(MSR_K7_EVNTSEL0 + idx, val); | 1240 | rdmsrl(x86_pmu.eventsel + idx, val); |
1230 | if (!(val & ARCH_PERFMON_EVENTSEL0_ENABLE)) | 1241 | if (!(val & ARCH_PERFMON_EVENTSEL0_ENABLE)) |
1231 | continue; | 1242 | continue; |
1232 | val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE; | 1243 | val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE; |
1233 | wrmsrl(MSR_K7_EVNTSEL0 + idx, val); | 1244 | wrmsrl(x86_pmu.eventsel + idx, val); |
1234 | } | 1245 | } |
1235 | } | 1246 | } |
1236 | 1247 | ||
@@ -1278,7 +1289,7 @@ static void intel_pmu_enable_all(void) | |||
1278 | } | 1289 | } |
1279 | } | 1290 | } |
1280 | 1291 | ||
1281 | static void amd_pmu_enable_all(void) | 1292 | static void x86_pmu_enable_all(void) |
1282 | { | 1293 | { |
1283 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | 1294 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); |
1284 | int idx; | 1295 | int idx; |
@@ -1292,7 +1303,7 @@ static void amd_pmu_enable_all(void) | |||
1292 | 1303 | ||
1293 | val = event->hw.config; | 1304 | val = event->hw.config; |
1294 | val |= ARCH_PERFMON_EVENTSEL0_ENABLE; | 1305 | val |= ARCH_PERFMON_EVENTSEL0_ENABLE; |
1295 | wrmsrl(MSR_K7_EVNTSEL0 + idx, val); | 1306 | wrmsrl(x86_pmu.eventsel + idx, val); |
1296 | } | 1307 | } |
1297 | } | 1308 | } |
1298 | 1309 | ||
@@ -1546,7 +1557,7 @@ static inline void intel_pmu_ack_status(u64 ack) | |||
1546 | wrmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, ack); | 1557 | wrmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, ack); |
1547 | } | 1558 | } |
1548 | 1559 | ||
1549 | static inline void x86_pmu_enable_event(struct hw_perf_event *hwc, int idx) | 1560 | static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc, int idx) |
1550 | { | 1561 | { |
1551 | (void)checking_wrmsrl(hwc->config_base + idx, | 1562 | (void)checking_wrmsrl(hwc->config_base + idx, |
1552 | hwc->config | ARCH_PERFMON_EVENTSEL0_ENABLE); | 1563 | hwc->config | ARCH_PERFMON_EVENTSEL0_ENABLE); |
@@ -1598,12 +1609,6 @@ intel_pmu_disable_event(struct hw_perf_event *hwc, int idx) | |||
1598 | x86_pmu_disable_event(hwc, idx); | 1609 | x86_pmu_disable_event(hwc, idx); |
1599 | } | 1610 | } |
1600 | 1611 | ||
1601 | static inline void | ||
1602 | amd_pmu_disable_event(struct hw_perf_event *hwc, int idx) | ||
1603 | { | ||
1604 | x86_pmu_disable_event(hwc, idx); | ||
1605 | } | ||
1606 | |||
1607 | static DEFINE_PER_CPU(u64 [X86_PMC_IDX_MAX], pmc_prev_left); | 1612 | static DEFINE_PER_CPU(u64 [X86_PMC_IDX_MAX], pmc_prev_left); |
1608 | 1613 | ||
1609 | /* | 1614 | /* |
@@ -1723,15 +1728,14 @@ static void intel_pmu_enable_event(struct hw_perf_event *hwc, int idx) | |||
1723 | return; | 1728 | return; |
1724 | } | 1729 | } |
1725 | 1730 | ||
1726 | x86_pmu_enable_event(hwc, idx); | 1731 | __x86_pmu_enable_event(hwc, idx); |
1727 | } | 1732 | } |
1728 | 1733 | ||
1729 | static void amd_pmu_enable_event(struct hw_perf_event *hwc, int idx) | 1734 | static void x86_pmu_enable_event(struct hw_perf_event *hwc, int idx) |
1730 | { | 1735 | { |
1731 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | 1736 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); |
1732 | |||
1733 | if (cpuc->enabled) | 1737 | if (cpuc->enabled) |
1734 | x86_pmu_enable_event(hwc, idx); | 1738 | __x86_pmu_enable_event(hwc, idx); |
1735 | } | 1739 | } |
1736 | 1740 | ||
1737 | /* | 1741 | /* |
@@ -1988,50 +1992,6 @@ static void intel_pmu_reset(void) | |||
1988 | local_irq_restore(flags); | 1992 | local_irq_restore(flags); |
1989 | } | 1993 | } |
1990 | 1994 | ||
1991 | static int p6_pmu_handle_irq(struct pt_regs *regs) | ||
1992 | { | ||
1993 | struct perf_sample_data data; | ||
1994 | struct cpu_hw_events *cpuc; | ||
1995 | struct perf_event *event; | ||
1996 | struct hw_perf_event *hwc; | ||
1997 | int idx, handled = 0; | ||
1998 | u64 val; | ||
1999 | |||
2000 | data.addr = 0; | ||
2001 | data.raw = NULL; | ||
2002 | |||
2003 | cpuc = &__get_cpu_var(cpu_hw_events); | ||
2004 | |||
2005 | for (idx = 0; idx < x86_pmu.num_events; idx++) { | ||
2006 | if (!test_bit(idx, cpuc->active_mask)) | ||
2007 | continue; | ||
2008 | |||
2009 | event = cpuc->events[idx]; | ||
2010 | hwc = &event->hw; | ||
2011 | |||
2012 | val = x86_perf_event_update(event, hwc, idx); | ||
2013 | if (val & (1ULL << (x86_pmu.event_bits - 1))) | ||
2014 | continue; | ||
2015 | |||
2016 | /* | ||
2017 | * event overflow | ||
2018 | */ | ||
2019 | handled = 1; | ||
2020 | data.period = event->hw.last_period; | ||
2021 | |||
2022 | if (!x86_perf_event_set_period(event, hwc, idx)) | ||
2023 | continue; | ||
2024 | |||
2025 | if (perf_event_overflow(event, 1, &data, regs)) | ||
2026 | p6_pmu_disable_event(hwc, idx); | ||
2027 | } | ||
2028 | |||
2029 | if (handled) | ||
2030 | inc_irq_stat(apic_perf_irqs); | ||
2031 | |||
2032 | return handled; | ||
2033 | } | ||
2034 | |||
2035 | /* | 1995 | /* |
2036 | * This handler is triggered by the local APIC, so the APIC IRQ handling | 1996 | * This handler is triggered by the local APIC, so the APIC IRQ handling |
2037 | * rules apply: | 1997 | * rules apply: |
@@ -2098,7 +2058,7 @@ again: | |||
2098 | return 1; | 2058 | return 1; |
2099 | } | 2059 | } |
2100 | 2060 | ||
2101 | static int amd_pmu_handle_irq(struct pt_regs *regs) | 2061 | static int x86_pmu_handle_irq(struct pt_regs *regs) |
2102 | { | 2062 | { |
2103 | struct perf_sample_data data; | 2063 | struct perf_sample_data data; |
2104 | struct cpu_hw_events *cpuc; | 2064 | struct cpu_hw_events *cpuc; |
@@ -2133,7 +2093,7 @@ static int amd_pmu_handle_irq(struct pt_regs *regs) | |||
2133 | continue; | 2093 | continue; |
2134 | 2094 | ||
2135 | if (perf_event_overflow(event, 1, &data, regs)) | 2095 | if (perf_event_overflow(event, 1, &data, regs)) |
2136 | amd_pmu_disable_event(hwc, idx); | 2096 | x86_pmu.disable(hwc, idx); |
2137 | } | 2097 | } |
2138 | 2098 | ||
2139 | if (handled) | 2099 | if (handled) |
@@ -2374,7 +2334,7 @@ static __read_mostly struct notifier_block perf_event_nmi_notifier = { | |||
2374 | 2334 | ||
2375 | static __initconst struct x86_pmu p6_pmu = { | 2335 | static __initconst struct x86_pmu p6_pmu = { |
2376 | .name = "p6", | 2336 | .name = "p6", |
2377 | .handle_irq = p6_pmu_handle_irq, | 2337 | .handle_irq = x86_pmu_handle_irq, |
2378 | .disable_all = p6_pmu_disable_all, | 2338 | .disable_all = p6_pmu_disable_all, |
2379 | .enable_all = p6_pmu_enable_all, | 2339 | .enable_all = p6_pmu_enable_all, |
2380 | .enable = p6_pmu_enable_event, | 2340 | .enable = p6_pmu_enable_event, |
@@ -2401,6 +2361,29 @@ static __initconst struct x86_pmu p6_pmu = { | |||
2401 | .event_constraints = intel_p6_event_constraints | 2361 | .event_constraints = intel_p6_event_constraints |
2402 | }; | 2362 | }; |
2403 | 2363 | ||
2364 | static __initconst struct x86_pmu core_pmu = { | ||
2365 | .name = "core", | ||
2366 | .handle_irq = x86_pmu_handle_irq, | ||
2367 | .disable_all = x86_pmu_disable_all, | ||
2368 | .enable_all = x86_pmu_enable_all, | ||
2369 | .enable = x86_pmu_enable_event, | ||
2370 | .disable = x86_pmu_disable_event, | ||
2371 | .eventsel = MSR_ARCH_PERFMON_EVENTSEL0, | ||
2372 | .perfctr = MSR_ARCH_PERFMON_PERFCTR0, | ||
2373 | .event_map = intel_pmu_event_map, | ||
2374 | .raw_event = intel_pmu_raw_event, | ||
2375 | .max_events = ARRAY_SIZE(intel_perfmon_event_map), | ||
2376 | .apic = 1, | ||
2377 | /* | ||
2378 | * Intel PMCs cannot be accessed sanely above 32 bit width, | ||
2379 | * so we install an artificial 1<<31 period regardless of | ||
2380 | * the generic event period: | ||
2381 | */ | ||
2382 | .max_period = (1ULL << 31) - 1, | ||
2383 | .get_event_constraints = intel_get_event_constraints, | ||
2384 | .event_constraints = intel_core_event_constraints, | ||
2385 | }; | ||
2386 | |||
2404 | static __initconst struct x86_pmu intel_pmu = { | 2387 | static __initconst struct x86_pmu intel_pmu = { |
2405 | .name = "Intel", | 2388 | .name = "Intel", |
2406 | .handle_irq = intel_pmu_handle_irq, | 2389 | .handle_irq = intel_pmu_handle_irq, |
@@ -2427,11 +2410,11 @@ static __initconst struct x86_pmu intel_pmu = { | |||
2427 | 2410 | ||
2428 | static __initconst struct x86_pmu amd_pmu = { | 2411 | static __initconst struct x86_pmu amd_pmu = { |
2429 | .name = "AMD", | 2412 | .name = "AMD", |
2430 | .handle_irq = amd_pmu_handle_irq, | 2413 | .handle_irq = x86_pmu_handle_irq, |
2431 | .disable_all = amd_pmu_disable_all, | 2414 | .disable_all = x86_pmu_disable_all, |
2432 | .enable_all = amd_pmu_enable_all, | 2415 | .enable_all = x86_pmu_enable_all, |
2433 | .enable = amd_pmu_enable_event, | 2416 | .enable = x86_pmu_enable_event, |
2434 | .disable = amd_pmu_disable_event, | 2417 | .disable = x86_pmu_disable_event, |
2435 | .eventsel = MSR_K7_EVNTSEL0, | 2418 | .eventsel = MSR_K7_EVNTSEL0, |
2436 | .perfctr = MSR_K7_PERFCTR0, | 2419 | .perfctr = MSR_K7_PERFCTR0, |
2437 | .event_map = amd_pmu_event_map, | 2420 | .event_map = amd_pmu_event_map, |
@@ -2498,9 +2481,10 @@ static __init int intel_pmu_init(void) | |||
2498 | 2481 | ||
2499 | version = eax.split.version_id; | 2482 | version = eax.split.version_id; |
2500 | if (version < 2) | 2483 | if (version < 2) |
2501 | return -ENODEV; | 2484 | x86_pmu = core_pmu; |
2485 | else | ||
2486 | x86_pmu = intel_pmu; | ||
2502 | 2487 | ||
2503 | x86_pmu = intel_pmu; | ||
2504 | x86_pmu.version = version; | 2488 | x86_pmu.version = version; |
2505 | x86_pmu.num_events = eax.split.num_events; | 2489 | x86_pmu.num_events = eax.split.num_events; |
2506 | x86_pmu.event_bits = eax.split.bit_width; | 2490 | x86_pmu.event_bits = eax.split.bit_width; |
@@ -2510,12 +2494,17 @@ static __init int intel_pmu_init(void) | |||
2510 | * Quirk: v2 perfmon does not report fixed-purpose events, so | 2494 | * Quirk: v2 perfmon does not report fixed-purpose events, so |
2511 | * assume at least 3 events: | 2495 | * assume at least 3 events: |
2512 | */ | 2496 | */ |
2513 | x86_pmu.num_events_fixed = max((int)edx.split.num_events_fixed, 3); | 2497 | if (version > 1) |
2498 | x86_pmu.num_events_fixed = max((int)edx.split.num_events_fixed, 3); | ||
2514 | 2499 | ||
2515 | /* | 2500 | /* |
2516 | * Install the hw-cache-events table: | 2501 | * Install the hw-cache-events table: |
2517 | */ | 2502 | */ |
2518 | switch (boot_cpu_data.x86_model) { | 2503 | switch (boot_cpu_data.x86_model) { |
2504 | case 14: /* 65 nm core solo/duo, "Yonah" */ | ||
2505 | pr_cont("Core events, "); | ||
2506 | break; | ||
2507 | |||
2519 | case 15: /* original 65 nm celeron/pentium/core2/xeon, "Merom"/"Conroe" */ | 2508 | case 15: /* original 65 nm celeron/pentium/core2/xeon, "Merom"/"Conroe" */ |
2520 | case 22: /* single-core 65 nm celeron/core2solo "Merom-L"/"Conroe-L" */ | 2509 | case 22: /* single-core 65 nm celeron/core2solo "Merom-L"/"Conroe-L" */ |
2521 | case 23: /* current 45 nm celeron/core2/xeon "Penryn"/"Wolfdale" */ | 2510 | case 23: /* current 45 nm celeron/core2/xeon "Penryn"/"Wolfdale" */ |
@@ -2523,7 +2512,7 @@ static __init int intel_pmu_init(void) | |||
2523 | memcpy(hw_cache_event_ids, core2_hw_cache_event_ids, | 2512 | memcpy(hw_cache_event_ids, core2_hw_cache_event_ids, |
2524 | sizeof(hw_cache_event_ids)); | 2513 | sizeof(hw_cache_event_ids)); |
2525 | 2514 | ||
2526 | x86_pmu.event_constraints = intel_core_event_constraints; | 2515 | x86_pmu.event_constraints = intel_core2_event_constraints; |
2527 | pr_cont("Core2 events, "); | 2516 | pr_cont("Core2 events, "); |
2528 | break; | 2517 | break; |
2529 | 2518 | ||