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