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 | ||
