Commit 0db1a7bc authored by Cyrill Gorcunov's avatar Cyrill Gorcunov Committed by Ingo Molnar

perf, x86: P4 PMU -- handle unflagged events

It might happen that an event can overflow without
the proper overflow flag set. Check the sign bit in
the raw counter value to solve this problem.
Tested-by: default avatarLin Ming <ming.m.lin@intel.com>
Signed-off-by: default avatarCyrill Gorcunov <gorcunov@openvz.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: fweisbec@gmail.com
Cc: Cyrill Gorcunov <gorcunov@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
LKML-Reference: <1274083984.6540.15.camel@minggr.sh.intel.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 32ec6acf
...@@ -465,15 +465,21 @@ static int p4_hw_config(struct perf_event *event) ...@@ -465,15 +465,21 @@ static int p4_hw_config(struct perf_event *event)
return rc; return rc;
} }
static inline void p4_pmu_clear_cccr_ovf(struct hw_perf_event *hwc) static inline int p4_pmu_clear_cccr_ovf(struct hw_perf_event *hwc)
{ {
unsigned long dummy; int overflow = 0;
u32 low, high;
rdmsrl(hwc->config_base + hwc->idx, dummy); rdmsr(hwc->config_base + hwc->idx, low, high);
if (dummy & P4_CCCR_OVF) {
/* we need to check high bit for unflagged overflows */
if ((low & P4_CCCR_OVF) || (high & (1 << 31))) {
overflow = 1;
(void)checking_wrmsrl(hwc->config_base + hwc->idx, (void)checking_wrmsrl(hwc->config_base + hwc->idx,
((u64)dummy) & ~P4_CCCR_OVF); ((u64)low) & ~P4_CCCR_OVF);
} }
return overflow;
} }
static inline void p4_pmu_disable_event(struct perf_event *event) static inline void p4_pmu_disable_event(struct perf_event *event)
...@@ -584,21 +590,15 @@ static int p4_pmu_handle_irq(struct pt_regs *regs) ...@@ -584,21 +590,15 @@ static int p4_pmu_handle_irq(struct pt_regs *regs)
WARN_ON_ONCE(hwc->idx != idx); WARN_ON_ONCE(hwc->idx != idx);
/* /* it might be unflagged overflow */
* FIXME: Redundant call, actually not needed handled = p4_pmu_clear_cccr_ovf(hwc);
* but just to check if we're screwed
*/
p4_pmu_clear_cccr_ovf(hwc);
val = x86_perf_event_update(event); val = x86_perf_event_update(event);
if (val & (1ULL << (x86_pmu.cntval_bits - 1))) if (!handled && (val & (1ULL << (x86_pmu.cntval_bits - 1))))
continue; continue;
/* /* event overflow for sure */
* event overflow data.period = event->hw.last_period;
*/
handled = 1;
data.period = event->hw.last_period;
if (!x86_perf_event_set_period(event)) if (!x86_perf_event_set_period(event))
continue; continue;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment