Linux 2.6.13-rc4
[linux-2.6/next.git] / arch / mips / sgi-ip22 / ip22-irq.S
blob6ccbd9e1d967a9a1e6df4eb6d64356a05a22c23c
1 /*
2  * ip22-irq.S: Interrupt exception dispatch code for FullHouse and
3  *             Guiness.
4  *
5  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
6  */
8 #include <asm/asm.h>
9 #include <asm/mipsregs.h>
10 #include <asm/regdef.h>
11 #include <asm/stackframe.h>
13 /* A lot of complication here is taken away because:
14  *
15  * 1) We handle one interrupt and return, sitting in a loop and moving across
16  *    all the pending IRQ bits in the cause register is _NOT_ the answer, the
17  *    common case is one pending IRQ so optimize in that direction.
18  *
19  * 2) We need not check against bits in the status register IRQ mask, that
20  *    would make this routine slow as hell.
21  *
22  * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
23  *    between like BSD spl() brain-damage.
24  *
25  * Furthermore, the IRQs on the INDY look basically (barring software IRQs
26  * which we don't use at all) like:
27  *
28  *      MIPS IRQ        Source
29  *      --------        ------
30  *             0        Software (ignored)
31  *             1        Software (ignored)
32  *             2        Local IRQ level zero
33  *             3        Local IRQ level one
34  *             4        8254 Timer zero
35  *             5        8254 Timer one
36  *             6        Bus Error
37  *             7        R4k timer (what we use)
38  *
39  * We handle the IRQ according to _our_ priority which is:
40  *
41  * Highest ----     R4k Timer
42  *                  Local IRQ zero
43  *                  Local IRQ one
44  *                  Bus Error
45  *                  8254 Timer zero
46  * Lowest  ----     8254 Timer one
47  *
48  * then we just return, if multiple IRQs are pending then we will just take
49  * another exception, big deal.
50  */
52         .text
53         .set    noreorder
54         .set    noat
55         .align  5
56         NESTED(indyIRQ, PT_SIZE, sp)
57         SAVE_ALL
58         CLI
59         .set    at
60         mfc0    s0, CP0_CAUSE           # get irq mask
62         /* First we check for r4k counter/timer IRQ. */
63         andi    a0, s0, CAUSEF_IP7
64         beq     a0, zero, 1f
65          andi   a0, s0, CAUSEF_IP2      # delay slot, check local level zero
67         /* Wheee, a timer interrupt. */
68         jal     indy_r4k_timer_interrupt
69          move   a0, sp                  # delay slot
70         j       ret_from_irq
71          nop                            # delay slot
74         beq     a0, zero, 1f
75          andi   a0, s0, CAUSEF_IP3      # delay slot, check local level one
77         /* Wheee, local level zero interrupt. */
78         jal     indy_local0_irqdispatch
79          move   a0, sp                  # delay slot
81         j       ret_from_irq
82          nop                            # delay slot
85         beq     a0, zero, 1f
86          andi   a0, s0, CAUSEF_IP6      # delay slot, check bus error
88         /* Wheee, local level one interrupt. */
89         jal     indy_local1_irqdispatch
90          move   a0, sp                  # delay slot
91         j       ret_from_irq
92          nop                            # delay slot
95         beq     a0, zero, 1f
96          andi   a0, s0, (CAUSEF_IP4 | CAUSEF_IP5)       # delay slot
98         /* Wheee, an asynchronous bus error... */
99         jal     indy_buserror_irq
100          move   a0, sp                  # delay slot
101         j       ret_from_irq
102          nop                            # delay slot
105         /* Here by mistake? It is possible, that by the time we take
106          * the exception the IRQ pin goes low, so just leave if this
107          * is the case.
108          */
109         beq     a0, zero, 1f
110          nop                            # delay slot
112         /* Must be one of the 8254 timers... */
113         jal     indy_8254timer_irq
114          move   a0, sp                  # delay slot
116         j       ret_from_irq
117          nop                            # delay slot
118         END(indyIRQ)