1/* 2 * arch/mips/ddb5074/int-handler.S -- NEC DDB Vrc-5074 interrupt handler 3 * 4 * Based on arch/mips/sgi/kernel/indyIRQ.S 5 * 6 * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) 7 * 8 * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> 9 * Sony Software Development Center Europe (SDCE), Brussels 10 */ 11#include <asm/asm.h> 12#include <asm/mipsregs.h> 13#include <asm/regdef.h> 14#include <asm/stackframe.h> 15 16/* A lot of complication here is taken away because: 17 * 18 * 1) We handle one interrupt and return, sitting in a loop and moving across 19 * all the pending IRQ bits in the cause register is _NOT_ the answer, the 20 * common case is one pending IRQ so optimize in that direction. 21 * 22 * 2) We need not check against bits in the status register IRQ mask, that 23 * would make this routine slow as hell. 24 * 25 * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in 26 * between like BSD spl() brain-damage. 27 * 28 * Furthermore, the IRQs on the INDY look basically (barring software IRQs 29 * which we don't use at all) like: 30 * 31 * MIPS IRQ Source 32 * -------- ------ 33 * 0 Software (ignored) 34 * 1 Software (ignored) 35 * 2 Local IRQ level zero 36 * 3 Local IRQ level one 37 * 4 8254 Timer zero 38 * 5 8254 Timer one 39 * 6 Bus Error 40 * 7 R4k timer (what we use) 41 * 42 * We handle the IRQ according to _our_ priority which is: 43 * 44 * Highest ---- R4k Timer 45 * Local IRQ zero 46 * Local IRQ one 47 * Bus Error 48 * 8254 Timer zero 49 * Lowest ---- 8254 Timer one 50 * 51 * then we just return, if multiple IRQs are pending then we will just take 52 * another exception, big deal. 53 */ 54 55 .text 56 .set noreorder 57 .set noat 58 .align 5 59 NESTED(ddbIRQ, PT_SIZE, sp) 60 SAVE_ALL 61 CLI 62 .set at 63 mfc0 s0, CP0_CAUSE # get irq mask 64 65 mfc0 t2,CP0_STATUS # get enabled interrupts 66 and s0,t2 # isolate allowed ones 67 /* First we check for r4k counter/timer IRQ. */ 68 andi a0, s0, CAUSEF_IP2 # delay slot, check local level zero 69 beq a0, zero, 1f 70 andi a0, s0, CAUSEF_IP3 # delay slot, check local level one 71 72 /* Wheee, local level zero interrupt. */ 73 jal ddb_local0_irqdispatch 74 move a0, sp # delay slot 75 76 j ret_from_irq 77 nop # delay slot 78 791: 80 beq a0, zero, 1f 81 andi a0, s0, CAUSEF_IP6 # delay slot, check bus error 82 83 /* Wheee, local level one interrupt. */ 84 move a0, sp 85 jal ddb_local1_irqdispatch 86 nop 87 88 j ret_from_irq 89 nop 90 911: 92 beq a0, zero, 1f 93 nop 94 95 /* Wheee, an asynchronous bus error... */ 96 move a0, sp 97 jal ddb_buserror_irq 98 nop 99 100 j ret_from_irq 101 nop 102 1031: 104 /* Here by mistake? This is possible, what can happen 105 * is that by the time we take the exception the IRQ 106 * pin goes low, so just leave if this is the case. 107 */ 108 andi a0, s0, (CAUSEF_IP4 | CAUSEF_IP5) 109 beq a0, zero, 1f 110 111 /* Must be one of the 8254 timers... */ 112 move a0, sp 113 jal ddb_8254timer_irq 114 nop 1151: 116 j ret_from_irq 117 nop 118 END(ddbIRQ) 119