xref: /openbmc/linux/arch/mips/dec/int-handler.S (revision 93dc544c)
1/*
2 * arch/mips/dec/int-handler.S
3 *
4 * Copyright (C) 1995, 1996, 1997 Paul M. Antoine and Harald Koerfgen
5 * Copyright (C) 2000, 2001, 2002, 2003, 2005  Maciej W. Rozycki
6 *
7 * Written by Ralf Baechle and Andreas Busse, modified for DECstation
8 * support by Paul Antoine and Harald Koerfgen.
9 *
10 * completly rewritten:
11 * Copyright (C) 1998 Harald Koerfgen
12 *
13 * Rewritten extensively for controller-driven IRQ support
14 * by Maciej W. Rozycki.
15 */
16
17#include <asm/addrspace.h>
18#include <asm/asm.h>
19#include <asm/mipsregs.h>
20#include <asm/regdef.h>
21#include <asm/stackframe.h>
22
23#include <asm/dec/interrupts.h>
24#include <asm/dec/ioasic_addrs.h>
25#include <asm/dec/ioasic_ints.h>
26#include <asm/dec/kn01.h>
27#include <asm/dec/kn02.h>
28#include <asm/dec/kn02xa.h>
29#include <asm/dec/kn03.h>
30
31#define KN02_CSR_BASE		CKSEG1ADDR(KN02_SLOT_BASE + KN02_CSR)
32#define KN02XA_IOASIC_BASE	CKSEG1ADDR(KN02XA_SLOT_BASE + IOASIC_IOCTL)
33#define KN03_IOASIC_BASE	CKSEG1ADDR(KN03_SLOT_BASE + IOASIC_IOCTL)
34
35		.text
36		.set	noreorder
37/*
38 * plat_irq_dispatch: Interrupt handler for DECstations
39 *
40 * We follow the model in the Indy interrupt code by David Miller, where he
41 * says: a lot of complication here is taken away because:
42 *
43 * 1) We handle one interrupt and return, sitting in a loop
44 *    and moving across all the pending IRQ bits in the cause
45 *    register is _NOT_ the answer, the common case is one
46 *    pending IRQ so optimize in that direction.
47 *
48 * 2) We need not check against bits in the status register
49 *    IRQ mask, that would make this routine slow as hell.
50 *
51 * 3) Linux only thinks in terms of all IRQs on or all IRQs
52 *    off, nothing in between like BSD spl() brain-damage.
53 *
54 * Furthermore, the IRQs on the DECstations look basically (barring
55 * software IRQs which we don't use at all) like...
56 *
57 * DS2100/3100's, aka kn01, aka Pmax:
58 *
59 *	MIPS IRQ	Source
60 *      --------        ------
61 *             0	Software (ignored)
62 *             1        Software (ignored)
63 *             2        SCSI
64 *             3        Lance Ethernet
65 *             4        DZ11 serial
66 *             5        RTC
67 *             6        Memory Controller & Video
68 *             7        FPU
69 *
70 * DS5000/200, aka kn02, aka 3max:
71 *
72 *	MIPS IRQ	Source
73 *      --------        ------
74 *             0	Software (ignored)
75 *             1        Software (ignored)
76 *             2        TurboChannel
77 *             3        RTC
78 *             4        Reserved
79 *             5        Memory Controller
80 *             6        Reserved
81 *             7        FPU
82 *
83 * DS5000/1xx's, aka kn02ba, aka 3min:
84 *
85 *	MIPS IRQ	Source
86 *      --------        ------
87 *             0	Software (ignored)
88 *             1        Software (ignored)
89 *             2        TurboChannel Slot 0
90 *             3        TurboChannel Slot 1
91 *             4        TurboChannel Slot 2
92 *             5        TurboChannel Slot 3 (ASIC)
93 *             6        Halt button
94 *             7        FPU/R4k timer
95 *
96 * DS5000/2x's, aka kn02ca, aka maxine:
97 *
98 *	MIPS IRQ	Source
99 *      --------        ------
100 *             0	Software (ignored)
101 *             1        Software (ignored)
102 *             2        Periodic Interrupt (100usec)
103 *             3        RTC
104 *             4        I/O write timeout
105 *             5        TurboChannel (ASIC)
106 *             6        Halt Keycode from Access.Bus keyboard (CTRL-ALT-ENTER)
107 *             7        FPU/R4k timer
108 *
109 * DS5000/2xx's, aka kn03, aka 3maxplus:
110 *
111 *	MIPS IRQ	Source
112 *      --------        ------
113 *             0	Software (ignored)
114 *             1        Software (ignored)
115 *             2        System Board (ASIC)
116 *             3        RTC
117 *             4        Reserved
118 *             5        Memory
119 *             6        Halt Button
120 *             7        FPU/R4k timer
121 *
122 * We handle the IRQ according to _our_ priority (see setup.c),
123 * then we just return.  If multiple IRQs are pending then we will
124 * just take another exception, big deal.
125 */
126		.align	5
127		NESTED(plat_irq_dispatch, PT_SIZE, ra)
128		.set	noreorder
129
130		/*
131		 * Get pending Interrupts
132		 */
133		mfc0	t0,CP0_CAUSE		# get pending interrupts
134		mfc0	t1,CP0_STATUS
135#ifdef CONFIG_32BIT
136		lw	t2,cpu_fpu_mask
137#endif
138		andi	t0,ST0_IM		# CAUSE.CE may be non-zero!
139		and	t0,t1			# isolate allowed ones
140
141		beqz	t0,spurious
142
143#ifdef CONFIG_32BIT
144		 and	t2,t0
145		bnez	t2,fpu			# handle FPU immediately
146#endif
147
148		/*
149		 * Find irq with highest priority
150		 */
151		 PTR_LA	t1,cpu_mask_nr_tbl
1521:		lw	t2,(t1)
153		nop
154		and	t2,t0
155		beqz	t2,1b
156		 addu	t1,2*PTRSIZE		# delay slot
157
158		/*
159		 * Do the low-level stuff
160		 */
161		lw	a0,(-PTRSIZE)(t1)
162		nop
163		bgez	a0,handle_it		# irq_nr >= 0?
164						# irq_nr < 0: it is an address
165		 nop
166		jr	a0
167						# a trick to save a branch:
168		 lui	t2,(KN03_IOASIC_BASE>>16)&0xffff
169						# upper part of IOASIC Address
170
171/*
172 * Handle "IRQ Controller" Interrupts
173 * Masked Interrupts are still visible and have to be masked "by hand".
174 */
175		FEXPORT(kn02_io_int)		# 3max
176		lui	t0,(KN02_CSR_BASE>>16)&0xffff
177						# get interrupt status and mask
178		lw	t0,(t0)
179		nop
180		andi	t1,t0,KN02_IRQ_ALL
181		b	1f
182		 srl	t0,16			# shift interrupt mask
183
184		FEXPORT(kn02xa_io_int)		# 3min/maxine
185		lui	t2,(KN02XA_IOASIC_BASE>>16)&0xffff
186						# upper part of IOASIC Address
187
188		FEXPORT(kn03_io_int)		# 3max+ (t2 loaded earlier)
189		lw	t0,IO_REG_SIR(t2)	# get status: IOASIC sir
190		lw	t1,IO_REG_SIMR(t2)	# get mask:   IOASIC simr
191		nop
192
1931:		and	t0,t1			# mask out allowed ones
194
195		beqz	t0,spurious
196
197		/*
198		 * Find irq with highest priority
199		 */
200		 PTR_LA	t1,asic_mask_nr_tbl
2012:		lw	t2,(t1)
202		nop
203		and	t2,t0
204		beq	zero,t2,2b
205		 addu	t1,2*PTRSIZE		# delay slot
206
207		/*
208		 * Do the low-level stuff
209		 */
210		lw	a0,%lo(-PTRSIZE)(t1)
211		nop
212		bgez	a0,handle_it		# irq_nr >= 0?
213						# irq_nr < 0: it is an address
214		 nop
215		jr	a0
216		 nop				# delay slot
217
218/*
219 * Dispatch low-priority interrupts.  We reconsider all status
220 * bits again, which looks like a lose, but it makes the code
221 * simple and O(log n), so it gets compensated.
222 */
223		FEXPORT(cpu_all_int)		# HALT, timers, software junk
224		li	a0,DEC_CPU_IRQ_BASE
225		srl	t0,CAUSEB_IP
226		li	t1,CAUSEF_IP>>CAUSEB_IP	# mask
227		b	1f
228		 li	t2,4			# nr of bits / 2
229
230		FEXPORT(kn02_all_int)		# impossible ?
231		li	a0,KN02_IRQ_BASE
232		li	t1,KN02_IRQ_ALL		# mask
233		b	1f
234		 li	t2,4			# nr of bits / 2
235
236		FEXPORT(asic_all_int)		# various I/O ASIC junk
237		li	a0,IO_IRQ_BASE
238		li	t1,IO_IRQ_ALL		# mask
239		b	1f
240		 li	t2,8			# nr of bits / 2
241
242/*
243 * Dispatch DMA interrupts -- O(log n).
244 */
245		FEXPORT(asic_dma_int)		# I/O ASIC DMA events
246		li	a0,IO_IRQ_BASE+IO_INR_DMA
247		srl	t0,IO_INR_DMA
248		li	t1,IO_IRQ_DMA>>IO_INR_DMA # mask
249		li	t2,8			# nr of bits / 2
250
251		/*
252		 * Find irq with highest priority.
253		 * Highest irq number takes precedence.
254		 */
2551:		srlv	t3,t1,t2
2562:		xor	t1,t3
257		and	t3,t0,t1
258		beqz	t3,3f
259		 nop
260		move	t0,t3
261		addu	a0,t2
2623:		srl	t2,1
263		bnez	t2,2b
264		 srlv	t3,t1,t2
265
266handle_it:
267		j	dec_irq_dispatch
268		 nop
269
270#ifdef CONFIG_32BIT
271fpu:
272		j	handle_fpe_int
273		 nop
274#endif
275
276spurious:
277		j	spurious_interrupt
278		 nop
279		END(plat_irq_dispatch)
280
281/*
282 * Generic unimplemented interrupt routines -- cpu_mask_nr_tbl
283 * and asic_mask_nr_tbl are initialized to point all interrupts here.
284 * The tables are then filled in by machine-specific initialisation
285 * in dec_setup().
286 */
287		FEXPORT(dec_intr_unimplemented)
288		move	a1,t0			# cheats way of printing an arg!
289		PANIC("Unimplemented cpu interrupt! CP0_CAUSE: 0x%08x");
290
291		FEXPORT(asic_intr_unimplemented)
292		move	a1,t0			# cheats way of printing an arg!
293		PANIC("Unimplemented asic interrupt! ASIC ISR: 0x%08x");
294