diff options
Diffstat (limited to 'arch/x86/kernel/cpu/perf_event.c')
-rw-r--r-- | arch/x86/kernel/cpu/perf_event.c | 50 |
1 files changed, 28 insertions, 22 deletions
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index eed3673a8656..3a0338b4b179 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <asm/nmi.h> | 31 | #include <asm/nmi.h> |
32 | #include <asm/compat.h> | 32 | #include <asm/compat.h> |
33 | #include <asm/smp.h> | 33 | #include <asm/smp.h> |
34 | #include <asm/alternative.h> | ||
34 | 35 | ||
35 | #if 0 | 36 | #if 0 |
36 | #undef wrmsrl | 37 | #undef wrmsrl |
@@ -363,12 +364,18 @@ again: | |||
363 | return new_raw_count; | 364 | return new_raw_count; |
364 | } | 365 | } |
365 | 366 | ||
366 | /* using X86_FEATURE_PERFCTR_CORE to later implement ALTERNATIVE() here */ | ||
367 | static inline int x86_pmu_addr_offset(int index) | 367 | static inline int x86_pmu_addr_offset(int index) |
368 | { | 368 | { |
369 | if (boot_cpu_has(X86_FEATURE_PERFCTR_CORE)) | 369 | int offset; |
370 | return index << 1; | 370 | |
371 | return index; | 371 | /* offset = X86_FEATURE_PERFCTR_CORE ? index << 1 : index */ |
372 | alternative_io(ASM_NOP2, | ||
373 | "shll $1, %%eax", | ||
374 | X86_FEATURE_PERFCTR_CORE, | ||
375 | "=a" (offset), | ||
376 | "a" (index)); | ||
377 | |||
378 | return offset; | ||
372 | } | 379 | } |
373 | 380 | ||
374 | static inline unsigned int x86_pmu_config_addr(int index) | 381 | static inline unsigned int x86_pmu_config_addr(int index) |
@@ -586,8 +593,12 @@ static int x86_setup_perfctr(struct perf_event *event) | |||
586 | return -EOPNOTSUPP; | 593 | return -EOPNOTSUPP; |
587 | } | 594 | } |
588 | 595 | ||
596 | /* | ||
597 | * Do not allow config1 (extended registers) to propagate, | ||
598 | * there's no sane user-space generalization yet: | ||
599 | */ | ||
589 | if (attr->type == PERF_TYPE_RAW) | 600 | if (attr->type == PERF_TYPE_RAW) |
590 | return x86_pmu_extra_regs(event->attr.config, event); | 601 | return 0; |
591 | 602 | ||
592 | if (attr->type == PERF_TYPE_HW_CACHE) | 603 | if (attr->type == PERF_TYPE_HW_CACHE) |
593 | return set_ext_hw_attr(hwc, event); | 604 | return set_ext_hw_attr(hwc, event); |
@@ -609,8 +620,8 @@ static int x86_setup_perfctr(struct perf_event *event) | |||
609 | /* | 620 | /* |
610 | * Branch tracing: | 621 | * Branch tracing: |
611 | */ | 622 | */ |
612 | if ((attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS) && | 623 | if (attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS && |
613 | (hwc->sample_period == 1)) { | 624 | !attr->freq && hwc->sample_period == 1) { |
614 | /* BTS is not supported by this architecture. */ | 625 | /* BTS is not supported by this architecture. */ |
615 | if (!x86_pmu.bts_active) | 626 | if (!x86_pmu.bts_active) |
616 | return -EOPNOTSUPP; | 627 | return -EOPNOTSUPP; |
@@ -1284,6 +1295,16 @@ static int x86_pmu_handle_irq(struct pt_regs *regs) | |||
1284 | 1295 | ||
1285 | cpuc = &__get_cpu_var(cpu_hw_events); | 1296 | cpuc = &__get_cpu_var(cpu_hw_events); |
1286 | 1297 | ||
1298 | /* | ||
1299 | * Some chipsets need to unmask the LVTPC in a particular spot | ||
1300 | * inside the nmi handler. As a result, the unmasking was pushed | ||
1301 | * into all the nmi handlers. | ||
1302 | * | ||
1303 | * This generic handler doesn't seem to have any issues where the | ||
1304 | * unmasking occurs so it was left at the top. | ||
1305 | */ | ||
1306 | apic_write(APIC_LVTPC, APIC_DM_NMI); | ||
1307 | |||
1287 | for (idx = 0; idx < x86_pmu.num_counters; idx++) { | 1308 | for (idx = 0; idx < x86_pmu.num_counters; idx++) { |
1288 | if (!test_bit(idx, cpuc->active_mask)) { | 1309 | if (!test_bit(idx, cpuc->active_mask)) { |
1289 | /* | 1310 | /* |
@@ -1370,8 +1391,6 @@ perf_event_nmi_handler(struct notifier_block *self, | |||
1370 | return NOTIFY_DONE; | 1391 | return NOTIFY_DONE; |
1371 | } | 1392 | } |
1372 | 1393 | ||
1373 | apic_write(APIC_LVTPC, APIC_DM_NMI); | ||
1374 | |||
1375 | handled = x86_pmu.handle_irq(args->regs); | 1394 | handled = x86_pmu.handle_irq(args->regs); |
1376 | if (!handled) | 1395 | if (!handled) |
1377 | return NOTIFY_DONE; | 1396 | return NOTIFY_DONE; |
@@ -1754,17 +1773,6 @@ static struct pmu pmu = { | |||
1754 | * callchain support | 1773 | * callchain support |
1755 | */ | 1774 | */ |
1756 | 1775 | ||
1757 | static void | ||
1758 | backtrace_warning_symbol(void *data, char *msg, unsigned long symbol) | ||
1759 | { | ||
1760 | /* Ignore warnings */ | ||
1761 | } | ||
1762 | |||
1763 | static void backtrace_warning(void *data, char *msg) | ||
1764 | { | ||
1765 | /* Ignore warnings */ | ||
1766 | } | ||
1767 | |||
1768 | static int backtrace_stack(void *data, char *name) | 1776 | static int backtrace_stack(void *data, char *name) |
1769 | { | 1777 | { |
1770 | return 0; | 1778 | return 0; |
@@ -1778,8 +1786,6 @@ static void backtrace_address(void *data, unsigned long addr, int reliable) | |||
1778 | } | 1786 | } |
1779 | 1787 | ||
1780 | static const struct stacktrace_ops backtrace_ops = { | 1788 | static const struct stacktrace_ops backtrace_ops = { |
1781 | .warning = backtrace_warning, | ||
1782 | .warning_symbol = backtrace_warning_symbol, | ||
1783 | .stack = backtrace_stack, | 1789 | .stack = backtrace_stack, |
1784 | .address = backtrace_address, | 1790 | .address = backtrace_address, |
1785 | .walk_stack = print_context_stack_bp, | 1791 | .walk_stack = print_context_stack_bp, |