This lets me get rid of plat_irq_dispatch, so I can later build a kernel with both the Au1000- and Au1300-style interrupt controllers selected at runtime. And another stupid global function is gone as well. Boots and runs on all my Alchemy boards. Signed-off-by: Manuel Lauss <manuel.lauss@xxxxxxxxxxxxxx> --- arch/mips/alchemy/common/irq.c | 55 ++++++++++++++-------------------------- arch/mips/kernel/genex.S | 12 ++++++++ 2 files changed, 31 insertions(+), 36 deletions(-) diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c index 8b60ba0..8cf7cc7 100644 --- a/arch/mips/alchemy/common/irq.c +++ b/arch/mips/alchemy/common/irq.c @@ -470,41 +470,6 @@ static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type) return ret; } -asmlinkage void plat_irq_dispatch(void) -{ - unsigned int pending = read_c0_status() & read_c0_cause(); - unsigned long s, off; - - if (pending & CAUSEF_IP7) { - off = MIPS_CPU_IRQ_BASE + 7; - goto handle; - } else if (pending & CAUSEF_IP2) { - s = KSEG1ADDR(AU1000_IC0_PHYS_ADDR) + IC_REQ0INT; - off = AU1000_INTC0_INT_BASE; - } else if (pending & CAUSEF_IP3) { - s = KSEG1ADDR(AU1000_IC0_PHYS_ADDR) + IC_REQ1INT; - off = AU1000_INTC0_INT_BASE; - } else if (pending & CAUSEF_IP4) { - s = KSEG1ADDR(AU1000_IC1_PHYS_ADDR) + IC_REQ0INT; - off = AU1000_INTC1_INT_BASE; - } else if (pending & CAUSEF_IP5) { - s = KSEG1ADDR(AU1000_IC1_PHYS_ADDR) + IC_REQ1INT; - off = AU1000_INTC1_INT_BASE; - } else - goto spurious; - - s = __raw_readl((void __iomem *)s); - if (unlikely(!s)) { -spurious: - spurious_interrupt(); - return; - } - off += __ffs(s); -handle: - do_IRQ(off); -} - - static inline void ic_init(void __iomem *base) { /* initialize interrupt controller to a safe state */ @@ -521,6 +486,21 @@ static inline void ic_init(void __iomem *base) wmb(); } +#define DISP(name, base, addr) \ +static void au1000_##name##_dispatch(unsigned int irq, struct irq_desc *d) \ +{ \ + unsigned long r = __raw_readl((void __iomem *)KSEG1ADDR(addr)); \ + if (likely(r)) \ + generic_handle_irq(base + __ffs(r)); \ + else \ + spurious_interrupt(); \ +} + +DISP(ic0r0, AU1000_INTC0_INT_BASE, AU1000_IC0_PHYS_ADDR + IC_REQ0INT) +DISP(ic0r1, AU1000_INTC0_INT_BASE, AU1000_IC0_PHYS_ADDR + IC_REQ1INT) +DISP(ic1r0, AU1000_INTC1_INT_BASE, AU1000_IC1_PHYS_ADDR + IC_REQ0INT) +DISP(ic1r1, AU1000_INTC1_INT_BASE, AU1000_IC1_PHYS_ADDR + IC_REQ1INT) + static void __init au1000_init_irq(struct au1xxx_irqmap *map) { unsigned int bit, irq_nr; @@ -561,7 +541,10 @@ static void __init au1000_init_irq(struct au1xxx_irqmap *map) ++map; } - set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3); + irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 2, au1000_ic0r0_dispatch); + irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 3, au1000_ic0r1_dispatch); + irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 4, au1000_ic1r0_dispatch); + irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 5, au1000_ic1r1_dispatch); } void __init arch_init_irq(void) diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S index 8882e57..306feaa 100644 --- a/arch/mips/kernel/genex.S +++ b/arch/mips/kernel/genex.S @@ -202,7 +202,19 @@ NESTED(handle_int, PT_SIZE, sp) LONG_L s0, TI_REGS($28) LONG_S sp, TI_REGS($28) PTR_LA ra, ret_from_irq +#ifdef CONFIG_MIPS_ALCHEMY + mfc0 t0, CP0_STATUS + mfc0 v1, CP0_CAUSE + and t0, v1, t0 + sra t0, t0, 8 + andi t0, t0, 0xff + li a0, 31 + clz t0, t0 + subu a0, a0, t0 + j do_IRQ +#else j plat_irq_dispatch +#endif END(handle_int) __INIT -- 1.7.6