sa11x0_irq.S revision 1.1 1 /* $NetBSD: sa11x0_irq.S,v 1.1 2001/07/08 23:37:53 rjs 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_cputypes.h"
41 #include "opt_irqstats.h"
42
43 #include "assym.h"
44 #include <machine/asm.h>
45 #include <machine/cpu.h>
46 #include <machine/frame.h>
47 #include <hpcarm/sa11x0/sa11x0_reg.h>
48
49
50 .text
51 .align 0
52
53 Lcurrent_spl_level:
54 .word _C_LABEL(current_spl_level)
55
56 Lcurrent_intr_depth:
57 .word _C_LABEL(current_intr_depth)
58
59 Lspl_masks:
60 .word _C_LABEL(spl_masks)
61
62 .globl _C_LABEL(saipic_base)
63 _C_LABEL(saipic_base):
64 .word 0x00000000
65
66 #ifdef INTR_DEBUG
67 Ldbg_str:
68 .asciz "irq_entry %x %x\n"
69 #endif
70
71 /*
72 * Regsister usage
73 *
74 * r6 - Address of current handler
75 * r7 - Pointer to handler pointer list
76 * r8 - Current IRQ requests.
77 * r9 - Used to count through possible IRQ bits.
78 * r10 - Base address of SAIP
79 */
80
81 ASENTRY_NP(irq_entry)
82 sub lr, lr, #0x00000004 /* Adjust the lr */
83
84 PUSHFRAMEINSVC /* Push an interrupt frame */
85
86 /* Load r8 with the SAIPIC interrupt requests */
87
88 ldr r10, [pc, #_C_LABEL(saipic_base) - . - 8]
89 ldr r8, [r10, #(SAIPIC_IP)] /* Load IRQ pending register */
90
91 #ifdef INTR_DEBUG
92 ldr r2, [r10, #(SAIPIC_MR)]
93 add r0, pc, #Ldbg_str - . - 8
94 mov r1, r8
95 bl _C_LABEL(printf)
96 #endif
97 /*
98 * Note that we have entered the IRQ handler.
99 * We are in SVC mode so we cannot use the processor mode
100 * to determine if we are in an IRQ. Instead we will count the
101 * each time the interrupt handler is nested.
102 */
103
104 ldr r0, Lcurrent_intr_depth
105 ldr r1, [r0]
106 add r1, r1, #1
107 str r1, [r0]
108
109 /*
110 * Need to block all interrupts at the IPL or lower for
111 * all asserted interrupts.
112 * This basically emulates hardware interrupt priority levels.
113 * Means we need to go through the interrupt mask and for
114 * every asserted interrupt we need to mask out all other
115 * interrupts at the same or lower IPL.
116 * If only we could wait until the main loop but we need to sort
117 * this out first so interrupts can be re-enabled.
118 *
119 * This would benefit from a special ffs type routine
120 */
121
122 mov r9, #(_SPL_LEVELS - 1)
123 ldr r7, Lspl_masks
124
125 Lfind_highest_ipl:
126 ldr r2, [r7, r9, lsl #2]
127 tst r8, r2
128 subeq r9, r9, #1
129 beq Lfind_highest_ipl
130
131 /* r9 = SPL level of highest priority interrupt */
132 add r9, r9, #1
133 ldr r2, [r7, r9, lsl #2]
134 mvn r2, r2
135
136 ldr r0, Lcurrent_spl_level
137 ldr r1, [r0]
138 str r9, [r0]
139 stmfd sp!, {r1}
140
141 /* Update the SAIP irq masks */
142 bl _C_LABEL(irq_setmasks)
143
144 #ifdef INTR_DEBUG
145 stmfd sp!, {r0,r1,r2}
146 add r0, pc, #Ldbg_str - . - 8
147 mov r1, #1
148 mov r2, r9
149 bl _C_LABEL(printf)
150 ldmia sp!, {r0,r1,r2}
151 #endif
152 mrs r0, cpsr_all /* Enable IRQ's */
153 bic r0, r0, #I32_bit
154 msr cpsr_all, r0
155
156 ldr r7, [pc, #Lirqhandlers - . - 8]
157 mov r9, #0x00000001
158
159 irqloop:
160 /* This would benefit from a special ffs type routine */
161 tst r8, r9 /* Is a bit set ? */
162 beq nextirq /* No ? try next bit */
163
164 ldr r6, [r7] /* Get address of first handler structure */
165
166 teq r6, #0x00000000 /* Do we have a handler */
167 moveq r0, r8 /* IRQ requests as arg 0 */
168 beq _C_LABEL(stray_irqhandler) /* call special handler */
169
170 ldr r0, Lcnt /* Stat info */
171 ldr r1, [r0, #(V_INTR)]
172 add r1, r1, #0x00000001
173 str r1, [r0, #(V_INTR)]
174
175 /*
176 * XXX: Should stats be accumlated for every interrupt routine
177 * called or for every physical interrupt that is serviced.
178 */
179
180 #ifdef IRQSTATS
181 ldr r0, Lintrcnt
182 ldr r1, [r6, #(IH_COUNT)]
183
184 add r0, r0, r1, lsl #2
185 ldr r1, [r0]
186 add r1, r1, #0x00000001
187 str r1, [r0]
188 #endif /* IRQSTATS */
189
190 irqchainloop:
191 #ifdef INTR_DEBUG
192 stmfd sp!, {r0,r1,r2}
193 add r0, pc, #Ldbg_str - . - 8
194 mov r1, #2
195 bl _C_LABEL(printf)
196 ldmia sp!, {r0,r1,r2}
197 #endif
198 add lr, pc, #nextinchain - . - 8 /* return address */
199 ldr r0, [r6, #(IH_ARG)] /* Get argument pointer */
200 teq r0, #0x00000000 /* If arg is zero pass stack frame */
201 addeq r0, sp, #4 /* ... stack frame [XXX needs care] */
202 ldr pc, [r6, #(IH_FUNC)] /* Call handler */
203
204 nextinchain:
205 teq r0, #0x00000001 /* Was the irq serviced ? */
206 beq irqdone
207
208 ldr r6, [r6, #(IH_NEXT)]
209 teq r6, #0x00000000
210 bne irqchainloop
211
212 irqdone:
213 nextirq:
214 add r7, r7, #0x00000004 /* update pointer to handlers */
215 mov r9, r9, lsl #1 /* move on to next bit */
216 teq r9, #(1 << 31) /* done the last bit ? */
217 bne irqloop /* no - loop back. */
218
219 ldmfd sp!, {r2}
220 ldr r1, Lcurrent_spl_level
221 str r2, [r1]
222
223 /* Restore previous disabled mask */
224 bl _C_LABEL(irq_setmasks)
225
226 bl _C_LABEL(dosoftints) /* Handle the soft interrupts */
227
228 /* Manage AST's. Maybe this should be done as a soft interrupt ? */
229 ldr r0, [sp] /* Get the SPSR from stack */
230
231 and r0, r0, #(PSR_MODE) /* Test for USR32 mode before the IRQ */
232 teq r0, #(PSR_USR32_MODE)
233 ldreq r0, Lastpending /* Do we have an AST pending ? */
234 ldreq r1, [r0]
235 teqeq r1, #0x00000001
236
237 beq irqast /* call the AST handler */
238
239 /* Kill IRQ's in preparation for exit */
240 mrs r0, cpsr_all
241 orr r0, r0, #(I32_bit)
242 msr cpsr_all, r0
243
244 #ifdef INTR_DEBUG
245 add r0, pc, #Ldbg_str - . - 8
246 mov r1, #3
247 ldr r2, [r10, #(SAIPIC_MR)]
248 bl _C_LABEL(printf)
249 #endif
250
251 /* Decrement the nest count */
252 ldr r0, Lcurrent_intr_depth
253 ldr r1, [r0]
254 sub r1, r1, #1
255 str r1, [r0]
256
257 PULLFRAMEFROMSVCANDEXIT
258
259 /* NOT REACHED */
260 b . - 8
261
262 /*
263 * Ok, snag with current intr depth ...
264 * If ast() calls mi_sleep() the current_intr_depth will not be
265 * decremented until the process is woken up. This can result
266 * in the system believing it is still in the interrupt handler.
267 * If we are calling ast() then correct the current_intr_depth
268 * before the call.
269 */
270 irqast:
271 mov r1, #0x00000000 /* Clear ast_pending */
272 str r1, [r0]
273
274 /* Kill IRQ's so we atomically decrement current_intr_depth */
275 mrs r2, cpsr_all
276 orr r3, r2, #(I32_bit)
277 msr cpsr_all, r3
278
279 /* Decrement the interrupt nesting count */
280 ldr r0, Lcurrent_intr_depth
281 ldr r1, [r0]
282 sub r1, r1, #1
283 str r1, [r0]
284
285 /* Restore IRQ's */
286 msr cpsr_all, r2
287
288 mov r0, sp
289 bl _C_LABEL(ast)
290
291 /* Kill IRQ's in preparation for exit */
292 mrs r0, cpsr_all
293 orr r0, r0, #(I32_bit)
294 msr cpsr_all, r0
295
296 PULLFRAMEFROMSVCANDEXIT
297
298 /* NOT REACHED */
299 b . - 8
300
301
302 ENTRY(irq_setmasks)
303 /* Disable interrupts */
304 mrs r3, cpsr_all
305 orr r1, r3, #(I32_bit)
306 msr cpsr_all, r1
307
308 /* Calculate interrupt mask */
309 ldr r0, Lspl_masks
310 ldr r2, Lcurrent_spl_level
311 ldr r2, [r2]
312 ldr r2, [r0, r2, lsl #2]
313
314 ldr r0, [pc, #_C_LABEL(saipic_base) - . - 8]
315 str r2, [r0, #(SAIPIC_MR)] /* Set mask register */
316
317 /* Restore old cpsr and exit */
318 msr cpsr_all, r3
319 mov pc, lr
320
321 Lcnt:
322 .word _C_LABEL(uvmexp)
323
324 #ifdef IRQSTATS
325 Lintrcnt:
326 .word _C_LABEL(intrcnt)
327 #endif
328
329 Lirqhandlers:
330 .word _C_LABEL(irqhandlers) /* Pointer to array of irqhandlers */
331
332 Lastpending:
333 .word _C_LABEL(astpending)
334
335
336
337 #ifdef IRQSTATS
338 .globl _C_LABEL(intrcnt), _C_LABEL(sintrcnt)
339
340 _C_LABEL(intrcnt):
341 .space ICU_LEN*4 /* XXX Should be linked to number of interrupts */
342
343 _C_LABEL(sintrcnt):
344 .space 32*4
345 #endif
346