perf, x86: P4 PMU -- update nmi irq statistics and unmask lvt entry properly
authorCyrill Gorcunov <gorcunov@openvz.org>
Thu, 5 Aug 2010 15:09:17 +0000 (19:09 +0400)
committerIngo Molnar <mingo@elte.hu>
Sun, 8 Aug 2010 20:53:50 +0000 (22:53 +0200)
In case if last active performance counter is not overflowed at
moment of NMI being triggered by another counter, the irq
statistics may miss an update stage. As a more serious
consequence -- apic quirk may not be triggered so apic lvt entry
stay masked.

Tested-by: Lin Ming <ming.m.lin@intel.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
LKML-Reference: <20100805150917.GA6311@lenovo>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
arch/x86/kernel/cpu/perf_event_p4.c

index 107711b..febb12c 100644 (file)
@@ -656,6 +656,7 @@ static int p4_pmu_handle_irq(struct pt_regs *regs)
        cpuc = &__get_cpu_var(cpu_hw_events);
 
        for (idx = 0; idx < x86_pmu.num_counters; idx++) {
+               int overflow;
 
                if (!test_bit(idx, cpuc->active_mask))
                        continue;
@@ -666,12 +667,14 @@ static int p4_pmu_handle_irq(struct pt_regs *regs)
                WARN_ON_ONCE(hwc->idx != idx);
 
                /* it might be unflagged overflow */
-               handled = p4_pmu_clear_cccr_ovf(hwc);
+               overflow = p4_pmu_clear_cccr_ovf(hwc);
 
                val = x86_perf_event_update(event);
-               if (!handled && (val & (1ULL << (x86_pmu.cntval_bits - 1))))
+               if (!overflow && (val & (1ULL << (x86_pmu.cntval_bits - 1))))
                        continue;
 
+               handled += overflow;
+
                /* event overflow for sure */
                data.period = event->hw.last_period;
 
@@ -687,7 +690,7 @@ static int p4_pmu_handle_irq(struct pt_regs *regs)
                inc_irq_stat(apic_perf_irqs);
        }
 
-       return handled;
+       return handled > 0;
 }
 
 /*