1/*
2 *  arch/mips/ddb5074/int-handler.S -- NEC DDB Vrc-5074 interrupt handler
3 *
4 *  Based on arch/mips/sgi/kernel/indyIRQ.S
5 *
6 *  Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
7 *
8 *  Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
9 *                     Sony Software Development Center Europe (SDCE), Brussels
10 */
11#include <asm/asm.h>
12#include <asm/mipsregs.h>
13#include <asm/regdef.h>
14#include <asm/stackframe.h>
15
16/* A lot of complication here is taken away because:
17 *
18 * 1) We handle one interrupt and return, sitting in a loop and moving across
19 *    all the pending IRQ bits in the cause register is _NOT_ the answer, the
20 *    common case is one pending IRQ so optimize in that direction.
21 *
22 * 2) We need not check against bits in the status register IRQ mask, that
23 *    would make this routine slow as hell.
24 *
25 * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
26 *    between like BSD spl() brain-damage.
27 *
28 * Furthermore, the IRQs on the INDY look basically (barring software IRQs
29 * which we don't use at all) like:
30 *
31 *	MIPS IRQ	Source
32 *      --------        ------
33 *             0	Software (ignored)
34 *             1        Software (ignored)
35 *             2        Local IRQ level zero
36 *             3        Local IRQ level one
37 *             4        8254 Timer zero
38 *             5        8254 Timer one
39 *             6        Bus Error
40 *             7        R4k timer (what we use)
41 *
42 * We handle the IRQ according to _our_ priority which is:
43 *
44 * Highest ----     R4k Timer
45 *                  Local IRQ zero
46 *                  Local IRQ one
47 *                  Bus Error
48 *                  8254 Timer zero
49 * Lowest  ----     8254 Timer one
50 *
51 * then we just return, if multiple IRQs are pending then we will just take
52 * another exception, big deal.
53 */
54
55	.text
56	.set	noreorder
57	.set	noat
58	.align	5
59	NESTED(ddbIRQ, PT_SIZE, sp)
60	SAVE_ALL
61	CLI
62	.set	at
63	mfc0	s0, CP0_CAUSE		# get irq mask
64
65	mfc0	t2,CP0_STATUS		# get enabled interrupts
66	and	s0,t2			# isolate allowed ones
67	/* First we check for r4k counter/timer IRQ. */
68	andi	a0, s0, CAUSEF_IP2	# delay slot, check local level zero
69	beq	a0, zero, 1f
70	 andi	a0, s0, CAUSEF_IP3	# delay slot, check local level one
71
72	/* Wheee, local level zero interrupt. */
73	jal	ddb_local0_irqdispatch
74	 move	a0, sp			# delay slot
75
76	j	ret_from_irq
77	 nop				# delay slot
78
791:
80	beq	a0, zero, 1f
81	 andi	a0, s0, CAUSEF_IP6	# delay slot, check bus error
82
83	/* Wheee, local level one interrupt. */
84	move	a0, sp
85	jal	ddb_local1_irqdispatch
86	 nop
87
88	j	ret_from_irq
89	 nop
90
911:
92	beq	a0, zero, 1f
93	 nop
94
95	/* Wheee, an asynchronous bus error... */
96	move	a0, sp
97	jal	ddb_buserror_irq
98	 nop
99
100	j	ret_from_irq
101	 nop
102
1031:
104	/* Here by mistake?  This is possible, what can happen
105	 * is that by the time we take the exception the IRQ
106	 * pin goes low, so just leave if this is the case.
107	 */
108	andi	a0, s0, (CAUSEF_IP4 | CAUSEF_IP5)
109	beq	a0, zero, 1f
110
111	/* Must be one of the 8254 timers... */
112	move	a0, sp
113	jal	ddb_8254timer_irq
114	 nop
1151:
116	j	ret_from_irq
117	 nop
118	END(ddbIRQ)
119