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