1 /* $NetBSD: sa11x0_irq.S,v 1.13 2008/04/27 18:58:45 matt Exp $ */
4 * Copyright (c) 1998 Mark Brinicombe.
5 * Copyright (c) 1998 Causality Limited
8 * This code is derived from software contributed to the NetBSD Foundation
9 * by IWAMOTO Toshihiro.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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
40 #include "opt_irqstats.h"
43 #include <machine/asm.h>
44 #include <machine/cpu.h>
45 #include <machine/frame.h>
46 #include <arm/sa11x0/sa11x0_reg.h>
53 .word _C_LABEL(spl_masks)
56 .word _C_LABEL(cpu_info_store)
58 .globl _C_LABEL(saipic_base)
59 _C_LABEL(saipic_base):
64 .asciz "irq_entry %x %x\n"
70 AST_ALIGNMENT_FAULT_LOCALS
75 * r6 - Address of current handler
76 * r7 - Pointer to handler pointer list
77 * r8 - Current IRQ requests.
78 * r9 - Used to count through possible IRQ bits.
79 * r10 - Base address of SAIP
83 sub lr, lr, #0x00000004 /* Adjust the lr */
85 PUSHFRAMEINSVC /* Push an interrupt frame */
86 ENABLE_ALIGNMENT_FAULTS
88 /* Load r8 with the SAIPIC interrupt requests */
90 ldr r10, _C_LABEL(saipic_base)
91 ldr r8, [r10, #(SAIPIC_IP)] /* Load IRQ pending register */
94 ldr r2, [r10, #(SAIPIC_MR)]
100 * Note that we have entered the IRQ handler.
101 * We are in SVC mode so we cannot use the processor mode
102 * to determine if we are in an IRQ. Instead we will count the
103 * each time the interrupt handler is nested.
106 ldr r1, [r4, #CI_INTR_DEPTH]
108 str r1, [r4, #CI_INTR_DEPTH]
111 * Need to block all interrupts at the IPL or lower for
112 * all asserted interrupts.
113 * This basically emulates hardware interrupt priority levels.
114 * Means we need to go through the interrupt mask and for
115 * every asserted interrupt we need to mask out all other
116 * interrupts at the same or lower IPL.
117 * If only we could wait until the main loop but we need to sort
118 * this out first so interrupts can be re-enabled.
120 * This would benefit from a special ffs type routine
127 ldr r2, [r7, r9, lsl #2]
130 beq Lfind_highest_ipl
132 /* r9 = SPL level of highest priority interrupt */
134 ldr r2, [r7, r9, lsl #2]
136 ldr r1, [r4, #CI_CPL]
137 str r9, [r4, #CI_CPL]
140 /* Update the SAIP irq masks */
141 bl _C_LABEL(irq_setmasks)
144 stmfd sp!, {r0,r1,r2}
149 ldmia sp!, {r0,r1,r2}
151 mrs r0, cpsr_all /* Enable IRQs */
159 /* This would benefit from a special ffs type routine */
160 tst r8, r9 /* Is a bit set ? */
161 beq nextirq /* No ? try next bit */
163 ldr r6, [r7] /* Get address of first handler structure */
165 teq r6, #0x00000000 /* Do we have a handler */
166 moveq r0, r8 /* IRQ requests as arg 0 */
167 beq _C_LABEL(stray_irqhandler) /* call special handler */
169 ldr r0, Lcnt /* Stat info */
170 ldr r1, [r0, #(V_INTR)]
171 add r1, r1, #0x00000001
172 str r1, [r0, #(V_INTR)]
175 * XXX: Should stats be accumulated for every interrupt routine
176 * called or for every physical interrupt that is serviced.
181 ldr r1, [r6, #(IH_COUNT)]
183 add r0, r0, r1, lsl #2
185 add r1, r1, #0x00000001
187 #endif /* IRQSTATS */
191 stmfd sp!, {r0,r1,r2}
195 ldmia sp!, {r0,r1,r2}
197 ldr r0, [r6, #(IH_ARG)] /* Get argument pointer */
198 teq r0, #0x00000000 /* If arg is zero pass stack frame */
199 addeq r0, sp, #4 /* ... stack frame [XXX needs care] */
200 mov lr, pc /* return address */
201 ldr pc, [r6, #(IH_FUNC)] /* Call handler */
203 teq r0, #0x00000001 /* Was the irq serviced ? */
206 ldr r6, [r6, #(IH_NEXT)]
212 add r7, r7, #0x00000004 /* update pointer to handlers */
213 mov r9, r9, lsl #1 /* move on to next bit */
214 teq r9, #(1 << 31) /* done the last bit ? */
215 bne irqloop /* no - loop back. */
218 str r2, [r4, #CI_CPL]
220 /* Restore previous disabled mask */
221 bl _C_LABEL(irq_setmasks)
223 #ifdef __HAVE_FAST_SOFTINTS
224 bl _C_LABEL(dosoftints) /* Handle the soft interrupts */
227 /* Kill IRQ's in preparation for exit */
229 orr r0, r0, #(I32_bit)
235 ldr r2, [r10, #(SAIPIC_MR)]
239 /* Decrement the nest count */
240 ldr r1, [r4, #CI_INTR_DEPTH]
242 str r1, [r4, #CI_INTR_DEPTH]
246 DO_AST_AND_RESTORE_ALIGNMENT_FAULTS
247 PULLFRAMEFROMSVCANDEXIT
253 stmfd sp!, {r0, r1, r4, lr} /* Preserve registers */
255 /* Disable interrupts */
257 orr r3, r1, #(I32_bit)
260 /* Calculate interrupt mask */
262 ldr r4, Lcpu_info_store
263 ldr r2, [r4, #CI_CPL]
264 ldr r2, [r0, r2, lsl #2]
266 ldr r0, _C_LABEL(saipic_base)
267 str r2, [r0, #(SAIPIC_MR)] /* Set mask register */
269 /* Restore old cpsr and exit */
271 ldmia sp!, {r0, r1, r4, pc} /* Restore registers */
274 .word _C_LABEL(uvmexp)
278 .word _C_LABEL(intrcnt)
282 .word _C_LABEL(irqhandlers) /* Pointer to array of irqhandlers */
286 .global _C_LABEL(intrnames), _C_LABEL(eintrnames)
287 .global _C_LABEL(eintrcnt)
289 _C_LABEL(eintrnames):
292 .globl _C_LABEL(intrcnt), _C_LABEL(sintrcnt)
295 .space ICU_LEN*4 /* XXX Should be linked to number of interrupts */