xref: /netbsd-src/sys/arch/arm/sa11x0/sa11x0_irq.S (revision 22949965b74e822d5528c56d17c0501f79d9a367)
1/*	$NetBSD: sa11x0_irq.S,v 1.21 2021/11/08 23:57:23 rin 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
44#include <arm/asm.h>
45#include <arm/locore.h>
46#include <arm/sa11x0/sa11x0_reg.h>
47
48
49	.text
50	.align 0
51
52Lspl_masks:
53	.word	_C_LABEL(spl_masks)
54
55Lcpu_info_store:
56        .word   _C_LABEL(cpu_info_store)
57
58	.globl	_C_LABEL(saipic_base)
59_C_LABEL(saipic_base):
60	.word	0x00000000
61
62#ifdef INTR_DEBUG
63Ldbg_str:
64	.asciz	"irq_entry %x %x\n"
65	.align 5
66#endif
67
68LOCK_CAS_CHECK_LOCALS
69
70AST_ALIGNMENT_FAULT_LOCALS
71
72/*
73 * Register usage
74 *
75 *  r4  - Pointer to curcpu
76 *  r5  - pointer to curlwp
77 *  r6  - Address of current handler
78 *  r7	- pspr mode
79 *  r8  - Current IRQ requests.
80 *  r9  - Used to count through possible IRQ bits.
81 *  r10 - Pointer to handler pointer list
82 */
83
84ASENTRY_NP(irq_entry)
85	sub	lr, lr, #0x00000004	/* Adjust the lr */
86
87	PUSHFRAMEINSVC			/* Push an interrupt frame */
88	ENABLE_ALIGNMENT_FAULTS		/* puts cur{cpu,lwp} in r4/r5 */
89
90	/* Load r8 with the SAIPIC interrupt requests */
91
92	ldr	r8, _C_LABEL(saipic_base)
93	ldr	r8, [r8, #(SAIPIC_IP)]	/* Load IRQ pending register */
94
95#ifdef INTR_DEBUG
96	adr	r0, Ldbg_str
97	mov	r1, r8
98	ldr	r2, _C_LABEL(saipic_base)
99	ldr	r2, [r2, #(SAIPIC_MR)]
100	bl	_C_LABEL(printf)
101#endif
102	/*
103	 * Note that we have entered the IRQ handler.
104	 * We are in SVC mode so we cannot use the processor mode
105	 * to determine if we are in an IRQ. Instead we will count the
106	 * each time the interrupt handler is nested.
107	 */
108
109	ldr	r1, [r4, #CI_INTR_DEPTH]
110	add	r1, r1, #1
111	str	r1, [r4, #CI_INTR_DEPTH]
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, #(NIPL - 1)
127	ldr	r10, Lspl_masks
128
129Lfind_highest_ipl:
130	ldr	r2, [r10, 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, [r10, r9, lsl #2]
138
139	ldr	r1, [r4, #CI_CPL]
140	str	r9, [r4, #CI_CPL]
141	stmfd	sp!, {r1}
142
143	/* Update the SAIP irq masks */
144	bl	_C_LABEL(irq_setmasks)
145
146#ifdef INTR_DEBUG
147	stmfd	sp!, {r0,r1,r2}
148	adr	r0, Ldbg_str
149	mov	r1, #1
150	mov	r2, r9
151	bl	_C_LABEL(printf)
152	ldmia	sp!, {r0,r1,r2}
153#endif
154        mrs     r0, cpsr		/* Enable IRQs */
155	bic	r0, r0, #I32_bit
156	msr	cpsr_all, r0
157
158	ldr	r10, Lirqhandlers
159        mov	r9, #0x00000001
160
161irqloop:
162	/* This would benefit from a special ffs type routine */
163	tst	r8, r9			/* Is a bit set ? */
164	beq	nextirq			/* No ? try next bit */
165
166	ldr	r6, [r10]		/* Get address of first handler structure */
167
168	teq	r6, #0x00000000		/* Do we have a handler */
169	moveq	r0, r8			/* IRQ requests as arg 0 */
170	beq	_C_LABEL(stray_irqhandler) /* call special handler */
171
172	ldr	r0, [r4, #(CI_CC_NINTR)]
173	ldr	r1, [r4, #(CI_CC_NINTR+4)]
174#ifdef _ARMEL
175	adds	r0, r0, #0x00000001
176	adc	r1, r1, #0x00000001
177#else
178	adds	r1, r1, #0x00000001
179	adc	r0, r0, #0x00000000
180#endif
181	str	r0, [r4, #(CI_CC_NINTR)]
182	str	r1, [r4, #(CI_CC_NINTR+4)]
183
184	/*
185	 * XXX: Should stats be accumulated for every interrupt routine
186	 * called or for every physical interrupt that is serviced.
187	 */
188
189#ifdef IRQSTATS
190	ldr	r0, Lintrcnt
191	ldr	r1, [r6, #(IH_COUNT)]
192
193	add	r0, r0, r1, lsl #2
194	ldr	r1, [r0]
195	add	r1, r1, #0x00000001
196	str	r1, [r0]
197#endif	/* IRQSTATS */
198
199irqchainloop:
200#ifdef INTR_DEBUG
201	stmfd	sp!, {r0,r1,r2}
202	adr	r0, Ldbg_str
203	mov	r1, #2
204	bl	_C_LABEL(printf)
205	ldmia	sp!, {r0,r1,r2}
206#endif
207	ldr	r0, [r6, #(IH_ARG)]	/* Get argument pointer */
208	teq	r0, #0x00000000		/* If arg is zero pass stack frame */
209	addeq	r0, sp, #4		/* ... stack frame [XXX needs care] */
210	mov	lr, pc			/* return address */
211	ldr	pc, [r6, #(IH_FUNC)]	/* Call handler */
212
213	teq	r0, #0x00000001		/* Was the irq serviced ? */
214	beq	irqdone
215
216	ldr	r6, [r6, #(IH_NEXT)]
217	teq	r6, #0x00000000
218	bne	irqchainloop
219
220irqdone:
221nextirq:
222	add	r10, r10, #0x00000004	/* update pointer to handlers */
223	mov	r9, r9, lsl #1		/* move on to next bit */
224	teq	r9, #(1 << 31)		/* done the last bit ? */
225	bne	irqloop			/* no - loop back. */
226
227	ldmfd	sp!, {r2}
228	str	r2, [r4, #CI_CPL]
229
230	/* Restore previous disabled mask */
231	bl	_C_LABEL(irq_setmasks)
232
233	/* Kill IRQ's in preparation for exit */
234        mrs     r0, cpsr
235        orr     r0, r0, #(I32_bit)
236        msr     cpsr_all, r0
237
238#ifdef INTR_DEBUG
239	adr	r0, Ldbg_str
240	mov	r1, #3
241	ldr	r2, _C_LABEL(saipic_base)
242	ldr	r2, [r2, #(SAIPIC_MR)]
243	bl	_C_LABEL(printf)
244#endif
245
246	/* Decrement the nest count */
247	ldr	r1, [r4, #CI_INTR_DEPTH]
248	sub	r1, r1, #1
249	str	r1, [r4, #CI_INTR_DEPTH]
250
251	LOCK_CAS_CHECK
252
253	DO_AST_AND_RESTORE_ALIGNMENT_FAULTS
254	PULLFRAMEFROMSVCANDEXIT
255
256	/* NOT REACHED */
257	b	. - 8
258
259ENTRY(irq_setmasks)
260	stmfd	sp!, {r0, r1, r4, lr}	/* Preserve registers */
261
262	/* Disable interrupts */
263	mrs	r1, cpsr
264	orr	r3, r1,  #(I32_bit)
265	msr	cpsr_all, r3
266
267	/* Calculate interrupt mask */
268	ldr	r0, Lspl_masks
269	ldr	r4, Lcpu_info_store
270	ldr	r2, [r4, #CI_CPL]
271	ldr	r2, [r0, r2, lsl #2]
272
273	ldr	r0, _C_LABEL(saipic_base)
274	str	r2, [r0, #(SAIPIC_MR)]	/* Set mask register */
275
276	/* Restore old cpsr and exit */
277	msr	cpsr_all, r1
278	ldmia	sp!, {r0, r1, r4, pc}	/* Restore registers */
279
280#ifdef IRQSTATS
281Lintrcnt:
282	.word	_C_LABEL(intrcnt)
283#endif
284
285Lirqhandlers:
286	.word	_C_LABEL(irqhandlers)	/* Pointer to array of irqhandlers */
287
288
289#ifdef IRQSTATS
290	.global _C_LABEL(intrnames), _C_LABEL(eintrnames)
291	.global _C_LABEL(eintrcnt)
292_C_LABEL(intrnames):
293_C_LABEL(eintrnames):
294_C_LABEL(eintrcnt):
295
296	.globl	_C_LABEL(intrcnt), _C_LABEL(sintrcnt)
297
298_C_LABEL(intrcnt):
299	.space	ICU_LEN*4  /* XXX Should be linked to number of interrupts */
300
301_C_LABEL(sintrcnt):
302	.space 32*4
303#endif
304