ar7: speed up irq handlers, fix asm/ar7/ar7.h
[openwrt/svn-archive/archive.git] / target / linux / ar7-2.6 / files / arch / mips / ar7 / irq.c
index 3d235dc45abcf2b6423beac1915dc1f6e6e45135..3019952273755ff1fcc3411d54084eff36256b90 100644 (file)
 #define PACE_OFFSET   0xA0
 #define CHNLS_OFFSET  0x200
 
-#define IRQ_NUM(irq) (irq % 40 % 32)
-#define REG_OFFSET(irq, reg) (((irq) < 40) ?                 \
-                             ((irq) / 32 * 0x4 + reg * 0x10) : \
-                             (EXCEPT_OFFSET + reg * 0x8)) 
-#define SR_OFFSET(irq)  (REG_OFFSET(irq, 0))
+#define REG_OFFSET(irq, reg) ((irq) / 32 * 0x4 + reg * 0x10)
+#define SEC_REG_OFFSET(reg) (EXCEPT_OFFSET + reg * 0x8)
+#define SR_OFFSET  (SEC_REG_OFFSET(0))
 #define CR_OFFSET(irq)  (REG_OFFSET(irq, 1))
+#define SEC_CR_OFFSET  (SEC_REG_OFFSET(1))
 #define ESR_OFFSET(irq) (REG_OFFSET(irq, 2))
+#define SEC_ESR_OFFSET  (SEC_REG_OFFSET(2))
 #define ECR_OFFSET(irq) (REG_OFFSET(irq, 3))
+#define SEC_ECR_OFFSET  (SEC_REG_OFFSET(3))
 #define PIR_OFFSET      (0x40)
 #define MSR_OFFSET      (0x44)
 #define PM_OFFSET(irq)  (REG_OFFSET(irq, 5))
 
 static void ar7_unmask_irq(unsigned int irq_nr);
 static void ar7_mask_irq(unsigned int irq_nr);
+static void ar7_unmask_secondary_irq(unsigned int irq_nr);
+static void ar7_mask_secondary_irq(unsigned int irq_nr);
 static irqreturn_t ar7_cascade(int interrupt, void *dev);
-void ar7_irq_init(int);
+static irqreturn_t ar7_secondary_cascade(int interrupt, void *dev);
+static void ar7_irq_init(int base);
+static int ar7_irq_base;
 
 static struct irq_chip ar7_irq_type = {
        .name = "AR7",
@@ -59,20 +64,28 @@ static struct irq_chip ar7_irq_type = {
        .mask = ar7_mask_irq,
 };
 
-static int ar7_irq_base;
+static struct irq_chip ar7_secondary_irq_type = {
+       .name = "AR7",
+       .unmask = ar7_unmask_secondary_irq,
+       .mask = ar7_mask_secondary_irq,
+};
 
 static struct irqaction ar7_cascade_action = {
        .handler = ar7_cascade, 
        .name = "AR7 cascade interrupt"
 };
 
+static struct irqaction ar7_secondary_cascade_action = {
+       .handler = ar7_secondary_cascade, 
+       .name = "AR7 secondary cascade interrupt"
+};
 
 static void ar7_unmask_irq(unsigned int irq)
 {
        unsigned long flags;
        local_irq_save(flags);
        /* enable the interrupt channel  bit */
-       REG(ESR_OFFSET(irq - ar7_irq_base)) = 1 << IRQ_NUM(irq - ar7_irq_base);
+       REG(ESR_OFFSET(irq)) = 1 << ((irq - ar7_irq_base) % 32);
        local_irq_restore(flags);
 }
 
@@ -81,7 +94,25 @@ static void ar7_mask_irq(unsigned int irq)
        unsigned long flags;
        local_irq_save(flags);
        /* disable the interrupt channel bit */
-       REG(ECR_OFFSET(irq - ar7_irq_base)) = 1 << IRQ_NUM(irq - ar7_irq_base);
+       REG(ECR_OFFSET(irq)) = 1 << ((irq - ar7_irq_base) % 32);
+       local_irq_restore(flags);
+}
+
+static void ar7_unmask_secondary_irq(unsigned int irq)
+{
+       unsigned long flags;
+       local_irq_save(flags);
+       /* enable the interrupt channel  bit */
+       REG(SEC_ESR_OFFSET) = 1 << (irq - ar7_irq_base - 40);
+       local_irq_restore(flags);
+}
+
+static void ar7_mask_secondary_irq(unsigned int irq)
+{
+       unsigned long flags;
+       local_irq_save(flags);
+       /* disable the interrupt channel bit */
+       REG(SEC_ECR_OFFSET) = 1 << (irq - ar7_irq_base - 40);
        local_irq_restore(flags);
 }
 
@@ -90,7 +121,7 @@ void __init arch_init_irq(void) {
        ar7_irq_init(8);
 }
 
-void __init ar7_irq_init(int base)
+static void __init ar7_irq_init(int base)
 {
        int i;
        /*  
@@ -98,54 +129,67 @@ void __init ar7_irq_init(int base)
        */
        REG(ECR_OFFSET(0)) = 0xffffffff;
        REG(ECR_OFFSET(32)) = 0xff;
-       REG(ECR_OFFSET(40)) = 0xffffffff;
+       REG(SEC_ECR_OFFSET) = 0xffffffff;
        REG(CR_OFFSET(0)) = 0xffffffff;
        REG(CR_OFFSET(32)) = 0xff;
-       REG(CR_OFFSET(40)) = 0xffffffff;
+       REG(SEC_CR_OFFSET) = 0xffffffff;
+
+       ar7_irq_base = base;
 
        for(i = 0; i < 40; i++) {
                REG(CHNL_OFFSET(i)) = i;
                /* Primary IRQ's */
                irq_desc[i + base].status = IRQ_DISABLED;
-               irq_desc[i + base].action = 0;
+               irq_desc[i + base].action = NULL;
                irq_desc[i + base].depth = 1;
                irq_desc[i + base].chip = &ar7_irq_type;
                /* Secondary IRQ's */
                if (i < 32) {
                        irq_desc[i + base + 40].status = IRQ_DISABLED;
-                       irq_desc[i + base + 40].action = 0;
+                       irq_desc[i + base + 40].action = NULL;
                        irq_desc[i + base + 40].depth = 1;
-                       irq_desc[i + base + 40].chip =
-                               &ar7_irq_type;
+                       irq_desc[i + base + 40].chip = &ar7_secondary_irq_type;
                }
        }
 
-       ar7_irq_base = base;
        setup_irq(2, &ar7_cascade_action);
+       setup_irq(ar7_irq_base, &ar7_secondary_cascade_action);
        set_c0_status(IE_IRQ0);
 }
 
 static irqreturn_t ar7_cascade(int interrupt, void *dev)
 {
-       int irq, i;
-       unsigned long status;
+       int irq;
 
        irq = (REG(PIR_OFFSET) & 0x3F);
-       if (irq == 40) return IRQ_NONE;
-       if (irq > 0) {
-               REG(CR_OFFSET(irq)) = 1 << IRQ_NUM(irq);
-       } else {
-               status = REG(SR_OFFSET(40));
-               for (i = 0; i < 32; i++) {
-                       if (status & (i << 1)) {
-                               irq = i + 40;
-                               REG(CR_OFFSET(irq)) = 1 << i;
-                               break;
-                       }
-               }
-               REG(CR_OFFSET(0)) = 1;
+       REG(CR_OFFSET(irq)) = 1 << (irq % 32);
+
+       do_IRQ(irq + ar7_irq_base);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t ar7_secondary_cascade(int interrupt, void *dev)
+{
+       int irq = 0, i;
+       unsigned long status;
+
+       status = REG(SR_OFFSET);
+       if (unlikely(!status)) {
+               spurious_interrupt();
+               return IRQ_NONE;
        }
-       return do_IRQ(irq + ar7_irq_base);
+
+       for (i = 0; i < 32; i++)
+               if (status & (i << 1)) {
+                       irq = i + 40;
+                       REG(SEC_CR_OFFSET) = 1 << i;
+                       break;
+               }
+
+       do_IRQ(irq + ar7_irq_base);
+
+       return IRQ_HANDLED;
 }
 
 asmlinkage void plat_irq_dispatch(void)