diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-12-08 08:20:16 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-12-08 09:56:42 -0500 |
commit | 87b9cf4623ad4e5fc009e48c020593dffd5d3793 (patch) | |
tree | bd49f47b3fee4f4dc956e7db303fb1c20d53eee3 /arch | |
parent | 241771ef016b5c0c83cd7a4372a74321c973c1e6 (diff) |
x86, perfcounters: read out MSR_CORE_PERF_GLOBAL_STATUS with counters disabled
Impact: make perfcounter NMI and IRQ sequence more robust
Make __smp_perf_counter_interrupt() a bit more conservative: first disable
all counters, then read out the status. Most invocations are because there
are real events, so there's no performance impact.
Code flow gets a bit simpler as well this way.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kernel/cpu/perf_counter.c | 12 |
1 files changed, 5 insertions, 7 deletions
diff --git a/arch/x86/kernel/cpu/perf_counter.c b/arch/x86/kernel/cpu/perf_counter.c index 82440cbed0e6..615e953208ef 100644 --- a/arch/x86/kernel/cpu/perf_counter.c +++ b/arch/x86/kernel/cpu/perf_counter.c | |||
@@ -383,18 +383,16 @@ static void __smp_perf_counter_interrupt(struct pt_regs *regs, int nmi) | |||
383 | struct cpu_hw_counters *cpuc; | 383 | struct cpu_hw_counters *cpuc; |
384 | u64 ack, status; | 384 | u64 ack, status; |
385 | 385 | ||
386 | rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, status); | ||
387 | if (!status) { | ||
388 | ack_APIC_irq(); | ||
389 | return; | ||
390 | } | ||
391 | |||
392 | /* Disable counters globally */ | 386 | /* Disable counters globally */ |
393 | wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, 0, 0); | 387 | wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, 0, 0); |
394 | ack_APIC_irq(); | 388 | ack_APIC_irq(); |
395 | 389 | ||
396 | cpuc = &per_cpu(cpu_hw_counters, cpu); | 390 | cpuc = &per_cpu(cpu_hw_counters, cpu); |
397 | 391 | ||
392 | rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, status); | ||
393 | if (!status) | ||
394 | goto out; | ||
395 | |||
398 | again: | 396 | again: |
399 | ack = status; | 397 | ack = status; |
400 | for_each_bit(bit, (unsigned long *) &status, nr_hw_counters) { | 398 | for_each_bit(bit, (unsigned long *) &status, nr_hw_counters) { |
@@ -440,7 +438,7 @@ again: | |||
440 | rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, status); | 438 | rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, status); |
441 | if (status) | 439 | if (status) |
442 | goto again; | 440 | goto again; |
443 | 441 | out: | |
444 | /* | 442 | /* |
445 | * Do not reenable when global enable is off: | 443 | * Do not reenable when global enable is off: |
446 | */ | 444 | */ |