sa11x0_irq.S revision 1.5 1 /* $NetBSD: sa11x0_irq.S,v 1.5 2003/03/31 19:52:35 chris Exp $ */
2
3 /*
4 * Copyright (c) 1998 Mark Brinicombe.
5 * Copyright (c) 1998 Causality Limited
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to the NetBSD Foundation
9 * by IWAMOTO Toshihiro.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by Mark Brinicombe
22 * for the NetBSD Project.
23 * 4. The name of the company nor the name of the author may be used to
24 * endorse or promote products derived from this software without specific
25 * prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
28 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
29 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
31 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
32 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 */
39
40 #include "opt_irqstats.h"
41
42 #include "assym.h"
43 #include <machine/asm.h>
44 #include <machine/cpu.h>
45 #include <machine/frame.h>
46 #include <arm/sa11x0/sa11x0_reg.h>
47
48
49 .text
50 .align 0
51
52 Lcurrent_spl_level:
53 .word _C_LABEL(current_spl_level)
54
55 Lcurrent_intr_depth:
56 .word _C_LABEL(current_intr_depth)
57
58 Lspl_masks:
59 .word _C_LABEL(spl_masks)
60
61 .globl _C_LABEL(saipic_base)
62 _C_LABEL(saipic_base):
63 .word 0x00000000
64
65 #ifdef INTR_DEBUG
66 Ldbg_str:
67 .asciz "irq_entry %x %x\n"
68 #endif
69
70 /*
71 * Regsister usage
72 *
73 * r6 - Address of current handler
74 * r7 - Pointer to handler pointer list
75 * r8 - Current IRQ requests.
76 * r9 - Used to count through possible IRQ bits.
77 * r10 - Base address of SAIP
78 */
79
80 ASENTRY_NP(irq_entry)
81 sub lr, lr, #0x00000004 /* Adjust the lr */
82
83 PUSHFRAMEINSVC /* Push an interrupt frame */
84
85 /* Load r8 with the SAIPIC interrupt requests */
86
87 ldr r10, _C_LABEL(saipic_base)
88 ldr r8, [r10, #(SAIPIC_IP)] /* Load IRQ pending register */
89
90 #ifdef INTR_DEBUG
91 ldr r2, [r10, #(SAIPIC_MR)]
92 adr r0, Ldbg_str
93 mov r1, r8
94 bl _C_LABEL(printf)
95 #endif
96 /*
97 * Note that we have entered the IRQ handler.
98 * We are in SVC mode so we cannot use the processor mode
99 * to determine if we are in an IRQ. Instead we will count the
100 * each time the interrupt handler is nested.
101 */
102
103 ldr r0, Lcurrent_intr_depth
104 ldr r1, [r0]
105 add r1, r1, #1
106 str r1, [r0]
107
108 /*
109 * Need to block all interrupts at the IPL or lower for
110 * all asserted interrupts.
111 * This basically emulates hardware interrupt priority levels.
112 * Means we need to go through the interrupt mask and for
113 * every asserted interrupt we need to mask out all other
114 * interrupts at the same or lower IPL.
115 * If only we could wait until the main loop but we need to sort
116 * this out first so interrupts can be re-enabled.
117 *
118 * This would benefit from a special ffs type routine
119 */
120
121 mov r9, #(_SPL_LEVELS - 1)
122 ldr r7, Lspl_masks
123
124 Lfind_highest_ipl:
125 ldr r2, [r7, r9, lsl #2]
126 tst r8, r2
127 subeq r9, r9, #1
128 beq Lfind_highest_ipl
129
130 /* r9 = SPL level of highest priority interrupt */
131 add r9, r9, #1
132 ldr r2, [r7, r9, lsl #2]
133 mvn r2, r2
134
135 ldr r0, Lcurrent_spl_level
136 ldr r1, [r0]
137 str r9, [r0]
138 stmfd sp!, {r1}
139
140 /* Update the SAIP irq masks */
141 bl _C_LABEL(irq_setmasks)
142
143 #ifdef INTR_DEBUG
144 stmfd sp!, {r0,r1,r2}
145 adr r0, Ldbg_str
146 mov r1, #1
147 mov r2, r9
148 bl _C_LABEL(printf)
149 ldmia sp!, {r0,r1,r2}
150 #endif
151 mrs r0, cpsr_all /* Enable IRQ's */
152 bic r0, r0, #I32_bit
153 msr cpsr_all, r0
154
155 ldr r7, Lirqhandlers
156 mov r9, #0x00000001
157
158 irqloop:
159 /* This would benefit from a special ffs type routine */
160 tst r8, r9 /* Is a bit set ? */
161 beq nextirq /* No ? try next bit */
162
163 ldr r6, [r7] /* Get address of first handler structure */
164
165 teq r6, #0x00000000 /* Do we have a handler */
166 moveq r0, r8 /* IRQ requests as arg 0 */
167 beq _C_LABEL(stray_irqhandler) /* call special handler */
168
169 ldr r0, Lcnt /* Stat info */
170 ldr r1, [r0, #(V_INTR)]
171 add r1, r1, #0x00000001
172 str r1, [r0, #(V_INTR)]
173
174 /*
175 * XXX: Should stats be accumlated for every interrupt routine
176 * called or for every physical interrupt that is serviced.
177 */
178
179 #ifdef IRQSTATS
180 ldr r0, Lintrcnt
181 ldr r1, [r6, #(IH_COUNT)]
182
183 add r0, r0, r1, lsl #2
184 ldr r1, [r0]
185 add r1, r1, #0x00000001
186 str r1, [r0]
187 #endif /* IRQSTATS */
188
189 irqchainloop:
190 #ifdef INTR_DEBUG
191 stmfd sp!, {r0,r1,r2}
192 adr r0, Ldbg_str
193 mov r1, #2
194 bl _C_LABEL(printf)
195 ldmia sp!, {r0,r1,r2}
196 #endif
197 ldr r0, [r6, #(IH_ARG)] /* Get argument pointer */
198 teq r0, #0x00000000 /* If arg is zero pass stack frame */
199 addeq r0, sp, #4 /* ... stack frame [XXX needs care] */
200 mov lr, pc /* return address */
201 ldr pc, [r6, #(IH_FUNC)] /* Call handler */
202
203 teq r0, #0x00000001 /* Was the irq serviced ? */
204 beq irqdone
205
206 ldr r6, [r6, #(IH_NEXT)]
207 teq r6, #0x00000000
208 bne irqchainloop
209
210 irqdone:
211 nextirq:
212 add r7, r7, #0x00000004 /* update pointer to handlers */
213 mov r9, r9, lsl #1 /* move on to next bit */
214 teq r9, #(1 << 31) /* done the last bit ? */
215 bne irqloop /* no - loop back. */
216
217 ldmfd sp!, {r2}
218 ldr r1, Lcurrent_spl_level
219 str r2, [r1]
220
221 /* Restore previous disabled mask */
222 bl _C_LABEL(irq_setmasks)
223
224 bl _C_LABEL(dosoftints) /* Handle the soft interrupts */
225
226 /* Manage AST's. Maybe this should be done as a soft interrupt ? */
227 ldr r0, [sp] /* Get the SPSR from stack */
228
229 and r0, r0, #(PSR_MODE) /* Test for USR32 mode before the IRQ */
230 teq r0, #(PSR_USR32_MODE)
231 ldreq r0, Lastpending /* Do we have an AST pending ? */
232 ldreq r1, [r0]
233 teqeq r1, #0x00000001
234
235 beq irqast /* call the AST handler */
236
237 /* Kill IRQ's in preparation for exit */
238 mrs r0, cpsr_all
239 orr r0, r0, #(I32_bit)
240 msr cpsr_all, r0
241
242 #ifdef INTR_DEBUG
243 adr r0, dbg_str
244 mov r1, #3
245 ldr r2, [r10, #(SAIPIC_MR)]
246 bl _C_LABEL(printf)
247 #endif
248
249 /* Decrement the nest count */
250 ldr r0, Lcurrent_intr_depth
251 ldr r1, [r0]
252 sub r1, r1, #1
253 str r1, [r0]
254
255 PULLFRAMEFROMSVCANDEXIT
256
257 /* NOT REACHED */
258 b . - 8
259
260 /*
261 * Ok, snag with current intr depth ...
262 * If ast() calls mi_sleep() the current_intr_depth will not be
263 * decremented until the process is woken up. This can result
264 * in the system believing it is still in the interrupt handler.
265 * If we are calling ast() then correct the current_intr_depth
266 * before the call.
267 */
268 irqast:
269 mov r1, #0x00000000 /* Clear ast_pending */
270 str r1, [r0]
271
272 /* Kill IRQ's so we atomically decrement current_intr_depth */
273 mrs r2, cpsr_all
274 orr r3, r2, #(I32_bit)
275 msr cpsr_all, r3
276
277 /* Decrement the interrupt nesting count */
278 ldr r0, Lcurrent_intr_depth
279 ldr r1, [r0]
280 sub r1, r1, #1
281 str r1, [r0]
282
283 /* Restore IRQ's */
284 msr cpsr_all, r2
285
286 mov r0, sp
287 bl _C_LABEL(ast)
288
289 /* Kill IRQ's in preparation for exit */
290 mrs r0, cpsr_all
291 orr r0, r0, #(I32_bit)
292 msr cpsr_all, r0
293
294 PULLFRAMEFROMSVCANDEXIT
295
296 /* NOT REACHED */
297 b . - 8
298
299
300 ENTRY(irq_setmasks)
301 /* Disable interrupts */
302 mrs r3, cpsr_all
303 orr r1, r3, #(I32_bit)
304 msr cpsr_all, r1
305
306 /* Calculate interrupt mask */
307 ldr r0, Lspl_masks
308 ldr r2, Lcurrent_spl_level
309 ldr r2, [r2]
310 ldr r2, [r0, r2, lsl #2]
311
312 ldr r0, _C_LABEL(saipic_base)
313 str r2, [r0, #(SAIPIC_MR)] /* Set mask register */
314
315 /* Restore old cpsr and exit */
316 msr cpsr_all, r3
317 mov pc, lr
318
319 Lcnt:
320 .word _C_LABEL(uvmexp)
321
322 #ifdef IRQSTATS
323 Lintrcnt:
324 .word _C_LABEL(intrcnt)
325 #endif
326
327 Lirqhandlers:
328 .word _C_LABEL(irqhandlers) /* Pointer to array of irqhandlers */
329
330 Lastpending:
331 .word _C_LABEL(astpending)
332
333
334
335 #ifdef IRQSTATS
336 .global _C_LABEL(intrnames), _C_LABEL(eintrnames)
337 .global _C_LABEL(eintrcnt)
338 _C_LABEL(intrnames):
339 _C_LABEL(eintrnames):
340 _C_LABEL(eintrcnt):
341
342 .globl _C_LABEL(intrcnt), _C_LABEL(sintrcnt)
343
344 _C_LABEL(intrcnt):
345 .space ICU_LEN*4 /* XXX Should be linked to number of interrupts */
346
347 _C_LABEL(sintrcnt):
348 .space 32*4
349 #endif
350