[POWERPC] cell: Add routines for managing PMU interrupts
authorKevin Corry <kevcorry@us.ibm.com>
Mon, 20 Nov 2006 17:45:15 +0000 (18:45 +0100)
committerPaul Mackerras <paulus@samba.org>
Mon, 4 Dec 2006 09:40:12 +0000 (20:40 +1100)
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>
arch/powerpc/platforms/cell/cbe_regs.h
arch/powerpc/platforms/cell/interrupt.c
arch/powerpc/platforms/cell/interrupt.h
arch/powerpc/platforms/cell/pmu.c
include/asm-powerpc/cell-pmu.h

index a29f4a5f52c5f62865f5274afbdf47bf61d43ec8..440a7ecc66eab1c3d2a894579c9dc399c7b9a351 100644 (file)
@@ -185,6 +185,14 @@ struct cbe_iic_regs {
        struct  cbe_iic_thread_regs thread[2];                  /* 0x0400 */
 
        u64     iic_ir;                                         /* 0x0440 */
+#define CBE_IIC_IR_PRIO(x)      (((x) & 0xf) << 12)
+#define CBE_IIC_IR_DEST_NODE(x) (((x) & 0xf) << 4)
+#define CBE_IIC_IR_DEST_UNIT(x) ((x) & 0xf)
+#define CBE_IIC_IR_IOC_0        0x0
+#define CBE_IIC_IR_IOC_1S       0xb
+#define CBE_IIC_IR_PT_0         0xe
+#define CBE_IIC_IR_PT_1         0xf
+
        u64     iic_is;                                         /* 0x0448 */
 #define CBE_IIC_IS_PMI         0x2
 
index a914c12b4060a2072d77a7bfc08e7c18c3265467..6666d037eb443c763fc9413f460f2ef5a275c86d 100644 (file)
@@ -396,3 +396,19 @@ void __init iic_init_IRQ(void)
        /* Enable on current CPU */
        iic_setup_cpu();
 }
+
+void iic_set_interrupt_routing(int cpu, int thread, int priority)
+{
+       struct cbe_iic_regs __iomem *iic_regs = cbe_get_cpu_iic_regs(cpu);
+       u64 iic_ir = 0;
+       int node = cpu >> 1;
+
+       /* Set which node and thread will handle the next interrupt */
+       iic_ir |= CBE_IIC_IR_PRIO(priority) |
+                 CBE_IIC_IR_DEST_NODE(node);
+       if (thread == 0)
+               iic_ir |= CBE_IIC_IR_DEST_UNIT(CBE_IIC_IR_PT_0);
+       else
+               iic_ir |= CBE_IIC_IR_DEST_UNIT(CBE_IIC_IR_PT_1);
+       out_be64(&iic_regs->iic_ir, iic_ir);
+}
index 9ba1d3c17b4b4c066dbb7cf1c7d168b01fea3f4d..942dc39d604559f4d1d58da68759a280dad968e7 100644 (file)
@@ -83,5 +83,7 @@ extern u8 iic_get_target_id(int cpu);
 
 extern void spider_init_IRQ(void);
 
+extern void iic_set_interrupt_routing(int cpu, int thread, int priority);
+
 #endif
 #endif /* ASM_CELL_PIC_H */
index ae6fd1c12d4e8c750f88dbb0238b73f68cadd88c..f28abf2fc273a7599277c01a82ade0703262ceee 100644 (file)
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <linux/interrupt.h>
 #include <linux/types.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
+#include <asm/pmc.h>
 #include <asm/reg.h>
 #include <asm/spu.h>
 
@@ -338,3 +340,71 @@ void cbe_read_trace_buffer(u32 cpu, u64 *buf)
 }
 EXPORT_SYMBOL_GPL(cbe_read_trace_buffer);
 
+/*
+ * Enabling/disabling interrupts for the entire performance monitoring unit.
+ */
+
+u32 cbe_query_pm_interrupts(u32 cpu)
+{
+       return cbe_read_pm(cpu, pm_status);
+}
+EXPORT_SYMBOL_GPL(cbe_query_pm_interrupts);
+
+u32 cbe_clear_pm_interrupts(u32 cpu)
+{
+       /* Reading pm_status clears the interrupt bits. */
+       return cbe_query_pm_interrupts(cpu);
+}
+EXPORT_SYMBOL_GPL(cbe_clear_pm_interrupts);
+
+void cbe_enable_pm_interrupts(u32 cpu, u32 thread, u32 mask)
+{
+       /* Set which node and thread will handle the next interrupt. */
+       iic_set_interrupt_routing(cpu, thread, 0);
+
+       /* Enable the interrupt bits in the pm_status register. */
+       if (mask)
+               cbe_write_pm(cpu, pm_status, mask);
+}
+EXPORT_SYMBOL_GPL(cbe_enable_pm_interrupts);
+
+void cbe_disable_pm_interrupts(u32 cpu)
+{
+       cbe_clear_pm_interrupts(cpu);
+       cbe_write_pm(cpu, pm_status, 0);
+}
+EXPORT_SYMBOL_GPL(cbe_disable_pm_interrupts);
+
+static irqreturn_t cbe_pm_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+       perf_irq(regs);
+       return IRQ_HANDLED;
+}
+
+int __init cbe_init_pm_irq(void)
+{
+       unsigned int irq;
+       int rc, node;
+
+       for_each_node(node) {
+               irq = irq_create_mapping(NULL, IIC_IRQ_IOEX_PMI |
+                                              (node << IIC_IRQ_NODE_SHIFT));
+               if (irq == NO_IRQ) {
+                       printk("ERROR: Unable to allocate irq for node %d\n",
+                              node);
+                       return -EINVAL;
+               }
+
+               rc = request_irq(irq, cbe_pm_irq,
+                                IRQF_DISABLED, "cbe-pmu-0", NULL);
+               if (rc) {
+                       printk("ERROR: Request for irq on node %d failed\n",
+                              node);
+                       return rc;
+               }
+       }
+
+       return 0;
+}
+arch_initcall(cbe_init_pm_irq);
+
index c416fe30dee2bc0c6b237662fa9137dc613b6fa0..63037c352fde8bd7a2e0d1a56d4dc7e6863e9161 100644 (file)
@@ -87,4 +87,9 @@ extern void cbe_disable_pm(u32 cpu);
 
 extern void cbe_read_trace_buffer(u32 cpu, u64 *buf);
 
+extern void cbe_enable_pm_interrupts(u32 cpu, u32 thread, u32 mask);
+extern void cbe_disable_pm_interrupts(u32 cpu);
+extern u32  cbe_query_pm_interrupts(u32 cpu);
+extern u32  cbe_clear_pm_interrupts(u32 cpu);
+
 #endif /* __ASM_CELL_PMU_H__ */