diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2006-04-03 17:56:36 +0100 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2006-04-19 04:14:21 +0200 |
commit | e4ac58afdfac792c0583af30dbd9eae53e24c78b (patch) | |
tree | 7517bef2c515fc630e4d3d238867b91cde96f558 /arch/mips/mips-boards/atlas/atlas_int.c | |
parent | d35d473c25d43d7db3e5e18b66d558d2a631cca8 (diff) |
[MIPS] Rewrite all the assembler interrupt handlers to C.
Saves like 1,600 lines of code, is way easier to debug, compilers
frequently do a better job than the cut and paste type of handlers many
boards had. And finally having all the stuff done in a single place
also means alot of bug potencial for the MT ASE is gone.
The only surviving handler in assembler is the DECstation one; I hope
Maciej will rewrite it.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/mips-boards/atlas/atlas_int.c')
-rw-r--r-- | arch/mips/mips-boards/atlas/atlas_int.c | 92 |
1 files changed, 86 insertions, 6 deletions
diff --git a/arch/mips/mips-boards/atlas/atlas_int.c b/arch/mips/mips-boards/atlas/atlas_int.c index bc0ebc69bfb3..db53950b7cfb 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 @@ -98,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; @@ -116,6 +114,91 @@ 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; @@ -128,9 +211,6 @@ void __init arch_init_irq(void) */ 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; |