Merge branch 'x86/kexec'
[linux-2.6/x86.git] / arch / mips / dec / int-handler.S
blob82c85281878143cfc6cc4d85131f978cc49c2467
1 /*
2  * Copyright (C) 1995, 1996, 1997 Paul M. Antoine and Harald Koerfgen
3  * Copyright (C) 2000, 2001, 2002, 2003, 2005  Maciej W. Rozycki
4  *
5  * Written by Ralf Baechle and Andreas Busse, modified for DECstation
6  * support by Paul Antoine and Harald Koerfgen.
7  *
8  * completly rewritten:
9  * Copyright (C) 1998 Harald Koerfgen
10  *
11  * Rewritten extensively for controller-driven IRQ support
12  * by Maciej W. Rozycki.
13  */
15 #include <asm/addrspace.h>
16 #include <asm/asm.h>
17 #include <asm/mipsregs.h>
18 #include <asm/regdef.h>
19 #include <asm/stackframe.h>
21 #include <asm/dec/interrupts.h>
22 #include <asm/dec/ioasic_addrs.h>
23 #include <asm/dec/ioasic_ints.h>
24 #include <asm/dec/kn01.h>
25 #include <asm/dec/kn02.h>
26 #include <asm/dec/kn02xa.h>
27 #include <asm/dec/kn03.h>
29 #define KN02_CSR_BASE           CKSEG1ADDR(KN02_SLOT_BASE + KN02_CSR)
30 #define KN02XA_IOASIC_BASE      CKSEG1ADDR(KN02XA_SLOT_BASE + IOASIC_IOCTL)
31 #define KN03_IOASIC_BASE        CKSEG1ADDR(KN03_SLOT_BASE + IOASIC_IOCTL)
33                 .text
34                 .set    noreorder
36  * plat_irq_dispatch: Interrupt handler for DECstations
37  *
38  * We follow the model in the Indy interrupt code by David Miller, where he
39  * says: a lot of complication here is taken away because:
40  *
41  * 1) We handle one interrupt and return, sitting in a loop
42  *    and moving across all the pending IRQ bits in the cause
43  *    register is _NOT_ the answer, the common case is one
44  *    pending IRQ so optimize in that direction.
45  *
46  * 2) We need not check against bits in the status register
47  *    IRQ mask, that would make this routine slow as hell.
48  *
49  * 3) Linux only thinks in terms of all IRQs on or all IRQs
50  *    off, nothing in between like BSD spl() brain-damage.
51  *
52  * Furthermore, the IRQs on the DECstations look basically (barring
53  * software IRQs which we don't use at all) like...
54  *
55  * DS2100/3100's, aka kn01, aka Pmax:
56  *
57  *      MIPS IRQ        Source
58  *      --------        ------
59  *             0        Software (ignored)
60  *             1        Software (ignored)
61  *             2        SCSI
62  *             3        Lance Ethernet
63  *             4        DZ11 serial
64  *             5        RTC
65  *             6        Memory Controller & Video
66  *             7        FPU
67  *
68  * DS5000/200, aka kn02, aka 3max:
69  *
70  *      MIPS IRQ        Source
71  *      --------        ------
72  *             0        Software (ignored)
73  *             1        Software (ignored)
74  *             2        TurboChannel
75  *             3        RTC
76  *             4        Reserved
77  *             5        Memory Controller
78  *             6        Reserved
79  *             7        FPU
80  *
81  * DS5000/1xx's, aka kn02ba, aka 3min:
82  *
83  *      MIPS IRQ        Source
84  *      --------        ------
85  *             0        Software (ignored)
86  *             1        Software (ignored)
87  *             2        TurboChannel Slot 0
88  *             3        TurboChannel Slot 1
89  *             4        TurboChannel Slot 2
90  *             5        TurboChannel Slot 3 (ASIC)
91  *             6        Halt button
92  *             7        FPU/R4k timer
93  *
94  * DS5000/2x's, aka kn02ca, aka maxine:
95  *
96  *      MIPS IRQ        Source
97  *      --------        ------
98  *             0        Software (ignored)
99  *             1        Software (ignored)
100  *             2        Periodic Interrupt (100usec)
101  *             3        RTC
102  *             4        I/O write timeout
103  *             5        TurboChannel (ASIC)
104  *             6        Halt Keycode from Access.Bus keyboard (CTRL-ALT-ENTER)
105  *             7        FPU/R4k timer
107  * DS5000/2xx's, aka kn03, aka 3maxplus:
109  *      MIPS IRQ        Source
110  *      --------        ------
111  *             0        Software (ignored)
112  *             1        Software (ignored)
113  *             2        System Board (ASIC)
114  *             3        RTC
115  *             4        Reserved
116  *             5        Memory
117  *             6        Halt Button
118  *             7        FPU/R4k timer
120  * We handle the IRQ according to _our_ priority (see setup.c),
121  * then we just return.  If multiple IRQs are pending then we will
122  * just take another exception, big deal.
123  */
124                 .align  5
125                 NESTED(plat_irq_dispatch, PT_SIZE, ra)
126                 .set    noreorder
128                 /*
129                  * Get pending Interrupts
130                  */
131                 mfc0    t0,CP0_CAUSE            # get pending interrupts
132                 mfc0    t1,CP0_STATUS
133 #ifdef CONFIG_32BIT
134                 lw      t2,cpu_fpu_mask
135 #endif
136                 andi    t0,ST0_IM               # CAUSE.CE may be non-zero!
137                 and     t0,t1                   # isolate allowed ones
139                 beqz    t0,spurious
141 #ifdef CONFIG_32BIT
142                  and    t2,t0
143                 bnez    t2,fpu                  # handle FPU immediately
144 #endif
146                 /*
147                  * Find irq with highest priority
148                  */
149                  PTR_LA t1,cpu_mask_nr_tbl
150 1:              lw      t2,(t1)
151                 nop
152                 and     t2,t0
153                 beqz    t2,1b
154                  addu   t1,2*PTRSIZE            # delay slot
156                 /*
157                  * Do the low-level stuff
158                  */
159                 lw      a0,(-PTRSIZE)(t1)
160                 nop
161                 bgez    a0,handle_it            # irq_nr >= 0?
162                                                 # irq_nr < 0: it is an address
163                  nop
164                 jr      a0
165                                                 # a trick to save a branch:
166                  lui    t2,(KN03_IOASIC_BASE>>16)&0xffff
167                                                 # upper part of IOASIC Address
170  * Handle "IRQ Controller" Interrupts
171  * Masked Interrupts are still visible and have to be masked "by hand".
172  */
173                 FEXPORT(kn02_io_int)            # 3max
174                 lui     t0,(KN02_CSR_BASE>>16)&0xffff
175                                                 # get interrupt status and mask
176                 lw      t0,(t0)
177                 nop
178                 andi    t1,t0,KN02_IRQ_ALL
179                 b       1f
180                  srl    t0,16                   # shift interrupt mask
182                 FEXPORT(kn02xa_io_int)          # 3min/maxine
183                 lui     t2,(KN02XA_IOASIC_BASE>>16)&0xffff
184                                                 # upper part of IOASIC Address
186                 FEXPORT(kn03_io_int)            # 3max+ (t2 loaded earlier)
187                 lw      t0,IO_REG_SIR(t2)       # get status: IOASIC sir
188                 lw      t1,IO_REG_SIMR(t2)      # get mask:   IOASIC simr
189                 nop
191 1:              and     t0,t1                   # mask out allowed ones
193                 beqz    t0,spurious
195                 /*
196                  * Find irq with highest priority
197                  */
198                  PTR_LA t1,asic_mask_nr_tbl
199 2:              lw      t2,(t1)
200                 nop
201                 and     t2,t0
202                 beq     zero,t2,2b
203                  addu   t1,2*PTRSIZE            # delay slot
205                 /*
206                  * Do the low-level stuff
207                  */
208                 lw      a0,%lo(-PTRSIZE)(t1)
209                 nop
210                 bgez    a0,handle_it            # irq_nr >= 0?
211                                                 # irq_nr < 0: it is an address
212                  nop
213                 jr      a0
214                  nop                            # delay slot
217  * Dispatch low-priority interrupts.  We reconsider all status
218  * bits again, which looks like a lose, but it makes the code
219  * simple and O(log n), so it gets compensated.
220  */
221                 FEXPORT(cpu_all_int)            # HALT, timers, software junk
222                 li      a0,DEC_CPU_IRQ_BASE
223                 srl     t0,CAUSEB_IP
224                 li      t1,CAUSEF_IP>>CAUSEB_IP # mask
225                 b       1f
226                  li     t2,4                    # nr of bits / 2
228                 FEXPORT(kn02_all_int)           # impossible ?
229                 li      a0,KN02_IRQ_BASE
230                 li      t1,KN02_IRQ_ALL         # mask
231                 b       1f
232                  li     t2,4                    # nr of bits / 2
234                 FEXPORT(asic_all_int)           # various I/O ASIC junk
235                 li      a0,IO_IRQ_BASE
236                 li      t1,IO_IRQ_ALL           # mask
237                 b       1f
238                  li     t2,8                    # nr of bits / 2
241  * Dispatch DMA interrupts -- O(log n).
242  */
243                 FEXPORT(asic_dma_int)           # I/O ASIC DMA events
244                 li      a0,IO_IRQ_BASE+IO_INR_DMA
245                 srl     t0,IO_INR_DMA
246                 li      t1,IO_IRQ_DMA>>IO_INR_DMA # mask
247                 li      t2,8                    # nr of bits / 2
249                 /*
250                  * Find irq with highest priority.
251                  * Highest irq number takes precedence.
252                  */
253 1:              srlv    t3,t1,t2
254 2:              xor     t1,t3
255                 and     t3,t0,t1
256                 beqz    t3,3f
257                  nop
258                 move    t0,t3
259                 addu    a0,t2
260 3:              srl     t2,1
261                 bnez    t2,2b
262                  srlv   t3,t1,t2
264 handle_it:
265                 j       dec_irq_dispatch
266                  nop
268 #ifdef CONFIG_32BIT
269 fpu:
270                 j       handle_fpe_int
271                  nop
272 #endif
274 spurious:
275                 j       spurious_interrupt
276                  nop
277                 END(plat_irq_dispatch)
280  * Generic unimplemented interrupt routines -- cpu_mask_nr_tbl
281  * and asic_mask_nr_tbl are initialized to point all interrupts here.
282  * The tables are then filled in by machine-specific initialisation
283  * in dec_setup().
284  */
285                 FEXPORT(dec_intr_unimplemented)
286                 move    a1,t0                   # cheats way of printing an arg!
287                 PANIC("Unimplemented cpu interrupt! CP0_CAUSE: 0x%08x");
289                 FEXPORT(asic_intr_unimplemented)
290                 move    a1,t0                   # cheats way of printing an arg!
291                 PANIC("Unimplemented asic interrupt! ASIC ISR: 0x%08x");