[POWERPC] Use the genirq framework
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Mon, 3 Jul 2006 09:32:51 +0000 (19:32 +1000)
committerPaul Mackerras <paulus@samba.org>
Mon, 3 Jul 2006 09:55:12 +0000 (19:55 +1000)
This adapts the generic powerpc interrupt handling code, and all of
the platforms except for the embedded 6xx machines, to use the new
genirq framework.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
17 files changed:
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/misc_64.S
arch/powerpc/platforms/cell/interrupt.c
arch/powerpc/platforms/cell/interrupt.h
arch/powerpc/platforms/cell/setup.c
arch/powerpc/platforms/cell/spider-pic.c
arch/powerpc/platforms/chrp/setup.c
arch/powerpc/platforms/iseries/irq.c
arch/powerpc/platforms/powermac/pic.c
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/platforms/pseries/xics.c
arch/powerpc/platforms/pseries/xics.h
arch/powerpc/sysdev/i8259.c
arch/powerpc/sysdev/mpic.c
include/asm-powerpc/i8259.h
include/asm-powerpc/irq.h
include/asm-powerpc/mpic.h

index 525baab..9124855 100644 (file)
 #endif
 
 int __irq_offset_value;
-#ifdef CONFIG_PPC32
-EXPORT_SYMBOL(__irq_offset_value);
-#endif
-
 static int ppc_spurious_interrupts;
 
 #ifdef CONFIG_PPC32
-#define NR_MASK_WORDS  ((NR_IRQS + 31) / 32)
+EXPORT_SYMBOL(__irq_offset_value);
+atomic_t ppc_n_lost_interrupts;
 
+#ifndef CONFIG_PPC_MERGE
+#define NR_MASK_WORDS  ((NR_IRQS + 31) / 32)
 unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
-atomic_t ppc_n_lost_interrupts;
+#endif
 
 #ifdef CONFIG_TAU_INT
 extern int tau_initialized;
 extern int tau_interrupts(int);
 #endif
+#endif /* CONFIG_PPC32 */
 
 #if defined(CONFIG_SMP) && !defined(CONFIG_PPC_MERGE)
 extern atomic_t ipi_recv;
 extern atomic_t ipi_sent;
 #endif
-#endif /* CONFIG_PPC32 */
 
 #ifdef CONFIG_PPC64
 EXPORT_SYMBOL(irq_desc);
@@ -219,15 +218,19 @@ void do_IRQ(struct pt_regs *regs)
                curtp = current_thread_info();
                irqtp = hardirq_ctx[smp_processor_id()];
                if (curtp != irqtp) {
+                       struct irq_desc *desc = irq_desc + irq;
+                       void *handler = desc->handle_irq;
+                       if (handler == NULL)
+                               handler = &__do_IRQ;
                        irqtp->task = curtp->task;
                        irqtp->flags = 0;
-                       call___do_IRQ(irq, regs, irqtp);
+                       call_handle_irq(irq, desc, regs, irqtp, handler);
                        irqtp->task = NULL;
                        if (irqtp->flags)
                                set_bits(irqtp->flags, &curtp->flags);
                } else
 #endif
-                       __do_IRQ(irq, regs);
+                       generic_handle_irq(irq, regs);
        } else if (irq != -2)
                /* That's not SMP safe ... but who cares ? */
                ppc_spurious_interrupts++;
@@ -245,15 +248,6 @@ void do_IRQ(struct pt_regs *regs)
 
 void __init init_IRQ(void)
 {
-#ifdef CONFIG_PPC64
-       static int once = 0;
-
-       if (once)
-               return;
-
-       once++;
-
-#endif
        ppc_md.init_IRQ();
 #ifdef CONFIG_PPC64
        irq_ctx_init();
index 0c3c70d..bfb407f 100644 (file)
@@ -51,12 +51,14 @@ _GLOBAL(call_do_softirq)
        mtlr    r0
        blr
 
-_GLOBAL(call___do_IRQ)
+_GLOBAL(call_handle_irq)
+       ld      r8,0(r7)
        mflr    r0
        std     r0,16(r1)
-       stdu    r1,THREAD_SIZE-112(r5)
-       mr      r1,r5
-       bl      .__do_IRQ
+       mtctr   r8
+       stdu    r1,THREAD_SIZE-112(r6)
+       mr      r1,r6
+       bctrl
        ld      r1,0(r1)
        ld      r0,16(r1)
        mtlr    r0
index 22da133..97936f5 100644 (file)
 struct iic {
        struct cbe_iic_thread_regs __iomem *regs;
        u8 target_id;
+       u8 eoi_stack[16];
+       int eoi_ptr;
 };
 
 static DEFINE_PER_CPU(struct iic, iic);
 
-void iic_local_enable(void)
+static void iic_mask(unsigned int irq)
 {
-       struct iic *iic = &__get_cpu_var(iic);
-       u64 tmp;
-
-       /*
-        * There seems to be a bug that is present in DD2.x CPUs
-        * and still only partially fixed in DD3.1.
-        * This bug causes a value written to the priority register
-        * not to make it there, resulting in a system hang unless we
-        * write it again.
-        * Masking with 0xf0 is done because the Cell BE does not
-        * implement the lower four bits of the interrupt priority,
-        * they always read back as zeroes, although future CPUs
-        * might implement different bits.
-        */
-       do {
-               out_be64(&iic->regs->prio, 0xff);
-               tmp = in_be64(&iic->regs->prio);
-       } while ((tmp & 0xf0) != 0xf0);
-}
-
-void iic_local_disable(void)
-{
-       out_be64(&__get_cpu_var(iic).regs->prio, 0x0);
-}
-
-static unsigned int iic_startup(unsigned int irq)
-{
-       return 0;
-}
-
-static void iic_enable(unsigned int irq)
-{
-       iic_local_enable();
 }
 
-static void iic_disable(unsigned int irq)
+static void iic_unmask(unsigned int irq)
 {
 }
 
-static void iic_end(unsigned int irq)
+static void iic_eoi(unsigned int irq)
 {
-       iic_local_enable();
+       struct iic *iic = &__get_cpu_var(iic);
+       out_be64(&iic->regs->prio, iic->eoi_stack[--iic->eoi_ptr]);
+       BUG_ON(iic->eoi_ptr < 0);
 }
 
-static struct hw_interrupt_type iic_pic = {
+static struct irq_chip iic_chip = {
        .typename = " CELL-IIC ",
-       .startup = iic_startup,
-       .enable = iic_enable,
-       .disable = iic_disable,
-       .end = iic_end,
+       .mask = iic_mask,
+       .unmask = iic_unmask,
+       .eoi = iic_eoi,
 };
 
+/* XXX All of this has to be reworked completely. We need to assign a real
+ * interrupt numbers to the external interrupts and remove all the hard coded
+ * interrupt maps (rely on the device-tree whenever possible).
+ *
+ * Basically, my scheme is to define the "pendings" bits to be the HW interrupt
+ * number (ignoring the data and flags here). That means we can sort-of split
+ * external sources based on priority, and we can use request_irq() on pretty
+ * much anything.
+ *
+ * For spider or axon, they have their own interrupt space. spider will just have
+ * local "hardward" interrupts 0...xx * node stride. The node stride is not
+ * necessary (separate interrupt chips will have separate HW number space), but
+ * will allow to be compatible with existing device-trees.
+ *
+ * All of thise little world will get a standard remapping scheme to map those HW
+ * numbers into the linux flat irq number space.
+*/
 static int iic_external_get_irq(struct cbe_iic_pending_bits pending)
 {
        int irq;
@@ -118,9 +105,10 @@ static int iic_external_get_irq(struct cbe_iic_pending_bits pending)
                 */
                if (pending.class != 2)
                        break;
-               irq = IIC_EXT_OFFSET
-                       + spider_get_irq(node)
-                       + node * IIC_NODE_STRIDE;
+               /* TODO: We might want to silently ignore cascade interrupts
+                * when no cascade handler exist yet
+                */
+               irq = IIC_EXT_CASCADE + node * IIC_NODE_STRIDE;
                break;
        case 0x01 ... 0x04:
        case 0x07 ... 0x0a:
@@ -152,6 +140,8 @@ int iic_get_irq(struct pt_regs *regs)
        iic = &__get_cpu_var(iic);
        *(unsigned long *) &pending = 
                in_be64((unsigned long __iomem *) &iic->regs->pending_destr);
+       iic->eoi_stack[++iic->eoi_ptr] = pending.prio;
+       BUG_ON(iic->eoi_ptr > 15);
 
        irq = -1;
        if (pending.flags & CBE_IIC_IRQ_VALID) {
@@ -172,7 +162,7 @@ int iic_get_irq(struct pt_regs *regs)
 
 /* hardcoded part to be compatible with older firmware */
 
-static int setup_iic_hardcoded(void)
+static int __init setup_iic_hardcoded(void)
 {
        struct device_node *np;
        int nodeid, cpu;
@@ -207,12 +197,13 @@ static int setup_iic_hardcoded(void)
                printk(KERN_INFO "IIC for CPU %d at %lx\n", cpu, regs);
                iic->regs = ioremap(regs, sizeof(struct cbe_iic_thread_regs));
                iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe);
+               iic->eoi_stack[0] = 0xff;
        }
 
        return 0;
 }
 
-static int setup_iic(void)
+static int __init setup_iic(void)
 {
        struct device_node *dn;
        unsigned long *regs;
@@ -248,11 +239,14 @@ static int setup_iic(void)
                iic = &per_cpu(iic, np[0]);
                iic->regs = ioremap(regs[0], sizeof(struct cbe_iic_thread_regs));
                iic->target_id = ((np[0] & 2) << 3) + ((np[0] & 1) ? 0xf : 0xe);
+               iic->eoi_stack[0] = 0xff;
                printk("IIC for CPU %d at %lx mapped to %p\n", np[0], regs[0], iic->regs);
 
                iic = &per_cpu(iic, np[1]);
                iic->regs = ioremap(regs[2], sizeof(struct cbe_iic_thread_regs));
                iic->target_id = ((np[1] & 2) << 3) + ((np[1] & 1) ? 0xf : 0xe);
+               iic->eoi_stack[0] = 0xff;
+
                printk("IIC for CPU %d at %lx mapped to %p\n", np[1], regs[2], iic->regs);
 
                found++;
@@ -304,10 +298,10 @@ static void iic_request_ipi(int ipi, const char *name)
        int irq;
 
        irq = iic_ipi_to_irq(ipi);
+
        /* IPIs are marked IRQF_DISABLED as they must run with irqs
         * disabled */
-       get_irq_desc(irq)->chip = &iic_pic;
-       get_irq_desc(irq)->status |= IRQ_PER_CPU;
+       set_irq_chip_and_handler(irq, &iic_chip, handle_percpu_irq);
        request_irq(irq, iic_ipi_action, IRQF_DISABLED, name, NULL);
 }
 
@@ -321,20 +315,26 @@ void iic_request_IPIs(void)
 }
 #endif /* CONFIG_SMP */
 
-static void iic_setup_spe_handlers(void)
+static void __init iic_setup_builtin_handlers(void)
 {
        int be, isrc;
 
-       /* Assume two threads per BE are present */
+       /* XXX FIXME: Assume two threads per BE are present */
        for (be=0; be < num_present_cpus() / 2; be++) {
+               int irq;
+
+               /* setup SPE chip and handlers */
                for (isrc = 0; isrc < IIC_CLASS_STRIDE * 3; isrc++) {
-                       int irq = IIC_NODE_STRIDE * be + IIC_SPE_OFFSET + isrc;
-                       get_irq_desc(irq)->chip = &iic_pic;
+                       irq = IIC_NODE_STRIDE * be + IIC_SPE_OFFSET + isrc;
+                       set_irq_chip_and_handler(irq, &iic_chip, handle_fasteoi_irq);
                }
+               /* setup cascade chip */
+               irq = IIC_EXT_CASCADE + be * IIC_NODE_STRIDE;
+               set_irq_chip_and_handler(irq, &iic_chip, handle_fasteoi_irq);
        }
 }
 
-void iic_init_IRQ(void)
+void __init iic_init_IRQ(void)
 {
        int cpu, irq_offset;
        struct iic *iic;
@@ -348,5 +348,6 @@ void iic_init_IRQ(void)
                if (iic->regs)
                        out_be64(&iic->regs->prio, 0xff);
        }
-       iic_setup_spe_handlers();
+       iic_setup_builtin_handlers();
+
 }
index 799f77d..c74515a 100644 (file)
@@ -38,6 +38,7 @@
 
 enum {
        IIC_EXT_OFFSET   = 0x00, /* Start of south bridge IRQs */
+       IIC_EXT_CASCADE  = 0x20, /* There is no interrupt 32 on spider */
        IIC_NUM_EXT      = 0x40, /* Number of south bridge IRQs */
        IIC_SPE_OFFSET   = 0x40, /* Start of SPE interrupts */
        IIC_CLASS_STRIDE = 0x10, /* SPE IRQs per class    */
@@ -51,13 +52,10 @@ extern int  iic_get_irq(struct pt_regs *regs);
 extern void iic_cause_IPI(int cpu, int mesg);
 extern void iic_request_IPIs(void);
 extern void iic_setup_cpu(void);
-extern void iic_local_enable(void);
-extern void iic_local_disable(void);
 
 extern u8 iic_get_target_id(int cpu);
 
 extern void spider_init_IRQ(void);
-extern int spider_get_irq(int node);
 
 #endif
 #endif /* ASM_CELL_PIC_H */
index 01ec394..70a4e90 100644 (file)
@@ -80,10 +80,14 @@ static void cell_progress(char *s, unsigned short hex)
        printk("*** %04x : %s\n", hex, s ? s : "");
 }
 
+static void __init cell_init_irq(void)
+{
+       iic_init_IRQ();
+       spider_init_IRQ();
+}
+
 static void __init cell_setup_arch(void)
 {
-       ppc_md.init_IRQ       = iic_init_IRQ;
-       ppc_md.get_irq        = iic_get_irq;
 #ifdef CONFIG_SPU_BASE
        spu_priv1_ops         = &spu_priv1_mmio_ops;
 #endif
@@ -109,7 +113,6 @@ static void __init cell_setup_arch(void)
        /* Find and initialize PCI host bridges */
        init_pci_config_tokens();
        find_and_init_phbs();
-       spider_init_IRQ();
        cbe_pervasive_init();
 #ifdef CONFIG_DUMMY_CONSOLE
        conswitchp = &dummy_con;
@@ -174,6 +177,9 @@ define_machine(cell) {
        .calibrate_decr         = generic_calibrate_decr,
        .check_legacy_ioport    = cell_check_legacy_ioport,
        .progress               = cell_progress,
+       .init_IRQ               = cell_init_irq,
+       .get_irq                = iic_get_irq,
+
 #ifdef CONFIG_KEXEC
        .machine_kexec          = default_machine_kexec,
        .machine_kexec_prepare  = default_machine_kexec_prepare,
index 7c3a0b6..98425ac 100644 (file)
@@ -82,17 +82,20 @@ static void __iomem *spider_get_irq_config(int irq)
        return pic + TIR_CFGA + 8 * spider_get_nr(irq);
 }
 
-static void spider_enable_irq(unsigned int irq)
+static void spider_unmask_irq(unsigned int irq)
 {
        int nodeid = (irq / IIC_NODE_STRIDE) * 0x10;
        void __iomem *cfg = spider_get_irq_config(irq);
        irq = spider_get_nr(irq);
 
+       /* FIXME: Most of that is configuration and has nothing to do with enabling/disable,
+        * besides, it's also partially bogus.
+        */
        out_be32(cfg, (in_be32(cfg) & ~0xf0)| 0x3107000eu | nodeid);
        out_be32(cfg + 4, in_be32(cfg + 4) | 0x00020000u | irq);
 }
 
-static void spider_disable_irq(unsigned int irq)
+static void spider_mask_irq(unsigned int irq)
 {
        void __iomem *cfg = spider_get_irq_config(irq);
        irq = spider_get_nr(irq);
@@ -100,39 +103,21 @@ static void spider_disable_irq(unsigned int irq)
        out_be32(cfg, in_be32(cfg) & ~0x30000000u);
 }
 
-static unsigned int spider_startup_irq(unsigned int irq)
-{
-       spider_enable_irq(irq);
-       return 0;
-}
-
-static void spider_shutdown_irq(unsigned int irq)
-{
-       spider_disable_irq(irq);
-}
-
-static void spider_end_irq(unsigned int irq)
-{
-       spider_enable_irq(irq);
-}
-
 static void spider_ack_irq(unsigned int irq)
 {
-       spider_disable_irq(irq);
-       iic_local_enable();
+       /* Should reset edge detection logic but we don't configure any edge interrupt
+        * at the moment.
+        */
 }
 
-static struct hw_interrupt_type spider_pic = {
+static struct irq_chip spider_pic = {
        .typename = " SPIDER   ",
-       .startup = spider_startup_irq,
-       .shutdown = spider_shutdown_irq,
-       .enable = spider_enable_irq,
-       .disable = spider_disable_irq,
+       .unmask = spider_unmask_irq,
+       .mask = spider_mask_irq,
        .ack = spider_ack_irq,
-       .end = spider_end_irq,
 };
 
-int spider_get_irq(int node)
+static int spider_get_irq(int node)
 {
        unsigned long cs;
        void __iomem *regs = spider_pics[node];
@@ -145,95 +130,89 @@ int spider_get_irq(int node)
                return cs;
 }
 
+static void spider_irq_cascade(unsigned int irq, struct irq_desc *desc,
+                              struct pt_regs *regs)
+{
+       int node = (int)(long)desc->handler_data;
+       int cascade_irq;
+
+       cascade_irq = spider_get_irq(node);
+       generic_handle_irq(cascade_irq, regs);
+       desc->chip->eoi(irq);
+}
+
 /* hardcoded part to be compatible with older firmware */
 
-void spider_init_IRQ_hardcoded(void)
+static void __init spider_init_one(int node, unsigned long addr)
 {
-       int node;
-       long spiderpic;
-       long pics[] = { 0x24000008000, 0x34000008000 };
-       int n;
-
-       pr_debug("%s(%d): Using hardcoded defaults\n", __FUNCTION__, __LINE__);
-
-       for (node = 0; node < num_present_cpus()/2; node++) {
-               spiderpic = pics[node];
-               printk(KERN_DEBUG "SPIDER addr: %lx\n", spiderpic);
-               spider_pics[node] = ioremap(spiderpic, 0x800);
-               for (n = 0; n < IIC_NUM_EXT; n++) {
-                       int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
-                       get_irq_desc(irq)->chip = &spider_pic;
-               }
-
-               /* do not mask any interrupts because of level */
-               out_be32(spider_pics[node] + TIR_MSK, 0x0);
-
-               /* disable edge detection clear */
-               /* out_be32(spider_pics[node] + TIR_EDC, 0x0); */
-
-               /* enable interrupt packets to be output */
-               out_be32(spider_pics[node] + TIR_PIEN,
-                       in_be32(spider_pics[node] + TIR_PIEN) | 0x1);
-
-               /* Enable the interrupt detection enable bit. Do this last! */
-               out_be32(spider_pics[node] + TIR_DEN,
-                       in_be32(spider_pics[node] + TIR_DEN) | 0x1);
+       int n, irq;
+
+       spider_pics[node] = ioremap(addr, 0x800);
+       if (spider_pics[node] == NULL)
+               panic("spider_pic: can't map registers !");
+
+       printk(KERN_INFO "spider_pic: mapped for node %d, addr: 0x%lx mapped to %p\n",
+              node, addr, spider_pics[node]);
+
+       for (n = 0; n < IIC_NUM_EXT; n++) {
+               if (n == IIC_EXT_CASCADE)
+                       continue;
+               irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
+               set_irq_chip_and_handler(irq, &spider_pic, handle_level_irq);
+               get_irq_desc(irq)->status |= IRQ_LEVEL;
        }
+
+       /* do not mask any interrupts because of level */
+       out_be32(spider_pics[node] + TIR_MSK, 0x0);
+
+       /* disable edge detection clear */
+       /* out_be32(spider_pics[node] + TIR_EDC, 0x0); */
+
+       /* enable interrupt packets to be output */
+       out_be32(spider_pics[node] + TIR_PIEN,
+                in_be32(spider_pics[node] + TIR_PIEN) | 0x1);
+
+       /* Hook up cascade */
+       irq = IIC_EXT_CASCADE + node * IIC_NODE_STRIDE;
+       set_irq_data(irq, (void *)(long)node);
+       set_irq_chained_handler(irq, spider_irq_cascade);
+
+       /* Enable the interrupt detection enable bit. Do this last! */
+       out_be32(spider_pics[node] + TIR_DEN,
+                in_be32(spider_pics[node] + TIR_DEN) | 0x1);
 }
 
-void spider_init_IRQ(void)
+void __init spider_init_IRQ(void)
 {
-       long spider_reg;
+       unsigned long *spider_reg;
        struct device_node *dn;
        char *compatible;
-       int n, node = 0;
-
+       int node = 0;
+
+       /* XXX node numbers are totally bogus. We _hope_ we get the device nodes in the right
+        * order here but that's definitely not guaranteed, we need to get the node from the
+        * device tree instead. There is currently no proper property for it (but our whole
+        * device-tree is bogus anyway) so all we can do is pray or maybe test the address
+        * and deduce the node-id
+        */
        for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) {
                compatible = (char *)get_property(dn, "compatible", NULL);
 
                if (!compatible)
                        continue;
 
-               if (strstr(compatible, "CBEA,platform-spider-pic"))
-                       spider_reg = *(long *)get_property(dn,"reg", NULL);
-               else if (strstr(compatible, "sti,platform-spider-pic")) {
-                       spider_init_IRQ_hardcoded();
-                       return;
+               if (strstr(compatible, "CBEA,platform-spider-pic"))
+                       spider_reg = (unsigned long *)get_property(dn, "reg", NULL);
+               else if (strstr(compatible, "sti,platform-spider-pic") && (node < 2)) {
+                       static long hard_coded_pics[] = { 0x24000008000, 0x34000008000 };
+                       spider_reg = &hard_coded_pics[node];
                } else
                        continue;
 
-               if (!spider_reg)
-                       printk("interrupt controller does not have reg property !\n");
-
-               n = prom_n_addr_cells(dn);
-
-               if ( n != 2)
-                       printk("reg property with invalid number of elements \n");
-
-               spider_pics[node] = ioremap(spider_reg, 0x800);
-
-               printk("SPIDER addr: %lx with %i addr_cells mapped to %p\n",
-                      spider_reg, n, spider_pics[node]);
-
-               for (n = 0; n < IIC_NUM_EXT; n++) {
-                       int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
-                       get_irq_desc(irq)->chip = &spider_pic;
-               }
-
-               /* do not mask any interrupts because of level */
-               out_be32(spider_pics[node] + TIR_MSK, 0x0);
-
-               /* disable edge detection clear */
-               /* out_be32(spider_pics[node] + TIR_EDC, 0x0); */
-
-               /* enable interrupt packets to be output */
-               out_be32(spider_pics[node] + TIR_PIEN,
-                       in_be32(spider_pics[node] + TIR_PIEN) | 0x1);
-
-               /* Enable the interrupt detection enable bit. Do this last! */
-               out_be32(spider_pics[node] + TIR_DEN,
-                       in_be32(spider_pics[node] + TIR_DEN) | 0x1);
+               if (spider_reg == NULL)
+                       printk(KERN_ERR "spider_pic: No address for node %d\n", node);
 
+               spider_init_one(node, *spider_reg);
                node++;
        }
 }
index 1f1771b..a5dffc8 100644 (file)
@@ -315,6 +315,21 @@ chrp_event_scan(unsigned long unused)
                  jiffies + event_scan_interval);
 }
 
+void chrp_8259_cascade(unsigned int irq, struct irq_desc *desc,
+                       struct pt_regs *regs)
+{
+       unsigned int max = 100;
+
+       while(max--) {
+               int irq = i8259_irq(regs);
+               if (max == 99)
+                       desc->chip->eoi(irq);
+               if (irq < 0)
+                       break;
+               generic_handle_irq(irq, regs);
+       };
+}
+
 /*
  * Finds the open-pic node and sets up the mpic driver.
  */
@@ -402,7 +417,7 @@ static void __init chrp_find_openpic(void)
        }
 
        mpic_init(chrp_mpic);
-       mpic_setup_cascade(NUM_ISA_INTERRUPTS, i8259_irq_cascade, NULL);
+       set_irq_chained_handler(NUM_ISA_INTERRUPTS, chrp_8259_cascade);
 }
 
 #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
index f70e820..7fb6a08 100644 (file)
@@ -297,13 +297,13 @@ static void iseries_end_IRQ(unsigned int irq)
                (REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq));
 }
 
-static hw_irq_controller iSeries_IRQ_handler = {
-       .typename = "iSeries irq controller",
-       .startup = iseries_startup_IRQ,
-       .shutdown = iseries_shutdown_IRQ,
-       .enable = iseries_enable_IRQ,
-       .disable = iseries_disable_IRQ,
-       .end = iseries_end_IRQ
+static struct irq_chip iseries_pic = {
+       .typename       = "iSeries irq controller",
+       .startup        = iseries_startup_IRQ,
+       .shutdown       = iseries_shutdown_IRQ,
+       .unmask         = iseries_enable_IRQ,
+       .mask           = iseries_disable_IRQ,
+       .eoi            = iseries_end_IRQ
 };
 
 /*
@@ -322,8 +322,7 @@ int __init iSeries_allocate_IRQ(HvBusNumber bus,
        realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3)
                + function;
        virtirq = virt_irq_create_mapping(realirq);
-
-       irq_desc[virtirq].chip = &iSeries_IRQ_handler;
+       set_irq_chip_and_handler(virtirq, &iseries_pic, handle_fasteoi_irq);
        return virtirq;
 }
 
index c9b09a9..58a4c7b 100644 (file)
@@ -70,18 +70,19 @@ static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE];
 
 #define NR_MASK_WORDS  ((NR_IRQS + 31) / 32)
 static unsigned long ppc_lost_interrupts[NR_MASK_WORDS];
+static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
+static int pmac_irq_cascade = -1;
 
-/*
- * Mark an irq as "lost".  This is only used on the pmac
- * since it can lose interrupts (see pmac_set_irq_mask).
- * -- Cort
- */
-void __set_lost(unsigned long irq_nr, int nokick)
+static void __pmac_retrigger(unsigned int irq_nr)
 {
-       if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) {
+       if (irq_nr >= max_real_irqs && pmac_irq_cascade > 0) {
+               __set_bit(irq_nr, ppc_lost_interrupts);
+               irq_nr = pmac_irq_cascade;
+               mb();
+       }
+       if (!__test_and_set_bit(irq_nr, ppc_lost_interrupts)) {
                atomic_inc(&ppc_n_lost_interrupts);
-               if (!nokick)
-                       set_dec(1);
+               set_dec(1);
        }
 }
 
@@ -94,10 +95,10 @@ static void pmac_mask_and_ack_irq(unsigned int irq_nr)
         if ((unsigned)irq_nr >= max_irqs)
                 return;
 
-        clear_bit(irq_nr, ppc_cached_irq_mask);
-        if (test_and_clear_bit(irq_nr, ppc_lost_interrupts))
-                atomic_dec(&ppc_n_lost_interrupts);
        spin_lock_irqsave(&pmac_pic_lock, flags);
+        __clear_bit(irq_nr, ppc_cached_irq_mask);
+        if (__test_and_clear_bit(irq_nr, ppc_lost_interrupts))
+                atomic_dec(&ppc_n_lost_interrupts);
         out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
         out_le32(&pmac_irq_hw[i]->ack, bit);
         do {
@@ -109,7 +110,7 @@ static void pmac_mask_and_ack_irq(unsigned int irq_nr)
        spin_unlock_irqrestore(&pmac_pic_lock, flags);
 }
 
-static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
+static void pmac_ack_irq(unsigned int irq_nr)
 {
         unsigned long bit = 1UL << (irq_nr & 0x1f);
         int i = irq_nr >> 5;
@@ -118,7 +119,22 @@ static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
         if ((unsigned)irq_nr >= max_irqs)
                 return;
 
-       spin_lock_irqsave(&pmac_pic_lock, flags);
+       spin_lock_irqsave(&pmac_pic_lock, flags);
+       if (__test_and_clear_bit(irq_nr, ppc_lost_interrupts))
+                atomic_dec(&ppc_n_lost_interrupts);
+        out_le32(&pmac_irq_hw[i]->ack, bit);
+        (void)in_le32(&pmac_irq_hw[i]->ack);
+       spin_unlock_irqrestore(&pmac_pic_lock, flags);
+}
+
+static void __pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
+{
+        unsigned long bit = 1UL << (irq_nr & 0x1f);
+        int i = irq_nr >> 5;
+
+        if ((unsigned)irq_nr >= max_irqs)
+                return;
+
         /* enable unmasked interrupts */
         out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
 
@@ -135,8 +151,7 @@ static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
          * the bit in the flag register or request another interrupt.
          */
         if (bit & ppc_cached_irq_mask[i] & in_le32(&pmac_irq_hw[i]->level))
-               __set_lost((ulong)irq_nr, nokicklost);
-       spin_unlock_irqrestore(&pmac_pic_lock, flags);
+               __pmac_retrigger(irq_nr);
 }
 
 /* When an irq gets requested for the first client, if it's an
@@ -144,62 +159,67 @@ static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
  */
 static unsigned int pmac_startup_irq(unsigned int irq_nr)
 {
+       unsigned long flags;
         unsigned long bit = 1UL << (irq_nr & 0x1f);
         int i = irq_nr >> 5;
 
+       spin_lock_irqsave(&pmac_pic_lock, flags);
        if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0)
                out_le32(&pmac_irq_hw[i]->ack, bit);
-        set_bit(irq_nr, ppc_cached_irq_mask);
-        pmac_set_irq_mask(irq_nr, 0);
+        __set_bit(irq_nr, ppc_cached_irq_mask);
+        __pmac_set_irq_mask(irq_nr, 0);
+       spin_unlock_irqrestore(&pmac_pic_lock, flags);
 
        return 0;
 }
 
 static void pmac_mask_irq(unsigned int irq_nr)
 {
-        clear_bit(irq_nr, ppc_cached_irq_mask);
-        pmac_set_irq_mask(irq_nr, 0);
-        mb();
+       unsigned long flags;
+
+       spin_lock_irqsave(&pmac_pic_lock, flags);
+        __clear_bit(irq_nr, ppc_cached_irq_mask);
+        __pmac_set_irq_mask(irq_nr, 0);
+       spin_unlock_irqrestore(&pmac_pic_lock, flags);
 }
 
 static void pmac_unmask_irq(unsigned int irq_nr)
 {
-        set_bit(irq_nr, ppc_cached_irq_mask);
-        pmac_set_irq_mask(irq_nr, 0);
+       unsigned long flags;
+
+       spin_lock_irqsave(&pmac_pic_lock, flags);
+       __set_bit(irq_nr, ppc_cached_irq_mask);
+        __pmac_set_irq_mask(irq_nr, 0);
+       spin_unlock_irqrestore(&pmac_pic_lock, flags);
 }
 
-static void pmac_end_irq(unsigned int irq_nr)
+static int pmac_retrigger(unsigned int irq_nr)
 {
-       if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
-           && irq_desc[irq_nr].action) {
-               set_bit(irq_nr, ppc_cached_irq_mask);
-               pmac_set_irq_mask(irq_nr, 1);
-       }
-}
+       unsigned long flags;
 
+       spin_lock_irqsave(&pmac_pic_lock, flags);
+       __pmac_retrigger(irq_nr);
+       spin_unlock_irqrestore(&pmac_pic_lock, flags);
+       return 1;
+}
 
-struct hw_interrupt_type pmac_pic = {
+static struct irq_chip pmac_pic = {
        .typename       = " PMAC-PIC ",
        .startup        = pmac_startup_irq,
-       .enable         = pmac_unmask_irq,
-       .disable        = pmac_mask_irq,
-       .ack            = pmac_mask_and_ack_irq,
-       .end            = pmac_end_irq,
-};
-
-struct hw_interrupt_type gatwick_pic = {
-       .typename       = " GATWICK  ",
-       .startup        = pmac_startup_irq,
-       .enable         = pmac_unmask_irq,
-       .disable        = pmac_mask_irq,
-       .ack            = pmac_mask_and_ack_irq,
-       .end            = pmac_end_irq,
+       .mask           = pmac_mask_irq,
+       .ack            = pmac_ack_irq,
+       .mask_ack       = pmac_mask_and_ack_irq,
+       .unmask         = pmac_unmask_irq,
+       .retrigger      = pmac_retrigger,
 };
 
 static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
 {
+       unsigned long flags;
        int irq, bits;
+       int rc = IRQ_NONE;
 
+       spin_lock_irqsave(&pmac_pic_lock, flags);
        for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) {
                int i = irq >> 5;
                bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];
@@ -209,17 +229,20 @@ static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
                if (bits == 0)
                        continue;
                irq += __ilog2(bits);
+               spin_unlock_irqrestore(&pmac_pic_lock, flags);
                __do_IRQ(irq, regs);
-               return IRQ_HANDLED;
+               spin_lock_irqsave(&pmac_pic_lock, flags);
+               rc = IRQ_HANDLED;
        }
-       printk("gatwick irq not from gatwick pic\n");
-       return IRQ_NONE;
+       spin_unlock_irqrestore(&pmac_pic_lock, flags);
+       return rc;
 }
 
 static int pmac_get_irq(struct pt_regs *regs)
 {
        int irq;
        unsigned long bits = 0;
+       unsigned long flags;
 
 #ifdef CONFIG_SMP
        void psurge_smp_message_recv(struct pt_regs *);
@@ -230,6 +253,7 @@ static int pmac_get_irq(struct pt_regs *regs)
                return -2;      /* ignore, already handled */
         }
 #endif /* CONFIG_SMP */
+       spin_lock_irqsave(&pmac_pic_lock, flags);
        for (irq = max_real_irqs; (irq -= 32) >= 0; ) {
                int i = irq >> 5;
                bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];
@@ -241,6 +265,7 @@ static int pmac_get_irq(struct pt_regs *regs)
                irq += __ilog2(bits);
                break;
        }
+       spin_unlock_irqrestore(&pmac_pic_lock, flags);
 
        return irq;
 }
@@ -389,7 +414,6 @@ static struct irqaction gatwick_cascade_action = {
 static void __init pmac_pic_probe_oldstyle(void)
 {
         int i;
-       int irq_cascade = -1;
         struct device_node *master = NULL;
        struct device_node *slave = NULL;
        u8 __iomem *addr;
@@ -443,9 +467,16 @@ static void __init pmac_pic_probe_oldstyle(void)
        }
        BUG_ON(master == NULL);
 
-       /* Set the handler for the main PIC */
-       for ( i = 0; i < max_real_irqs ; i++ )
-               irq_desc[i].chip = &pmac_pic;
+       /* Mark level interrupts and set handlers */
+       for (i = 0; i < max_irqs; i++) {
+               int level = !!(level_mask[i >> 5] & (1UL << (i & 0x1f)));
+               if (level)
+                       irq_desc[i].status |= IRQ_LEVEL;
+               else
+                       irq_desc[i].status |= IRQ_DELAYED_DISABLE;
+               set_irq_chip_and_handler(i, &pmac_pic, level ?
+                                        handle_level_irq : handle_edge_irq);
+       }
 
        /* Get addresses of first controller if we have a node for it */
        BUG_ON(of_address_to_resource(master, 0, &r));
@@ -472,29 +503,22 @@ static void __init pmac_pic_probe_oldstyle(void)
                        pmac_irq_hw[i++] =
                                (volatile struct pmac_irq_hw __iomem *)
                                (addr + 0x10);
-               irq_cascade = slave->intrs[0].line;
+               pmac_irq_cascade = slave->intrs[0].line;
 
                printk(KERN_INFO "irq: Found slave Apple PIC %s for %d irqs"
                       " cascade: %d\n", slave->full_name,
-                      max_irqs - max_real_irqs, irq_cascade);
+                      max_irqs - max_real_irqs, pmac_irq_cascade);
        }
        of_node_put(slave);
 
-       /* disable all interrupts in all controllers */
+       /* Disable all interrupts in all controllers */
        for (i = 0; i * 32 < max_irqs; ++i)
                out_le32(&pmac_irq_hw[i]->enable, 0);
 
-       /* mark level interrupts */
-       for (i = 0; i < max_irqs; i++)
-               if (level_mask[i >> 5] & (1UL << (i & 0x1f)))
-                       irq_desc[i].status = IRQ_LEVEL;
+       /* Hookup cascade irq */
+       if (slave)
+               setup_irq(pmac_irq_cascade, &gatwick_cascade_action);
 
-       /* Setup handlers for secondary controller and hook cascade irq*/
-       if (slave) {
-               for ( i = max_real_irqs ; i < max_irqs ; i++ )
-                       irq_desc[i].chip = &gatwick_pic;
-               setup_irq(irq_cascade, &gatwick_cascade_action);
-       }
        printk(KERN_INFO "irq: System has %d possible interrupts\n", max_irqs);
 #ifdef CONFIG_XMON
        setup_irq(20, &xmon_action);
@@ -502,9 +526,20 @@ static void __init pmac_pic_probe_oldstyle(void)
 }
 #endif /* CONFIG_PPC32 */
 
-static int pmac_u3_cascade(struct pt_regs *regs, void *data)
+static void pmac_u3_cascade(unsigned int irq, struct irq_desc *desc,
+                           struct pt_regs *regs)
 {
-       return mpic_get_one_irq((struct mpic *)data, regs);
+       struct mpic *mpic = desc->handler_data;
+       unsigned int max = 100;
+
+       while(max--) {
+               int cascade_irq = mpic_get_one_irq(mpic, regs);
+               if (max == 99)
+                       desc->chip->eoi(irq);
+               if (irq < 0)
+                       break;
+               generic_handle_irq(cascade_irq, regs);
+       };
 }
 
 static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic)
@@ -612,7 +647,8 @@ static int __init pmac_pic_probe_mpic(void)
                of_node_put(slave);
                return 0;
        }
-       mpic_setup_cascade(slave->intrs[0].line, pmac_u3_cascade, mpic2);
+       set_irq_data(slave->intrs[0].line, mpic2);
+       set_irq_chained_handler(slave->intrs[0].line, pmac_u3_cascade);
 
        of_node_put(slave);
        return 0;
index 999509d..476b564 100644 (file)
@@ -118,6 +118,21 @@ static void __init fwnmi_init(void)
                fwnmi_active = 1;
 }
 
+void pSeries_8259_cascade(unsigned int irq, struct irq_desc *desc,
+                         struct pt_regs *regs)
+{
+       unsigned int max = 100;
+
+       while(max--) {
+               int cascade_irq = i8259_irq(regs);
+               if (max == 99)
+                       desc->chip->eoi(irq);
+               if (cascade_irq < 0)
+                       break;
+               generic_handle_irq(cascade_irq, regs);
+       };
+}
+
 static void __init pSeries_init_mpic(void)
 {
         unsigned int *addrp;
@@ -140,7 +155,7 @@ static void __init pSeries_init_mpic(void)
        i8259_init(intack, 0);
 
        /* Hook cascade to mpic */
-       mpic_setup_cascade(NUM_ISA_INTERRUPTS, i8259_irq_cascade, NULL);
+       set_irq_chained_handler(NUM_ISA_INTERRUPTS, pSeries_8259_cascade);
 }
 
 static void __init pSeries_setup_mpic(void)
@@ -201,10 +216,8 @@ static void __init pSeries_setup_arch(void)
                /* Allocate the mpic now, so that find_and_init_phbs() can
                 * fill the ISUs */
                pSeries_setup_mpic();
-       } else {
+       } else
                ppc_md.init_IRQ       = xics_init_IRQ;
-               ppc_md.get_irq        = xics_get_irq;
-       }
 
 #ifdef CONFIG_SMP
        smp_init_pSeries();
@@ -291,10 +304,7 @@ static void pSeries_mach_cpu_die(void)
 {
        local_irq_disable();
        idle_task_exit();
-       /* Some hardware requires clearing the CPPR, while other hardware does not
-        * it is safe either way
-        */
-       pSeriesLP_cppr_info(0, 0);
+       xics_teardown_cpu(0);
        rtas_stop_self();
        /* Should never get here... */
        BUG();
index 2ffebe3..c7f0442 100644 (file)
 
 #include "xics.h"
 
-static unsigned int xics_startup(unsigned int irq);
-static void xics_enable_irq(unsigned int irq);
-static void xics_disable_irq(unsigned int irq);
-static void xics_mask_and_ack_irq(unsigned int irq);
-static void xics_end_irq(unsigned int irq);
-static void xics_set_affinity(unsigned int irq_nr, cpumask_t cpumask);
-
-static struct hw_interrupt_type xics_pic = {
-       .typename = " XICS     ",
-       .startup = xics_startup,
-       .enable = xics_enable_irq,
-       .disable = xics_disable_irq,
-       .ack = xics_mask_and_ack_irq,
-       .end = xics_end_irq,
-       .set_affinity = xics_set_affinity
-};
-
 /* This is used to map real irq numbers to virtual */
 static struct radix_tree_root irq_map = RADIX_TREE_INIT(GFP_ATOMIC);
 
@@ -98,47 +81,33 @@ static int ibm_set_xive;
 static int ibm_int_on;
 static int ibm_int_off;
 
-typedef struct {
-       int (*xirr_info_get)(int cpu);
-       void (*xirr_info_set)(int cpu, int val);
-       void (*cppr_info)(int cpu, u8 val);
-       void (*qirr_info)(int cpu, u8 val);
-} xics_ops;
 
+/* Direct HW low level accessors */
 
-/* SMP */
 
-static int pSeries_xirr_info_get(int n_cpu)
+static inline int direct_xirr_info_get(int n_cpu)
 {
        return in_be32(&xics_per_cpu[n_cpu]->xirr.word);
 }
 
-static void pSeries_xirr_info_set(int n_cpu, int value)
+static inline void direct_xirr_info_set(int n_cpu, int value)
 {
        out_be32(&xics_per_cpu[n_cpu]->xirr.word, value);
 }
 
-static void pSeries_cppr_info(int n_cpu, u8 value)
+static inline void direct_cppr_info(int n_cpu, u8 value)
 {
        out_8(&xics_per_cpu[n_cpu]->xirr.bytes[0], value);
 }
 
-static void pSeries_qirr_info(int n_cpu, u8 value)
+static inline void direct_qirr_info(int n_cpu, u8 value)
 {
        out_8(&xics_per_cpu[n_cpu]->qirr.bytes[0], value);
 }
 
-static xics_ops pSeries_ops = {
-       pSeries_xirr_info_get,
-       pSeries_xirr_info_set,
-       pSeries_cppr_info,
-       pSeries_qirr_info
-};
-
-static xics_ops *ops = &pSeries_ops;
 
+/* LPAR low level accessors */
 
-/* LPAR */
 
 static inline long plpar_eoi(unsigned long xirr)
 {
@@ -161,7 +130,7 @@ static inline long plpar_xirr(unsigned long *xirr_ret)
        return plpar_hcall(H_XIRR, 0, 0, 0, 0, xirr_ret, &dummy, &dummy);
 }
 
-static int pSeriesLP_xirr_info_get(int n_cpu)
+static inline int lpar_xirr_info_get(int n_cpu)
 {
        unsigned long lpar_rc;
        unsigned long return_value;
@@ -172,7 +141,7 @@ static int pSeriesLP_xirr_info_get(int n_cpu)
        return (int)return_value;
 }
 
-static void pSeriesLP_xirr_info_set(int n_cpu, int value)
+static inline void lpar_xirr_info_set(int n_cpu, int value)
 {
        unsigned long lpar_rc;
        unsigned long val64 = value & 0xffffffff;
@@ -183,7 +152,7 @@ static void pSeriesLP_xirr_info_set(int n_cpu, int value)
                      val64);
 }
 
-void pSeriesLP_cppr_info(int n_cpu, u8 value)
+static inline void lpar_cppr_info(int n_cpu, u8 value)
 {
        unsigned long lpar_rc;
 
@@ -192,7 +161,7 @@ void pSeriesLP_cppr_info(int n_cpu, u8 value)
                panic("bad return code cppr - rc = %lx\n", lpar_rc);
 }
 
-static void pSeriesLP_qirr_info(int n_cpu , u8 value)
+static inline void lpar_qirr_info(int n_cpu , u8 value)
 {
        unsigned long lpar_rc;
 
@@ -201,36 +170,9 @@ static void pSeriesLP_qirr_info(int n_cpu , u8 value)
                panic("bad return code qirr - rc = %lx\n", lpar_rc);
 }
 
-xics_ops pSeriesLP_ops = {
-       pSeriesLP_xirr_info_get,
-       pSeriesLP_xirr_info_set,
-       pSeriesLP_cppr_info,
-       pSeriesLP_qirr_info
-};
 
-static unsigned int xics_startup(unsigned int virq)
-{
-       unsigned int irq;
+/* High level handlers and init code */
 
-       irq = irq_offset_down(virq);
-       if (radix_tree_insert(&irq_map, virt_irq_to_real(irq),
-                             &virt_irq_to_real_map[irq]) == -ENOMEM)
-               printk(KERN_CRIT "Out of memory creating real -> virtual"
-                      " IRQ mapping for irq %u (real 0x%x)\n",
-                      virq, virt_irq_to_real(irq));
-       xics_enable_irq(virq);
-       return 0;       /* return value is ignored */
-}
-
-static unsigned int real_irq_to_virt(unsigned int real_irq)
-{
-       unsigned int *ptr;
-
-       ptr = radix_tree_lookup(&irq_map, real_irq);
-       if (ptr == NULL)
-               return NO_IRQ;
-       return ptr - virt_irq_to_real_map;
-}
 
 #ifdef CONFIG_SMP
 static int get_irq_server(unsigned int irq)
@@ -264,17 +206,20 @@ static int get_irq_server(unsigned int irq)
 }
 #endif
 
-static void xics_enable_irq(unsigned int virq)
+
+static void xics_unmask_irq(unsigned int virq)
 {
        unsigned int irq;
        int call_status;
        unsigned int server;
 
        irq = virt_irq_to_real(irq_offset_down(virq));
-       if (irq == XICS_IPI)
+       WARN_ON(irq == NO_IRQ);
+       if (irq == XICS_IPI || irq == NO_IRQ)
                return;
 
        server = get_irq_server(virq);
+
        call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server,
                                DEFAULT_PRIORITY);
        if (call_status != 0) {
@@ -293,7 +238,7 @@ static void xics_enable_irq(unsigned int virq)
        }
 }
 
-static void xics_disable_real_irq(unsigned int irq)
+static void xics_mask_real_irq(unsigned int irq)
 {
        int call_status;
        unsigned int server;
@@ -318,75 +263,104 @@ static void xics_disable_real_irq(unsigned int irq)
        }
 }
 
-static void xics_disable_irq(unsigned int virq)
+static void xics_mask_irq(unsigned int virq)
 {
        unsigned int irq;
 
        irq = virt_irq_to_real(irq_offset_down(virq));
-       xics_disable_real_irq(irq);
+       WARN_ON(irq == NO_IRQ);
+       if (irq != NO_IRQ)
+               xics_mask_real_irq(irq);
+}
+
+static void xics_set_irq_revmap(unsigned int virq)
+{
+       unsigned int irq;
+
+       irq = irq_offset_down(virq);
+       if (radix_tree_insert(&irq_map, virt_irq_to_real(irq),
+                             &virt_irq_to_real_map[irq]) == -ENOMEM)
+               printk(KERN_CRIT "Out of memory creating real -> virtual"
+                      " IRQ mapping for irq %u (real 0x%x)\n",
+                      virq, virt_irq_to_real(irq));
 }
 
-static void xics_end_irq(unsigned int irq)
+static unsigned int xics_startup(unsigned int virq)
+{
+       xics_set_irq_revmap(virq);
+       xics_unmask_irq(virq);
+       return 0;
+}
+
+static unsigned int real_irq_to_virt(unsigned int real_irq)
+{
+       unsigned int *ptr;
+
+       ptr = radix_tree_lookup(&irq_map, real_irq);
+       if (ptr == NULL)
+               return NO_IRQ;
+       return ptr - virt_irq_to_real_map;
+}
+
+static void xics_eoi_direct(unsigned int irq)
 {
        int cpu = smp_processor_id();
 
        iosync();
-       ops->xirr_info_set(cpu, ((0xff << 24) |
-                                (virt_irq_to_real(irq_offset_down(irq)))));
-
+       direct_xirr_info_set(cpu, ((0xff << 24) |
+                                  (virt_irq_to_real(irq_offset_down(irq)))));
 }
 
-static void xics_mask_and_ack_irq(unsigned int irq)
+
+static void xics_eoi_lpar(unsigned int irq)
 {
        int cpu = smp_processor_id();
 
-       if (irq < irq_offset_value()) {
-               i8259_pic.ack(irq);
-               iosync();
-               ops->xirr_info_set(cpu, ((0xff<<24) |
-                                        xics_irq_8259_cascade_real));
-               iosync();
-       }
+       iosync();
+       lpar_xirr_info_set(cpu, ((0xff << 24) |
+                                (virt_irq_to_real(irq_offset_down(irq)))));
+
 }
 
-int xics_get_irq(struct pt_regs *regs)
+static inline int xics_remap_irq(int vec)
 {
-       unsigned int cpu = smp_processor_id();
-       unsigned int vec;
        int irq;
 
-       vec = ops->xirr_info_get(cpu);
-       /*  (vec >> 24) == old priority */
        vec &= 0x00ffffff;
 
-       /* for sanity, this had better be < NR_IRQS - 16 */
-       if (vec == xics_irq_8259_cascade_real) {
-               irq = i8259_irq(regs);
-               xics_end_irq(irq_offset_up(xics_irq_8259_cascade));
-       } else if (vec == XICS_IRQ_SPURIOUS) {
-               irq = -1;
-       } else {
-               irq = real_irq_to_virt(vec);
-               if (irq == NO_IRQ)
-                       irq = real_irq_to_virt_slowpath(vec);
-               if (irq == NO_IRQ) {
-                       printk(KERN_ERR "Interrupt %u (real) is invalid,"
-                              " disabling it.\n", vec);
-                       xics_disable_real_irq(vec);
-               } else
-                       irq = irq_offset_up(irq);
-       }
-       return irq;
+       if (vec == XICS_IRQ_SPURIOUS)
+               return NO_IRQ;
+
+       irq = real_irq_to_virt(vec);
+       if (irq == NO_IRQ)
+               irq = real_irq_to_virt_slowpath(vec);
+       if (likely(irq != NO_IRQ))
+               return irq_offset_up(irq);
+
+       printk(KERN_ERR "Interrupt %u (real) is invalid,"
+              " disabling it.\n", vec);
+       xics_mask_real_irq(vec);
+       return NO_IRQ;
 }
 
-#ifdef CONFIG_SMP
+static int xics_get_irq_direct(struct pt_regs *regs)
+{
+       unsigned int cpu = smp_processor_id();
 
-static irqreturn_t xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
+       return xics_remap_irq(direct_xirr_info_get(cpu));
+}
+
+static int xics_get_irq_lpar(struct pt_regs *regs)
 {
-       int cpu = smp_processor_id();
+       unsigned int cpu = smp_processor_id();
 
-       ops->qirr_info(cpu, 0xff);
+       return xics_remap_irq(lpar_xirr_info_get(cpu));
+}
+
+#ifdef CONFIG_SMP
 
+static irqreturn_t xics_ipi_dispatch(int cpu, struct pt_regs *regs)
+{
        WARN_ON(cpu_is_offline(cpu));
 
        while (xics_ipi_message[cpu].value) {
@@ -418,18 +392,108 @@ static irqreturn_t xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
+static irqreturn_t xics_ipi_action_direct(int irq, void *dev_id, struct pt_regs *regs)
+{
+       int cpu = smp_processor_id();
+
+       direct_qirr_info(cpu, 0xff);
+
+       return xics_ipi_dispatch(cpu, regs);
+}
+
+static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id, struct pt_regs *regs)
+{
+       int cpu = smp_processor_id();
+
+       lpar_qirr_info(cpu, 0xff);
+
+       return xics_ipi_dispatch(cpu, regs);
+}
+
 void xics_cause_IPI(int cpu)
 {
-       ops->qirr_info(cpu, IPI_PRIORITY);
+       if (firmware_has_feature(FW_FEATURE_LPAR))
+               lpar_qirr_info(cpu, IPI_PRIORITY);
+       else
+               direct_qirr_info(cpu, IPI_PRIORITY);
 }
+
 #endif /* CONFIG_SMP */
 
+static void xics_set_cpu_priority(int cpu, unsigned char cppr)
+{
+       if (firmware_has_feature(FW_FEATURE_LPAR))
+               lpar_cppr_info(cpu, cppr);
+       else
+               direct_cppr_info(cpu, cppr);
+       iosync();
+}
+
+static void xics_set_affinity(unsigned int virq, cpumask_t cpumask)
+{
+       unsigned int irq;
+       int status;
+       int xics_status[2];
+       unsigned long newmask;
+       cpumask_t tmp = CPU_MASK_NONE;
+
+       irq = virt_irq_to_real(irq_offset_down(virq));
+       if (irq == XICS_IPI || irq == NO_IRQ)
+               return;
+
+       status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq);
+
+       if (status) {
+               printk(KERN_ERR "xics_set_affinity: irq=%u ibm,get-xive "
+                      "returns %d\n", irq, status);
+               return;
+       }
+
+       /* For the moment only implement delivery to all cpus or one cpu */
+       if (cpus_equal(cpumask, CPU_MASK_ALL)) {
+               newmask = default_distrib_server;
+       } else {
+               cpus_and(tmp, cpu_online_map, cpumask);
+               if (cpus_empty(tmp))
+                       return;
+               newmask = get_hard_smp_processor_id(first_cpu(tmp));
+       }
+
+       status = rtas_call(ibm_set_xive, 3, 1, NULL,
+                               irq, newmask, xics_status[1]);
+
+       if (status) {
+               printk(KERN_ERR "xics_set_affinity: irq=%u ibm,set-xive "
+                      "returns %d\n", irq, status);
+               return;
+       }
+}
+
+static struct irq_chip xics_pic_direct = {
+       .typename = " XICS     ",
+       .startup = xics_startup,
+       .mask = xics_mask_irq,
+       .unmask = xics_unmask_irq,
+       .eoi = xics_eoi_direct,
+       .set_affinity = xics_set_affinity
+};
+
+
+static struct irq_chip xics_pic_lpar = {
+       .typename = " XICS     ",
+       .startup = xics_startup,
+       .mask = xics_mask_irq,
+       .unmask = xics_unmask_irq,
+       .eoi = xics_eoi_lpar,
+       .set_affinity = xics_set_affinity
+};
+
+
 void xics_setup_cpu(void)
 {
        int cpu = smp_processor_id();
 
-       ops->cppr_info(cpu, 0xff);
-       iosync();
+       xics_set_cpu_priority(cpu, 0xff);
 
        /*
         * Put the calling processor into the GIQ.  This is really only
@@ -453,6 +517,7 @@ void xics_init_IRQ(void)
                unsigned long addr;
                unsigned long size;
        } intnodes[NR_CPUS];
+       struct irq_chip *chip;
 
        ppc64_boot_msg(0x20, "XICS Init");
 
@@ -519,26 +584,10 @@ nextnode:
        intr_base = intnodes[0].addr;
        intr_size = intnodes[0].size;
 
-       np = of_find_node_by_type(NULL, "interrupt-controller");
-       if (!np) {
-               printk(KERN_DEBUG "xics: no ISA interrupt controller\n");
-               xics_irq_8259_cascade_real = -1;
-               xics_irq_8259_cascade = -1;
-       } else {
-               ireg = (uint *) get_property(np, "interrupts", NULL);
-               if (!ireg)
-                       panic("xics_init_IRQ: can't find ISA interrupts property");
-
-               xics_irq_8259_cascade_real = *ireg;
-               xics_irq_8259_cascade
-                       = virt_irq_create_mapping(xics_irq_8259_cascade_real);
-               i8259_init(0, 0);
-               of_node_put(np);
-       }
-
-       if (firmware_has_feature(FW_FEATURE_LPAR))
-               ops = &pSeriesLP_ops;
-       else {
+       if (firmware_has_feature(FW_FEATURE_LPAR)) {
+               ppc_md.get_irq = xics_get_irq_lpar;
+               chip = &xics_pic_lpar;
+       } else {
 #ifdef CONFIG_SMP
                for_each_possible_cpu(i) {
                        int hard_id;
@@ -554,32 +603,54 @@ nextnode:
 #else
                xics_per_cpu[0] = ioremap(intr_base, intr_size);
 #endif /* CONFIG_SMP */
+               ppc_md.get_irq = xics_get_irq_direct;
+               chip = &xics_pic_direct;
+
        }
 
-       for (i = irq_offset_value(); i < NR_IRQS; ++i)
-               get_irq_desc(i)->chip = &xics_pic;
+       for (i = irq_offset_value(); i < NR_IRQS; ++i) {
+               /* All IRQs on XICS are level for now. MSI code may want to modify
+                * that for reporting purposes
+                */
+               get_irq_desc(i)->status |= IRQ_LEVEL;
+               set_irq_chip_and_handler(i, chip, handle_fasteoi_irq);
+       }
 
        xics_setup_cpu();
 
        ppc64_boot_msg(0x21, "XICS Done");
 }
 
-/*
- * We cant do this in init_IRQ because we need the memory subsystem up for
- * request_irq()
- */
-static int __init xics_setup_i8259(void)
-{
-       if (ppc64_interrupt_controller == IC_PPC_XIC &&
-           xics_irq_8259_cascade != -1) {
-               if (request_irq(irq_offset_up(xics_irq_8259_cascade),
-                               no_action, 0, "8259 cascade", NULL))
-                       printk(KERN_ERR "xics_setup_i8259: couldn't get 8259 "
-                                       "cascade\n");
+static int xics_setup_8259_cascade(void)
+{
+       struct device_node *np;
+       uint *ireg;
+
+       np = of_find_node_by_type(NULL, "interrupt-controller");
+       if (np == NULL) {
+               printk(KERN_WARNING "xics: no ISA interrupt controller\n");
+               xics_irq_8259_cascade_real = -1;
+               xics_irq_8259_cascade = -1;
+               return 0;
        }
+
+       ireg = (uint *) get_property(np, "interrupts", NULL);
+       if (!ireg)
+               panic("xics_init_IRQ: can't find ISA interrupts property");
+
+       xics_irq_8259_cascade_real = *ireg;
+       xics_irq_8259_cascade = irq_offset_up
+               (virt_irq_create_mapping(xics_irq_8259_cascade_real));
+       i8259_init(0, 0);
+       of_node_put(np);
+
+       xics_set_irq_revmap(xics_irq_8259_cascade);
+       set_irq_chained_handler(xics_irq_8259_cascade, pSeries_8259_cascade);
+
        return 0;
 }
-arch_initcall(xics_setup_i8259);
+arch_initcall(xics_setup_8259_cascade);
+
 
 #ifdef CONFIG_SMP
 void xics_request_IPIs(void)
@@ -590,61 +661,22 @@ void xics_request_IPIs(void)
         * IPIs are marked IRQF_DISABLED as they must run with irqs
         * disabled
         */
-       request_irq(irq_offset_up(XICS_IPI), xics_ipi_action,
-                   IRQF_DISABLED, "IPI", NULL);
-       get_irq_desc(irq_offset_up(XICS_IPI))->status |= IRQ_PER_CPU;
-}
-#endif
-
-static void xics_set_affinity(unsigned int virq, cpumask_t cpumask)
-{
-       unsigned int irq;
-       int status;
-       int xics_status[2];
-       unsigned long newmask;
-       cpumask_t tmp = CPU_MASK_NONE;
-
-       irq = virt_irq_to_real(irq_offset_down(virq));
-       if (irq == XICS_IPI || irq == NO_IRQ)
-               return;
-
-       status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq);
-
-       if (status) {
-               printk(KERN_ERR "xics_set_affinity: irq=%u ibm,get-xive "
-                      "returns %d\n", irq, status);
-               return;
-       }
-
-       /* For the moment only implement delivery to all cpus or one cpu */
-       if (cpus_equal(cpumask, CPU_MASK_ALL)) {
-               newmask = default_distrib_server;
-       } else {
-               cpus_and(tmp, cpu_online_map, cpumask);
-               if (cpus_empty(tmp))
-                       return;
-               newmask = get_hard_smp_processor_id(first_cpu(tmp));
-       }
-
-       status = rtas_call(ibm_set_xive, 3, 1, NULL,
-                               irq, newmask, xics_status[1]);
-
-       if (status) {
-               printk(KERN_ERR "xics_set_affinity: irq=%u ibm,set-xive "
-                      "returns %d\n", irq, status);
-               return;
-       }
+       set_irq_handler(irq_offset_up(XICS_IPI), handle_percpu_irq);
+       if (firmware_has_feature(FW_FEATURE_LPAR))
+               request_irq(irq_offset_up(XICS_IPI), xics_ipi_action_lpar,
+                           SA_INTERRUPT, "IPI", NULL);
+       else
+               request_irq(irq_offset_up(XICS_IPI), xics_ipi_action_direct,
+                           SA_INTERRUPT, "IPI", NULL);
 }
+#endif /* CONFIG_SMP */
 
 void xics_teardown_cpu(int secondary)
 {
+       struct irq_desc *desc = get_irq_desc(irq_offset_up(XICS_IPI));
        int cpu = smp_processor_id();
 
-       ops->cppr_info(cpu, 0x00);
-       iosync();
-
-       /* Clear IPI */
-       ops->qirr_info(cpu, 0xff);
+       xics_set_cpu_priority(cpu, 0);
 
        /*
         * we need to EOI the IPI if we got here from kexec down IPI
@@ -653,7 +685,8 @@ void xics_teardown_cpu(int secondary)
         * should we be flagging idle loop instead?
         * or creating some task to be scheduled?
         */
-       ops->xirr_info_set(cpu, XICS_IPI);
+       if (desc->chip && desc->chip->eoi)
+               desc->chip->eoi(XICS_IPI);
 
        /*
         * Some machines need to have at least one cpu in the GIQ,
@@ -674,8 +707,7 @@ void xics_migrate_irqs_away(void)
        unsigned int irq, virq, cpu = smp_processor_id();
 
        /* Reject any interrupt that was queued to us... */
-       ops->cppr_info(cpu, 0);
-       iosync();
+       xics_set_cpu_priority(cpu, 0);
 
        /* remove ourselves from the global interrupt queue */
        status = rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE,
@@ -683,11 +715,10 @@ void xics_migrate_irqs_away(void)
        WARN_ON(status < 0);
 
        /* Allow IPIs again... */
-       ops->cppr_info(cpu, DEFAULT_PRIORITY);
-       iosync();
+       xics_set_cpu_priority(cpu, DEFAULT_PRIORITY);
 
        for_each_irq(virq) {
-               irq_desc_t *desc;
+               struct irq_desc *desc;
                int xics_status[2];
                unsigned long flags;
 
index e14c708..67dedf3 100644 (file)
 
 #include <linux/cache.h>
 
-void xics_init_IRQ(void);
-int xics_get_irq(struct pt_regs *);
-void xics_setup_cpu(void);
-void xics_teardown_cpu(int secondary);
-void xics_cause_IPI(int cpu);
-void xics_request_IPIs(void);
-void xics_migrate_irqs_away(void);
+extern void xics_init_IRQ(void);
+extern void xics_setup_cpu(void);
+extern void xics_teardown_cpu(int secondary);
+extern void xics_cause_IPI(int cpu);
+extern  void xics_request_IPIs(void);
+extern void xics_migrate_irqs_away(void);
 
 /* first argument is ignored for now*/
 void pSeriesLP_cppr_info(int n_cpu, u8 value);
@@ -31,4 +30,8 @@ struct xics_ipi_struct {
 
 extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
 
+struct irq_desc;
+extern void pSeries_8259_cascade(unsigned int irq, struct irq_desc *desc,
+                                struct pt_regs *regs);
+
 #endif /* _POWERPC_KERNEL_XICS_H */
index 1a3ef1a..c2e9465 100644 (file)
@@ -69,11 +69,6 @@ int i8259_irq(struct pt_regs *regs)
        return irq + i8259_pic_irq_offset;
 }
 
-int i8259_irq_cascade(struct pt_regs *regs, void *unused)
-{
-       return i8259_irq(regs);
-}
-
 static void i8259_mask_and_ack_irq(unsigned int irq_nr)
 {
        unsigned long flags;
@@ -129,19 +124,11 @@ static void i8259_unmask_irq(unsigned int irq_nr)
        spin_unlock_irqrestore(&i8259_lock, flags);
 }
 
-static void i8259_end_irq(unsigned int irq)
-{
-       if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))
-           && irq_desc[irq].action)
-               i8259_unmask_irq(irq);
-}
-
-struct hw_interrupt_type i8259_pic = {
-       .typename = " i8259    ",
-       .enable = i8259_unmask_irq,
-       .disable = i8259_mask_irq,
-       .ack = i8259_mask_and_ack_irq,
-       .end = i8259_end_irq,
+static struct irq_chip i8259_pic = {
+       .typename       = " i8259    ",
+       .mask           = i8259_mask_irq,
+       .unmask         = i8259_unmask_irq,
+       .mask_ack       = i8259_mask_and_ack_irq,
 };
 
 static struct resource pic1_iores = {
@@ -207,8 +194,11 @@ void __init i8259_init(unsigned long intack_addr, int offset)
 
        spin_unlock_irqrestore(&i8259_lock, flags);
 
-       for (i = 0; i < NUM_ISA_INTERRUPTS; ++i)
-               irq_desc[offset + i].chip = &i8259_pic;
+       for (i = 0; i < NUM_ISA_INTERRUPTS; ++i) {
+               set_irq_chip_and_handler(offset + i, &i8259_pic,
+                                        handle_level_irq);
+               irq_desc[offset + i].status |= IRQ_LEVEL;
+       }
 
        /* reserve our resources */
        setup_irq(offset + 2, &i8259_irqaction);
index 7e46935..9a95f16 100644 (file)
@@ -100,8 +100,8 @@ static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg)
 
        if (mpic->flags & MPIC_PRIMARY)
                cpu = hard_smp_processor_id();
-
-       return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, mpic->cpuregs[cpu], reg);
+       return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN,
+                         mpic->cpuregs[cpu], reg);
 }
 
 static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value)
@@ -378,14 +378,14 @@ static inline u32 mpic_physmask(u32 cpumask)
 /* Get the mpic structure from the IPI number */
 static inline struct mpic * mpic_from_ipi(unsigned int ipi)
 {
-       return container_of(irq_desc[ipi].chip, struct mpic, hc_ipi);
+       return irq_desc[ipi].chip_data;
 }
 #endif
 
 /* Get the mpic structure from the irq number */
 static inline struct mpic * mpic_from_irq(unsigned int irq)
 {
-       return container_of(irq_desc[irq].chip, struct mpic, hc_irq);
+       return irq_desc[irq].chip_data;
 }
 
 /* Send an EOI */
@@ -410,7 +410,7 @@ static irqreturn_t mpic_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
  */
 
 
-static void mpic_enable_irq(unsigned int irq)
+static void mpic_unmask_irq(unsigned int irq)
 {
        unsigned int loops = 100000;
        struct mpic *mpic = mpic_from_irq(irq);
@@ -429,35 +429,9 @@ static void mpic_enable_irq(unsigned int irq)
                        break;
                }
        } while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK);    
-
-#ifdef CONFIG_MPIC_BROKEN_U3
-       if (mpic->flags & MPIC_BROKEN_U3) {
-               unsigned int src = irq - mpic->irq_offset;
-               if (mpic_is_ht_interrupt(mpic, src) &&
-                   (irq_desc[irq].status & IRQ_LEVEL))
-                       mpic_ht_end_irq(mpic, src);
-       }
-#endif /* CONFIG_MPIC_BROKEN_U3 */
-}
-
-static unsigned int mpic_startup_irq(unsigned int irq)
-{
-#ifdef CONFIG_MPIC_BROKEN_U3
-       struct mpic *mpic = mpic_from_irq(irq);
-       unsigned int src = irq - mpic->irq_offset;
-#endif /* CONFIG_MPIC_BROKEN_U3 */
-
-       mpic_enable_irq(irq);
-
-#ifdef CONFIG_MPIC_BROKEN_U3
-       if (mpic_is_ht_interrupt(mpic, src))
-               mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status);
-#endif /* CONFIG_MPIC_BROKEN_U3 */
-
-       return 0;
 }
 
-static void mpic_disable_irq(unsigned int irq)
+static void mpic_mask_irq(unsigned int irq)
 {
        unsigned int loops = 100000;
        struct mpic *mpic = mpic_from_irq(irq);
@@ -478,23 +452,58 @@ static void mpic_disable_irq(unsigned int irq)
        } while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK));
 }
 
-static void mpic_shutdown_irq(unsigned int irq)
+static void mpic_end_irq(unsigned int irq)
 {
+       struct mpic *mpic = mpic_from_irq(irq);
+
+#ifdef DEBUG_IRQ
+       DBG("%s: end_irq: %d\n", mpic->name, irq);
+#endif
+       /* We always EOI on end_irq() even for edge interrupts since that
+        * should only lower the priority, the MPIC should have properly
+        * latched another edge interrupt coming in anyway
+        */
+
+       mpic_eoi(mpic);
+}
+
 #ifdef CONFIG_MPIC_BROKEN_U3
+
+static void mpic_unmask_ht_irq(unsigned int irq)
+{
        struct mpic *mpic = mpic_from_irq(irq);
        unsigned int src = irq - mpic->irq_offset;
 
-       if (mpic_is_ht_interrupt(mpic, src))
-               mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status);
+       mpic_unmask_irq(irq);
 
-#endif /* CONFIG_MPIC_BROKEN_U3 */
+       if (irq_desc[irq].status & IRQ_LEVEL)
+               mpic_ht_end_irq(mpic, src);
+}
+
+static unsigned int mpic_startup_ht_irq(unsigned int irq)
+{
+       struct mpic *mpic = mpic_from_irq(irq);
+       unsigned int src = irq - mpic->irq_offset;
 
-       mpic_disable_irq(irq);
+       mpic_unmask_irq(irq);
+       mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status);
+
+       return 0;
 }
 
-static void mpic_end_irq(unsigned int irq)
+static void mpic_shutdown_ht_irq(unsigned int irq)
+{
+       struct mpic *mpic = mpic_from_irq(irq);
+       unsigned int src = irq - mpic->irq_offset;
+
+       mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status);
+       mpic_mask_irq(irq);
+}
+
+static void mpic_end_ht_irq(unsigned int irq)
 {
        struct mpic *mpic = mpic_from_irq(irq);
+       unsigned int src = irq - mpic->irq_offset;
 
 #ifdef DEBUG_IRQ
        DBG("%s: end_irq: %d\n", mpic->name, irq);
@@ -504,21 +513,16 @@ static void mpic_end_irq(unsigned int irq)
         * latched another edge interrupt coming in anyway
         */
 
-#ifdef CONFIG_MPIC_BROKEN_U3
-       if (mpic->flags & MPIC_BROKEN_U3) {
-               unsigned int src = irq - mpic->irq_offset;
-               if (mpic_is_ht_interrupt(mpic, src) &&
-                   (irq_desc[irq].status & IRQ_LEVEL))
-                       mpic_ht_end_irq(mpic, src);
-       }
-#endif /* CONFIG_MPIC_BROKEN_U3 */
-
+       if (irq_desc[irq].status & IRQ_LEVEL)
+               mpic_ht_end_irq(mpic, src);
        mpic_eoi(mpic);
 }
 
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+
 #ifdef CONFIG_SMP
 
-static void mpic_enable_ipi(unsigned int irq)
+static void mpic_unmask_ipi(unsigned int irq)
 {
        struct mpic *mpic = mpic_from_ipi(irq);
        unsigned int src = irq - mpic->ipi_offset;
@@ -527,7 +531,7 @@ static void mpic_enable_ipi(unsigned int irq)
        mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK);
 }
 
-static void mpic_disable_ipi(unsigned int irq)
+static void mpic_mask_ipi(unsigned int irq)
 {
        /* NEVER disable an IPI... that's just plain wrong! */
 }
@@ -560,6 +564,30 @@ static void mpic_set_affinity(unsigned int irq, cpumask_t cpumask)
                       mpic_physmask(cpus_addr(tmp)[0]));       
 }
 
+static struct irq_chip mpic_irq_chip = {
+       .mask   = mpic_mask_irq,
+       .unmask = mpic_unmask_irq,
+       .eoi    = mpic_end_irq,
+};
+
+#ifdef CONFIG_SMP
+static struct irq_chip mpic_ipi_chip = {
+       .mask   = mpic_mask_ipi,
+       .unmask = mpic_unmask_ipi,
+       .eoi    = mpic_end_ipi,
+};
+#endif /* CONFIG_SMP */
+
+#ifdef CONFIG_MPIC_BROKEN_U3
+static struct irq_chip mpic_irq_ht_chip = {
+       .startup        = mpic_startup_ht_irq,
+       .shutdown       = mpic_shutdown_ht_irq,
+       .mask           = mpic_mask_irq,
+       .unmask         = mpic_unmask_ht_irq,
+       .eoi            = mpic_end_ht_irq,
+};
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+
 
 /*
  * Exported functions
@@ -589,19 +617,19 @@ struct mpic * __init mpic_alloc(unsigned long phys_addr,
        memset(mpic, 0, sizeof(struct mpic));
        mpic->name = name;
 
+       mpic->hc_irq = mpic_irq_chip;
        mpic->hc_irq.typename = name;
-       mpic->hc_irq.startup = mpic_startup_irq;
-       mpic->hc_irq.shutdown = mpic_shutdown_irq;
-       mpic->hc_irq.enable = mpic_enable_irq;
-       mpic->hc_irq.disable = mpic_disable_irq;
-       mpic->hc_irq.end = mpic_end_irq;
        if (flags & MPIC_PRIMARY)
                mpic->hc_irq.set_affinity = mpic_set_affinity;
+#ifdef CONFIG_MPIC_BROKEN_U3
+       mpic->hc_ht_irq = mpic_irq_ht_chip;
+       mpic->hc_ht_irq.typename = name;
+       if (flags & MPIC_PRIMARY)
+               mpic->hc_ht_irq.set_affinity = mpic_set_affinity;
+#endif /* CONFIG_MPIC_BROKEN_U3 */
 #ifdef CONFIG_SMP
        mpic->hc_ipi.typename = name;
-       mpic->hc_ipi.enable = mpic_enable_ipi;
-       mpic->hc_ipi.disable = mpic_disable_ipi;
-       mpic->hc_ipi.end = mpic_end_ipi;
+       mpic->hc_ipi = mpic_ipi_chip;
 #endif /* CONFIG_SMP */
 
        mpic->flags = flags;
@@ -697,28 +725,6 @@ void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num,
                mpic->num_sources = isu_first + mpic->isu_size;
 }
 
-void __init mpic_setup_cascade(unsigned int irq, mpic_cascade_t handler,
-                              void *data)
-{
-       struct mpic *mpic = mpic_find(irq, NULL);
-       unsigned long flags;
-
-       /* Synchronization here is a bit dodgy, so don't try to replace cascade
-        * interrupts on the fly too often ... but normally it's set up at boot.
-        */
-       spin_lock_irqsave(&mpic_lock, flags);
-       if (mpic->cascade)             
-               mpic_disable_irq(mpic->cascade_vec + mpic->irq_offset);
-       mpic->cascade = NULL;
-       wmb();
-       mpic->cascade_vec = irq - mpic->irq_offset;
-       mpic->cascade_data = data;
-       wmb();
-       mpic->cascade = handler;
-       mpic_enable_irq(irq);
-       spin_unlock_irqrestore(&mpic_lock, flags);
-}
-
 void __init mpic_init(struct mpic *mpic)
 {
        int i;
@@ -750,8 +756,10 @@ void __init mpic_init(struct mpic *mpic)
 #ifdef CONFIG_SMP
                if (!(mpic->flags & MPIC_PRIMARY))
                        continue;
-               irq_desc[mpic->ipi_offset+i].status |= IRQ_PER_CPU;
-               irq_desc[mpic->ipi_offset+i].chip = &mpic->hc_ipi;
+               set_irq_chip_data(mpic->ipi_offset+i, mpic);
+               set_irq_chip_and_handler(mpic->ipi_offset+i,
+                                        &mpic->hc_ipi,
+                                        handle_percpu_irq);
 #endif /* CONFIG_SMP */
        }
 
@@ -763,7 +771,7 @@ void __init mpic_init(struct mpic *mpic)
        /* Do the HT PIC fixups on U3 broken mpic */
        DBG("MPIC flags: %x\n", mpic->flags);
        if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY))
-               mpic_scan_ht_pics(mpic);
+               mpic_scan_ht_pics(mpic);
 #endif /* CONFIG_MPIC_BROKEN_U3 */
 
        for (i = 0; i < mpic->num_sources; i++) {
@@ -811,8 +819,17 @@ void __init mpic_init(struct mpic *mpic)
 
                /* init linux descriptors */
                if (i < mpic->irq_count) {
-                       irq_desc[mpic->irq_offset+i].status = level ? IRQ_LEVEL : 0;
-                       irq_desc[mpic->irq_offset+i].chip = &mpic->hc_irq;
+                       struct irq_chip *chip = &mpic->hc_irq;
+
+                       irq_desc[mpic->irq_offset+i].status |=
+                               level ? IRQ_LEVEL : 0;
+#ifdef CONFIG_MPIC_BROKEN_U3
+                       if (mpic_is_ht_interrupt(mpic, i))
+                               chip = &mpic->hc_ht_irq;
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+                       set_irq_chip_data(mpic->irq_offset+i, mpic);
+                       set_irq_chip_and_handler(mpic->irq_offset+i, chip,
+                                                handle_fasteoi_irq);
                }
        }
        
@@ -986,14 +1003,6 @@ int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs)
 #ifdef DEBUG_LOW
        DBG("%s: get_one_irq(): %d\n", mpic->name, irq);
 #endif
-       if (mpic->cascade && irq == mpic->cascade_vec) {
-#ifdef DEBUG_LOW
-               DBG("%s: cascading ...\n", mpic->name);
-#endif
-               irq = mpic->cascade(regs, mpic->cascade_data);
-               mpic_eoi(mpic);
-               return irq;
-       }
        if (unlikely(irq == MPIC_VEC_SPURRIOUS))
                return -1;
        if (irq < MPIC_VEC_IPI_0) {
index 0392159..ff31cb9 100644 (file)
@@ -4,11 +4,8 @@
 
 #include <linux/irq.h>
 
-extern struct hw_interrupt_type i8259_pic;
-
 extern void i8259_init(unsigned long intack_addr, int offset);
 extern int i8259_irq(struct pt_regs *regs);
-extern int i8259_irq_cascade(struct pt_regs *regs, void *unused);
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_I8259_H */
index eb5f33e..13fa2ef 100644 (file)
@@ -514,9 +514,12 @@ extern u64 ppc64_interrupt_controller;
 
 #endif
 
+#ifndef CONFIG_PPC_MERGE
 #define NR_MASK_WORDS  ((NR_IRQS + 31) / 32)
 /* pedantic: these are long because they are used with set_bit --RR */
 extern unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
+#endif
+
 extern atomic_t ppc_n_lost_interrupts;
 
 #define virt_irq_create_mapping(x)     (x)
@@ -579,9 +582,8 @@ extern struct thread_info *softirq_ctx[NR_CPUS];
 
 extern void irq_ctx_init(void);
 extern void call_do_softirq(struct thread_info *tp);
-extern int call___do_IRQ(int irq, struct pt_regs *regs,
-               struct thread_info *tp);
-
+extern int call_handle_irq(int irq, void *p1, void *p2,
+                          struct thread_info *tp, void *func);
 #else
 #define irq_ctx_init()
 
index f0d22ac..a2277cb 100644 (file)
 #define MPIC_VEC_TIMER_1       248
 #define MPIC_VEC_TIMER_0       247
 
-/* Type definition of the cascade handler */
-typedef int (*mpic_cascade_t)(struct pt_regs *regs, void *data);
-
 #ifdef CONFIG_MPIC_BROKEN_U3
 /* Fixup table entry */
 struct mpic_irq_fixup
@@ -133,9 +130,12 @@ struct mpic_irq_fixup
 struct mpic
 {
        /* The "linux" controller struct */
-       hw_irq_controller       hc_irq;
+       struct irq_chip         hc_irq;
+#ifdef CONFIG_MPIC_BROKEN_U3
+       struct irq_chip         hc_ht_irq;
+#endif
 #ifdef CONFIG_SMP
-       hw_irq_controller       hc_ipi;
+       struct irq_chip         hc_ipi;
 #endif
        const char              *name;
        /* Flags */
@@ -153,10 +153,6 @@ struct mpic
        unsigned int            num_sources;
        /* Number of CPUs */
        unsigned int            num_cpus;
-       /* cascade handler */
-       mpic_cascade_t          cascade;
-       void                    *cascade_data;
-       unsigned int            cascade_vec;
        /* senses array */
        unsigned char           *senses;
        unsigned int            senses_count;
@@ -237,17 +233,6 @@ extern void mpic_assign_isu(struct mpic *mpic, unsigned int isu_num,
  */
 extern void mpic_init(struct mpic *mpic);
 
-/* Setup a cascade. Currently, only one cascade is supported this
- * way, though you can always do a normal request_irq() and add
- * other cascades this way. You should call this _after_ having
- * added all the ISUs
- *
- * @irq_no:    "linux" irq number of the cascade (that is offset'ed vector)
- * @handler:   cascade handler function
- */
-extern void mpic_setup_cascade(unsigned int irq_no, mpic_cascade_t hanlder,
-                              void *data);
-
 /*
  * All of the following functions must only be used after the
  * ISUs have been assigned and the controller fully initialized