| From e73ff5c0c0bba8cb9c7b51691bc290a7e4a9fc61 Mon Sep 17 00:00:00 2001 |
| From: "David S. Miller" <davem@davemloft.net> |
| Date: Tue, 16 Oct 2012 13:05:25 -0700 |
| Subject: sparc64: Fix bit twiddling in sparc_pmu_enable_event(). |
| |
| |
| From: "David S. Miller" <davem@davemloft.net> |
| |
| [ Upstream commit e793d8c6740f8fe704fa216e95685f4d92c4c4b9 ] |
| |
| There was a serious disconnect in the logic happening in |
| sparc_pmu_disable_event() vs. sparc_pmu_enable_event(). |
| |
| Event disable is implemented by programming a NOP event into the PCR. |
| |
| However, event enable was not reversing this operation. Instead, it |
| was setting the User/Priv/Hypervisor trace enable bits. |
| |
| That's not sparc_pmu_enable_event()'s job, that's what |
| sparc_pmu_enable() and sparc_pmu_disable() do . |
| |
| The intent of sparc_pmu_enable_event() is clear, since it first clear |
| out the event type encoding field. So fix this by OR'ing in the event |
| encoding rather than the trace enable bits. |
| |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/sparc/kernel/perf_event.c | 6 ++++-- |
| 1 file changed, 4 insertions(+), 2 deletions(-) |
| |
| --- a/arch/sparc/kernel/perf_event.c |
| +++ b/arch/sparc/kernel/perf_event.c |
| @@ -513,11 +513,13 @@ static u64 nop_for_index(int idx) |
| |
| static inline void sparc_pmu_enable_event(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc, int idx) |
| { |
| - u64 val, mask = mask_for_index(idx); |
| + u64 enc, val, mask = mask_for_index(idx); |
| + |
| + enc = perf_event_get_enc(cpuc->events[idx]); |
| |
| val = cpuc->pcr; |
| val &= ~mask; |
| - val |= hwc->config; |
| + val |= event_encoding(enc, idx); |
| cpuc->pcr = val; |
| |
| pcr_ops->write(cpuc->pcr); |