Merge branch 'ioat' into dmaengine
[pandora-kernel.git] / arch / arm / oprofile / op_model_mpcore.c
1 /**
2  * @file op_model_mpcore.c
3  * MPCORE Event Monitor Driver
4  * @remark Copyright 2004 ARM SMP Development Team
5  * @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
6  * @remark Copyright 2000-2004 MontaVista Software Inc
7  * @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com>
8  * @remark Copyright 2004 Intel Corporation
9  * @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
10  * @remark Copyright 2004 Oprofile Authors
11  *
12  * @remark Read the file COPYING
13  *
14  * @author Zwane Mwaikambo
15  *
16  *  Counters:
17  *    0: PMN0 on CPU0, per-cpu configurable event counter
18  *    1: PMN1 on CPU0, per-cpu configurable event counter
19  *    2: CCNT on CPU0
20  *    3: PMN0 on CPU1
21  *    4: PMN1 on CPU1
22  *    5: CCNT on CPU1
23  *    6: PMN0 on CPU1
24  *    7: PMN1 on CPU1
25  *    8: CCNT on CPU1
26  *    9: PMN0 on CPU1
27  *   10: PMN1 on CPU1
28  *   11: CCNT on CPU1
29  *   12-19: configurable SCU event counters
30  */
31
32 /* #define DEBUG */
33 #include <linux/types.h>
34 #include <linux/errno.h>
35 #include <linux/err.h>
36 #include <linux/sched.h>
37 #include <linux/oprofile.h>
38 #include <linux/interrupt.h>
39 #include <linux/smp.h>
40 #include <linux/io.h>
41
42 #include <asm/irq.h>
43 #include <asm/mach/irq.h>
44 #include <mach/hardware.h>
45 #include <mach/board-eb.h>
46 #include <asm/system.h>
47 #include <asm/pmu.h>
48
49 #include "op_counter.h"
50 #include "op_arm_model.h"
51 #include "op_model_arm11_core.h"
52 #include "op_model_mpcore.h"
53
54 /*
55  * MPCore SCU event monitor support
56  */
57 #define SCU_EVENTMONITORS_VA_BASE __io_address(REALVIEW_EB11MP_SCU_BASE + 0x10)
58
59 /*
60  * Bitmask of used SCU counters
61  */
62 static unsigned int scu_em_used;
63 static const struct pmu_irqs *pmu_irqs;
64
65 /*
66  * 2 helper fns take a counter number from 0-7 (not the userspace-visible counter number)
67  */
68 static inline void scu_reset_counter(struct eventmonitor __iomem *emc, unsigned int n)
69 {
70         writel(-(u32)counter_config[SCU_COUNTER(n)].count, &emc->MC[n]);
71 }
72
73 static inline void scu_set_event(struct eventmonitor __iomem *emc, unsigned int n, u32 event)
74 {
75         event &= 0xff;
76         writeb(event, &emc->MCEB[n]);
77 }
78
79 /*
80  * SCU counters' IRQ handler (one IRQ per counter => 2 IRQs per CPU)
81  */
82 static irqreturn_t scu_em_interrupt(int irq, void *arg)
83 {
84         struct eventmonitor __iomem *emc = SCU_EVENTMONITORS_VA_BASE;
85         unsigned int cnt;
86
87         cnt = irq - IRQ_EB11MP_PMU_SCU0;
88         oprofile_add_sample(get_irq_regs(), SCU_COUNTER(cnt));
89         scu_reset_counter(emc, cnt);
90
91         /* Clear overflow flag for this counter */
92         writel(1 << (cnt + 16), &emc->PMCR);
93
94         return IRQ_HANDLED;
95 }
96
97 /* Configure just the SCU counters that the user has requested */
98 static void scu_setup(void)
99 {
100         struct eventmonitor __iomem *emc = SCU_EVENTMONITORS_VA_BASE;
101         unsigned int i;
102
103         scu_em_used = 0;
104
105         for (i = 0; i < NUM_SCU_COUNTERS; i++) {
106                 if (counter_config[SCU_COUNTER(i)].enabled &&
107                     counter_config[SCU_COUNTER(i)].event) {
108                         scu_set_event(emc, i, 0); /* disable counter for now */
109                         scu_em_used |= 1 << i;
110                 }
111         }
112 }
113
114 static int scu_start(void)
115 {
116         struct eventmonitor __iomem *emc = SCU_EVENTMONITORS_VA_BASE;
117         unsigned int temp, i;
118         unsigned long event;
119         int ret = 0;
120
121         /*
122          * request the SCU counter interrupts that we need
123          */
124         for (i = 0; i < NUM_SCU_COUNTERS; i++) {
125                 if (scu_em_used & (1 << i)) {
126                         ret = request_irq(IRQ_EB11MP_PMU_SCU0 + i, scu_em_interrupt, IRQF_DISABLED, "SCU PMU", NULL);
127                         if (ret) {
128                                 printk(KERN_ERR "oprofile: unable to request IRQ%u for SCU Event Monitor\n",
129                                        IRQ_EB11MP_PMU_SCU0 + i);
130                                 goto err_free_scu;
131                         }
132                 }
133         }
134
135         /*
136          * clear overflow and enable interrupt for all used counters
137          */
138         temp = readl(&emc->PMCR);
139         for (i = 0; i < NUM_SCU_COUNTERS; i++) {
140                 if (scu_em_used & (1 << i)) {
141                         scu_reset_counter(emc, i);
142                         event = counter_config[SCU_COUNTER(i)].event;
143                         scu_set_event(emc, i, event);
144
145                         /* clear overflow/interrupt */
146                         temp |= 1 << (i + 16);
147                         /* enable interrupt*/
148                         temp |= 1 << (i + 8);
149                 }
150         }
151
152         /* Enable all 8 counters */
153         temp |= PMCR_E;
154         writel(temp, &emc->PMCR);
155
156         return 0;
157
158  err_free_scu:
159         while (i--)
160                 free_irq(IRQ_EB11MP_PMU_SCU0 + i, NULL);
161         return ret;
162 }
163
164 static void scu_stop(void)
165 {
166         struct eventmonitor __iomem *emc = SCU_EVENTMONITORS_VA_BASE;
167         unsigned int temp, i;
168
169         /* Disable counter interrupts */
170         /* Don't disable all 8 counters (with the E bit) as they may be in use */
171         temp = readl(&emc->PMCR);
172         for (i = 0; i < NUM_SCU_COUNTERS; i++) {
173                 if (scu_em_used & (1 << i))
174                         temp &= ~(1 << (i + 8));
175         }
176         writel(temp, &emc->PMCR);
177
178         /* Free counter interrupts and reset counters */
179         for (i = 0; i < NUM_SCU_COUNTERS; i++) {
180                 if (scu_em_used & (1 << i)) {
181                         scu_reset_counter(emc, i);
182                         free_irq(IRQ_EB11MP_PMU_SCU0 + i, NULL);
183                 }
184         }
185 }
186
187 struct em_function_data {
188         int (*fn)(void);
189         int ret;
190 };
191
192 static void em_func(void *data)
193 {
194         struct em_function_data *d = data;
195         int ret = d->fn();
196         if (ret)
197                 d->ret = ret;
198 }
199
200 static int em_call_function(int (*fn)(void))
201 {
202         struct em_function_data data;
203
204         data.fn = fn;
205         data.ret = 0;
206
207         preempt_disable();
208         smp_call_function(em_func, &data, 1);
209         em_func(&data);
210         preempt_enable();
211
212         return data.ret;
213 }
214
215 /*
216  * Glue to stick the individual ARM11 PMUs and the SCU
217  * into the oprofile framework.
218  */
219 static int em_setup_ctrs(void)
220 {
221         int ret;
222
223         /* Configure CPU counters by cross-calling to the other CPUs */
224         ret = em_call_function(arm11_setup_pmu);
225         if (ret == 0)
226                 scu_setup();
227
228         return 0;
229 }
230
231 static int em_start(void)
232 {
233         int ret;
234
235         pmu_irqs = reserve_pmu();
236         if (IS_ERR(pmu_irqs)) {
237                 ret = PTR_ERR(pmu_irqs);
238                 goto out;
239         }
240
241         ret = arm11_request_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
242         if (ret == 0) {
243                 em_call_function(arm11_start_pmu);
244
245                 ret = scu_start();
246                 if (ret) {
247                         arm11_release_interrupts(pmu_irqs->irqs,
248                                                  pmu_irqs->num_irqs);
249                 } else {
250                         release_pmu(pmu_irqs);
251                         pmu_irqs = NULL;
252                 }
253         }
254
255 out:
256         return ret;
257 }
258
259 static void em_stop(void)
260 {
261         em_call_function(arm11_stop_pmu);
262         arm11_release_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
263         scu_stop();
264         release_pmu(pmu_irqs);
265 }
266
267 /*
268  * Why isn't there a function to route an IRQ to a specific CPU in
269  * genirq?
270  */
271 static void em_route_irq(int irq, unsigned int cpu)
272 {
273         struct irq_desc *desc = irq_desc + irq;
274         const struct cpumask *mask = cpumask_of(cpu);
275
276         spin_lock_irq(&desc->lock);
277         cpumask_copy(desc->affinity, mask);
278         desc->chip->set_affinity(irq, mask);
279         spin_unlock_irq(&desc->lock);
280 }
281
282 static int em_setup(void)
283 {
284         /*
285          * Send SCU PMU interrupts to the "owner" CPU.
286          */
287         em_route_irq(IRQ_EB11MP_PMU_SCU0, 0);
288         em_route_irq(IRQ_EB11MP_PMU_SCU1, 0);
289         em_route_irq(IRQ_EB11MP_PMU_SCU2, 1);
290         em_route_irq(IRQ_EB11MP_PMU_SCU3, 1);
291         em_route_irq(IRQ_EB11MP_PMU_SCU4, 2);
292         em_route_irq(IRQ_EB11MP_PMU_SCU5, 2);
293         em_route_irq(IRQ_EB11MP_PMU_SCU6, 3);
294         em_route_irq(IRQ_EB11MP_PMU_SCU7, 3);
295
296         return init_pmu();
297 }
298
299 struct op_arm_model_spec op_mpcore_spec = {
300         .init           = em_setup,
301         .num_counters   = MPCORE_NUM_COUNTERS,
302         .setup_ctrs     = em_setup_ctrs,
303         .start          = em_start,
304         .stop           = em_stop,
305         .name           = "arm/mpcore",
306 };