xref: /netbsd/sys/arch/arm/sa11x0/sa11x0_irq.S (revision bf9ec67e)
1/*	$NetBSD: sa11x0_irq.S,v 1.2 2002/04/12 18:50:32 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 <hpcarm/sa11x0/sa11x0_reg.h>
47
48
49	.text
50	.align 0
51
52Lcurrent_spl_level:
53	.word	_C_LABEL(current_spl_level)
54
55Lcurrent_intr_depth:
56	.word	_C_LABEL(current_intr_depth)
57
58Lspl_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
66Ldbg_str:
67	.asciz	"irq_entry %x %x\n"
68#endif
69
70/*
71 * Regsister usage
72 *
73 *  r6  - Address of current handler
74 *  r7  - Pointer to handler pointer list
75 *  r8  - Current IRQ requests.
76 *  r9  - Used to count through possible IRQ bits.
77 *  r10 - Base address of SAIP
78 */
79
80ASENTRY_NP(irq_entry)
81	sub	lr, lr, #0x00000004	/* Adjust the lr */
82
83	PUSHFRAMEINSVC			/* Push an interrupt frame */
84
85	/* Load r8 with the SAIPIC interrupt requests */
86
87	ldr	r10, [pc, #_C_LABEL(saipic_base) - . - 8]
88	ldr	r8, [r10, #(SAIPIC_IP)]	/* Load IRQ pending register */
89
90#ifdef INTR_DEBUG
91	ldr	r2, [r10, #(SAIPIC_MR)]
92	add	r0, pc, #Ldbg_str - . - 8
93	mov	r1, r8
94	bl	_C_LABEL(printf)
95#endif
96	/*
97	 * Note that we have entered the IRQ handler.
98	 * We are in SVC mode so we cannot use the processor mode
99	 * to determine if we are in an IRQ. Instead we will count the
100	 * each time the interrupt handler is nested.
101	 */
102
103	ldr	r0, Lcurrent_intr_depth
104	ldr	r1, [r0]
105	add	r1, r1, #1
106	str	r1, [r0]
107
108	/*
109 	 * Need to block all interrupts at the IPL or lower for
110	 * all asserted interrupts.
111	 * This basically emulates hardware interrupt priority levels.
112	 * Means we need to go through the interrupt mask and for
113	 * every asserted interrupt we need to mask out all other
114	 * interrupts at the same or lower IPL.
115	 * If only we could wait until the main loop but we need to sort
116	 * this out first so interrupts can be re-enabled.
117	 *
118	 * This would benefit from a special ffs type routine
119	 */
120
121	mov	r9, #(_SPL_LEVELS - 1)
122	ldr	r7, Lspl_masks
123
124Lfind_highest_ipl:
125	ldr	r2, [r7, r9, lsl #2]
126	tst	r8, r2
127	subeq	r9, r9, #1
128	beq	Lfind_highest_ipl
129
130	/* r9 = SPL level of highest priority interrupt */
131	add	r9, r9, #1
132	ldr	r2, [r7, r9, lsl #2]
133	mvn	r2, r2
134
135	ldr	r0, Lcurrent_spl_level
136	ldr	r1, [r0]
137	str	r9, [r0]
138	stmfd	sp!, {r1}
139
140	/* Update the SAIP irq masks */
141	bl	_C_LABEL(irq_setmasks)
142
143#ifdef INTR_DEBUG
144	stmfd	sp!, {r0,r1,r2}
145	add	r0, pc, #Ldbg_str - . - 8
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 IRQ's */
152	bic	r0, r0, #I32_bit
153	msr	cpsr_all, r0
154
155	ldr	r7, [pc, #Lirqhandlers - . - 8]
156        mov	r9, #0x00000001
157
158irqloop:
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 */
162
163	ldr	r6, [r7]		/* Get address of first handler structure */
164
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 */
168
169        ldr	r0, Lcnt		/* Stat info */
170	ldr	r1, [r0, #(V_INTR)]
171	add	r1, r1, #0x00000001
172	str	r1, [r0, #(V_INTR)]
173
174	/*
175	 * XXX: Should stats be accumlated for every interrupt routine
176	 * called or for every physical interrupt that is serviced.
177	 */
178
179#ifdef IRQSTATS
180	ldr	r0, Lintrcnt
181	ldr	r1, [r6, #(IH_COUNT)]
182
183	add	r0, r0, r1, lsl #2
184	ldr	r1, [r0]
185	add	r1, r1, #0x00000001
186	str	r1, [r0]
187#endif	/* IRQSTATS */
188
189irqchainloop:
190#ifdef INTR_DEBUG
191	stmfd	sp!, {r0,r1,r2}
192	add	r0, pc, #Ldbg_str - . - 8
193	mov	r1, #2
194	bl	_C_LABEL(printf)
195	ldmia	sp!, {r0,r1,r2}
196#endif
197	add	lr, pc, #nextinchain - . - 8	/* return address */
198	ldr	r0, [r6, #(IH_ARG)]	/* Get argument pointer */
199	teq	r0, #0x00000000		/* If arg is zero pass stack frame */
200	addeq	r0, sp, #4		/* ... stack frame [XXX needs care] */
201	ldr	pc, [r6, #(IH_FUNC)]	/* Call handler */
202
203nextinchain:
204	teq	r0, #0x00000001		/* Was the irq serviced ? */
205	beq	irqdone
206
207	ldr	r6, [r6, #(IH_NEXT)]
208	teq	r6, #0x00000000
209	bne	irqchainloop
210
211irqdone:
212nextirq:
213	add	r7, r7, #0x00000004	/* update pointer to handlers */
214	mov	r9, r9, lsl #1		/* move on to next bit */
215	teq	r9, #(1 << 31)		/* done the last bit ? */
216	bne	irqloop			/* no - loop back. */
217
218	ldmfd	sp!, {r2}
219	ldr	r1, Lcurrent_spl_level
220	str	r2, [r1]
221
222	/* Restore previous disabled mask */
223	bl	_C_LABEL(irq_setmasks)
224
225	bl	_C_LABEL(dosoftints)	/* Handle the soft interrupts */
226
227	/* Manage AST's. Maybe this should be done as a soft interrupt ? */
228	ldr	r0, [sp]		/* Get the SPSR from stack */
229
230	and	r0, r0, #(PSR_MODE)	/* Test for USR32 mode before the IRQ */
231	teq	r0, #(PSR_USR32_MODE)
232	ldreq	r0, Lastpending		/* Do we have an AST pending ? */
233	ldreq	r1, [r0]
234	teqeq	r1, #0x00000001
235
236	beq	irqast			/* call the AST handler */
237
238	/* Kill IRQ's in preparation for exit */
239        mrs     r0, cpsr_all
240        orr     r0, r0, #(I32_bit)
241        msr     cpsr_all, r0
242
243#ifdef INTR_DEBUG
244	add	r0, pc, #Ldbg_str - . - 8
245	mov	r1, #3
246	ldr	r2, [r10, #(SAIPIC_MR)]
247	bl	_C_LABEL(printf)
248#endif
249
250	/* Decrement the nest count */
251	ldr	r0, Lcurrent_intr_depth
252	ldr	r1, [r0]
253	sub	r1, r1, #1
254	str	r1, [r0]
255
256	PULLFRAMEFROMSVCANDEXIT
257
258	/* NOT REACHED */
259	b	. - 8
260
261	/*
262	 * Ok, snag with current intr depth ...
263	 * If ast() calls mi_sleep() the current_intr_depth will not be
264	 * decremented until the process is woken up. This can result
265	 * in the system believing it is still in the interrupt handler.
266	 * If we are calling ast() then correct the current_intr_depth
267	 * before the call.
268	 */
269irqast:
270	mov	r1, #0x00000000		/* Clear ast_pending */
271	str	r1, [r0]
272
273	/* Kill IRQ's so we atomically decrement current_intr_depth */
274        mrs     r2, cpsr_all
275        orr     r3, r2, #(I32_bit)
276        msr     cpsr_all, r3
277
278	/* Decrement the interrupt nesting count */
279	ldr	r0, Lcurrent_intr_depth
280	ldr	r1, [r0]
281	sub	r1, r1, #1
282	str	r1, [r0]
283
284	/* Restore IRQ's */
285        msr     cpsr_all, r2
286
287	mov	r0, sp
288	bl	_C_LABEL(ast)
289
290	/* Kill IRQ's in preparation for exit */
291        mrs     r0, cpsr_all
292        orr     r0, r0, #(I32_bit)
293        msr     cpsr_all, r0
294
295	PULLFRAMEFROMSVCANDEXIT
296
297	/* NOT REACHED */
298	b	. - 8
299
300
301ENTRY(irq_setmasks)
302	/* Disable interrupts */
303	mrs	r3, cpsr_all
304	orr	r1, r3,  #(I32_bit)
305	msr	cpsr_all, r1
306
307	/* Calculate interrupt mask */
308	ldr	r0, Lspl_masks
309	ldr	r2, Lcurrent_spl_level
310	ldr	r2, [r2]
311	ldr	r2, [r0, r2, lsl #2]
312
313	ldr	r0, [pc, #_C_LABEL(saipic_base) - . - 8]
314	str	r2, [r0, #(SAIPIC_MR)]	/* Set mask register */
315
316	/* Restore old cpsr and exit */
317	msr	cpsr_all, r3
318	mov	pc, lr
319
320Lcnt:
321	.word	_C_LABEL(uvmexp)
322
323#ifdef IRQSTATS
324Lintrcnt:
325	.word	_C_LABEL(intrcnt)
326#endif
327
328Lirqhandlers:
329	.word	_C_LABEL(irqhandlers)	/* Pointer to array of irqhandlers */
330
331Lastpending:
332	.word	_C_LABEL(astpending)
333
334
335
336#ifdef IRQSTATS
337	.globl	_C_LABEL(intrcnt), _C_LABEL(sintrcnt)
338
339_C_LABEL(intrcnt):
340	.space	ICU_LEN*4  /* XXX Should be linked to number of interrupts */
341
342_C_LABEL(sintrcnt):
343	.space 32*4
344#endif
345