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