[MIPS] Use ARRAY_SIZE macro when appropriate
[sfrench/cifs-2.6.git] / arch / mips / mips-boards / malta / malta_int.c
index d06dc5ad6c9e55edd2284540ea01e729f2678d55..3c206bb171602ff3ce331586ee63a11fc7319825 100644 (file)
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
+#include <linux/kernel.h>
 #include <linux/random.h>
 
 #include <asm/i8259.h>
 #include <asm/irq_cpu.h>
 #include <asm/io.h>
+#include <asm/irq_regs.h>
 #include <asm/mips-boards/malta.h>
 #include <asm/mips-boards/maltaint.h>
 #include <asm/mips-boards/piix4.h>
@@ -40,7 +42,6 @@
 #include <asm/mips-boards/msc01_pci.h>
 #include <asm/msc01_ic.h>
 
-extern asmlinkage void mipsIRQ(void);
 extern void mips_timer_interrupt(void);
 
 static DEFINE_SPINLOCK(mips_irq_lock);
@@ -58,6 +59,7 @@ static inline int mips_pcibios_iack(void)
        case MIPS_REVISION_CORID_CORE_MSC:
        case MIPS_REVISION_CORID_CORE_FPGA2:
        case MIPS_REVISION_CORID_CORE_FPGA3:
+       case MIPS_REVISION_CORID_CORE_24K:
        case MIPS_REVISION_CORID_CORE_EMUL_MSC:
                MSC_READ(MSC01_PCI_IACK, irq);
                irq &= 0xff;
@@ -114,25 +116,30 @@ static inline int get_int(void)
        return irq;
 }
 
-void malta_hw0_irqdispatch(struct pt_regs *regs)
+static void malta_hw0_irqdispatch(void)
 {
        int irq;
 
        irq = get_int();
-       if (irq < 0)
+       if (irq < 0) {
                return;  /* interrupt has already been cleared */
+       }
 
-       do_IRQ(MALTA_INT_BASE+irq, regs);
+       do_IRQ(MALTA_INT_BASE + irq);
 }
 
-void corehi_irqdispatch(struct pt_regs *regs)
+static void corehi_irqdispatch(void)
 {
+       unsigned int intedge, intsteer, pcicmd, pcibadaddr;
+        unsigned int pcimstat, intisr, inten, intpol;
        unsigned int intrcause,datalo,datahi;
-        unsigned int pcimstat, intisr, inten, intpol, intedge, intsteer, pcicmd, pcibadaddr;
+       struct pt_regs *regs = get_irq_regs();
 
         printk("CoreHI interrupt, shouldn't happen, so we die here!!!\n");
-        printk("epc   : %08lx\nStatus: %08lx\nCause : %08lx\nbadVaddr : %08lx\n"
-, regs->cp0_epc, regs->cp0_status, regs->cp0_cause, regs->cp0_badvaddr);
+        printk("epc   : %08lx\nStatus: %08lx\n"
+              "Cause : %08lx\nbadVaddr : %08lx\n",
+              regs->cp0_epc, regs->cp0_status,
+              regs->cp0_cause, regs->cp0_badvaddr);
 
        /* Read all the registers and then print them as there is a
           problem with interspersed printk's upsetting the Bonito controller.
@@ -143,8 +150,9 @@ void corehi_irqdispatch(struct pt_regs *regs)
         case MIPS_REVISION_CORID_CORE_MSC:
         case MIPS_REVISION_CORID_CORE_FPGA2:
         case MIPS_REVISION_CORID_CORE_FPGA3:
+        case MIPS_REVISION_CORID_CORE_24K:
         case MIPS_REVISION_CORID_CORE_EMUL_MSC:
-                ll_msc_irq(regs);
+                ll_msc_irq();
                 break;
         case MIPS_REVISION_CORID_QED_RM5261:
         case MIPS_REVISION_CORID_CORE_LV:
@@ -182,6 +190,92 @@ void corehi_irqdispatch(struct pt_regs *regs)
         die("CoreHi interrupt", regs);
 }
 
+static inline int clz(unsigned long x)
+{
+       __asm__ (
+       "       .set    push                                    \n"
+       "       .set    mips32                                  \n"
+       "       clz     %0, %1                                  \n"
+       "       .set    pop                                     \n"
+       : "=r" (x)
+       : "r" (x));
+
+       return x;
+}
+
+/*
+ * Version of ffs that only looks at bits 12..15.
+ */
+static inline unsigned int irq_ffs(unsigned int pending)
+{
+#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
+       return -clz(pending) + 31 - CAUSEB_IP;
+#else
+       unsigned int a0 = 7;
+       unsigned int t0;
+
+       t0 = pending & 0xf000;
+       t0 = t0 < 1;
+       t0 = t0 << 2;
+       a0 = a0 - t0;
+       pending = pending << t0;
+
+       t0 = pending & 0xc000;
+       t0 = t0 < 1;
+       t0 = t0 << 1;
+       a0 = a0 - t0;
+       pending = pending << t0;
+
+       t0 = pending & 0x8000;
+       t0 = t0 < 1;
+       //t0 = t0 << 2;
+       a0 = a0 - t0;
+       //pending = pending << t0;
+
+       return a0;
+#endif
+}
+
+/*
+ * IRQs on the Malta board look basically (barring software IRQs which we
+ * don't use at all and all external interrupt sources are combined together
+ * on hardware interrupt 0 (MIPS IRQ 2)) like:
+ *
+ *     MIPS IRQ        Source
+ *      --------        ------
+ *             0       Software (ignored)
+ *             1        Software (ignored)
+ *             2        Combined hardware interrupt (hw0)
+ *             3        Hardware (ignored)
+ *             4        Hardware (ignored)
+ *             5        Hardware (ignored)
+ *             6        Hardware (ignored)
+ *             7        R4k timer (what we use)
+ *
+ * We handle the IRQ according to _our_ priority which is:
+ *
+ * Highest ----     R4k Timer
+ * Lowest  ----     Combined hardware interrupt
+ *
+ * then we just return, if multiple IRQs are pending then we will just take
+ * another exception, big deal.
+ */
+
+asmlinkage void plat_irq_dispatch(void)
+{
+       unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
+       int irq;
+
+       irq = irq_ffs(pending);
+
+       if (irq == MIPSCPU_INT_I8259A)
+               malta_hw0_irqdispatch();
+       else if (irq > 0)
+               do_IRQ(MIPSCPU_INT_BASE + irq);
+       else
+               spurious_interrupt();
+}
+
 static struct irqaction i8259irq = {
        .handler = no_action,
        .name = "XT-PIC cascade"
@@ -196,7 +290,7 @@ msc_irqmap_t __initdata msc_irqmap[] = {
        {MSC01C_INT_TMR,                MSC01_IRQ_EDGE, 0},
        {MSC01C_INT_PCI,                MSC01_IRQ_LEVEL, 0},
 };
-int __initdata msc_nr_irqs = sizeof(msc_irqmap)/sizeof(msc_irqmap_t);
+int __initdata msc_nr_irqs = ARRAY_SIZE(msc_irqmap);
 
 msc_irqmap_t __initdata msc_eicirqmap[] = {
        {MSC01E_INT_SW0,                MSC01_IRQ_LEVEL, 0},
@@ -210,20 +304,20 @@ msc_irqmap_t __initdata msc_eicirqmap[] = {
        {MSC01E_INT_PERFCTR,            MSC01_IRQ_LEVEL, 0},
        {MSC01E_INT_CPUCTR,             MSC01_IRQ_LEVEL, 0}
 };
-int __initdata msc_nr_eicirqs = sizeof(msc_eicirqmap)/sizeof(msc_irqmap_t);
+int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap);
 
 void __init arch_init_irq(void)
 {
-       set_except_vector(0, mipsIRQ);
        init_i8259_irqs();
 
        if (!cpu_has_veic)
-               mips_cpu_irq_init (MIPSCPU_INT_BASE);
+               mips_cpu_irq_init();
 
         switch(mips_revision_corid) {
         case MIPS_REVISION_CORID_CORE_MSC:
         case MIPS_REVISION_CORID_CORE_FPGA2:
         case MIPS_REVISION_CORID_CORE_FPGA3:
+        case MIPS_REVISION_CORID_CORE_24K:
         case MIPS_REVISION_CORID_CORE_EMUL_MSC:
                if (cpu_has_veic)
                        init_msc_irqs (MSC01E_INT_BASE, msc_eicirqmap, msc_nr_eicirqs);
@@ -240,12 +334,17 @@ void __init arch_init_irq(void)
        else if (cpu_has_vint) {
                set_vi_handler (MIPSCPU_INT_I8259A, malta_hw0_irqdispatch);
                set_vi_handler (MIPSCPU_INT_COREHI, corehi_irqdispatch);
-
+#ifdef CONFIG_MIPS_MT_SMTC
+               setup_irq_smtc (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq,
+                       (0x100 << MIPSCPU_INT_I8259A));
+               setup_irq_smtc (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI,
+                       &corehi_irqaction, (0x100 << MIPSCPU_INT_COREHI));
+#else /* Not SMTC */
                setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq);
                setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction);
+#endif /* CONFIG_MIPS_MT_SMTC */
        }
        else {
-               set_except_vector(0, mipsIRQ);
                setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq);
                setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction);
        }