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