sa11x0_irq.S revision 1.10 1 /* $NetBSD: sa11x0_irq.S,v 1.10 2007/03/09 19:21:59 thorpej 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 LOCK_CAS_CHECK_LOCALS
71
72 AST_ALIGNMENT_FAULT_LOCALS
73
74 /*
75 * Register usage
76 *
77 * r6 - Address of current handler
78 * r7 - Pointer to handler pointer list
79 * r8 - Current IRQ requests.
80 * r9 - Used to count through possible IRQ bits.
81 * r10 - Base address of SAIP
82 */
83
84 ASENTRY_NP(irq_entry)
85 sub lr, lr, #0x00000004 /* Adjust the lr */
86
87 PUSHFRAMEINSVC /* Push an interrupt frame */
88 ENABLE_ALIGNMENT_FAULTS
89
90 /* Load r8 with the SAIPIC interrupt requests */
91
92 ldr r10, _C_LABEL(saipic_base)
93 ldr r8, [r10, #(SAIPIC_IP)] /* Load IRQ pending register */
94
95 #ifdef INTR_DEBUG
96 ldr r2, [r10, #(SAIPIC_MR)]
97 adr r0, Ldbg_str
98 mov r1, r8
99 bl _C_LABEL(printf)
100 #endif
101 /*
102 * Note that we have entered the IRQ handler.
103 * We are in SVC mode so we cannot use the processor mode
104 * to determine if we are in an IRQ. Instead we will count the
105 * each time the interrupt handler is nested.
106 */
107
108 ldr r0, Lcurrent_intr_depth
109 ldr r1, [r0]
110 add r1, r1, #1
111 str r1, [r0]
112
113 /*
114 * Need to block all interrupts at the IPL or lower for
115 * all asserted interrupts.
116 * This basically emulates hardware interrupt priority levels.
117 * Means we need to go through the interrupt mask and for
118 * every asserted interrupt we need to mask out all other
119 * interrupts at the same or lower IPL.
120 * If only we could wait until the main loop but we need to sort
121 * this out first so interrupts can be re-enabled.
122 *
123 * This would benefit from a special ffs type routine
124 */
125
126 mov r9, #(_SPL_LEVELS - 1)
127 ldr r7, Lspl_masks
128
129 Lfind_highest_ipl:
130 ldr r2, [r7, r9, lsl #2]
131 tst r8, r2
132 subeq r9, r9, #1
133 beq Lfind_highest_ipl
134
135 /* r9 = SPL level of highest priority interrupt */
136 add r9, r9, #1
137 ldr r2, [r7, r9, lsl #2]
138 mvn r2, r2
139
140 ldr r0, Lcurrent_spl_level
141 ldr r1, [r0]
142 str r9, [r0]
143 stmfd sp!, {r1}
144
145 /* Update the SAIP irq masks */
146 bl _C_LABEL(irq_setmasks)
147
148 #ifdef INTR_DEBUG
149 stmfd sp!, {r0,r1,r2}
150 adr r0, Ldbg_str
151 mov r1, #1
152 mov r2, r9
153 bl _C_LABEL(printf)
154 ldmia sp!, {r0,r1,r2}
155 #endif
156 mrs r0, cpsr_all /* Enable IRQs */
157 bic r0, r0, #I32_bit
158 msr cpsr_all, r0
159
160 ldr r7, Lirqhandlers
161 mov r9, #0x00000001
162
163 irqloop:
164 /* This would benefit from a special ffs type routine */
165 tst r8, r9 /* Is a bit set ? */
166 beq nextirq /* No ? try next bit */
167
168 ldr r6, [r7] /* Get address of first handler structure */
169
170 teq r6, #0x00000000 /* Do we have a handler */
171 moveq r0, r8 /* IRQ requests as arg 0 */
172 beq _C_LABEL(stray_irqhandler) /* call special handler */
173
174 ldr r0, Lcnt /* Stat info */
175 ldr r1, [r0, #(V_INTR)]
176 add r1, r1, #0x00000001
177 str r1, [r0, #(V_INTR)]
178
179 /*
180 * XXX: Should stats be accumulated for every interrupt routine
181 * called or for every physical interrupt that is serviced.
182 */
183
184 #ifdef IRQSTATS
185 ldr r0, Lintrcnt
186 ldr r1, [r6, #(IH_COUNT)]
187
188 add r0, r0, r1, lsl #2
189 ldr r1, [r0]
190 add r1, r1, #0x00000001
191 str r1, [r0]
192 #endif /* IRQSTATS */
193
194 irqchainloop:
195 #ifdef INTR_DEBUG
196 stmfd sp!, {r0,r1,r2}
197 adr r0, Ldbg_str
198 mov r1, #2
199 bl _C_LABEL(printf)
200 ldmia sp!, {r0,r1,r2}
201 #endif
202 ldr r0, [r6, #(IH_ARG)] /* Get argument pointer */
203 teq r0, #0x00000000 /* If arg is zero pass stack frame */
204 addeq r0, sp, #4 /* ... stack frame [XXX needs care] */
205 mov lr, pc /* return address */
206 ldr pc, [r6, #(IH_FUNC)] /* Call handler */
207
208 teq r0, #0x00000001 /* Was the irq serviced ? */
209 beq irqdone
210
211 ldr r6, [r6, #(IH_NEXT)]
212 teq r6, #0x00000000
213 bne irqchainloop
214
215 irqdone:
216 nextirq:
217 add r7, r7, #0x00000004 /* update pointer to handlers */
218 mov r9, r9, lsl #1 /* move on to next bit */
219 teq r9, #(1 << 31) /* done the last bit ? */
220 bne irqloop /* no - loop back. */
221
222 ldmfd sp!, {r2}
223 ldr r1, Lcurrent_spl_level
224 str r2, [r1]
225
226 /* Restore previous disabled mask */
227 bl _C_LABEL(irq_setmasks)
228
229 bl _C_LABEL(dosoftints) /* Handle the soft interrupts */
230
231 /* Kill IRQ's in preparation for exit */
232 mrs r0, cpsr_all
233 orr r0, r0, #(I32_bit)
234 msr cpsr_all, r0
235
236 #ifdef INTR_DEBUG
237 adr r0, Ldbg_str
238 mov r1, #3
239 ldr r2, [r10, #(SAIPIC_MR)]
240 bl _C_LABEL(printf)
241 #endif
242
243 /* Decrement the nest count */
244 ldr r0, Lcurrent_intr_depth
245 ldr r1, [r0]
246 sub r1, r1, #1
247 str r1, [r0]
248
249 LOCK_CAS_CHECK
250
251 DO_AST_AND_RESTORE_ALIGNMENT_FAULTS
252 PULLFRAMEFROMSVCANDEXIT
253
254 /* NOT REACHED */
255 b . - 8
256
257 ENTRY(irq_setmasks)
258 /* Disable interrupts */
259 mrs r3, cpsr_all
260 orr r1, r3, #(I32_bit)
261 msr cpsr_all, r1
262
263 /* Calculate interrupt mask */
264 ldr r0, Lspl_masks
265 ldr r2, Lcurrent_spl_level
266 ldr r2, [r2]
267 ldr r2, [r0, r2, lsl #2]
268
269 ldr r0, _C_LABEL(saipic_base)
270 str r2, [r0, #(SAIPIC_MR)] /* Set mask register */
271
272 /* Restore old cpsr and exit */
273 msr cpsr_all, r3
274 mov pc, lr
275
276 Lcnt:
277 .word _C_LABEL(uvmexp)
278
279 #ifdef IRQSTATS
280 Lintrcnt:
281 .word _C_LABEL(intrcnt)
282 #endif
283
284 Lirqhandlers:
285 .word _C_LABEL(irqhandlers) /* Pointer to array of irqhandlers */
286
287
288 #ifdef IRQSTATS
289 .global _C_LABEL(intrnames), _C_LABEL(eintrnames)
290 .global _C_LABEL(eintrcnt)
291 _C_LABEL(intrnames):
292 _C_LABEL(eintrnames):
293 _C_LABEL(eintrcnt):
294
295 .globl _C_LABEL(intrcnt), _C_LABEL(sintrcnt)
296
297 _C_LABEL(intrcnt):
298 .space ICU_LEN*4 /* XXX Should be linked to number of interrupts */
299
300 _C_LABEL(sintrcnt):
301 .space 32*4
302 #endif
303