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