]> err.no Git - linux-2.6/blobdiff - arch/powerpc/platforms/cell/interrupt.c
Merge branch 'for-2.6.26' of master.kernel.org:/pub/scm/linux/kernel/git/jwboyer...
[linux-2.6] / arch / powerpc / platforms / cell / interrupt.c
index 4fc4e92775d0d1735ef1f0c38eec093b1a1e3a4d..5bf7df14602288b1d4daafb79e1116ac92066864 100644 (file)
 #include <linux/percpu.h>
 #include <linux/types.h>
 #include <linux/ioport.h>
+#include <linux/kernel_stat.h>
 
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/prom.h>
 #include <asm/ptrace.h>
 #include <asm/machdep.h>
+#include <asm/cell-regs.h>
 
 #include "interrupt.h"
-#include "cbe_regs.h"
 
 struct iic {
        struct cbe_iic_thread_regs __iomem *regs;
@@ -158,6 +159,18 @@ static unsigned int iic_get_irq(void)
        return virq;
 }
 
+void iic_setup_cpu(void)
+{
+       out_be64(&__get_cpu_var(iic).regs->prio, 0xff);
+}
+
+u8 iic_get_target_id(int cpu)
+{
+       return per_cpu(iic, cpu).target_id;
+}
+
+EXPORT_SYMBOL_GPL(iic_get_target_id);
+
 #ifdef CONFIG_SMP
 
 /* Use the highest interrupt priorities for IPI */
@@ -166,29 +179,17 @@ static inline int iic_ipi_to_irq(int ipi)
        return IIC_IRQ_TYPE_IPI + 0xf - ipi;
 }
 
-void iic_setup_cpu(void)
-{
-       out_be64(&__get_cpu_var(iic).regs->prio, 0xff);
-}
-
 void iic_cause_IPI(int cpu, int mesg)
 {
        out_be64(&per_cpu(iic, cpu).regs->generate, (0xf - mesg) << 4);
 }
 
-u8 iic_get_target_id(int cpu)
-{
-       return per_cpu(iic, cpu).target_id;
-}
-EXPORT_SYMBOL_GPL(iic_get_target_id);
-
 struct irq_host *iic_get_irq_host(int node)
 {
        return iic_host;
 }
 EXPORT_SYMBOL_GPL(iic_get_irq_host);
 
-
 static irqreturn_t iic_ipi_action(int irq, void *dev_id)
 {
        int ipi = (int)(long)dev_id;
@@ -227,10 +228,58 @@ void iic_request_IPIs(void)
 
 static int iic_host_match(struct irq_host *h, struct device_node *node)
 {
-       return device_is_compatible(node,
+       return of_device_is_compatible(node,
                                    "IBM,CBEA-Internal-Interrupt-Controller");
 }
 
+extern int noirqdebug;
+
+static void handle_iic_irq(unsigned int irq, struct irq_desc *desc)
+{
+       const unsigned int cpu = smp_processor_id();
+
+       spin_lock(&desc->lock);
+
+       desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
+
+       /*
+        * If we're currently running this IRQ, or its disabled,
+        * we shouldn't process the IRQ. Mark it pending, handle
+        * the necessary masking and go out
+        */
+       if (unlikely((desc->status & (IRQ_INPROGRESS | IRQ_DISABLED)) ||
+                   !desc->action)) {
+               desc->status |= IRQ_PENDING;
+               goto out_eoi;
+       }
+
+       kstat_cpu(cpu).irqs[irq]++;
+
+       /* Mark the IRQ currently in progress.*/
+       desc->status |= IRQ_INPROGRESS;
+
+       do {
+               struct irqaction *action = desc->action;
+               irqreturn_t action_ret;
+
+               if (unlikely(!action))
+                       goto out_eoi;
+
+               desc->status &= ~IRQ_PENDING;
+               spin_unlock(&desc->lock);
+               action_ret = handle_IRQ_event(irq, action);
+               if (!noirqdebug)
+                       note_interrupt(irq, desc, action_ret);
+               spin_lock(&desc->lock);
+
+       } while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING);
+
+       desc->status &= ~IRQ_INPROGRESS;
+out_eoi:
+       desc->chip->eoi(irq);
+       spin_unlock(&desc->lock);
+}
+
 static int iic_host_map(struct irq_host *h, unsigned int virq,
                        irq_hw_number_t hw)
 {
@@ -240,10 +289,10 @@ static int iic_host_map(struct irq_host *h, unsigned int virq,
                break;
        case IIC_IRQ_TYPE_IOEXC:
                set_irq_chip_and_handler(virq, &iic_ioexc_chip,
-                                        handle_fasteoi_irq);
+                                        handle_iic_irq);
                break;
        default:
-               set_irq_chip_and_handler(virq, &iic_chip, handle_fasteoi_irq);
+               set_irq_chip_and_handler(virq, &iic_chip, handle_iic_irq);
        }
        return 0;
 }
@@ -256,7 +305,7 @@ static int iic_host_xlate(struct irq_host *h, struct device_node *ct,
        unsigned int node, ext, unit, class;
        const u32 *val;
 
-       if (!device_is_compatible(ct,
+       if (!of_device_is_compatible(ct,
                                     "IBM,CBEA-Internal-Interrupt-Controller"))
                return -ENODEV;
        if (intsize != 1)
@@ -324,7 +373,7 @@ static int __init setup_iic(void)
 
        for (dn = NULL;
             (dn = of_find_node_by_name(dn,"interrupt-controller")) != NULL;) {
-               if (!device_is_compatible(dn,
+               if (!of_device_is_compatible(dn,
                                     "IBM,CBEA-Internal-Interrupt-Controller"))
                        continue;
                np = of_get_property(dn, "ibm,interrupt-server-ranges", NULL);
@@ -381,7 +430,7 @@ static int __init setup_iic(void)
 void __init iic_init_IRQ(void)
 {
        /* Setup an irq host data structure */
-       iic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, IIC_SOURCE_COUNT,
+       iic_host = irq_alloc_host(NULL, IRQ_HOST_MAP_LINEAR, IIC_SOURCE_COUNT,
                                  &iic_host_ops, IIC_IRQ_INVALID);
        BUG_ON(iic_host == NULL);
        irq_set_default_host(iic_host);