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