diff options
author | David Daney <david.daney@cavium.com> | 2011-09-23 20:29:55 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2011-10-24 18:34:26 -0400 |
commit | 82091564cfd7ab8def42777a9c662dbf655c5d25 (patch) | |
tree | 2e0328b9795a694aa64561958f397770610fab2b /arch/mips | |
parent | e5dcb58aa51090f462959b9789eb477286bd2279 (diff) |
MIPS: perf: Add support for 64-bit perf counters.
The hard coded constants are moved to struct mips_pmu. All counter
register access move to the read_counter and write_counter function
pointers, which are set to either 32-bit or 64-bit access methods at
initialization time.
Many of the function pointers in struct mips_pmu were not needed as
there was only a single implementation, these were removed.
I couldn't figure out what made struct cpu_hw_events.msbs[] at all
useful, so I removed it too.
Some functions and other declarations were reordered to reduce the
need for forward declarations.
Signed-off-by: David Daney <david.daney@cavium.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Deng-Cheng Zhu <dengcheng.zhu@gmail.com>
To: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/2792/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/kernel/perf_event_mipsxx.c | 858 |
1 files changed, 389 insertions, 469 deletions
diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c index eb74dce69c1b..0c9549480c42 100644 --- a/arch/mips/kernel/perf_event_mipsxx.c +++ b/arch/mips/kernel/perf_event_mipsxx.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * Linux performance counter support for MIPS. | 2 | * Linux performance counter support for MIPS. |
3 | * | 3 | * |
4 | * Copyright (C) 2010 MIPS Technologies, Inc. | 4 | * Copyright (C) 2010 MIPS Technologies, Inc. |
5 | * Copyright (C) 2011 Cavium Networks, Inc. | ||
5 | * Author: Deng-Cheng Zhu | 6 | * Author: Deng-Cheng Zhu |
6 | * | 7 | * |
7 | * This code is based on the implementation for ARM, which is in turn | 8 | * This code is based on the implementation for ARM, which is in turn |
@@ -26,12 +27,6 @@ | |||
26 | #include <asm/stacktrace.h> | 27 | #include <asm/stacktrace.h> |
27 | #include <asm/time.h> /* For perf_irq */ | 28 | #include <asm/time.h> /* For perf_irq */ |
28 | 29 | ||
29 | /* These are for 32bit counters. For 64bit ones, define them accordingly. */ | ||
30 | #define MAX_PERIOD ((1ULL << 32) - 1) | ||
31 | #define VALID_COUNT 0x7fffffff | ||
32 | #define TOTAL_BITS 32 | ||
33 | #define HIGHEST_BIT 31 | ||
34 | |||
35 | #define MIPS_MAX_HWEVENTS 4 | 30 | #define MIPS_MAX_HWEVENTS 4 |
36 | 31 | ||
37 | struct cpu_hw_events { | 32 | struct cpu_hw_events { |
@@ -45,15 +40,6 @@ struct cpu_hw_events { | |||
45 | unsigned long used_mask[BITS_TO_LONGS(MIPS_MAX_HWEVENTS)]; | 40 | unsigned long used_mask[BITS_TO_LONGS(MIPS_MAX_HWEVENTS)]; |
46 | 41 | ||
47 | /* | 42 | /* |
48 | * The borrowed MSB for the performance counter. A MIPS performance | ||
49 | * counter uses its bit 31 (for 32bit counters) or bit 63 (for 64bit | ||
50 | * counters) as a factor of determining whether a counter overflow | ||
51 | * should be signaled. So here we use a separate MSB for each | ||
52 | * counter to make things easy. | ||
53 | */ | ||
54 | unsigned long msbs[BITS_TO_LONGS(MIPS_MAX_HWEVENTS)]; | ||
55 | |||
56 | /* | ||
57 | * Software copy of the control register for each performance counter. | 43 | * Software copy of the control register for each performance counter. |
58 | * MIPS CPUs vary in performance counters. They use this differently, | 44 | * MIPS CPUs vary in performance counters. They use this differently, |
59 | * and even may not use it. | 45 | * and even may not use it. |
@@ -75,6 +61,7 @@ struct mips_perf_event { | |||
75 | unsigned int cntr_mask; | 61 | unsigned int cntr_mask; |
76 | #define CNTR_EVEN 0x55555555 | 62 | #define CNTR_EVEN 0x55555555 |
77 | #define CNTR_ODD 0xaaaaaaaa | 63 | #define CNTR_ODD 0xaaaaaaaa |
64 | #define CNTR_ALL 0xffffffff | ||
78 | #ifdef CONFIG_MIPS_MT_SMP | 65 | #ifdef CONFIG_MIPS_MT_SMP |
79 | enum { | 66 | enum { |
80 | T = 0, | 67 | T = 0, |
@@ -95,18 +82,13 @@ static DEFINE_MUTEX(raw_event_mutex); | |||
95 | #define C(x) PERF_COUNT_HW_CACHE_##x | 82 | #define C(x) PERF_COUNT_HW_CACHE_##x |
96 | 83 | ||
97 | struct mips_pmu { | 84 | struct mips_pmu { |
85 | u64 max_period; | ||
86 | u64 valid_count; | ||
87 | u64 overflow; | ||
98 | const char *name; | 88 | const char *name; |
99 | int irq; | 89 | int irq; |
100 | irqreturn_t (*handle_irq)(int irq, void *dev); | ||
101 | int (*handle_shared_irq)(void); | ||
102 | void (*start)(void); | ||
103 | void (*stop)(void); | ||
104 | int (*alloc_counter)(struct cpu_hw_events *cpuc, | ||
105 | struct hw_perf_event *hwc); | ||
106 | u64 (*read_counter)(unsigned int idx); | 90 | u64 (*read_counter)(unsigned int idx); |
107 | void (*write_counter)(unsigned int idx, u64 val); | 91 | void (*write_counter)(unsigned int idx, u64 val); |
108 | void (*enable_event)(struct hw_perf_event *evt, int idx); | ||
109 | void (*disable_event)(int idx); | ||
110 | const struct mips_perf_event *(*map_raw_event)(u64 config); | 92 | const struct mips_perf_event *(*map_raw_event)(u64 config); |
111 | const struct mips_perf_event (*general_event_map)[PERF_COUNT_HW_MAX]; | 93 | const struct mips_perf_event (*general_event_map)[PERF_COUNT_HW_MAX]; |
112 | const struct mips_perf_event (*cache_event_map) | 94 | const struct mips_perf_event (*cache_event_map) |
@@ -116,44 +98,302 @@ struct mips_pmu { | |||
116 | unsigned int num_counters; | 98 | unsigned int num_counters; |
117 | }; | 99 | }; |
118 | 100 | ||
119 | static const struct mips_pmu *mipspmu; | 101 | static struct mips_pmu mipspmu; |
102 | |||
103 | #define M_CONFIG1_PC (1 << 4) | ||
104 | |||
105 | #define M_PERFCTL_EXL (1 << 0) | ||
106 | #define M_PERFCTL_KERNEL (1 << 1) | ||
107 | #define M_PERFCTL_SUPERVISOR (1 << 2) | ||
108 | #define M_PERFCTL_USER (1 << 3) | ||
109 | #define M_PERFCTL_INTERRUPT_ENABLE (1 << 4) | ||
110 | #define M_PERFCTL_EVENT(event) (((event) & 0x3ff) << 5) | ||
111 | #define M_PERFCTL_VPEID(vpe) ((vpe) << 16) | ||
112 | #define M_PERFCTL_MT_EN(filter) ((filter) << 20) | ||
113 | #define M_TC_EN_ALL M_PERFCTL_MT_EN(0) | ||
114 | #define M_TC_EN_VPE M_PERFCTL_MT_EN(1) | ||
115 | #define M_TC_EN_TC M_PERFCTL_MT_EN(2) | ||
116 | #define M_PERFCTL_TCID(tcid) ((tcid) << 22) | ||
117 | #define M_PERFCTL_WIDE (1 << 30) | ||
118 | #define M_PERFCTL_MORE (1 << 31) | ||
119 | |||
120 | #define M_PERFCTL_COUNT_EVENT_WHENEVER (M_PERFCTL_EXL | \ | ||
121 | M_PERFCTL_KERNEL | \ | ||
122 | M_PERFCTL_USER | \ | ||
123 | M_PERFCTL_SUPERVISOR | \ | ||
124 | M_PERFCTL_INTERRUPT_ENABLE) | ||
125 | |||
126 | #ifdef CONFIG_MIPS_MT_SMP | ||
127 | #define M_PERFCTL_CONFIG_MASK 0x3fff801f | ||
128 | #else | ||
129 | #define M_PERFCTL_CONFIG_MASK 0x1f | ||
130 | #endif | ||
131 | #define M_PERFCTL_EVENT_MASK 0xfe0 | ||
132 | |||
133 | |||
134 | #ifdef CONFIG_MIPS_MT_SMP | ||
135 | static int cpu_has_mipsmt_pertccounters; | ||
136 | |||
137 | static DEFINE_RWLOCK(pmuint_rwlock); | ||
138 | |||
139 | /* | ||
140 | * FIXME: For VSMP, vpe_id() is redefined for Perf-events, because | ||
141 | * cpu_data[cpuid].vpe_id reports 0 for _both_ CPUs. | ||
142 | */ | ||
143 | #if defined(CONFIG_HW_PERF_EVENTS) | ||
144 | #define vpe_id() (cpu_has_mipsmt_pertccounters ? \ | ||
145 | 0 : smp_processor_id()) | ||
146 | #else | ||
147 | #define vpe_id() (cpu_has_mipsmt_pertccounters ? \ | ||
148 | 0 : cpu_data[smp_processor_id()].vpe_id) | ||
149 | #endif | ||
150 | |||
151 | /* Copied from op_model_mipsxx.c */ | ||
152 | static unsigned int vpe_shift(void) | ||
153 | { | ||
154 | if (num_possible_cpus() > 1) | ||
155 | return 1; | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static unsigned int counters_total_to_per_cpu(unsigned int counters) | ||
161 | { | ||
162 | return counters >> vpe_shift(); | ||
163 | } | ||
164 | |||
165 | static unsigned int counters_per_cpu_to_total(unsigned int counters) | ||
166 | { | ||
167 | return counters << vpe_shift(); | ||
168 | } | ||
169 | |||
170 | #else /* !CONFIG_MIPS_MT_SMP */ | ||
171 | #define vpe_id() 0 | ||
172 | |||
173 | #endif /* CONFIG_MIPS_MT_SMP */ | ||
174 | |||
175 | static void resume_local_counters(void); | ||
176 | static void pause_local_counters(void); | ||
177 | static irqreturn_t mipsxx_pmu_handle_irq(int, void *); | ||
178 | static int mipsxx_pmu_handle_shared_irq(void); | ||
179 | |||
180 | static unsigned int mipsxx_pmu_swizzle_perf_idx(unsigned int idx) | ||
181 | { | ||
182 | if (vpe_id() == 1) | ||
183 | idx = (idx + 2) & 3; | ||
184 | return idx; | ||
185 | } | ||
186 | |||
187 | static u64 mipsxx_pmu_read_counter(unsigned int idx) | ||
188 | { | ||
189 | idx = mipsxx_pmu_swizzle_perf_idx(idx); | ||
190 | |||
191 | switch (idx) { | ||
192 | case 0: | ||
193 | /* | ||
194 | * The counters are unsigned, we must cast to truncate | ||
195 | * off the high bits. | ||
196 | */ | ||
197 | return (u32)read_c0_perfcntr0(); | ||
198 | case 1: | ||
199 | return (u32)read_c0_perfcntr1(); | ||
200 | case 2: | ||
201 | return (u32)read_c0_perfcntr2(); | ||
202 | case 3: | ||
203 | return (u32)read_c0_perfcntr3(); | ||
204 | default: | ||
205 | WARN_ONCE(1, "Invalid performance counter number (%d)\n", idx); | ||
206 | return 0; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | static u64 mipsxx_pmu_read_counter_64(unsigned int idx) | ||
211 | { | ||
212 | idx = mipsxx_pmu_swizzle_perf_idx(idx); | ||
213 | |||
214 | switch (idx) { | ||
215 | case 0: | ||
216 | return read_c0_perfcntr0_64(); | ||
217 | case 1: | ||
218 | return read_c0_perfcntr1_64(); | ||
219 | case 2: | ||
220 | return read_c0_perfcntr2_64(); | ||
221 | case 3: | ||
222 | return read_c0_perfcntr3_64(); | ||
223 | default: | ||
224 | WARN_ONCE(1, "Invalid performance counter number (%d)\n", idx); | ||
225 | return 0; | ||
226 | } | ||
227 | } | ||
228 | |||
229 | static void mipsxx_pmu_write_counter(unsigned int idx, u64 val) | ||
230 | { | ||
231 | idx = mipsxx_pmu_swizzle_perf_idx(idx); | ||
232 | |||
233 | switch (idx) { | ||
234 | case 0: | ||
235 | write_c0_perfcntr0(val); | ||
236 | return; | ||
237 | case 1: | ||
238 | write_c0_perfcntr1(val); | ||
239 | return; | ||
240 | case 2: | ||
241 | write_c0_perfcntr2(val); | ||
242 | return; | ||
243 | case 3: | ||
244 | write_c0_perfcntr3(val); | ||
245 | return; | ||
246 | } | ||
247 | } | ||
248 | |||
249 | static void mipsxx_pmu_write_counter_64(unsigned int idx, u64 val) | ||
250 | { | ||
251 | idx = mipsxx_pmu_swizzle_perf_idx(idx); | ||
252 | |||
253 | switch (idx) { | ||
254 | case 0: | ||
255 | write_c0_perfcntr0_64(val); | ||
256 | return; | ||
257 | case 1: | ||
258 | write_c0_perfcntr1_64(val); | ||
259 | return; | ||
260 | case 2: | ||
261 | write_c0_perfcntr2_64(val); | ||
262 | return; | ||
263 | case 3: | ||
264 | write_c0_perfcntr3_64(val); | ||
265 | return; | ||
266 | } | ||
267 | } | ||
268 | |||
269 | static unsigned int mipsxx_pmu_read_control(unsigned int idx) | ||
270 | { | ||
271 | idx = mipsxx_pmu_swizzle_perf_idx(idx); | ||
272 | |||
273 | switch (idx) { | ||
274 | case 0: | ||
275 | return read_c0_perfctrl0(); | ||
276 | case 1: | ||
277 | return read_c0_perfctrl1(); | ||
278 | case 2: | ||
279 | return read_c0_perfctrl2(); | ||
280 | case 3: | ||
281 | return read_c0_perfctrl3(); | ||
282 | default: | ||
283 | WARN_ONCE(1, "Invalid performance counter number (%d)\n", idx); | ||
284 | return 0; | ||
285 | } | ||
286 | } | ||
287 | |||
288 | static void mipsxx_pmu_write_control(unsigned int idx, unsigned int val) | ||
289 | { | ||
290 | idx = mipsxx_pmu_swizzle_perf_idx(idx); | ||
291 | |||
292 | switch (idx) { | ||
293 | case 0: | ||
294 | write_c0_perfctrl0(val); | ||
295 | return; | ||
296 | case 1: | ||
297 | write_c0_perfctrl1(val); | ||
298 | return; | ||
299 | case 2: | ||
300 | write_c0_perfctrl2(val); | ||
301 | return; | ||
302 | case 3: | ||
303 | write_c0_perfctrl3(val); | ||
304 | return; | ||
305 | } | ||
306 | } | ||
307 | |||
308 | static int mipsxx_pmu_alloc_counter(struct cpu_hw_events *cpuc, | ||
309 | struct hw_perf_event *hwc) | ||
310 | { | ||
311 | int i; | ||
312 | |||
313 | /* | ||
314 | * We only need to care the counter mask. The range has been | ||
315 | * checked definitely. | ||
316 | */ | ||
317 | unsigned long cntr_mask = (hwc->event_base >> 8) & 0xffff; | ||
318 | |||
319 | for (i = mipspmu.num_counters - 1; i >= 0; i--) { | ||
320 | /* | ||
321 | * Note that some MIPS perf events can be counted by both | ||
322 | * even and odd counters, wheresas many other are only by | ||
323 | * even _or_ odd counters. This introduces an issue that | ||
324 | * when the former kind of event takes the counter the | ||
325 | * latter kind of event wants to use, then the "counter | ||
326 | * allocation" for the latter event will fail. In fact if | ||
327 | * they can be dynamically swapped, they both feel happy. | ||
328 | * But here we leave this issue alone for now. | ||
329 | */ | ||
330 | if (test_bit(i, &cntr_mask) && | ||
331 | !test_and_set_bit(i, cpuc->used_mask)) | ||
332 | return i; | ||
333 | } | ||
334 | |||
335 | return -EAGAIN; | ||
336 | } | ||
337 | |||
338 | static void mipsxx_pmu_enable_event(struct hw_perf_event *evt, int idx) | ||
339 | { | ||
340 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | ||
341 | |||
342 | WARN_ON(idx < 0 || idx >= mipspmu.num_counters); | ||
343 | |||
344 | cpuc->saved_ctrl[idx] = M_PERFCTL_EVENT(evt->event_base & 0xff) | | ||
345 | (evt->config_base & M_PERFCTL_CONFIG_MASK) | | ||
346 | /* Make sure interrupt enabled. */ | ||
347 | M_PERFCTL_INTERRUPT_ENABLE; | ||
348 | /* | ||
349 | * We do not actually let the counter run. Leave it until start(). | ||
350 | */ | ||
351 | } | ||
352 | |||
353 | static void mipsxx_pmu_disable_event(int idx) | ||
354 | { | ||
355 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | ||
356 | unsigned long flags; | ||
357 | |||
358 | WARN_ON(idx < 0 || idx >= mipspmu.num_counters); | ||
359 | |||
360 | local_irq_save(flags); | ||
361 | cpuc->saved_ctrl[idx] = mipsxx_pmu_read_control(idx) & | ||
362 | ~M_PERFCTL_COUNT_EVENT_WHENEVER; | ||
363 | mipsxx_pmu_write_control(idx, cpuc->saved_ctrl[idx]); | ||
364 | local_irq_restore(flags); | ||
365 | } | ||
120 | 366 | ||
121 | static int mipspmu_event_set_period(struct perf_event *event, | 367 | static int mipspmu_event_set_period(struct perf_event *event, |
122 | struct hw_perf_event *hwc, | 368 | struct hw_perf_event *hwc, |
123 | int idx) | 369 | int idx) |
124 | { | 370 | { |
125 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | 371 | u64 left = local64_read(&hwc->period_left); |
126 | s64 left = local64_read(&hwc->period_left); | 372 | u64 period = hwc->sample_period; |
127 | s64 period = hwc->sample_period; | ||
128 | int ret = 0; | 373 | int ret = 0; |
129 | u64 uleft; | ||
130 | unsigned long flags; | ||
131 | 374 | ||
132 | if (unlikely(left <= -period)) { | 375 | if (unlikely((left + period) & (1ULL << 63))) { |
376 | /* left underflowed by more than period. */ | ||
133 | left = period; | 377 | left = period; |
134 | local64_set(&hwc->period_left, left); | 378 | local64_set(&hwc->period_left, left); |
135 | hwc->last_period = period; | 379 | hwc->last_period = period; |
136 | ret = 1; | 380 | ret = 1; |
137 | } | 381 | } else if (unlikely((left + period) <= period)) { |
138 | 382 | /* left underflowed by less than period. */ | |
139 | if (unlikely(left <= 0)) { | ||
140 | left += period; | 383 | left += period; |
141 | local64_set(&hwc->period_left, left); | 384 | local64_set(&hwc->period_left, left); |
142 | hwc->last_period = period; | 385 | hwc->last_period = period; |
143 | ret = 1; | 386 | ret = 1; |
144 | } | 387 | } |
145 | 388 | ||
146 | if (left > (s64)MAX_PERIOD) | 389 | if (left > mipspmu.max_period) { |
147 | left = MAX_PERIOD; | 390 | left = mipspmu.max_period; |
391 | local64_set(&hwc->period_left, left); | ||
392 | } | ||
148 | 393 | ||
149 | local64_set(&hwc->prev_count, (u64)-left); | 394 | local64_set(&hwc->prev_count, mipspmu.overflow - left); |
150 | 395 | ||
151 | local_irq_save(flags); | 396 | mipspmu.write_counter(idx, mipspmu.overflow - left); |
152 | uleft = (u64)(-left) & MAX_PERIOD; | ||
153 | uleft > VALID_COUNT ? | ||
154 | set_bit(idx, cpuc->msbs) : clear_bit(idx, cpuc->msbs); | ||
155 | mipspmu->write_counter(idx, (u64)(-left) & VALID_COUNT); | ||
156 | local_irq_restore(flags); | ||
157 | 397 | ||
158 | perf_event_update_userpage(event); | 398 | perf_event_update_userpage(event); |
159 | 399 | ||
@@ -164,30 +404,18 @@ static void mipspmu_event_update(struct perf_event *event, | |||
164 | struct hw_perf_event *hwc, | 404 | struct hw_perf_event *hwc, |
165 | int idx) | 405 | int idx) |
166 | { | 406 | { |
167 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | 407 | u64 prev_raw_count, new_raw_count; |
168 | unsigned long flags; | ||
169 | int shift = 64 - TOTAL_BITS; | ||
170 | s64 prev_raw_count, new_raw_count; | ||
171 | u64 delta; | 408 | u64 delta; |
172 | 409 | ||
173 | again: | 410 | again: |
174 | prev_raw_count = local64_read(&hwc->prev_count); | 411 | prev_raw_count = local64_read(&hwc->prev_count); |
175 | local_irq_save(flags); | 412 | new_raw_count = mipspmu.read_counter(idx); |
176 | /* Make the counter value be a "real" one. */ | ||
177 | new_raw_count = mipspmu->read_counter(idx); | ||
178 | if (new_raw_count & (test_bit(idx, cpuc->msbs) << HIGHEST_BIT)) { | ||
179 | new_raw_count &= VALID_COUNT; | ||
180 | clear_bit(idx, cpuc->msbs); | ||
181 | } else | ||
182 | new_raw_count |= (test_bit(idx, cpuc->msbs) << HIGHEST_BIT); | ||
183 | local_irq_restore(flags); | ||
184 | 413 | ||
185 | if (local64_cmpxchg(&hwc->prev_count, prev_raw_count, | 414 | if (local64_cmpxchg(&hwc->prev_count, prev_raw_count, |
186 | new_raw_count) != prev_raw_count) | 415 | new_raw_count) != prev_raw_count) |
187 | goto again; | 416 | goto again; |
188 | 417 | ||
189 | delta = (new_raw_count << shift) - (prev_raw_count << shift); | 418 | delta = new_raw_count - prev_raw_count; |
190 | delta >>= shift; | ||
191 | 419 | ||
192 | local64_add(delta, &event->count); | 420 | local64_add(delta, &event->count); |
193 | local64_sub(delta, &hwc->period_left); | 421 | local64_sub(delta, &hwc->period_left); |
@@ -197,9 +425,6 @@ static void mipspmu_start(struct perf_event *event, int flags) | |||
197 | { | 425 | { |
198 | struct hw_perf_event *hwc = &event->hw; | 426 | struct hw_perf_event *hwc = &event->hw; |
199 | 427 | ||
200 | if (!mipspmu) | ||
201 | return; | ||
202 | |||
203 | if (flags & PERF_EF_RELOAD) | 428 | if (flags & PERF_EF_RELOAD) |
204 | WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE)); | 429 | WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE)); |
205 | 430 | ||
@@ -209,19 +434,16 @@ static void mipspmu_start(struct perf_event *event, int flags) | |||
209 | mipspmu_event_set_period(event, hwc, hwc->idx); | 434 | mipspmu_event_set_period(event, hwc, hwc->idx); |
210 | 435 | ||
211 | /* Enable the event. */ | 436 | /* Enable the event. */ |
212 | mipspmu->enable_event(hwc, hwc->idx); | 437 | mipsxx_pmu_enable_event(hwc, hwc->idx); |
213 | } | 438 | } |
214 | 439 | ||
215 | static void mipspmu_stop(struct perf_event *event, int flags) | 440 | static void mipspmu_stop(struct perf_event *event, int flags) |
216 | { | 441 | { |
217 | struct hw_perf_event *hwc = &event->hw; | 442 | struct hw_perf_event *hwc = &event->hw; |
218 | 443 | ||
219 | if (!mipspmu) | ||
220 | return; | ||
221 | |||
222 | if (!(hwc->state & PERF_HES_STOPPED)) { | 444 | if (!(hwc->state & PERF_HES_STOPPED)) { |
223 | /* We are working on a local event. */ | 445 | /* We are working on a local event. */ |
224 | mipspmu->disable_event(hwc->idx); | 446 | mipsxx_pmu_disable_event(hwc->idx); |
225 | barrier(); | 447 | barrier(); |
226 | mipspmu_event_update(event, hwc, hwc->idx); | 448 | mipspmu_event_update(event, hwc, hwc->idx); |
227 | hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE; | 449 | hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE; |
@@ -238,7 +460,7 @@ static int mipspmu_add(struct perf_event *event, int flags) | |||
238 | perf_pmu_disable(event->pmu); | 460 | perf_pmu_disable(event->pmu); |
239 | 461 | ||
240 | /* To look for a free counter for this event. */ | 462 | /* To look for a free counter for this event. */ |
241 | idx = mipspmu->alloc_counter(cpuc, hwc); | 463 | idx = mipsxx_pmu_alloc_counter(cpuc, hwc); |
242 | if (idx < 0) { | 464 | if (idx < 0) { |
243 | err = idx; | 465 | err = idx; |
244 | goto out; | 466 | goto out; |
@@ -249,7 +471,7 @@ static int mipspmu_add(struct perf_event *event, int flags) | |||
249 | * make sure it is disabled. | 471 | * make sure it is disabled. |
250 | */ | 472 | */ |
251 | event->hw.idx = idx; | 473 | event->hw.idx = idx; |
252 | mipspmu->disable_event(idx); | 474 | mipsxx_pmu_disable_event(idx); |
253 | cpuc->events[idx] = event; | 475 | cpuc->events[idx] = event; |
254 | 476 | ||
255 | hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE; | 477 | hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE; |
@@ -270,7 +492,7 @@ static void mipspmu_del(struct perf_event *event, int flags) | |||
270 | struct hw_perf_event *hwc = &event->hw; | 492 | struct hw_perf_event *hwc = &event->hw; |
271 | int idx = hwc->idx; | 493 | int idx = hwc->idx; |
272 | 494 | ||
273 | WARN_ON(idx < 0 || idx >= mipspmu->num_counters); | 495 | WARN_ON(idx < 0 || idx >= mipspmu.num_counters); |
274 | 496 | ||
275 | mipspmu_stop(event, PERF_EF_UPDATE); | 497 | mipspmu_stop(event, PERF_EF_UPDATE); |
276 | cpuc->events[idx] = NULL; | 498 | cpuc->events[idx] = NULL; |
@@ -292,14 +514,29 @@ static void mipspmu_read(struct perf_event *event) | |||
292 | 514 | ||
293 | static void mipspmu_enable(struct pmu *pmu) | 515 | static void mipspmu_enable(struct pmu *pmu) |
294 | { | 516 | { |
295 | if (mipspmu) | 517 | #ifdef CONFIG_MIPS_MT_SMP |
296 | mipspmu->start(); | 518 | write_unlock(&pmuint_rwlock); |
519 | #endif | ||
520 | resume_local_counters(); | ||
297 | } | 521 | } |
298 | 522 | ||
523 | /* | ||
524 | * MIPS performance counters can be per-TC. The control registers can | ||
525 | * not be directly accessed accross CPUs. Hence if we want to do global | ||
526 | * control, we need cross CPU calls. on_each_cpu() can help us, but we | ||
527 | * can not make sure this function is called with interrupts enabled. So | ||
528 | * here we pause local counters and then grab a rwlock and leave the | ||
529 | * counters on other CPUs alone. If any counter interrupt raises while | ||
530 | * we own the write lock, simply pause local counters on that CPU and | ||
531 | * spin in the handler. Also we know we won't be switched to another | ||
532 | * CPU after pausing local counters and before grabbing the lock. | ||
533 | */ | ||
299 | static void mipspmu_disable(struct pmu *pmu) | 534 | static void mipspmu_disable(struct pmu *pmu) |
300 | { | 535 | { |
301 | if (mipspmu) | 536 | pause_local_counters(); |
302 | mipspmu->stop(); | 537 | #ifdef CONFIG_MIPS_MT_SMP |
538 | write_lock(&pmuint_rwlock); | ||
539 | #endif | ||
303 | } | 540 | } |
304 | 541 | ||
305 | static atomic_t active_events = ATOMIC_INIT(0); | 542 | static atomic_t active_events = ATOMIC_INIT(0); |
@@ -310,21 +547,21 @@ static int mipspmu_get_irq(void) | |||
310 | { | 547 | { |
311 | int err; | 548 | int err; |
312 | 549 | ||
313 | if (mipspmu->irq >= 0) { | 550 | if (mipspmu.irq >= 0) { |
314 | /* Request my own irq handler. */ | 551 | /* Request my own irq handler. */ |
315 | err = request_irq(mipspmu->irq, mipspmu->handle_irq, | 552 | err = request_irq(mipspmu.irq, mipsxx_pmu_handle_irq, |
316 | IRQF_DISABLED | IRQF_NOBALANCING, | 553 | IRQF_PERCPU | IRQF_NOBALANCING, |
317 | "mips_perf_pmu", NULL); | 554 | "mips_perf_pmu", NULL); |
318 | if (err) { | 555 | if (err) { |
319 | pr_warning("Unable to request IRQ%d for MIPS " | 556 | pr_warning("Unable to request IRQ%d for MIPS " |
320 | "performance counters!\n", mipspmu->irq); | 557 | "performance counters!\n", mipspmu.irq); |
321 | } | 558 | } |
322 | } else if (cp0_perfcount_irq < 0) { | 559 | } else if (cp0_perfcount_irq < 0) { |
323 | /* | 560 | /* |
324 | * We are sharing the irq number with the timer interrupt. | 561 | * We are sharing the irq number with the timer interrupt. |
325 | */ | 562 | */ |
326 | save_perf_irq = perf_irq; | 563 | save_perf_irq = perf_irq; |
327 | perf_irq = mipspmu->handle_shared_irq; | 564 | perf_irq = mipsxx_pmu_handle_shared_irq; |
328 | err = 0; | 565 | err = 0; |
329 | } else { | 566 | } else { |
330 | pr_warning("The platform hasn't properly defined its " | 567 | pr_warning("The platform hasn't properly defined its " |
@@ -337,8 +574,8 @@ static int mipspmu_get_irq(void) | |||
337 | 574 | ||
338 | static void mipspmu_free_irq(void) | 575 | static void mipspmu_free_irq(void) |
339 | { | 576 | { |
340 | if (mipspmu->irq >= 0) | 577 | if (mipspmu.irq >= 0) |
341 | free_irq(mipspmu->irq, NULL); | 578 | free_irq(mipspmu.irq, NULL); |
342 | else if (cp0_perfcount_irq < 0) | 579 | else if (cp0_perfcount_irq < 0) |
343 | perf_irq = save_perf_irq; | 580 | perf_irq = save_perf_irq; |
344 | } | 581 | } |
@@ -359,7 +596,7 @@ static void hw_perf_event_destroy(struct perf_event *event) | |||
359 | * disabled. | 596 | * disabled. |
360 | */ | 597 | */ |
361 | on_each_cpu(reset_counters, | 598 | on_each_cpu(reset_counters, |
362 | (void *)(long)mipspmu->num_counters, 1); | 599 | (void *)(long)mipspmu.num_counters, 1); |
363 | mipspmu_free_irq(); | 600 | mipspmu_free_irq(); |
364 | mutex_unlock(&pmu_reserve_mutex); | 601 | mutex_unlock(&pmu_reserve_mutex); |
365 | } | 602 | } |
@@ -379,8 +616,8 @@ static int mipspmu_event_init(struct perf_event *event) | |||
379 | return -ENOENT; | 616 | return -ENOENT; |
380 | } | 617 | } |
381 | 618 | ||
382 | if (!mipspmu || event->cpu >= nr_cpumask_bits || | 619 | if (event->cpu >= nr_cpumask_bits || |
383 | (event->cpu >= 0 && !cpu_online(event->cpu))) | 620 | (event->cpu >= 0 && !cpu_online(event->cpu))) |
384 | return -ENODEV; | 621 | return -ENODEV; |
385 | 622 | ||
386 | if (!atomic_inc_not_zero(&active_events)) { | 623 | if (!atomic_inc_not_zero(&active_events)) { |
@@ -439,9 +676,9 @@ static const struct mips_perf_event *mipspmu_map_general_event(int idx) | |||
439 | { | 676 | { |
440 | const struct mips_perf_event *pev; | 677 | const struct mips_perf_event *pev; |
441 | 678 | ||
442 | pev = ((*mipspmu->general_event_map)[idx].event_id == | 679 | pev = ((*mipspmu.general_event_map)[idx].event_id == |
443 | UNSUPPORTED_PERF_EVENT_ID ? ERR_PTR(-EOPNOTSUPP) : | 680 | UNSUPPORTED_PERF_EVENT_ID ? ERR_PTR(-EOPNOTSUPP) : |
444 | &(*mipspmu->general_event_map)[idx]); | 681 | &(*mipspmu.general_event_map)[idx]); |
445 | 682 | ||
446 | return pev; | 683 | return pev; |
447 | } | 684 | } |
@@ -463,7 +700,7 @@ static const struct mips_perf_event *mipspmu_map_cache_event(u64 config) | |||
463 | if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX) | 700 | if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX) |
464 | return ERR_PTR(-EINVAL); | 701 | return ERR_PTR(-EINVAL); |
465 | 702 | ||
466 | pev = &((*mipspmu->cache_event_map) | 703 | pev = &((*mipspmu.cache_event_map) |
467 | [cache_type] | 704 | [cache_type] |
468 | [cache_op] | 705 | [cache_op] |
469 | [cache_result]); | 706 | [cache_result]); |
@@ -484,7 +721,7 @@ static int validate_event(struct cpu_hw_events *cpuc, | |||
484 | if (event->pmu != &pmu || event->state <= PERF_EVENT_STATE_OFF) | 721 | if (event->pmu != &pmu || event->state <= PERF_EVENT_STATE_OFF) |
485 | return 1; | 722 | return 1; |
486 | 723 | ||
487 | return mipspmu->alloc_counter(cpuc, &fake_hwc) >= 0; | 724 | return mipsxx_pmu_alloc_counter(cpuc, &fake_hwc) >= 0; |
488 | } | 725 | } |
489 | 726 | ||
490 | static int validate_group(struct perf_event *event) | 727 | static int validate_group(struct perf_event *event) |
@@ -522,123 +759,9 @@ static void handle_associated_event(struct cpu_hw_events *cpuc, | |||
522 | return; | 759 | return; |
523 | 760 | ||
524 | if (perf_event_overflow(event, data, regs)) | 761 | if (perf_event_overflow(event, data, regs)) |
525 | mipspmu->disable_event(idx); | 762 | mipsxx_pmu_disable_event(idx); |
526 | } | 763 | } |
527 | 764 | ||
528 | #define M_CONFIG1_PC (1 << 4) | ||
529 | |||
530 | #define M_PERFCTL_EXL (1UL << 0) | ||
531 | #define M_PERFCTL_KERNEL (1UL << 1) | ||
532 | #define M_PERFCTL_SUPERVISOR (1UL << 2) | ||
533 | #define M_PERFCTL_USER (1UL << 3) | ||
534 | #define M_PERFCTL_INTERRUPT_ENABLE (1UL << 4) | ||
535 | #define M_PERFCTL_EVENT(event) (((event) & 0x3ff) << 5) | ||
536 | #define M_PERFCTL_VPEID(vpe) ((vpe) << 16) | ||
537 | #define M_PERFCTL_MT_EN(filter) ((filter) << 20) | ||
538 | #define M_TC_EN_ALL M_PERFCTL_MT_EN(0) | ||
539 | #define M_TC_EN_VPE M_PERFCTL_MT_EN(1) | ||
540 | #define M_TC_EN_TC M_PERFCTL_MT_EN(2) | ||
541 | #define M_PERFCTL_TCID(tcid) ((tcid) << 22) | ||
542 | #define M_PERFCTL_WIDE (1UL << 30) | ||
543 | #define M_PERFCTL_MORE (1UL << 31) | ||
544 | |||
545 | #define M_PERFCTL_COUNT_EVENT_WHENEVER (M_PERFCTL_EXL | \ | ||
546 | M_PERFCTL_KERNEL | \ | ||
547 | M_PERFCTL_USER | \ | ||
548 | M_PERFCTL_SUPERVISOR | \ | ||
549 | M_PERFCTL_INTERRUPT_ENABLE) | ||
550 | |||
551 | #ifdef CONFIG_MIPS_MT_SMP | ||
552 | #define M_PERFCTL_CONFIG_MASK 0x3fff801f | ||
553 | #else | ||
554 | #define M_PERFCTL_CONFIG_MASK 0x1f | ||
555 | #endif | ||
556 | #define M_PERFCTL_EVENT_MASK 0xfe0 | ||
557 | |||
558 | #define M_COUNTER_OVERFLOW (1UL << 31) | ||
559 | |||
560 | #ifdef CONFIG_MIPS_MT_SMP | ||
561 | static int cpu_has_mipsmt_pertccounters; | ||
562 | |||
563 | /* | ||
564 | * FIXME: For VSMP, vpe_id() is redefined for Perf-events, because | ||
565 | * cpu_data[cpuid].vpe_id reports 0 for _both_ CPUs. | ||
566 | */ | ||
567 | #if defined(CONFIG_HW_PERF_EVENTS) | ||
568 | #define vpe_id() (cpu_has_mipsmt_pertccounters ? \ | ||
569 | 0 : smp_processor_id()) | ||
570 | #else | ||
571 | #define vpe_id() (cpu_has_mipsmt_pertccounters ? \ | ||
572 | 0 : cpu_data[smp_processor_id()].vpe_id) | ||
573 | #endif | ||
574 | |||
575 | /* Copied from op_model_mipsxx.c */ | ||
576 | static unsigned int vpe_shift(void) | ||
577 | { | ||
578 | if (num_possible_cpus() > 1) | ||
579 | return 1; | ||
580 | |||
581 | return 0; | ||
582 | } | ||
583 | |||
584 | static unsigned int counters_total_to_per_cpu(unsigned int counters) | ||
585 | { | ||
586 | return counters >> vpe_shift(); | ||
587 | } | ||
588 | |||
589 | static unsigned int counters_per_cpu_to_total(unsigned int counters) | ||
590 | { | ||
591 | return counters << vpe_shift(); | ||
592 | } | ||
593 | |||
594 | #else /* !CONFIG_MIPS_MT_SMP */ | ||
595 | #define vpe_id() 0 | ||
596 | |||
597 | #endif /* CONFIG_MIPS_MT_SMP */ | ||
598 | |||
599 | #define __define_perf_accessors(r, n, np) \ | ||
600 | \ | ||
601 | static unsigned int r_c0_ ## r ## n(void) \ | ||
602 | { \ | ||
603 | unsigned int cpu = vpe_id(); \ | ||
604 | \ | ||
605 | switch (cpu) { \ | ||
606 | case 0: \ | ||
607 | return read_c0_ ## r ## n(); \ | ||
608 | case 1: \ | ||
609 | return read_c0_ ## r ## np(); \ | ||
610 | default: \ | ||
611 | BUG(); \ | ||
612 | } \ | ||
613 | return 0; \ | ||
614 | } \ | ||
615 | \ | ||
616 | static void w_c0_ ## r ## n(unsigned int value) \ | ||
617 | { \ | ||
618 | unsigned int cpu = vpe_id(); \ | ||
619 | \ | ||
620 | switch (cpu) { \ | ||
621 | case 0: \ | ||
622 | write_c0_ ## r ## n(value); \ | ||
623 | return; \ | ||
624 | case 1: \ | ||
625 | write_c0_ ## r ## np(value); \ | ||
626 | return; \ | ||
627 | default: \ | ||
628 | BUG(); \ | ||
629 | } \ | ||
630 | return; \ | ||
631 | } \ | ||
632 | |||
633 | __define_perf_accessors(perfcntr, 0, 2) | ||
634 | __define_perf_accessors(perfcntr, 1, 3) | ||
635 | __define_perf_accessors(perfcntr, 2, 0) | ||
636 | __define_perf_accessors(perfcntr, 3, 1) | ||
637 | |||
638 | __define_perf_accessors(perfctrl, 0, 2) | ||
639 | __define_perf_accessors(perfctrl, 1, 3) | ||
640 | __define_perf_accessors(perfctrl, 2, 0) | ||
641 | __define_perf_accessors(perfctrl, 3, 1) | ||
642 | 765 | ||
643 | static int __n_counters(void) | 766 | static int __n_counters(void) |
644 | { | 767 | { |
@@ -680,94 +803,20 @@ static void reset_counters(void *arg) | |||
680 | int counters = (int)(long)arg; | 803 | int counters = (int)(long)arg; |
681 | switch (counters) { | 804 | switch (counters) { |
682 | case 4: | 805 | case 4: |
683 | w_c0_perfctrl3(0); | 806 | mipsxx_pmu_write_control(3, 0); |
684 | w_c0_perfcntr3(0); | 807 | mipspmu.write_counter(3, 0); |
685 | case 3: | ||
686 | w_c0_perfctrl2(0); | ||
687 | w_c0_perfcntr2(0); | ||
688 | case 2: | ||
689 | w_c0_perfctrl1(0); | ||
690 | w_c0_perfcntr1(0); | ||
691 | case 1: | ||
692 | w_c0_perfctrl0(0); | ||
693 | w_c0_perfcntr0(0); | ||
694 | } | ||
695 | } | ||
696 | |||
697 | static u64 mipsxx_pmu_read_counter(unsigned int idx) | ||
698 | { | ||
699 | switch (idx) { | ||
700 | case 0: | ||
701 | return r_c0_perfcntr0(); | ||
702 | case 1: | ||
703 | return r_c0_perfcntr1(); | ||
704 | case 2: | ||
705 | return r_c0_perfcntr2(); | ||
706 | case 3: | 808 | case 3: |
707 | return r_c0_perfcntr3(); | 809 | mipsxx_pmu_write_control(2, 0); |
708 | default: | 810 | mipspmu.write_counter(2, 0); |
709 | WARN_ONCE(1, "Invalid performance counter number (%d)\n", idx); | ||
710 | return 0; | ||
711 | } | ||
712 | } | ||
713 | |||
714 | static void mipsxx_pmu_write_counter(unsigned int idx, u64 val) | ||
715 | { | ||
716 | switch (idx) { | ||
717 | case 0: | ||
718 | w_c0_perfcntr0(val); | ||
719 | return; | ||
720 | case 1: | ||
721 | w_c0_perfcntr1(val); | ||
722 | return; | ||
723 | case 2: | 811 | case 2: |
724 | w_c0_perfcntr2(val); | 812 | mipsxx_pmu_write_control(1, 0); |
725 | return; | 813 | mipspmu.write_counter(1, 0); |
726 | case 3: | ||
727 | w_c0_perfcntr3(val); | ||
728 | return; | ||
729 | } | ||
730 | } | ||
731 | |||
732 | static unsigned int mipsxx_pmu_read_control(unsigned int idx) | ||
733 | { | ||
734 | switch (idx) { | ||
735 | case 0: | ||
736 | return r_c0_perfctrl0(); | ||
737 | case 1: | 814 | case 1: |
738 | return r_c0_perfctrl1(); | 815 | mipsxx_pmu_write_control(0, 0); |
739 | case 2: | 816 | mipspmu.write_counter(0, 0); |
740 | return r_c0_perfctrl2(); | ||
741 | case 3: | ||
742 | return r_c0_perfctrl3(); | ||
743 | default: | ||
744 | WARN_ONCE(1, "Invalid performance counter number (%d)\n", idx); | ||
745 | return 0; | ||
746 | } | 817 | } |
747 | } | 818 | } |
748 | 819 | ||
749 | static void mipsxx_pmu_write_control(unsigned int idx, unsigned int val) | ||
750 | { | ||
751 | switch (idx) { | ||
752 | case 0: | ||
753 | w_c0_perfctrl0(val); | ||
754 | return; | ||
755 | case 1: | ||
756 | w_c0_perfctrl1(val); | ||
757 | return; | ||
758 | case 2: | ||
759 | w_c0_perfctrl2(val); | ||
760 | return; | ||
761 | case 3: | ||
762 | w_c0_perfctrl3(val); | ||
763 | return; | ||
764 | } | ||
765 | } | ||
766 | |||
767 | #ifdef CONFIG_MIPS_MT_SMP | ||
768 | static DEFINE_RWLOCK(pmuint_rwlock); | ||
769 | #endif | ||
770 | |||
771 | /* 24K/34K/1004K cores can share the same event map. */ | 820 | /* 24K/34K/1004K cores can share the same event map. */ |
772 | static const struct mips_perf_event mipsxxcore_event_map | 821 | static const struct mips_perf_event mipsxxcore_event_map |
773 | [PERF_COUNT_HW_MAX] = { | 822 | [PERF_COUNT_HW_MAX] = { |
@@ -1073,7 +1122,7 @@ static int __hw_perf_event_init(struct perf_event *event) | |||
1073 | } else if (PERF_TYPE_RAW == event->attr.type) { | 1122 | } else if (PERF_TYPE_RAW == event->attr.type) { |
1074 | /* We are working on the global raw event. */ | 1123 | /* We are working on the global raw event. */ |
1075 | mutex_lock(&raw_event_mutex); | 1124 | mutex_lock(&raw_event_mutex); |
1076 | pev = mipspmu->map_raw_event(event->attr.config); | 1125 | pev = mipspmu.map_raw_event(event->attr.config); |
1077 | } else { | 1126 | } else { |
1078 | /* The event type is not (yet) supported. */ | 1127 | /* The event type is not (yet) supported. */ |
1079 | return -EOPNOTSUPP; | 1128 | return -EOPNOTSUPP; |
@@ -1118,7 +1167,7 @@ static int __hw_perf_event_init(struct perf_event *event) | |||
1118 | hwc->config = 0; | 1167 | hwc->config = 0; |
1119 | 1168 | ||
1120 | if (!hwc->sample_period) { | 1169 | if (!hwc->sample_period) { |
1121 | hwc->sample_period = MAX_PERIOD; | 1170 | hwc->sample_period = mipspmu.max_period; |
1122 | hwc->last_period = hwc->sample_period; | 1171 | hwc->last_period = hwc->sample_period; |
1123 | local64_set(&hwc->period_left, hwc->sample_period); | 1172 | local64_set(&hwc->period_left, hwc->sample_period); |
1124 | } | 1173 | } |
@@ -1131,70 +1180,47 @@ static int __hw_perf_event_init(struct perf_event *event) | |||
1131 | } | 1180 | } |
1132 | 1181 | ||
1133 | event->destroy = hw_perf_event_destroy; | 1182 | event->destroy = hw_perf_event_destroy; |
1134 | |||
1135 | return err; | 1183 | return err; |
1136 | } | 1184 | } |
1137 | 1185 | ||
1138 | static void pause_local_counters(void) | 1186 | static void pause_local_counters(void) |
1139 | { | 1187 | { |
1140 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | 1188 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); |
1141 | int counters = mipspmu->num_counters; | 1189 | int ctr = mipspmu.num_counters; |
1142 | unsigned long flags; | 1190 | unsigned long flags; |
1143 | 1191 | ||
1144 | local_irq_save(flags); | 1192 | local_irq_save(flags); |
1145 | switch (counters) { | 1193 | do { |
1146 | case 4: | 1194 | ctr--; |
1147 | cpuc->saved_ctrl[3] = r_c0_perfctrl3(); | 1195 | cpuc->saved_ctrl[ctr] = mipsxx_pmu_read_control(ctr); |
1148 | w_c0_perfctrl3(cpuc->saved_ctrl[3] & | 1196 | mipsxx_pmu_write_control(ctr, cpuc->saved_ctrl[ctr] & |
1149 | ~M_PERFCTL_COUNT_EVENT_WHENEVER); | 1197 | ~M_PERFCTL_COUNT_EVENT_WHENEVER); |
1150 | case 3: | 1198 | } while (ctr > 0); |
1151 | cpuc->saved_ctrl[2] = r_c0_perfctrl2(); | ||
1152 | w_c0_perfctrl2(cpuc->saved_ctrl[2] & | ||
1153 | ~M_PERFCTL_COUNT_EVENT_WHENEVER); | ||
1154 | case 2: | ||
1155 | cpuc->saved_ctrl[1] = r_c0_perfctrl1(); | ||
1156 | w_c0_perfctrl1(cpuc->saved_ctrl[1] & | ||
1157 | ~M_PERFCTL_COUNT_EVENT_WHENEVER); | ||
1158 | case 1: | ||
1159 | cpuc->saved_ctrl[0] = r_c0_perfctrl0(); | ||
1160 | w_c0_perfctrl0(cpuc->saved_ctrl[0] & | ||
1161 | ~M_PERFCTL_COUNT_EVENT_WHENEVER); | ||
1162 | } | ||
1163 | local_irq_restore(flags); | 1199 | local_irq_restore(flags); |
1164 | } | 1200 | } |
1165 | 1201 | ||
1166 | static void resume_local_counters(void) | 1202 | static void resume_local_counters(void) |
1167 | { | 1203 | { |
1168 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | 1204 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); |
1169 | int counters = mipspmu->num_counters; | 1205 | int ctr = mipspmu.num_counters; |
1170 | unsigned long flags; | ||
1171 | 1206 | ||
1172 | local_irq_save(flags); | 1207 | do { |
1173 | switch (counters) { | 1208 | ctr--; |
1174 | case 4: | 1209 | mipsxx_pmu_write_control(ctr, cpuc->saved_ctrl[ctr]); |
1175 | w_c0_perfctrl3(cpuc->saved_ctrl[3]); | 1210 | } while (ctr > 0); |
1176 | case 3: | ||
1177 | w_c0_perfctrl2(cpuc->saved_ctrl[2]); | ||
1178 | case 2: | ||
1179 | w_c0_perfctrl1(cpuc->saved_ctrl[1]); | ||
1180 | case 1: | ||
1181 | w_c0_perfctrl0(cpuc->saved_ctrl[0]); | ||
1182 | } | ||
1183 | local_irq_restore(flags); | ||
1184 | } | 1211 | } |
1185 | 1212 | ||
1186 | static int mipsxx_pmu_handle_shared_irq(void) | 1213 | static int mipsxx_pmu_handle_shared_irq(void) |
1187 | { | 1214 | { |
1188 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | 1215 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); |
1189 | struct perf_sample_data data; | 1216 | struct perf_sample_data data; |
1190 | unsigned int counters = mipspmu->num_counters; | 1217 | unsigned int counters = mipspmu.num_counters; |
1191 | unsigned int counter; | 1218 | u64 counter; |
1192 | int handled = IRQ_NONE; | 1219 | int handled = IRQ_NONE; |
1193 | struct pt_regs *regs; | 1220 | struct pt_regs *regs; |
1194 | 1221 | ||
1195 | if (cpu_has_mips_r2 && !(read_c0_cause() & (1 << 26))) | 1222 | if (cpu_has_mips_r2 && !(read_c0_cause() & (1 << 26))) |
1196 | return handled; | 1223 | return handled; |
1197 | |||
1198 | /* | 1224 | /* |
1199 | * First we pause the local counters, so that when we are locked | 1225 | * First we pause the local counters, so that when we are locked |
1200 | * here, the counters are all paused. When it gets locked due to | 1226 | * here, the counters are all paused. When it gets locked due to |
@@ -1215,13 +1241,9 @@ static int mipsxx_pmu_handle_shared_irq(void) | |||
1215 | #define HANDLE_COUNTER(n) \ | 1241 | #define HANDLE_COUNTER(n) \ |
1216 | case n + 1: \ | 1242 | case n + 1: \ |
1217 | if (test_bit(n, cpuc->used_mask)) { \ | 1243 | if (test_bit(n, cpuc->used_mask)) { \ |
1218 | counter = r_c0_perfcntr ## n(); \ | 1244 | counter = mipspmu.read_counter(n); \ |
1219 | if (counter & M_COUNTER_OVERFLOW) { \ | 1245 | if (counter & mipspmu.overflow) { \ |
1220 | w_c0_perfcntr ## n(counter & \ | 1246 | handle_associated_event(cpuc, n, &data, regs); \ |
1221 | VALID_COUNT); \ | ||
1222 | if (test_and_change_bit(n, cpuc->msbs)) \ | ||
1223 | handle_associated_event(cpuc, \ | ||
1224 | n, &data, regs); \ | ||
1225 | handled = IRQ_HANDLED; \ | 1247 | handled = IRQ_HANDLED; \ |
1226 | } \ | 1248 | } \ |
1227 | } | 1249 | } |
@@ -1251,95 +1273,6 @@ static irqreturn_t mipsxx_pmu_handle_irq(int irq, void *dev) | |||
1251 | return mipsxx_pmu_handle_shared_irq(); | 1273 | return mipsxx_pmu_handle_shared_irq(); |
1252 | } | 1274 | } |
1253 | 1275 | ||
1254 | static void mipsxx_pmu_start(void) | ||
1255 | { | ||
1256 | #ifdef CONFIG_MIPS_MT_SMP | ||
1257 | write_unlock(&pmuint_rwlock); | ||
1258 | #endif | ||
1259 | resume_local_counters(); | ||
1260 | } | ||
1261 | |||
1262 | /* | ||
1263 | * MIPS performance counters can be per-TC. The control registers can | ||
1264 | * not be directly accessed across CPUs. Hence if we want to do global | ||
1265 | * control, we need cross CPU calls. on_each_cpu() can help us, but we | ||
1266 | * can not make sure this function is called with interrupts enabled. So | ||
1267 | * here we pause local counters and then grab a rwlock and leave the | ||
1268 | * counters on other CPUs alone. If any counter interrupt raises while | ||
1269 | * we own the write lock, simply pause local counters on that CPU and | ||
1270 | * spin in the handler. Also we know we won't be switched to another | ||
1271 | * CPU after pausing local counters and before grabbing the lock. | ||
1272 | */ | ||
1273 | static void mipsxx_pmu_stop(void) | ||
1274 | { | ||
1275 | pause_local_counters(); | ||
1276 | #ifdef CONFIG_MIPS_MT_SMP | ||
1277 | write_lock(&pmuint_rwlock); | ||
1278 | #endif | ||
1279 | } | ||
1280 | |||
1281 | static int mipsxx_pmu_alloc_counter(struct cpu_hw_events *cpuc, | ||
1282 | struct hw_perf_event *hwc) | ||
1283 | { | ||
1284 | int i; | ||
1285 | |||
1286 | /* | ||
1287 | * We only need to care the counter mask. The range has been | ||
1288 | * checked definitely. | ||
1289 | */ | ||
1290 | unsigned long cntr_mask = (hwc->event_base >> 8) & 0xffff; | ||
1291 | |||
1292 | for (i = mipspmu->num_counters - 1; i >= 0; i--) { | ||
1293 | /* | ||
1294 | * Note that some MIPS perf events can be counted by both | ||
1295 | * even and odd counters, wheresas many other are only by | ||
1296 | * even _or_ odd counters. This introduces an issue that | ||
1297 | * when the former kind of event takes the counter the | ||
1298 | * latter kind of event wants to use, then the "counter | ||
1299 | * allocation" for the latter event will fail. In fact if | ||
1300 | * they can be dynamically swapped, they both feel happy. | ||
1301 | * But here we leave this issue alone for now. | ||
1302 | */ | ||
1303 | if (test_bit(i, &cntr_mask) && | ||
1304 | !test_and_set_bit(i, cpuc->used_mask)) | ||
1305 | return i; | ||
1306 | } | ||
1307 | |||
1308 | return -EAGAIN; | ||
1309 | } | ||
1310 | |||
1311 | static void mipsxx_pmu_enable_event(struct hw_perf_event *evt, int idx) | ||
1312 | { | ||
1313 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | ||
1314 | unsigned long flags; | ||
1315 | |||
1316 | WARN_ON(idx < 0 || idx >= mipspmu->num_counters); | ||
1317 | |||
1318 | local_irq_save(flags); | ||
1319 | cpuc->saved_ctrl[idx] = M_PERFCTL_EVENT(evt->event_base & 0xff) | | ||
1320 | (evt->config_base & M_PERFCTL_CONFIG_MASK) | | ||
1321 | /* Make sure interrupt enabled. */ | ||
1322 | M_PERFCTL_INTERRUPT_ENABLE; | ||
1323 | /* | ||
1324 | * We do not actually let the counter run. Leave it until start(). | ||
1325 | */ | ||
1326 | local_irq_restore(flags); | ||
1327 | } | ||
1328 | |||
1329 | static void mipsxx_pmu_disable_event(int idx) | ||
1330 | { | ||
1331 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | ||
1332 | unsigned long flags; | ||
1333 | |||
1334 | WARN_ON(idx < 0 || idx >= mipspmu->num_counters); | ||
1335 | |||
1336 | local_irq_save(flags); | ||
1337 | cpuc->saved_ctrl[idx] = mipsxx_pmu_read_control(idx) & | ||
1338 | ~M_PERFCTL_COUNT_EVENT_WHENEVER; | ||
1339 | mipsxx_pmu_write_control(idx, cpuc->saved_ctrl[idx]); | ||
1340 | local_irq_restore(flags); | ||
1341 | } | ||
1342 | |||
1343 | /* 24K */ | 1276 | /* 24K */ |
1344 | #define IS_UNSUPPORTED_24K_EVENT(r, b) \ | 1277 | #define IS_UNSUPPORTED_24K_EVENT(r, b) \ |
1345 | ((b) == 12 || (r) == 151 || (r) == 152 || (b) == 26 || \ | 1278 | ((b) == 12 || (r) == 151 || (r) == 152 || (b) == 26 || \ |
@@ -1478,40 +1411,11 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config) | |||
1478 | return &raw_event; | 1411 | return &raw_event; |
1479 | } | 1412 | } |
1480 | 1413 | ||
1481 | static struct mips_pmu mipsxxcore_pmu = { | ||
1482 | .handle_irq = mipsxx_pmu_handle_irq, | ||
1483 | .handle_shared_irq = mipsxx_pmu_handle_shared_irq, | ||
1484 | .start = mipsxx_pmu_start, | ||
1485 | .stop = mipsxx_pmu_stop, | ||
1486 | .alloc_counter = mipsxx_pmu_alloc_counter, | ||
1487 | .read_counter = mipsxx_pmu_read_counter, | ||
1488 | .write_counter = mipsxx_pmu_write_counter, | ||
1489 | .enable_event = mipsxx_pmu_enable_event, | ||
1490 | .disable_event = mipsxx_pmu_disable_event, | ||
1491 | .map_raw_event = mipsxx_pmu_map_raw_event, | ||
1492 | .general_event_map = &mipsxxcore_event_map, | ||
1493 | .cache_event_map = &mipsxxcore_cache_map, | ||
1494 | }; | ||
1495 | |||
1496 | static struct mips_pmu mipsxx74Kcore_pmu = { | ||
1497 | .handle_irq = mipsxx_pmu_handle_irq, | ||
1498 | .handle_shared_irq = mipsxx_pmu_handle_shared_irq, | ||
1499 | .start = mipsxx_pmu_start, | ||
1500 | .stop = mipsxx_pmu_stop, | ||
1501 | .alloc_counter = mipsxx_pmu_alloc_counter, | ||
1502 | .read_counter = mipsxx_pmu_read_counter, | ||
1503 | .write_counter = mipsxx_pmu_write_counter, | ||
1504 | .enable_event = mipsxx_pmu_enable_event, | ||
1505 | .disable_event = mipsxx_pmu_disable_event, | ||
1506 | .map_raw_event = mipsxx_pmu_map_raw_event, | ||
1507 | .general_event_map = &mipsxx74Kcore_event_map, | ||
1508 | .cache_event_map = &mipsxx74Kcore_cache_map, | ||
1509 | }; | ||
1510 | |||
1511 | static int __init | 1414 | static int __init |
1512 | init_hw_perf_events(void) | 1415 | init_hw_perf_events(void) |
1513 | { | 1416 | { |
1514 | int counters, irq; | 1417 | int counters, irq; |
1418 | int counter_bits; | ||
1515 | 1419 | ||
1516 | pr_info("Performance counters: "); | 1420 | pr_info("Performance counters: "); |
1517 | 1421 | ||
@@ -1543,32 +1447,28 @@ init_hw_perf_events(void) | |||
1543 | } | 1447 | } |
1544 | #endif | 1448 | #endif |
1545 | 1449 | ||
1546 | on_each_cpu(reset_counters, (void *)(long)counters, 1); | 1450 | mipspmu.map_raw_event = mipsxx_pmu_map_raw_event; |
1547 | 1451 | ||
1548 | switch (current_cpu_type()) { | 1452 | switch (current_cpu_type()) { |
1549 | case CPU_24K: | 1453 | case CPU_24K: |
1550 | mipsxxcore_pmu.name = "mips/24K"; | 1454 | mipspmu.name = "mips/24K"; |
1551 | mipsxxcore_pmu.num_counters = counters; | 1455 | mipspmu.general_event_map = &mipsxxcore_event_map; |
1552 | mipsxxcore_pmu.irq = irq; | 1456 | mipspmu.cache_event_map = &mipsxxcore_cache_map; |
1553 | mipspmu = &mipsxxcore_pmu; | ||
1554 | break; | 1457 | break; |
1555 | case CPU_34K: | 1458 | case CPU_34K: |
1556 | mipsxxcore_pmu.name = "mips/34K"; | 1459 | mipspmu.name = "mips/34K"; |
1557 | mipsxxcore_pmu.num_counters = counters; | 1460 | mipspmu.general_event_map = &mipsxxcore_event_map; |
1558 | mipsxxcore_pmu.irq = irq; | 1461 | mipspmu.cache_event_map = &mipsxxcore_cache_map; |
1559 | mipspmu = &mipsxxcore_pmu; | ||
1560 | break; | 1462 | break; |
1561 | case CPU_74K: | 1463 | case CPU_74K: |
1562 | mipsxx74Kcore_pmu.name = "mips/74K"; | 1464 | mipspmu.name = "mips/74K"; |
1563 | mipsxx74Kcore_pmu.num_counters = counters; | 1465 | mipspmu.general_event_map = &mipsxx74Kcore_event_map; |
1564 | mipsxx74Kcore_pmu.irq = irq; | 1466 | mipspmu.cache_event_map = &mipsxx74Kcore_cache_map; |
1565 | mipspmu = &mipsxx74Kcore_pmu; | ||
1566 | break; | 1467 | break; |
1567 | case CPU_1004K: | 1468 | case CPU_1004K: |
1568 | mipsxxcore_pmu.name = "mips/1004K"; | 1469 | mipspmu.name = "mips/1004K"; |
1569 | mipsxxcore_pmu.num_counters = counters; | 1470 | mipspmu.general_event_map = &mipsxxcore_event_map; |
1570 | mipsxxcore_pmu.irq = irq; | 1471 | mipspmu.cache_event_map = &mipsxxcore_cache_map; |
1571 | mipspmu = &mipsxxcore_pmu; | ||
1572 | break; | 1472 | break; |
1573 | default: | 1473 | default: |
1574 | pr_cont("Either hardware does not support performance " | 1474 | pr_cont("Either hardware does not support performance " |
@@ -1576,10 +1476,30 @@ init_hw_perf_events(void) | |||
1576 | return -ENODEV; | 1476 | return -ENODEV; |
1577 | } | 1477 | } |
1578 | 1478 | ||
1579 | if (mipspmu) | 1479 | mipspmu.num_counters = counters; |
1580 | pr_cont("%s PMU enabled, %d counters available to each " | 1480 | mipspmu.irq = irq; |
1581 | "CPU, irq %d%s\n", mipspmu->name, counters, irq, | 1481 | |
1582 | irq < 0 ? " (share with timer interrupt)" : ""); | 1482 | if (read_c0_perfctrl0() & M_PERFCTL_WIDE) { |
1483 | mipspmu.max_period = (1ULL << 63) - 1; | ||
1484 | mipspmu.valid_count = (1ULL << 63) - 1; | ||
1485 | mipspmu.overflow = 1ULL << 63; | ||
1486 | mipspmu.read_counter = mipsxx_pmu_read_counter_64; | ||
1487 | mipspmu.write_counter = mipsxx_pmu_write_counter_64; | ||
1488 | counter_bits = 64; | ||
1489 | } else { | ||
1490 | mipspmu.max_period = (1ULL << 31) - 1; | ||
1491 | mipspmu.valid_count = (1ULL << 31) - 1; | ||
1492 | mipspmu.overflow = 1ULL << 31; | ||
1493 | mipspmu.read_counter = mipsxx_pmu_read_counter; | ||
1494 | mipspmu.write_counter = mipsxx_pmu_write_counter; | ||
1495 | counter_bits = 32; | ||
1496 | } | ||
1497 | |||
1498 | on_each_cpu(reset_counters, (void *)(long)counters, 1); | ||
1499 | |||
1500 | pr_cont("%s PMU enabled, %d %d-bit counters available to each " | ||
1501 | "CPU, irq %d%s\n", mipspmu.name, counters, counter_bits, irq, | ||
1502 | irq < 0 ? " (share with timer interrupt)" : ""); | ||
1583 | 1503 | ||
1584 | perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW); | 1504 | perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW); |
1585 | 1505 | ||