Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee13...
[pandora-kernel.git] / arch / mips / cobalt / irq.c
index 6d2a815..1117fab 100644 (file)
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
 
 #include <asm/i8259.h>
 #include <asm/irq_cpu.h>
 #include <asm/gt64120.h>
 #include <asm/ptrace.h>
 
-#include <asm/cobalt/cobalt.h>
-
-extern void cobalt_handle_int(void);
+#include <asm/mach-cobalt/cobalt.h>
 
 /*
  * We have two types of interrupts that we handle, ones that come in through
  * the CPU interrupt lines, and ones that come in on the via chip. The CPU
  * mappings are:
  *
- *    16,  - Software interrupt 0 (unused)     IE_SW0
- *    17   - Software interrupt 1 (unused)     IE_SW0
+ *    16   - Software interrupt 0 (unused)     IE_SW0
+ *    17   - Software interrupt 1 (unused)     IE_SW1
  *    18   - Galileo chip (timer)              IE_IRQ0
  *    19   - Tulip 0 + NCR SCSI                        IE_IRQ1
  *    20   - Tulip 1                           IE_IRQ2
@@ -42,61 +42,79 @@ extern void cobalt_handle_int(void);
  *    15  - IDE1
  */
 
-asmlinkage void cobalt_irq(struct pt_regs *regs)
+static inline void galileo_irq(void)
 {
-       unsigned int pending = read_c0_status() & read_c0_cause();
-
-       if (pending & CAUSEF_IP2) {                     /* int 18 */
-               unsigned long irq_src = GALILEO_INL(GT_INTRCAUSE_OFS);
-
-               /* Check for timer irq ... */
-               if (irq_src & GALILEO_T0EXP) {
-                       /* Clear the int line */
-                       GALILEO_OUTL(0, GT_INTRCAUSE_OFS);
-                       do_IRQ(COBALT_TIMER_IRQ, regs);
-               }
-               return;
-       }
+       unsigned int mask, pending, devfn;
 
-       if (pending & CAUSEF_IP6) {                     /* int 22 */
-               int irq = i8259_irq();
+       mask = GALILEO_INL(GT_INTRMASK_OFS);
+       pending = GALILEO_INL(GT_INTRCAUSE_OFS) & mask;
 
-               if (irq >= 0)
-                       do_IRQ(irq, regs);
-               return;
-       }
+       if (pending & GALILEO_INTR_T0EXP) {
 
-       if (pending & CAUSEF_IP3) {                     /* int 19 */
-               do_IRQ(COBALT_ETH0_IRQ, regs);
-               return;
-       }
+               GALILEO_OUTL(~GALILEO_INTR_T0EXP, GT_INTRCAUSE_OFS);
+               do_IRQ(COBALT_GALILEO_IRQ);
 
-       if (pending & CAUSEF_IP4) {                     /* int 20 */
-               do_IRQ(COBALT_ETH1_IRQ, regs);
-               return;
-       }
+       } else if (pending & GALILEO_INTR_RETRY_CTR) {
 
-       if (pending & CAUSEF_IP5) {                     /* int 21 */
-               do_IRQ(COBALT_SERIAL_IRQ, regs);
-               return;
-       }
+               devfn = GALILEO_INL(GT_PCI0_CFGADDR_OFS) >> 8;
+               GALILEO_OUTL(~GALILEO_INTR_RETRY_CTR, GT_INTRCAUSE_OFS);
+               printk(KERN_WARNING "Galileo: PCI retry count exceeded (%02x.%u)\n",
+                       PCI_SLOT(devfn), PCI_FUNC(devfn));
+
+       } else {
 
-       if (pending & CAUSEF_IP7) {                     /* int 23 */
-               do_IRQ(COBALT_QUBE_SLOT_IRQ, regs);
-               return;
+               GALILEO_OUTL(mask & ~pending, GT_INTRMASK_OFS);
+               printk(KERN_WARNING "Galileo: masking unexpected interrupt %08x\n", pending);
        }
 }
 
+static inline void via_pic_irq(void)
+{
+       int irq;
+
+       irq = i8259_irq();
+       if (irq >= 0)
+               do_IRQ(irq);
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+       unsigned pending = read_c0_status() & read_c0_cause();
+
+       if (pending & CAUSEF_IP2)               /* COBALT_GALILEO_IRQ (18) */
+               galileo_irq();
+       else if (pending & CAUSEF_IP6)          /* COBALT_VIA_IRQ (22) */
+               via_pic_irq();
+       else if (pending & CAUSEF_IP3)          /* COBALT_ETH0_IRQ (19) */
+               do_IRQ(COBALT_CPU_IRQ + 3);
+       else if (pending & CAUSEF_IP4)          /* COBALT_ETH1_IRQ (20) */
+               do_IRQ(COBALT_CPU_IRQ + 4);
+       else if (pending & CAUSEF_IP5)          /* COBALT_SERIAL_IRQ (21) */
+               do_IRQ(COBALT_CPU_IRQ + 5);
+       else if (pending & CAUSEF_IP7)          /* IRQ 23 */
+               do_IRQ(COBALT_CPU_IRQ + 7);
+}
+
+static struct irqaction irq_via = {
+       no_action, 0, { { 0, } }, "cascade", NULL, NULL
+};
+
 void __init arch_init_irq(void)
 {
-       set_except_vector(0, cobalt_handle_int);
+       /*
+        * Mask all Galileo interrupts. The Galileo
+        * handler is set in cobalt_timer_setup()
+        */
+       GALILEO_OUTL(0, GT_INTRMASK_OFS);
 
        init_i8259_irqs();                              /*  0 ... 15 */
-       mips_cpu_irq_init(16);                          /* 16 ... 23 */
+       mips_cpu_irq_init(COBALT_CPU_IRQ);              /* 16 ... 23 */
 
        /*
         * Mask all cpu interrupts
         *  (except IE4, we already masked those at VIA level)
         */
        change_c0_status(ST0_IM, IE_IRQ4);
+
+       setup_irq(COBALT_VIA_IRQ, &irq_via);
 }