diff options
author | Kevin Corry <kevcorry@us.ibm.com> | 2006-11-20 12:45:15 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-12-04 04:40:12 -0500 |
commit | 0443bbd3d8496f9c2bc3e8c9d1833c6638722743 (patch) | |
tree | 7166aeb19de3d4cc538c7153843e009a5a33f32b /arch/powerpc | |
parent | e4f6948cfc8b9626022db0f93e7cf2ce5c0998cd (diff) |
[POWERPC] cell: Add routines for managing PMU interrupts
The following routines are added to arch/powerpc/platforms/cell/pmu.c:
cbe_clear_pm_interrupts()
cbe_enable_pm_interrupts()
cbe_disable_pm_interrupts()
cbe_query_pm_interrupts()
cbe_pm_irq()
cbe_init_pm_irq()
This also adds a routine in arch/powerpc/platforms/cell/interrupt.c and
some macros in cbe_regs.h to manipulate the IIC_IR register:
iic_set_interrupt_routing()
Signed-off-by: Kevin Corry <kevcorry@us.ibm.com>
Signed-off-by: Carl Love <carll@us.ibm.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/platforms/cell/cbe_regs.h | 8 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/interrupt.c | 16 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/interrupt.h | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/pmu.c | 70 |
4 files changed, 96 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/cell/cbe_regs.h b/arch/powerpc/platforms/cell/cbe_regs.h index a29f4a5f52c5..440a7ecc66ea 100644 --- a/arch/powerpc/platforms/cell/cbe_regs.h +++ b/arch/powerpc/platforms/cell/cbe_regs.h | |||
@@ -185,6 +185,14 @@ struct cbe_iic_regs { | |||
185 | struct cbe_iic_thread_regs thread[2]; /* 0x0400 */ | 185 | struct cbe_iic_thread_regs thread[2]; /* 0x0400 */ |
186 | 186 | ||
187 | u64 iic_ir; /* 0x0440 */ | 187 | u64 iic_ir; /* 0x0440 */ |
188 | #define CBE_IIC_IR_PRIO(x) (((x) & 0xf) << 12) | ||
189 | #define CBE_IIC_IR_DEST_NODE(x) (((x) & 0xf) << 4) | ||
190 | #define CBE_IIC_IR_DEST_UNIT(x) ((x) & 0xf) | ||
191 | #define CBE_IIC_IR_IOC_0 0x0 | ||
192 | #define CBE_IIC_IR_IOC_1S 0xb | ||
193 | #define CBE_IIC_IR_PT_0 0xe | ||
194 | #define CBE_IIC_IR_PT_1 0xf | ||
195 | |||
188 | u64 iic_is; /* 0x0448 */ | 196 | u64 iic_is; /* 0x0448 */ |
189 | #define CBE_IIC_IS_PMI 0x2 | 197 | #define CBE_IIC_IS_PMI 0x2 |
190 | 198 | ||
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index a914c12b4060..6666d037eb44 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c | |||
@@ -396,3 +396,19 @@ void __init iic_init_IRQ(void) | |||
396 | /* Enable on current CPU */ | 396 | /* Enable on current CPU */ |
397 | iic_setup_cpu(); | 397 | iic_setup_cpu(); |
398 | } | 398 | } |
399 | |||
400 | void iic_set_interrupt_routing(int cpu, int thread, int priority) | ||
401 | { | ||
402 | struct cbe_iic_regs __iomem *iic_regs = cbe_get_cpu_iic_regs(cpu); | ||
403 | u64 iic_ir = 0; | ||
404 | int node = cpu >> 1; | ||
405 | |||
406 | /* Set which node and thread will handle the next interrupt */ | ||
407 | iic_ir |= CBE_IIC_IR_PRIO(priority) | | ||
408 | CBE_IIC_IR_DEST_NODE(node); | ||
409 | if (thread == 0) | ||
410 | iic_ir |= CBE_IIC_IR_DEST_UNIT(CBE_IIC_IR_PT_0); | ||
411 | else | ||
412 | iic_ir |= CBE_IIC_IR_DEST_UNIT(CBE_IIC_IR_PT_1); | ||
413 | out_be64(&iic_regs->iic_ir, iic_ir); | ||
414 | } | ||
diff --git a/arch/powerpc/platforms/cell/interrupt.h b/arch/powerpc/platforms/cell/interrupt.h index 9ba1d3c17b4b..942dc39d6045 100644 --- a/arch/powerpc/platforms/cell/interrupt.h +++ b/arch/powerpc/platforms/cell/interrupt.h | |||
@@ -83,5 +83,7 @@ extern u8 iic_get_target_id(int cpu); | |||
83 | 83 | ||
84 | extern void spider_init_IRQ(void); | 84 | extern void spider_init_IRQ(void); |
85 | 85 | ||
86 | extern void iic_set_interrupt_routing(int cpu, int thread, int priority); | ||
87 | |||
86 | #endif | 88 | #endif |
87 | #endif /* ASM_CELL_PIC_H */ | 89 | #endif /* ASM_CELL_PIC_H */ |
diff --git a/arch/powerpc/platforms/cell/pmu.c b/arch/powerpc/platforms/cell/pmu.c index ae6fd1c12d4e..f28abf2fc273 100644 --- a/arch/powerpc/platforms/cell/pmu.c +++ b/arch/powerpc/platforms/cell/pmu.c | |||
@@ -22,9 +22,11 @@ | |||
22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <linux/interrupt.h> | ||
25 | #include <linux/types.h> | 26 | #include <linux/types.h> |
26 | #include <asm/io.h> | 27 | #include <asm/io.h> |
27 | #include <asm/machdep.h> | 28 | #include <asm/machdep.h> |
29 | #include <asm/pmc.h> | ||
28 | #include <asm/reg.h> | 30 | #include <asm/reg.h> |
29 | #include <asm/spu.h> | 31 | #include <asm/spu.h> |
30 | 32 | ||
@@ -338,3 +340,71 @@ void cbe_read_trace_buffer(u32 cpu, u64 *buf) | |||
338 | } | 340 | } |
339 | EXPORT_SYMBOL_GPL(cbe_read_trace_buffer); | 341 | EXPORT_SYMBOL_GPL(cbe_read_trace_buffer); |
340 | 342 | ||
343 | /* | ||
344 | * Enabling/disabling interrupts for the entire performance monitoring unit. | ||
345 | */ | ||
346 | |||
347 | u32 cbe_query_pm_interrupts(u32 cpu) | ||
348 | { | ||
349 | return cbe_read_pm(cpu, pm_status); | ||
350 | } | ||
351 | EXPORT_SYMBOL_GPL(cbe_query_pm_interrupts); | ||
352 | |||
353 | u32 cbe_clear_pm_interrupts(u32 cpu) | ||
354 | { | ||
355 | /* Reading pm_status clears the interrupt bits. */ | ||
356 | return cbe_query_pm_interrupts(cpu); | ||
357 | } | ||
358 | EXPORT_SYMBOL_GPL(cbe_clear_pm_interrupts); | ||
359 | |||
360 | void cbe_enable_pm_interrupts(u32 cpu, u32 thread, u32 mask) | ||
361 | { | ||
362 | /* Set which node and thread will handle the next interrupt. */ | ||
363 | iic_set_interrupt_routing(cpu, thread, 0); | ||
364 | |||
365 | /* Enable the interrupt bits in the pm_status register. */ | ||
366 | if (mask) | ||
367 | cbe_write_pm(cpu, pm_status, mask); | ||
368 | } | ||
369 | EXPORT_SYMBOL_GPL(cbe_enable_pm_interrupts); | ||
370 | |||
371 | void cbe_disable_pm_interrupts(u32 cpu) | ||
372 | { | ||
373 | cbe_clear_pm_interrupts(cpu); | ||
374 | cbe_write_pm(cpu, pm_status, 0); | ||
375 | } | ||
376 | EXPORT_SYMBOL_GPL(cbe_disable_pm_interrupts); | ||
377 | |||
378 | static irqreturn_t cbe_pm_irq(int irq, void *dev_id, struct pt_regs *regs) | ||
379 | { | ||
380 | perf_irq(regs); | ||
381 | return IRQ_HANDLED; | ||
382 | } | ||
383 | |||
384 | int __init cbe_init_pm_irq(void) | ||
385 | { | ||
386 | unsigned int irq; | ||
387 | int rc, node; | ||
388 | |||
389 | for_each_node(node) { | ||
390 | irq = irq_create_mapping(NULL, IIC_IRQ_IOEX_PMI | | ||
391 | (node << IIC_IRQ_NODE_SHIFT)); | ||
392 | if (irq == NO_IRQ) { | ||
393 | printk("ERROR: Unable to allocate irq for node %d\n", | ||
394 | node); | ||
395 | return -EINVAL; | ||
396 | } | ||
397 | |||
398 | rc = request_irq(irq, cbe_pm_irq, | ||
399 | IRQF_DISABLED, "cbe-pmu-0", NULL); | ||
400 | if (rc) { | ||
401 | printk("ERROR: Request for irq on node %d failed\n", | ||
402 | node); | ||
403 | return rc; | ||
404 | } | ||
405 | } | ||
406 | |||
407 | return 0; | ||
408 | } | ||
409 | arch_initcall(cbe_init_pm_irq); | ||
410 | |||