diff options
author | Cyrill Gorcunov <gorcunov@gmail.com> | 2010-05-14 15:08:15 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-05-15 02:38:55 -0400 |
commit | 1ff3d7d79204612ebe2e611d2592f8898908ca00 (patch) | |
tree | 666a907c25cc9ebeff05dfe982b5d480f42f64ad | |
parent | 5d2be7cb198a0a6bc6088d3806fb7261b184ad89 (diff) |
x86, perf: P4 PMU - fix counters management logic
Jaswinder reported this #GP:
|
| Message from syslogd@ht at May 14 09:39:32 ...
| kernel:[ 314.908612] EIP: [<c100ccca>]
| x86_perf_event_set_period+0x19d/0x1b2 SS:ESP 0068:edac3d70
|
Ming has narrowed it down to a comparision issue
between arguments with different sizes and
signs. As result event index reached a wrong
value which in turn led to a GP fault.
At the same time it was found that p4_next_cntr
has broken logic and should return the counter
index only if it was not yet borrowed for
another event.
Reported-by: Jaswinder Singh Rajput <jaswinderlinux@gmail.com>
Reported-by: Lin Ming <ming.m.lin@intel.com>
Bisected-by: Lin Ming <ming.m.lin@intel.com>
Tested-by: Jaswinder Singh Rajput <jaswinderlinux@gmail.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
CC: Peter Zijlstra <a.p.zijlstra@chello.nl>
CC: Frederic Weisbecker <fweisbec@gmail.com>
LKML-Reference: <20100514190815.GG13509@lenovo>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | arch/x86/kernel/cpu/perf_event_p4.c | 8 |
1 files changed, 4 insertions, 4 deletions
diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c index cb875b1e2e87..424fc8de68e4 100644 --- a/arch/x86/kernel/cpu/perf_event_p4.c +++ b/arch/x86/kernel/cpu/perf_event_p4.c | |||
@@ -18,7 +18,7 @@ | |||
18 | struct p4_event_bind { | 18 | struct p4_event_bind { |
19 | unsigned int opcode; /* Event code and ESCR selector */ | 19 | unsigned int opcode; /* Event code and ESCR selector */ |
20 | unsigned int escr_msr[2]; /* ESCR MSR for this event */ | 20 | unsigned int escr_msr[2]; /* ESCR MSR for this event */ |
21 | unsigned char cntr[2][P4_CNTR_LIMIT]; /* counter index (offset), -1 on abscence */ | 21 | char cntr[2][P4_CNTR_LIMIT]; /* counter index (offset), -1 on abscence */ |
22 | }; | 22 | }; |
23 | 23 | ||
24 | struct p4_cache_event_bind { | 24 | struct p4_cache_event_bind { |
@@ -747,11 +747,11 @@ static int p4_get_escr_idx(unsigned int addr) | |||
747 | static int p4_next_cntr(int thread, unsigned long *used_mask, | 747 | static int p4_next_cntr(int thread, unsigned long *used_mask, |
748 | struct p4_event_bind *bind) | 748 | struct p4_event_bind *bind) |
749 | { | 749 | { |
750 | int i = 0, j; | 750 | int i, j; |
751 | 751 | ||
752 | for (i = 0; i < P4_CNTR_LIMIT; i++) { | 752 | for (i = 0; i < P4_CNTR_LIMIT; i++) { |
753 | j = bind->cntr[thread][i++]; | 753 | j = bind->cntr[thread][i]; |
754 | if (j == -1 || !test_bit(j, used_mask)) | 754 | if (j != -1 && !test_bit(j, used_mask)) |
755 | return j; | 755 | return j; |
756 | } | 756 | } |
757 | 757 | ||