X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fmips%2Fmips-boards%2Fatlas%2Fatlas_int.c;h=db53950b7cfbae7bd9e8936ede6fd6f6f5c64882;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=8f1d875217a21241f5c5fd0c84441c2e783aeb43;hpb=6a77f38946aaee1cd85eeec6cf4229b204c15071;p=linux-2.6.git diff --git a/arch/mips/mips-boards/atlas/atlas_int.c b/arch/mips/mips-boards/atlas/atlas_int.c index 8f1d87521..db53950b7 100644 --- a/arch/mips/mips-boards/atlas/atlas_int.c +++ b/arch/mips/mips-boards/atlas/atlas_int.c @@ -39,8 +39,6 @@ static struct atlas_ictrl_regs *atlas_hw0_icregs; -extern asmlinkage void mipsIRQ(void); - #if 0 #define DEBUG_INT(x...) printk(x) #else @@ -76,14 +74,13 @@ static void end_atlas_irq(unsigned int irq) } static struct hw_interrupt_type atlas_irq_type = { - "Atlas", - startup_atlas_irq, - shutdown_atlas_irq, - enable_atlas_irq, - disable_atlas_irq, - mask_and_ack_atlas_irq, - end_atlas_irq, - NULL + .typename = "Atlas", + .startup = startup_atlas_irq, + .shutdown = shutdown_atlas_irq, + .enable = enable_atlas_irq, + .disable = disable_atlas_irq, + .ack = mask_and_ack_atlas_irq, + .end = end_atlas_irq, }; static inline int ls1bit32(unsigned int x) @@ -99,7 +96,7 @@ static inline int ls1bit32(unsigned int x) return b; } -void atlas_hw0_irqdispatch(struct pt_regs *regs) +static inline void atlas_hw0_irqdispatch(struct pt_regs *regs) { unsigned long int_status; int irq; @@ -117,21 +114,103 @@ void atlas_hw0_irqdispatch(struct pt_regs *regs) do_IRQ(irq, 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 = s0 & 0xf000; + t0 = t0 < 1; + t0 = t0 << 2; + a0 = a0 - t0; + s0 = s0 << t0; + + t0 = s0 & 0xc000; + t0 = t0 < 1; + t0 = t0 << 1; + a0 = a0 - t0; + s0 = s0 << t0; + + t0 = s0 & 0x8000; + t0 = t0 < 1; + //t0 = t0 << 2; + a0 = a0 - t0; + //s0 = s0 << t0; + + return a0; +#endif +} + +/* + * IRQs on the Atlas 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(struct pt_regs *regs) +{ + unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; + int irq; + + irq = irq_ffs(pending); + + if (irq == MIPSCPU_INT_ATLAS) + atlas_hw0_irqdispatch(regs); + else if (irq > 0) + do_IRQ(MIPSCPU_INT_BASE + irq, regs); + else + spurious_interrupt(regs); +} + void __init arch_init_irq(void) { int i; atlas_hw0_icregs = (struct atlas_ictrl_regs *)ioremap (ATLAS_ICTRL_REGS_BASE, sizeof(struct atlas_ictrl_regs *)); - + /* * Mask out all interrupt by writing "1" to all bit position in * the interrupt reset reg. */ atlas_hw0_icregs->intrsten = 0xffffffff; - /* Now safe to set the exception vector. */ - set_except_vector(0, mipsIRQ); - for (i = ATLASINT_BASE; i <= ATLASINT_END; i++) { irq_desc[i].status = IRQ_DISABLED; irq_desc[i].action = 0;