diff options
author | Will Deacon <will.deacon@arm.com> | 2010-04-30 06:37:51 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-05-17 06:53:58 -0400 |
commit | fe166148f699cc7865ca07b6754872cfb5ebc312 (patch) | |
tree | 421392e3fb9866c40cc8cfd952be44fd63336221 /arch/arm/oprofile/op_model_v7.c | |
parent | 8c1fc96f6fd1f361428ba805103af0d0eee65179 (diff) |
ARM: 6073/1: oprofile: remove old files and update KConfig
Enable hardware perf-events if CPU_HAS_PMU and select
HAVE_OPROFILE if HAVE_PERF_EVENTS. If no hardware support
is present, OProfile will fall back to timer mode.
This patch also removes the old OProfile drivers in favour
of the code implemented by perf.
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/oprofile/op_model_v7.c')
-rw-r--r-- | arch/arm/oprofile/op_model_v7.c | 415 |
1 files changed, 0 insertions, 415 deletions
diff --git a/arch/arm/oprofile/op_model_v7.c b/arch/arm/oprofile/op_model_v7.c deleted file mode 100644 index 8642d0891ae1..000000000000 --- a/arch/arm/oprofile/op_model_v7.c +++ /dev/null | |||
@@ -1,415 +0,0 @@ | |||
1 | /** | ||
2 | * op_model_v7.c | ||
3 | * ARM V7 (Cortex A8) Event Monitor Driver | ||
4 | * | ||
5 | * Copyright 2008 Jean Pihet <jpihet@mvista.com> | ||
6 | * Copyright 2004 ARM SMP Development Team | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #include <linux/types.h> | ||
13 | #include <linux/errno.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/oprofile.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/irq.h> | ||
18 | #include <linux/smp.h> | ||
19 | |||
20 | #include <asm/pmu.h> | ||
21 | |||
22 | #include "op_counter.h" | ||
23 | #include "op_arm_model.h" | ||
24 | #include "op_model_v7.h" | ||
25 | |||
26 | /* #define DEBUG */ | ||
27 | |||
28 | |||
29 | /* | ||
30 | * ARM V7 PMNC support | ||
31 | */ | ||
32 | |||
33 | static u32 cnt_en[CNTMAX]; | ||
34 | |||
35 | static inline void armv7_pmnc_write(u32 val) | ||
36 | { | ||
37 | val &= PMNC_MASK; | ||
38 | asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (val)); | ||
39 | } | ||
40 | |||
41 | static inline u32 armv7_pmnc_read(void) | ||
42 | { | ||
43 | u32 val; | ||
44 | |||
45 | asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val)); | ||
46 | return val; | ||
47 | } | ||
48 | |||
49 | static inline u32 armv7_pmnc_enable_counter(unsigned int cnt) | ||
50 | { | ||
51 | u32 val; | ||
52 | |||
53 | if (cnt >= CNTMAX) { | ||
54 | printk(KERN_ERR "oprofile: CPU%u enabling wrong PMNC counter" | ||
55 | " %d\n", smp_processor_id(), cnt); | ||
56 | return -1; | ||
57 | } | ||
58 | |||
59 | if (cnt == CCNT) | ||
60 | val = CNTENS_C; | ||
61 | else | ||
62 | val = (1 << (cnt - CNT0)); | ||
63 | |||
64 | val &= CNTENS_MASK; | ||
65 | asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val)); | ||
66 | |||
67 | return cnt; | ||
68 | } | ||
69 | |||
70 | static inline u32 armv7_pmnc_disable_counter(unsigned int cnt) | ||
71 | { | ||
72 | u32 val; | ||
73 | |||
74 | if (cnt >= CNTMAX) { | ||
75 | printk(KERN_ERR "oprofile: CPU%u disabling wrong PMNC counter" | ||
76 | " %d\n", smp_processor_id(), cnt); | ||
77 | return -1; | ||
78 | } | ||
79 | |||
80 | if (cnt == CCNT) | ||
81 | val = CNTENC_C; | ||
82 | else | ||
83 | val = (1 << (cnt - CNT0)); | ||
84 | |||
85 | val &= CNTENC_MASK; | ||
86 | asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val)); | ||
87 | |||
88 | return cnt; | ||
89 | } | ||
90 | |||
91 | static inline u32 armv7_pmnc_enable_intens(unsigned int cnt) | ||
92 | { | ||
93 | u32 val; | ||
94 | |||
95 | if (cnt >= CNTMAX) { | ||
96 | printk(KERN_ERR "oprofile: CPU%u enabling wrong PMNC counter" | ||
97 | " interrupt enable %d\n", smp_processor_id(), cnt); | ||
98 | return -1; | ||
99 | } | ||
100 | |||
101 | if (cnt == CCNT) | ||
102 | val = INTENS_C; | ||
103 | else | ||
104 | val = (1 << (cnt - CNT0)); | ||
105 | |||
106 | val &= INTENS_MASK; | ||
107 | asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (val)); | ||
108 | |||
109 | return cnt; | ||
110 | } | ||
111 | |||
112 | static inline u32 armv7_pmnc_getreset_flags(void) | ||
113 | { | ||
114 | u32 val; | ||
115 | |||
116 | /* Read */ | ||
117 | asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val)); | ||
118 | |||
119 | /* Write to clear flags */ | ||
120 | val &= FLAG_MASK; | ||
121 | asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (val)); | ||
122 | |||
123 | return val; | ||
124 | } | ||
125 | |||
126 | static inline int armv7_pmnc_select_counter(unsigned int cnt) | ||
127 | { | ||
128 | u32 val; | ||
129 | |||
130 | if ((cnt == CCNT) || (cnt >= CNTMAX)) { | ||
131 | printk(KERN_ERR "oprofile: CPU%u selecting wrong PMNC counteri" | ||
132 | " %d\n", smp_processor_id(), cnt); | ||
133 | return -1; | ||
134 | } | ||
135 | |||
136 | val = (cnt - CNT0) & SELECT_MASK; | ||
137 | asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val)); | ||
138 | |||
139 | return cnt; | ||
140 | } | ||
141 | |||
142 | static inline void armv7_pmnc_write_evtsel(unsigned int cnt, u32 val) | ||
143 | { | ||
144 | if (armv7_pmnc_select_counter(cnt) == cnt) { | ||
145 | val &= EVTSEL_MASK; | ||
146 | asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val)); | ||
147 | } | ||
148 | } | ||
149 | |||
150 | static void armv7_pmnc_reset_counter(unsigned int cnt) | ||
151 | { | ||
152 | u32 cpu_cnt = CPU_COUNTER(smp_processor_id(), cnt); | ||
153 | u32 val = -(u32)counter_config[cpu_cnt].count; | ||
154 | |||
155 | switch (cnt) { | ||
156 | case CCNT: | ||
157 | armv7_pmnc_disable_counter(cnt); | ||
158 | |||
159 | asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (val)); | ||
160 | |||
161 | if (cnt_en[cnt] != 0) | ||
162 | armv7_pmnc_enable_counter(cnt); | ||
163 | |||
164 | break; | ||
165 | |||
166 | case CNT0: | ||
167 | case CNT1: | ||
168 | case CNT2: | ||
169 | case CNT3: | ||
170 | armv7_pmnc_disable_counter(cnt); | ||
171 | |||
172 | if (armv7_pmnc_select_counter(cnt) == cnt) | ||
173 | asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (val)); | ||
174 | |||
175 | if (cnt_en[cnt] != 0) | ||
176 | armv7_pmnc_enable_counter(cnt); | ||
177 | |||
178 | break; | ||
179 | |||
180 | default: | ||
181 | printk(KERN_ERR "oprofile: CPU%u resetting wrong PMNC counter" | ||
182 | " %d\n", smp_processor_id(), cnt); | ||
183 | break; | ||
184 | } | ||
185 | } | ||
186 | |||
187 | int armv7_setup_pmnc(void) | ||
188 | { | ||
189 | unsigned int cnt; | ||
190 | |||
191 | if (armv7_pmnc_read() & PMNC_E) { | ||
192 | printk(KERN_ERR "oprofile: CPU%u PMNC still enabled when setup" | ||
193 | " new event counter.\n", smp_processor_id()); | ||
194 | return -EBUSY; | ||
195 | } | ||
196 | |||
197 | /* Initialize & Reset PMNC: C bit and P bit */ | ||
198 | armv7_pmnc_write(PMNC_P | PMNC_C); | ||
199 | |||
200 | |||
201 | for (cnt = CCNT; cnt < CNTMAX; cnt++) { | ||
202 | unsigned long event; | ||
203 | u32 cpu_cnt = CPU_COUNTER(smp_processor_id(), cnt); | ||
204 | |||
205 | /* | ||
206 | * Disable counter | ||
207 | */ | ||
208 | armv7_pmnc_disable_counter(cnt); | ||
209 | cnt_en[cnt] = 0; | ||
210 | |||
211 | if (!counter_config[cpu_cnt].enabled) | ||
212 | continue; | ||
213 | |||
214 | event = counter_config[cpu_cnt].event & 255; | ||
215 | |||
216 | /* | ||
217 | * Set event (if destined for PMNx counters) | ||
218 | * We don't need to set the event if it's a cycle count | ||
219 | */ | ||
220 | if (cnt != CCNT) | ||
221 | armv7_pmnc_write_evtsel(cnt, event); | ||
222 | |||
223 | /* | ||
224 | * Enable interrupt for this counter | ||
225 | */ | ||
226 | armv7_pmnc_enable_intens(cnt); | ||
227 | |||
228 | /* | ||
229 | * Reset counter | ||
230 | */ | ||
231 | armv7_pmnc_reset_counter(cnt); | ||
232 | |||
233 | /* | ||
234 | * Enable counter | ||
235 | */ | ||
236 | armv7_pmnc_enable_counter(cnt); | ||
237 | cnt_en[cnt] = 1; | ||
238 | } | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static inline void armv7_start_pmnc(void) | ||
244 | { | ||
245 | armv7_pmnc_write(armv7_pmnc_read() | PMNC_E); | ||
246 | } | ||
247 | |||
248 | static inline void armv7_stop_pmnc(void) | ||
249 | { | ||
250 | armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E); | ||
251 | } | ||
252 | |||
253 | /* | ||
254 | * CPU counters' IRQ handler (one IRQ per CPU) | ||
255 | */ | ||
256 | static irqreturn_t armv7_pmnc_interrupt(int irq, void *arg) | ||
257 | { | ||
258 | struct pt_regs *regs = get_irq_regs(); | ||
259 | unsigned int cnt; | ||
260 | u32 flags; | ||
261 | |||
262 | |||
263 | /* | ||
264 | * Stop IRQ generation | ||
265 | */ | ||
266 | armv7_stop_pmnc(); | ||
267 | |||
268 | /* | ||
269 | * Get and reset overflow status flags | ||
270 | */ | ||
271 | flags = armv7_pmnc_getreset_flags(); | ||
272 | |||
273 | /* | ||
274 | * Cycle counter | ||
275 | */ | ||
276 | if (flags & FLAG_C) { | ||
277 | u32 cpu_cnt = CPU_COUNTER(smp_processor_id(), CCNT); | ||
278 | armv7_pmnc_reset_counter(CCNT); | ||
279 | oprofile_add_sample(regs, cpu_cnt); | ||
280 | } | ||
281 | |||
282 | /* | ||
283 | * PMNC counters 0:3 | ||
284 | */ | ||
285 | for (cnt = CNT0; cnt < CNTMAX; cnt++) { | ||
286 | if (flags & (1 << (cnt - CNT0))) { | ||
287 | u32 cpu_cnt = CPU_COUNTER(smp_processor_id(), cnt); | ||
288 | armv7_pmnc_reset_counter(cnt); | ||
289 | oprofile_add_sample(regs, cpu_cnt); | ||
290 | } | ||
291 | } | ||
292 | |||
293 | /* | ||
294 | * Allow IRQ generation | ||
295 | */ | ||
296 | armv7_start_pmnc(); | ||
297 | |||
298 | return IRQ_HANDLED; | ||
299 | } | ||
300 | |||
301 | int armv7_request_interrupts(const int *irqs, int nr) | ||
302 | { | ||
303 | unsigned int i; | ||
304 | int ret = 0; | ||
305 | |||
306 | for (i = 0; i < nr; i++) { | ||
307 | ret = request_irq(irqs[i], armv7_pmnc_interrupt, | ||
308 | IRQF_DISABLED, "CP15 PMNC", NULL); | ||
309 | if (ret != 0) { | ||
310 | printk(KERN_ERR "oprofile: unable to request IRQ%u" | ||
311 | " for ARMv7\n", | ||
312 | irqs[i]); | ||
313 | break; | ||
314 | } | ||
315 | } | ||
316 | |||
317 | if (i != nr) | ||
318 | while (i-- != 0) | ||
319 | free_irq(irqs[i], NULL); | ||
320 | |||
321 | return ret; | ||
322 | } | ||
323 | |||
324 | void armv7_release_interrupts(const int *irqs, int nr) | ||
325 | { | ||
326 | unsigned int i; | ||
327 | |||
328 | for (i = 0; i < nr; i++) | ||
329 | free_irq(irqs[i], NULL); | ||
330 | } | ||
331 | |||
332 | #ifdef DEBUG | ||
333 | static void armv7_pmnc_dump_regs(void) | ||
334 | { | ||
335 | u32 val; | ||
336 | unsigned int cnt; | ||
337 | |||
338 | printk(KERN_INFO "PMNC registers dump:\n"); | ||
339 | |||
340 | asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val)); | ||
341 | printk(KERN_INFO "PMNC =0x%08x\n", val); | ||
342 | |||
343 | asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r" (val)); | ||
344 | printk(KERN_INFO "CNTENS=0x%08x\n", val); | ||
345 | |||
346 | asm volatile("mrc p15, 0, %0, c9, c14, 1" : "=r" (val)); | ||
347 | printk(KERN_INFO "INTENS=0x%08x\n", val); | ||
348 | |||
349 | asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val)); | ||
350 | printk(KERN_INFO "FLAGS =0x%08x\n", val); | ||
351 | |||
352 | asm volatile("mrc p15, 0, %0, c9, c12, 5" : "=r" (val)); | ||
353 | printk(KERN_INFO "SELECT=0x%08x\n", val); | ||
354 | |||
355 | asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val)); | ||
356 | printk(KERN_INFO "CCNT =0x%08x\n", val); | ||
357 | |||
358 | for (cnt = CNT0; cnt < CNTMAX; cnt++) { | ||
359 | armv7_pmnc_select_counter(cnt); | ||
360 | asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val)); | ||
361 | printk(KERN_INFO "CNT[%d] count =0x%08x\n", cnt-CNT0, val); | ||
362 | asm volatile("mrc p15, 0, %0, c9, c13, 1" : "=r" (val)); | ||
363 | printk(KERN_INFO "CNT[%d] evtsel=0x%08x\n", cnt-CNT0, val); | ||
364 | } | ||
365 | } | ||
366 | #endif | ||
367 | |||
368 | static const struct pmu_irqs *pmu_irqs; | ||
369 | |||
370 | static void armv7_pmnc_stop(void) | ||
371 | { | ||
372 | #ifdef DEBUG | ||
373 | armv7_pmnc_dump_regs(); | ||
374 | #endif | ||
375 | armv7_stop_pmnc(); | ||
376 | armv7_release_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs); | ||
377 | release_pmu(pmu_irqs); | ||
378 | pmu_irqs = NULL; | ||
379 | } | ||
380 | |||
381 | static int armv7_pmnc_start(void) | ||
382 | { | ||
383 | int ret; | ||
384 | |||
385 | pmu_irqs = reserve_pmu(); | ||
386 | if (IS_ERR(pmu_irqs)) | ||
387 | return PTR_ERR(pmu_irqs); | ||
388 | |||
389 | #ifdef DEBUG | ||
390 | armv7_pmnc_dump_regs(); | ||
391 | #endif | ||
392 | ret = armv7_request_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs); | ||
393 | if (ret >= 0) { | ||
394 | armv7_start_pmnc(); | ||
395 | } else { | ||
396 | release_pmu(pmu_irqs); | ||
397 | pmu_irqs = NULL; | ||
398 | } | ||
399 | |||
400 | return ret; | ||
401 | } | ||
402 | |||
403 | static int armv7_detect_pmnc(void) | ||
404 | { | ||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | struct op_arm_model_spec op_armv7_spec = { | ||
409 | .init = armv7_detect_pmnc, | ||
410 | .num_counters = 5, | ||
411 | .setup_ctrs = armv7_setup_pmnc, | ||
412 | .start = armv7_pmnc_start, | ||
413 | .stop = armv7_pmnc_stop, | ||
414 | .name = "arm/armv7", | ||
415 | }; | ||