OSDN Git Service

Merge 4.4.137 into android-4.4
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / arch / mips / dec / int-handler.S
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  * completely rewritten:
9  * Copyright (C) 1998 Harald Koerfgen
10  *
11  * Rewritten extensively for controller-driven IRQ support
12  * by Maciej W. Rozycki.
13  */
14
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>
20
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>
28
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)
32
33                 .text
34                 .set    noreorder
35 /*
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
106  *
107  * DS5000/2xx's, aka kn03, aka 3maxplus:
108  *
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
119  *
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
127
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
138
139                 beqz    t0,spurious
140
141 #ifdef CONFIG_32BIT
142                  and    t2,t0
143                 bnez    t2,fpu                  # handle FPU immediately
144 #endif
145
146                 /*
147                  * Find irq with highest priority
148                  */
149                 # open coded PTR_LA t1, cpu_mask_nr_tbl
150 #if (_MIPS_SZPTR == 32)
151                 # open coded la t1, cpu_mask_nr_tbl
152                 lui     t1, %hi(cpu_mask_nr_tbl)
153                 addiu   t1, %lo(cpu_mask_nr_tbl)
154
155 #endif
156 #if (_MIPS_SZPTR == 64)
157                 # open coded dla t1, cpu_mask_nr_tbl
158                 .set    push
159                 .set    noat
160                 lui     t1, %highest(cpu_mask_nr_tbl)
161                 lui     AT, %hi(cpu_mask_nr_tbl)
162                 daddiu  t1, t1, %higher(cpu_mask_nr_tbl)
163                 daddiu  AT, AT, %lo(cpu_mask_nr_tbl)
164                 dsll    t1, 32
165                 daddu   t1, t1, AT
166                 .set    pop
167 #endif
168 1:              lw      t2,(t1)
169                 nop
170                 and     t2,t0
171                 beqz    t2,1b
172                  addu   t1,2*PTRSIZE            # delay slot
173
174                 /*
175                  * Do the low-level stuff
176                  */
177                 lw      a0,(-PTRSIZE)(t1)
178                 nop
179                 bgez    a0,handle_it            # irq_nr >= 0?
180                                                 # irq_nr < 0: it is an address
181                  nop
182                 jr      a0
183                                                 # a trick to save a branch:
184                  lui    t2,(KN03_IOASIC_BASE>>16)&0xffff
185                                                 # upper part of IOASIC Address
186
187 /*
188  * Handle "IRQ Controller" Interrupts
189  * Masked Interrupts are still visible and have to be masked "by hand".
190  */
191                 FEXPORT(kn02_io_int)            # 3max
192                 lui     t0,(KN02_CSR_BASE>>16)&0xffff
193                                                 # get interrupt status and mask
194                 lw      t0,(t0)
195                 nop
196                 andi    t1,t0,KN02_IRQ_ALL
197                 b       1f
198                  srl    t0,16                   # shift interrupt mask
199
200                 FEXPORT(kn02xa_io_int)          # 3min/maxine
201                 lui     t2,(KN02XA_IOASIC_BASE>>16)&0xffff
202                                                 # upper part of IOASIC Address
203
204                 FEXPORT(kn03_io_int)            # 3max+ (t2 loaded earlier)
205                 lw      t0,IO_REG_SIR(t2)       # get status: IOASIC sir
206                 lw      t1,IO_REG_SIMR(t2)      # get mask:   IOASIC simr
207                 nop
208
209 1:              and     t0,t1                   # mask out allowed ones
210
211                 beqz    t0,spurious
212
213                 /*
214                  * Find irq with highest priority
215                  */
216                 # open coded PTR_LA t1,asic_mask_nr_tbl
217 #if (_MIPS_SZPTR == 32)
218                 # open coded la t1, asic_mask_nr_tbl
219                 lui     t1, %hi(asic_mask_nr_tbl)
220                 addiu   t1, %lo(asic_mask_nr_tbl)
221
222 #endif
223 #if (_MIPS_SZPTR == 64)
224                 # open coded dla t1, asic_mask_nr_tbl
225                 .set    push
226                 .set    noat
227                 lui     t1, %highest(asic_mask_nr_tbl)
228                 lui     AT, %hi(asic_mask_nr_tbl)
229                 daddiu  t1, t1, %higher(asic_mask_nr_tbl)
230                 daddiu  AT, AT, %lo(asic_mask_nr_tbl)
231                 dsll    t1, 32
232                 daddu   t1, t1, AT
233                 .set    pop
234 #endif
235 2:              lw      t2,(t1)
236                 nop
237                 and     t2,t0
238                 beq     zero,t2,2b
239                  addu   t1,2*PTRSIZE            # delay slot
240
241                 /*
242                  * Do the low-level stuff
243                  */
244                 lw      a0,%lo(-PTRSIZE)(t1)
245                 nop
246                 bgez    a0,handle_it            # irq_nr >= 0?
247                                                 # irq_nr < 0: it is an address
248                  nop
249                 jr      a0
250                  nop                            # delay slot
251
252 /*
253  * Dispatch low-priority interrupts.  We reconsider all status
254  * bits again, which looks like a lose, but it makes the code
255  * simple and O(log n), so it gets compensated.
256  */
257                 FEXPORT(cpu_all_int)            # HALT, timers, software junk
258                 li      a0,DEC_CPU_IRQ_BASE
259                 srl     t0,CAUSEB_IP
260                 li      t1,CAUSEF_IP>>CAUSEB_IP # mask
261                 b       1f
262                  li     t2,4                    # nr of bits / 2
263
264                 FEXPORT(kn02_all_int)           # impossible ?
265                 li      a0,KN02_IRQ_BASE
266                 li      t1,KN02_IRQ_ALL         # mask
267                 b       1f
268                  li     t2,4                    # nr of bits / 2
269
270                 FEXPORT(asic_all_int)           # various I/O ASIC junk
271                 li      a0,IO_IRQ_BASE
272                 li      t1,IO_IRQ_ALL           # mask
273                 b       1f
274                  li     t2,8                    # nr of bits / 2
275
276 /*
277  * Dispatch DMA interrupts -- O(log n).
278  */
279                 FEXPORT(asic_dma_int)           # I/O ASIC DMA events
280                 li      a0,IO_IRQ_BASE+IO_INR_DMA
281                 srl     t0,IO_INR_DMA
282                 li      t1,IO_IRQ_DMA>>IO_INR_DMA # mask
283                 li      t2,8                    # nr of bits / 2
284
285                 /*
286                  * Find irq with highest priority.
287                  * Highest irq number takes precedence.
288                  */
289 1:              srlv    t3,t1,t2
290 2:              xor     t1,t3
291                 and     t3,t0,t1
292                 beqz    t3,3f
293                  nop
294                 move    t0,t3
295                 addu    a0,t2
296 3:              srl     t2,1
297                 bnez    t2,2b
298                  srlv   t3,t1,t2
299
300 handle_it:
301                 j       dec_irq_dispatch
302                  nop
303
304 #ifdef CONFIG_32BIT
305 fpu:
306                 lw      t0,fpu_kstat_irq
307                 nop
308                 lw      t1,(t0)
309                 nop
310                 addu    t1,1
311                 j       handle_fpe_int
312                  sw     t1,(t0)
313 #endif
314
315 spurious:
316                 j       spurious_interrupt
317                  nop
318                 END(plat_irq_dispatch)
319
320 /*
321  * Generic unimplemented interrupt routines -- cpu_mask_nr_tbl
322  * and asic_mask_nr_tbl are initialized to point all interrupts here.
323  * The tables are then filled in by machine-specific initialisation
324  * in dec_setup().
325  */
326                 FEXPORT(dec_intr_unimplemented)
327                 move    a1,t0                   # cheats way of printing an arg!
328                 PANIC("Unimplemented cpu interrupt! CP0_CAUSE: 0x%08x");
329
330                 FEXPORT(asic_intr_unimplemented)
331                 move    a1,t0                   # cheats way of printing an arg!
332                 PANIC("Unimplemented asic interrupt! ASIC ISR: 0x%08x");