Commit 047a3772 authored by Cyrill Gorcunov's avatar Cyrill Gorcunov Committed by Ingo Molnar

perf, x86: P4 PMU - Fix unflagged overflows handling

Don found that P4 PMU reads CCCR register instead of counter
itself (in attempt to catch unflagged event) this makes P4
NMI handler to consume all NMIs it observes. So the other
NMI users such as kgdb simply have no chance to get NMI
on their hands.

Side note: at moment there is no way to run nmi-watchdog
together with perf tool. This is because both 'perf top' and
nmi-watchdog use same event. So while nmi-watchdog reserves
one event/counter for own needs there is no room for perf tool
left (there is a way to disable nmi-watchdog on boot of course).

Ming has tested this patch with the following results

 | 1. watchdog disabled
 |
 | kgdb tests on boot OK
 | perf works OK
 |
 | 2. watchdog enabled, without patch perf-x86-p4-nmi-4
 |
 | kgdb tests on boot hang
 |
 | 3. watchdog enabled, without patch perf-x86-p4-nmi-4 and do not run kgdb
 | tests on boot
 |
 | "perf top" partialy works
 |   cpu-cycles            no
 |   instructions          yes
 |   cache-references      no
 |   cache-misses          no
 |   branch-instructions   no
 |   branch-misses         yes
 |   bus-cycles            no
 |
 | 4. watchdog enabled, with patch perf-x86-p4-nmi-4 applied
 |
 | kgdb tests on boot OK
 | perf does not work, NMI "Dazed and confused" messages show up
 |

Which means we still have problems with p4 box due to 'unknown'
nmi happens but at least it should fix kgdb test cases.
Reported-by: default avatarJason Wessel <jason.wessel@windriver.com>
Reported-by: default avatarDon Zickus <dzickus@redhat.com>
Signed-off-by: default avatarCyrill Gorcunov <gorcunov@openvz.org>
Acked-by: default avatarDon Zickus <dzickus@redhat.com>
Acked-by: default avatarLin Ming <ming.m.lin@intel.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
LKML-Reference: <4D275E7E.3040903@gmail.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 625dbc3b
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
#define ARCH_P4_MAX_ESCR (ARCH_P4_TOTAL_ESCR - ARCH_P4_RESERVED_ESCR) #define ARCH_P4_MAX_ESCR (ARCH_P4_TOTAL_ESCR - ARCH_P4_RESERVED_ESCR)
#define ARCH_P4_MAX_CCCR (18) #define ARCH_P4_MAX_CCCR (18)
#define ARCH_P4_CNTRVAL_BITS (40)
#define ARCH_P4_CNTRVAL_MASK ((1ULL << ARCH_P4_CNTRVAL_BITS) - 1)
#define P4_ESCR_EVENT_MASK 0x7e000000U #define P4_ESCR_EVENT_MASK 0x7e000000U
#define P4_ESCR_EVENT_SHIFT 25 #define P4_ESCR_EVENT_SHIFT 25
#define P4_ESCR_EVENTMASK_MASK 0x01fffe00U #define P4_ESCR_EVENTMASK_MASK 0x01fffe00U
......
...@@ -753,19 +753,21 @@ static int p4_hw_config(struct perf_event *event) ...@@ -753,19 +753,21 @@ static int p4_hw_config(struct perf_event *event)
static inline int p4_pmu_clear_cccr_ovf(struct hw_perf_event *hwc) static inline int p4_pmu_clear_cccr_ovf(struct hw_perf_event *hwc)
{ {
int overflow = 0; u64 v;
u32 low, high;
rdmsr(hwc->config_base + hwc->idx, low, high); /* an official way for overflow indication */
rdmsrl(hwc->config_base + hwc->idx, v);
/* we need to check high bit for unflagged overflows */ if (v & P4_CCCR_OVF) {
if ((low & P4_CCCR_OVF) || !(high & (1 << 31))) { wrmsrl(hwc->config_base + hwc->idx, v & ~P4_CCCR_OVF);
overflow = 1; return 1;
(void)checking_wrmsrl(hwc->config_base + hwc->idx,
((u64)low) & ~P4_CCCR_OVF);
} }
return overflow; /* it might be unflagged overflow */
rdmsrl(hwc->event_base + hwc->idx, v);
if (!(v & ARCH_P4_CNTRVAL_MASK))
return 1;
return 0;
} }
static void p4_pmu_disable_pebs(void) static void p4_pmu_disable_pebs(void)
...@@ -1152,9 +1154,9 @@ static __initconst const struct x86_pmu p4_pmu = { ...@@ -1152,9 +1154,9 @@ static __initconst const struct x86_pmu p4_pmu = {
*/ */
.num_counters = ARCH_P4_MAX_CCCR, .num_counters = ARCH_P4_MAX_CCCR,
.apic = 1, .apic = 1,
.cntval_bits = 40, .cntval_bits = ARCH_P4_CNTRVAL_BITS,
.cntval_mask = (1ULL << 40) - 1, .cntval_mask = ARCH_P4_CNTRVAL_MASK,
.max_period = (1ULL << 39) - 1, .max_period = (1ULL << (ARCH_P4_CNTRVAL_BITS - 1)) - 1,
.hw_config = p4_hw_config, .hw_config = p4_hw_config,
.schedule_events = p4_pmu_schedule_events, .schedule_events = p4_pmu_schedule_events,
/* /*
......
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