This source file includes following definitions.
- cbe_read_phys_ctr
- cbe_write_phys_ctr
- cbe_read_ctr
- cbe_write_ctr
- cbe_read_pm07_control
- cbe_write_pm07_control
- cbe_read_pm
- cbe_write_pm
- cbe_get_ctr_size
- cbe_set_ctr_size
- cbe_enable_pm
- cbe_disable_pm
- cbe_read_trace_buffer
- cbe_get_and_clear_pm_interrupts
- cbe_enable_pm_interrupts
- cbe_disable_pm_interrupts
- cbe_pm_irq
- cbe_init_pm_irq
- cbe_sync_irq
1
2
3
4
5
6
7
8
9
10
11
12 #include <linux/interrupt.h>
13 #include <linux/types.h>
14 #include <linux/export.h>
15 #include <asm/io.h>
16 #include <asm/irq_regs.h>
17 #include <asm/machdep.h>
18 #include <asm/pmc.h>
19 #include <asm/reg.h>
20 #include <asm/spu.h>
21 #include <asm/cell-regs.h>
22
23 #include "interrupt.h"
24
25
26
27
28
29
30
31 #define WRITE_WO_MMIO(reg, x) \
32 do { \
33 u32 _x = (x); \
34 struct cbe_pmd_regs __iomem *pmd_regs; \
35 struct cbe_pmd_shadow_regs *shadow_regs; \
36 pmd_regs = cbe_get_cpu_pmd_regs(cpu); \
37 shadow_regs = cbe_get_cpu_pmd_shadow_regs(cpu); \
38 out_be64(&(pmd_regs->reg), (((u64)_x) << 32)); \
39 shadow_regs->reg = _x; \
40 } while (0)
41
42 #define READ_SHADOW_REG(val, reg) \
43 do { \
44 struct cbe_pmd_shadow_regs *shadow_regs; \
45 shadow_regs = cbe_get_cpu_pmd_shadow_regs(cpu); \
46 (val) = shadow_regs->reg; \
47 } while (0)
48
49 #define READ_MMIO_UPPER32(val, reg) \
50 do { \
51 struct cbe_pmd_regs __iomem *pmd_regs; \
52 pmd_regs = cbe_get_cpu_pmd_regs(cpu); \
53 (val) = (u32)(in_be64(&pmd_regs->reg) >> 32); \
54 } while (0)
55
56
57
58
59
60
61 u32 cbe_read_phys_ctr(u32 cpu, u32 phys_ctr)
62 {
63 u32 val_in_latch, val = 0;
64
65 if (phys_ctr < NR_PHYS_CTRS) {
66 READ_SHADOW_REG(val_in_latch, counter_value_in_latch);
67
68
69 if (val_in_latch & (1 << phys_ctr)) {
70 READ_SHADOW_REG(val, pm_ctr[phys_ctr]);
71 } else {
72 READ_MMIO_UPPER32(val, pm_ctr[phys_ctr]);
73 }
74 }
75
76 return val;
77 }
78 EXPORT_SYMBOL_GPL(cbe_read_phys_ctr);
79
80 void cbe_write_phys_ctr(u32 cpu, u32 phys_ctr, u32 val)
81 {
82 struct cbe_pmd_shadow_regs *shadow_regs;
83 u32 pm_ctrl;
84
85 if (phys_ctr < NR_PHYS_CTRS) {
86
87
88
89
90 WRITE_WO_MMIO(pm_ctr[phys_ctr], val);
91
92 pm_ctrl = cbe_read_pm(cpu, pm_control);
93 if (pm_ctrl & CBE_PM_ENABLE_PERF_MON) {
94
95
96
97
98 cbe_write_pm(cpu, pm_control, pm_ctrl);
99 } else {
100 shadow_regs = cbe_get_cpu_pmd_shadow_regs(cpu);
101 shadow_regs->counter_value_in_latch |= (1 << phys_ctr);
102 }
103 }
104 }
105 EXPORT_SYMBOL_GPL(cbe_write_phys_ctr);
106
107
108
109
110
111
112
113 u32 cbe_read_ctr(u32 cpu, u32 ctr)
114 {
115 u32 val;
116 u32 phys_ctr = ctr & (NR_PHYS_CTRS - 1);
117
118 val = cbe_read_phys_ctr(cpu, phys_ctr);
119
120 if (cbe_get_ctr_size(cpu, phys_ctr) == 16)
121 val = (ctr < NR_PHYS_CTRS) ? (val >> 16) : (val & 0xffff);
122
123 return val;
124 }
125 EXPORT_SYMBOL_GPL(cbe_read_ctr);
126
127 void cbe_write_ctr(u32 cpu, u32 ctr, u32 val)
128 {
129 u32 phys_ctr;
130 u32 phys_val;
131
132 phys_ctr = ctr & (NR_PHYS_CTRS - 1);
133
134 if (cbe_get_ctr_size(cpu, phys_ctr) == 16) {
135 phys_val = cbe_read_phys_ctr(cpu, phys_ctr);
136
137 if (ctr < NR_PHYS_CTRS)
138 val = (val << 16) | (phys_val & 0xffff);
139 else
140 val = (val & 0xffff) | (phys_val & 0xffff0000);
141 }
142
143 cbe_write_phys_ctr(cpu, phys_ctr, val);
144 }
145 EXPORT_SYMBOL_GPL(cbe_write_ctr);
146
147
148
149
150
151
152 u32 cbe_read_pm07_control(u32 cpu, u32 ctr)
153 {
154 u32 pm07_control = 0;
155
156 if (ctr < NR_CTRS)
157 READ_SHADOW_REG(pm07_control, pm07_control[ctr]);
158
159 return pm07_control;
160 }
161 EXPORT_SYMBOL_GPL(cbe_read_pm07_control);
162
163 void cbe_write_pm07_control(u32 cpu, u32 ctr, u32 val)
164 {
165 if (ctr < NR_CTRS)
166 WRITE_WO_MMIO(pm07_control[ctr], val);
167 }
168 EXPORT_SYMBOL_GPL(cbe_write_pm07_control);
169
170
171
172
173
174 u32 cbe_read_pm(u32 cpu, enum pm_reg_name reg)
175 {
176 u32 val = 0;
177
178 switch (reg) {
179 case group_control:
180 READ_SHADOW_REG(val, group_control);
181 break;
182
183 case debug_bus_control:
184 READ_SHADOW_REG(val, debug_bus_control);
185 break;
186
187 case trace_address:
188 READ_MMIO_UPPER32(val, trace_address);
189 break;
190
191 case ext_tr_timer:
192 READ_SHADOW_REG(val, ext_tr_timer);
193 break;
194
195 case pm_status:
196 READ_MMIO_UPPER32(val, pm_status);
197 break;
198
199 case pm_control:
200 READ_SHADOW_REG(val, pm_control);
201 break;
202
203 case pm_interval:
204 READ_MMIO_UPPER32(val, pm_interval);
205 break;
206
207 case pm_start_stop:
208 READ_SHADOW_REG(val, pm_start_stop);
209 break;
210 }
211
212 return val;
213 }
214 EXPORT_SYMBOL_GPL(cbe_read_pm);
215
216 void cbe_write_pm(u32 cpu, enum pm_reg_name reg, u32 val)
217 {
218 switch (reg) {
219 case group_control:
220 WRITE_WO_MMIO(group_control, val);
221 break;
222
223 case debug_bus_control:
224 WRITE_WO_MMIO(debug_bus_control, val);
225 break;
226
227 case trace_address:
228 WRITE_WO_MMIO(trace_address, val);
229 break;
230
231 case ext_tr_timer:
232 WRITE_WO_MMIO(ext_tr_timer, val);
233 break;
234
235 case pm_status:
236 WRITE_WO_MMIO(pm_status, val);
237 break;
238
239 case pm_control:
240 WRITE_WO_MMIO(pm_control, val);
241 break;
242
243 case pm_interval:
244 WRITE_WO_MMIO(pm_interval, val);
245 break;
246
247 case pm_start_stop:
248 WRITE_WO_MMIO(pm_start_stop, val);
249 break;
250 }
251 }
252 EXPORT_SYMBOL_GPL(cbe_write_pm);
253
254
255
256
257
258 u32 cbe_get_ctr_size(u32 cpu, u32 phys_ctr)
259 {
260 u32 pm_ctrl, size = 0;
261
262 if (phys_ctr < NR_PHYS_CTRS) {
263 pm_ctrl = cbe_read_pm(cpu, pm_control);
264 size = (pm_ctrl & CBE_PM_16BIT_CTR(phys_ctr)) ? 16 : 32;
265 }
266
267 return size;
268 }
269 EXPORT_SYMBOL_GPL(cbe_get_ctr_size);
270
271 void cbe_set_ctr_size(u32 cpu, u32 phys_ctr, u32 ctr_size)
272 {
273 u32 pm_ctrl;
274
275 if (phys_ctr < NR_PHYS_CTRS) {
276 pm_ctrl = cbe_read_pm(cpu, pm_control);
277 switch (ctr_size) {
278 case 16:
279 pm_ctrl |= CBE_PM_16BIT_CTR(phys_ctr);
280 break;
281
282 case 32:
283 pm_ctrl &= ~CBE_PM_16BIT_CTR(phys_ctr);
284 break;
285 }
286 cbe_write_pm(cpu, pm_control, pm_ctrl);
287 }
288 }
289 EXPORT_SYMBOL_GPL(cbe_set_ctr_size);
290
291
292
293
294
295
296 void cbe_enable_pm(u32 cpu)
297 {
298 struct cbe_pmd_shadow_regs *shadow_regs;
299 u32 pm_ctrl;
300
301 shadow_regs = cbe_get_cpu_pmd_shadow_regs(cpu);
302 shadow_regs->counter_value_in_latch = 0;
303
304 pm_ctrl = cbe_read_pm(cpu, pm_control) | CBE_PM_ENABLE_PERF_MON;
305 cbe_write_pm(cpu, pm_control, pm_ctrl);
306 }
307 EXPORT_SYMBOL_GPL(cbe_enable_pm);
308
309 void cbe_disable_pm(u32 cpu)
310 {
311 u32 pm_ctrl;
312 pm_ctrl = cbe_read_pm(cpu, pm_control) & ~CBE_PM_ENABLE_PERF_MON;
313 cbe_write_pm(cpu, pm_control, pm_ctrl);
314 }
315 EXPORT_SYMBOL_GPL(cbe_disable_pm);
316
317
318
319
320
321
322
323 void cbe_read_trace_buffer(u32 cpu, u64 *buf)
324 {
325 struct cbe_pmd_regs __iomem *pmd_regs = cbe_get_cpu_pmd_regs(cpu);
326
327 *buf++ = in_be64(&pmd_regs->trace_buffer_0_63);
328 *buf++ = in_be64(&pmd_regs->trace_buffer_64_127);
329 }
330 EXPORT_SYMBOL_GPL(cbe_read_trace_buffer);
331
332
333
334
335
336 u32 cbe_get_and_clear_pm_interrupts(u32 cpu)
337 {
338
339 return cbe_read_pm(cpu, pm_status);
340 }
341 EXPORT_SYMBOL_GPL(cbe_get_and_clear_pm_interrupts);
342
343 void cbe_enable_pm_interrupts(u32 cpu, u32 thread, u32 mask)
344 {
345
346 iic_set_interrupt_routing(cpu, thread, 0);
347
348
349 if (mask)
350 cbe_write_pm(cpu, pm_status, mask);
351 }
352 EXPORT_SYMBOL_GPL(cbe_enable_pm_interrupts);
353
354 void cbe_disable_pm_interrupts(u32 cpu)
355 {
356 cbe_get_and_clear_pm_interrupts(cpu);
357 cbe_write_pm(cpu, pm_status, 0);
358 }
359 EXPORT_SYMBOL_GPL(cbe_disable_pm_interrupts);
360
361 static irqreturn_t cbe_pm_irq(int irq, void *dev_id)
362 {
363 perf_irq(get_irq_regs());
364 return IRQ_HANDLED;
365 }
366
367 static int __init cbe_init_pm_irq(void)
368 {
369 unsigned int irq;
370 int rc, node;
371
372 for_each_online_node(node) {
373 irq = irq_create_mapping(NULL, IIC_IRQ_IOEX_PMI |
374 (node << IIC_IRQ_NODE_SHIFT));
375 if (!irq) {
376 printk("ERROR: Unable to allocate irq for node %d\n",
377 node);
378 return -EINVAL;
379 }
380
381 rc = request_irq(irq, cbe_pm_irq,
382 0, "cbe-pmu-0", NULL);
383 if (rc) {
384 printk("ERROR: Request for irq on node %d failed\n",
385 node);
386 return rc;
387 }
388 }
389
390 return 0;
391 }
392 machine_arch_initcall(cell, cbe_init_pm_irq);
393
394 void cbe_sync_irq(int node)
395 {
396 unsigned int irq;
397
398 irq = irq_find_mapping(NULL,
399 IIC_IRQ_IOEX_PMI
400 | (node << IIC_IRQ_NODE_SHIFT));
401
402 if (!irq) {
403 printk(KERN_WARNING "ERROR, unable to get existing irq %d " \
404 "for node %d\n", irq, node);
405 return;
406 }
407
408 synchronize_irq(irq);
409 }
410 EXPORT_SYMBOL_GPL(cbe_sync_irq);
411