Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / arch / arm / sa11x0 / sa11x0_irq.S
blobd43172a9bcdd96f0aefbfd2489ea5783fec57d14
1 /*      $NetBSD: sa11x0_irq.S,v 1.13 2008/04/27 18:58:45 matt Exp $     */
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  */
40 #include "opt_irqstats.h"
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>
49         .text
50         .align 0
52 Lspl_masks:
53         .word   _C_LABEL(spl_masks)
55 Lcpu_info_store:
56         .word   _C_LABEL(cpu_info_store)
58         .globl  _C_LABEL(saipic_base)
59 _C_LABEL(saipic_base):
60         .word   0x00000000
62 #ifdef INTR_DEBUG
63 Ldbg_str:
64         .asciz  "irq_entry %x %x\n"
65         .align 5
66 #endif
68 LOCK_CAS_CHECK_LOCALS
70 AST_ALIGNMENT_FAULT_LOCALS
73  * Register usage
74  *
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
80  */
82 ASENTRY_NP(irq_entry)
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 */
93 #ifdef INTR_DEBUG
94         ldr     r2, [r10, #(SAIPIC_MR)]
95         adr     r0, Ldbg_str
96         mov     r1, r8
97         bl      _C_LABEL(printf)
98 #endif
99         /*
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.
104          */
106         ldr     r1, [r4, #CI_INTR_DEPTH]
107         add     r1, r1, #1
108         str     r1, [r4, #CI_INTR_DEPTH]
110         /*
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.
119          *
120          * This would benefit from a special ffs type routine
121          */
123         mov     r9, #(NIPL - 1)
124         ldr     r7, Lspl_masks
126 Lfind_highest_ipl:
127         ldr     r2, [r7, r9, lsl #2]
128         tst     r8, r2
129         subeq   r9, r9, #1
130         beq     Lfind_highest_ipl
132         /* r9 = SPL level of highest priority interrupt */
133         add     r9, r9, #1
134         ldr     r2, [r7, r9, lsl #2]
136         ldr     r1, [r4, #CI_CPL]
137         str     r9, [r4, #CI_CPL]
138         stmfd   sp!, {r1}
140         /* Update the SAIP irq masks */
141         bl      _C_LABEL(irq_setmasks)
143 #ifdef INTR_DEBUG
144         stmfd   sp!, {r0,r1,r2}
145         adr     r0, Ldbg_str
146         mov     r1, #1
147         mov     r2, r9
148         bl      _C_LABEL(printf)
149         ldmia   sp!, {r0,r1,r2}
150 #endif
151         mrs     r0, cpsr_all            /* Enable IRQs */
152         bic     r0, r0, #I32_bit
153         msr     cpsr_all, r0
155         ldr     r7, Lirqhandlers
156         mov     r9, #0x00000001
158 irqloop:
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)]
174         /*
175          * XXX: Should stats be accumulated for every interrupt routine
176          * called or for every physical interrupt that is serviced.
177          */
179 #ifdef IRQSTATS
180         ldr     r0, Lintrcnt
181         ldr     r1, [r6, #(IH_COUNT)]
183         add     r0, r0, r1, lsl #2
184         ldr     r1, [r0]
185         add     r1, r1, #0x00000001
186         str     r1, [r0]
187 #endif  /* IRQSTATS */
189 irqchainloop:
190 #ifdef INTR_DEBUG
191         stmfd   sp!, {r0,r1,r2}
192         adr     r0, Ldbg_str
193         mov     r1, #2
194         bl      _C_LABEL(printf)
195         ldmia   sp!, {r0,r1,r2}
196 #endif
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 ? */
204         beq     irqdone
206         ldr     r6, [r6, #(IH_NEXT)]
207         teq     r6, #0x00000000
208         bne     irqchainloop
210 irqdone:
211 nextirq:
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. */
217         ldmfd   sp!, {r2}
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 */
225 #endif
227         /* Kill IRQ's in preparation for exit */
228         mrs     r0, cpsr_all
229         orr     r0, r0, #(I32_bit)
230         msr     cpsr_all, r0
232 #ifdef INTR_DEBUG
233         adr     r0, Ldbg_str
234         mov     r1, #3
235         ldr     r2, [r10, #(SAIPIC_MR)]
236         bl      _C_LABEL(printf)
237 #endif
239         /* Decrement the nest count */
240         ldr     r1, [r4, #CI_INTR_DEPTH]
241         sub     r1, r1, #1
242         str     r1, [r4, #CI_INTR_DEPTH]
244         LOCK_CAS_CHECK
246         DO_AST_AND_RESTORE_ALIGNMENT_FAULTS
247         PULLFRAMEFROMSVCANDEXIT
249         /* NOT REACHED */
250         b       . - 8
252 ENTRY(irq_setmasks)
253         stmfd   sp!, {r0, r1, r4, lr}   /* Preserve registers */
255         /* Disable interrupts */
256         mrs     r1, cpsr_all
257         orr     r3, r1,  #(I32_bit)
258         msr     cpsr_all, r3
260         /* Calculate interrupt mask */
261         ldr     r0, Lspl_masks
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 */
270         msr     cpsr_all, r1
271         ldmia   sp!, {r0, r1, r4, pc}   /* Restore registers */
273 Lcnt:
274         .word   _C_LABEL(uvmexp)
276 #ifdef IRQSTATS
277 Lintrcnt:
278         .word   _C_LABEL(intrcnt)
279 #endif
281 Lirqhandlers:
282         .word   _C_LABEL(irqhandlers)   /* Pointer to array of irqhandlers */
285 #ifdef IRQSTATS
286         .global _C_LABEL(intrnames), _C_LABEL(eintrnames)
287         .global _C_LABEL(eintrcnt)
288 _C_LABEL(intrnames): 
289 _C_LABEL(eintrnames):
290 _C_LABEL(eintrcnt):
292         .globl  _C_LABEL(intrcnt), _C_LABEL(sintrcnt)
294 _C_LABEL(intrcnt):
295         .space  ICU_LEN*4  /* XXX Should be linked to number of interrupts */
297 _C_LABEL(sintrcnt):
298         .space 32*4
299 #endif