1104074Sjake/*-
2104074Sjake * Copyright (c) 2002 Jake Burkholder.
3104074Sjake * All rights reserved.
4104074Sjake *
5104074Sjake * Redistribution and use in source and binary forms, with or without
6104074Sjake * modification, are permitted provided that the following conditions
7104074Sjake * are met:
8104074Sjake * 1. Redistributions of source code must retain the above copyright
9104074Sjake *    notice, this list of conditions and the following disclaimer.
10104074Sjake * 2. Redistributions in binary form must reproduce the above copyright
11104074Sjake *    notice, this list of conditions and the following disclaimer in the
12104074Sjake *    documentation and/or other materials provided with the distribution.
13104074Sjake *
14104074Sjake * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15104074Sjake * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16104074Sjake * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17104074Sjake * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18104074Sjake * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19104074Sjake * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20104074Sjake * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21104074Sjake * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22104074Sjake * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23104074Sjake * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24104074Sjake * SUCH DAMAGE.
25104074Sjake */
26104074Sjake
27114188Sjake#include <machine/asm.h>
28114188Sjake__FBSDID("$FreeBSD$");
29114188Sjake
30104074Sjake#include <machine/asi.h>
31104074Sjake#include <machine/asmacros.h>
32166105Smarius#include <machine/intr_machdep.h>
33104074Sjake#include <machine/pstate.h>
34223721Smarius#include <machine/ver.h>
35104074Sjake
36104074Sjake#include "assym.s"
37104074Sjake
38104074Sjake/*
39104074Sjake * Handle a vectored interrupt.
40104074Sjake *
41104074Sjake * This is either a data bearing mondo vector interrupt, or a cross trap
42104074Sjake * request from another cpu.  In either case the hardware supplies an
43104074Sjake * interrupt packet, in the form of 3 data words which are read from internal
44104074Sjake * registers.  A data bearing mondo vector packet consists of an interrupt
45104074Sjake * number in the first data word, and zero in 2nd and 3rd.  We use the
46104074Sjake * interrupt number to find the function, argument and priority from the
47104074Sjake * intr_vector table, allocate and fill in an intr_request from the per-cpu
48104074Sjake * free list, link it onto the per-cpu active list and finally post a softint
49104074Sjake * at the desired priority.  Cross trap requests come in 2 forms, direct
50104074Sjake * and queued.  Direct requests are distinguished by the first data word
51104074Sjake * being zero.  The 2nd data word carries a function to call and the 3rd
52104074Sjake * an argument to pass.  The function is jumped to directly.  It executes
53104074Sjake * in nucleus context on interrupt globals and with all interrupts disabled,
54104074Sjake * therefore it must be fast, and the things that it can do are limited.
55104074Sjake * Queued cross trap requests are handled much like mondo vectors, except
56104074Sjake * that the function, argument and priority are contained in the interrupt
57104074Sjake * packet itself.  They are distinguished by the upper 4 bits of the data
58104074Sjake * word being non-zero, which specifies the priority of the softint to
59104074Sjake * deliver.
60104074Sjake *
61104074Sjake * Register usage:
62104074Sjake *	%g1 - pointer to intr_request
63104074Sjake *	%g2 - pointer to intr_vector, temp once required data is loaded
64104074Sjake *	%g3 - interrupt number for mondo vectors, unused otherwise
65104074Sjake *	%g4 - function, from the interrupt packet for cross traps, or
66104074Sjake *	      loaded from the interrupt registers for mondo vecors
67104074Sjake *	%g5 - argument, as above for %g4
68104074Sjake *	%g6 - softint priority
69104074Sjake */
70104075SjakeENTRY(intr_vector)
71104074Sjake	/*
72104074Sjake	 * Load the interrupt packet from the hardware.
73104074Sjake	 */
74104074Sjake	wr	%g0, ASI_SDB_INTR_R, %asi
75104074Sjake	ldxa	[%g0 + AA_SDB_INTR_D0] %asi, %g3
76104074Sjake	ldxa	[%g0 + AA_SDB_INTR_D1] %asi, %g4
77104074Sjake	ldxa	[%g0 + AA_SDB_INTR_D2] %asi, %g5
78104074Sjake	stxa	%g0, [%g0] ASI_INTR_RECEIVE
79104074Sjake	membar	#Sync
80104074Sjake
81104074Sjake	/*
82104074Sjake	 * If the first data word is zero this is a direct cross trap request.
83104074Sjake	 * The 2nd word points to code to execute and the 3rd is an argument
84104074Sjake	 * to pass.  Jump to it.
85104074Sjake	 */
86245017Smarius	brnz,pt %g3, 1f
87207500Smarius	/*
88207500Smarius	 * NB: Zeus CPUs set some undocumented bits in the first data word.
89207500Smarius	 */
90245017Smarius	 and	%g3, IV_MAX - 1, %g3
91241740Smarius	jmpl	%g4, %g0
92245017Smarius	 nop
93104074Sjake	/* NOTREACHED */
94104074Sjake
95104074Sjake	/*
96104074Sjake	 * If the high 4 bits of the 1st data word are non-zero, this is a
97104074Sjake	 * queued cross trap request to be delivered as a softint.  The high
98104074Sjake	 * 4 bits of the 1st data word specify a priority, and the 2nd and
99104074Sjake	 * 3rd a function and argument.
100104074Sjake	 */
101245017Smarius1:	srlx	%g3, 60, %g6
102245017Smarius	brnz,a,pn %g6, 2f
103104074Sjake	 clr	%g3
104104074Sjake
105104074Sjake	/*
106104074Sjake	 * Find the function, argument and desired priority from the
107104074Sjake	 * intr_vector table.
108104074Sjake	 */
109104074Sjake	SET(intr_vectors, %g4, %g2)
110104074Sjake	sllx	%g3, IV_SHIFT, %g4
111104074Sjake	add	%g2, %g4, %g2
112104074Sjake
113104074Sjake	ldx	[%g2 + IV_FUNC], %g4
114104074Sjake	ldx	[%g2 + IV_ARG], %g5
115104074Sjake	lduw	[%g2 + IV_PRI], %g6
116104074Sjake
117104074Sjake	/*
118108533Sschweikh	 * Get an intr_request from the free list.  There should always be one
119104074Sjake	 * unless we are getting an interrupt storm from stray interrupts, in
120104074Sjake	 * which case the we will deference a NULL pointer and panic.
121104074Sjake	 */
122104074Sjake2:	ldx	[PCPU(IRFREE)], %g1
123104074Sjake	ldx	[%g1 + IR_NEXT], %g2
124104074Sjake	stx	%g2, [PCPU(IRFREE)]
125104074Sjake
126104074Sjake	/*
127104074Sjake	 * Store the vector number, function, argument and priority.
128104074Sjake	 */
129104074Sjake	stw	%g3, [%g1 + IR_VEC]
130104074Sjake	stx	%g4, [%g1 + IR_FUNC]
131104074Sjake	stx	%g5, [%g1 + IR_ARG]
132104074Sjake	stw	%g6, [%g1 + IR_PRI]
133104074Sjake
134104074Sjake	/*
135104074Sjake	 * Link it onto the end of the active list.
136104074Sjake	 */
137104074Sjake	stx	%g0, [%g1 + IR_NEXT]
138104074Sjake	ldx	[PCPU(IRTAIL)], %g4
139104074Sjake	stx	%g1, [%g4]
140104074Sjake	add	%g1, IR_NEXT, %g1
141104074Sjake	stx	%g1, [PCPU(IRTAIL)]
142104074Sjake
143104074Sjake	/*
144104074Sjake	 * Trigger a softint at the level indicated by the priority.
145104074Sjake	 */
146104074Sjake	mov	1, %g1
147104074Sjake	sllx	%g1, %g6, %g1
148108379Sjake	wr	%g1, 0, %set_softint
149104074Sjake
150104074Sjake	/*
151104074Sjake	 * Done, retry the instruction.
152104074Sjake	 */
153104074Sjake	retry
154104075SjakeEND(intr_vector)
155104074Sjake
156223721SmariusENTRY(intr_vector_stray)
157223721Smarius	/*
158223721Smarius	 * SPARC64-VI trigger stray vector interrupts in order to indicate
159223721Smarius	 * uncorrectable errors in interrupt packets, which still need to be
160223721Smarius	 * acknowledged though.
161223721Smarius	 * US-IV occasionally trigger stray vector interrupts for reasons
162223721Smarius	 * unknown accompanied by a state in which they even fault on locked
163223721Smarius	 * TLB entries so we can't even log these here.  Just retrying the
164223721Smarius	 * instruction in that case gets the CPU back on track.
165223721Smarius	 */
166223721Smarius	rdpr	%ver, %g1
167223721Smarius	srlx	%g1, VER_IMPL_SHIFT, %g1
168223721Smarius	sll	%g1, VER_IMPL_SIZE, %g1
169223721Smarius	srl	%g1, VER_IMPL_SIZE, %g1
170223721Smarius	cmp	%g1, CPU_IMPL_SPARC64VI
171223721Smarius	bne,a,pn %icc, 1f
172223721Smarius	 nop
173223721Smarius	stxa	%g0, [%g0] ASI_INTR_RECEIVE
174223721Smarius	membar	#Sync
175223721Smarius
176223721Smarius1:	retry
177223721SmariusEND(intr_vector_stray)
178223721Smarius
179104075SjakeENTRY(intr_fast)
180104074Sjake	save	%sp, -CCFSZ, %sp
181104074Sjake
182157825Smarius	/*
183157825Smarius	 * Disable interrupts while we fiddle with the interrupt request lists
184157825Smarius	 * as interrupts at levels higher than what got us here aren't blocked.
185157825Smarius	 */
186157825Smarius1:	wrpr	%g0, PSTATE_NORMAL, %pstate
187157825Smarius
188157825Smarius	ldx	[PCPU(IRHEAD)], %l0
189104074Sjake	brnz,a,pt %l0, 2f
190104074Sjake	 nop
191104074Sjake
192157825Smarius	wrpr	%g0, PSTATE_KERNEL, %pstate
193157825Smarius
194104074Sjake	ret
195104074Sjake	 restore
196104074Sjake
197157825Smarius2:	ldx	[%l0 + IR_NEXT], %l1
198104074Sjake	brnz,pt	%l1, 3f
199104074Sjake	 stx	%l1, [PCPU(IRHEAD)]
200104074Sjake	PCPU_ADDR(IRHEAD, %l1)
201104074Sjake	stx	%l1, [PCPU(IRTAIL)]
202104074Sjake
203104074Sjake3:	ldx	[%l0 + IR_FUNC], %o0
204104074Sjake	ldx	[%l0 + IR_ARG], %o1
205200914Smarius	lduw	[%l0 + IR_VEC], %l2
206104074Sjake
207157825Smarius	ldx	[PCPU(IRFREE)], %l1
208157825Smarius	stx	%l1, [%l0 + IR_NEXT]
209157825Smarius	stx	%l0, [PCPU(IRFREE)]
210157825Smarius
211157825Smarius	wrpr	%g0, PSTATE_KERNEL, %pstate
212157825Smarius
213157825Smarius	KASSERT(%o0, "intr_fast: ir_func null")
214157825Smarius	call	%o0
215157825Smarius	 mov	%o1, %o0
216157825Smarius
217200914Smarius	/* intrcnt[intr_countp[%l2]]++ */
218200914Smarius	SET(intrcnt, %l7, %l3)		/* %l3 = intrcnt */
219200914Smarius	prefetcha [%l3] ASI_N, 1
220200914Smarius	SET(intr_countp, %l7, %l4)	/* %l4 = intr_countp */
221200914Smarius	sllx	%l2, 1, %l2		/* %l2 = vec << 1 */
222200914Smarius	lduh	[%l4 + %l2], %l4	/* %l4 = intr_countp[%l2] */
223200914Smarius	sllx	%l4, 3, %l4		/* %l4 = intr_countp[%l2] << 3 */
224200914Smarius	add	%l4, %l3, %l4		/* %l4 = intrcnt[intr_countp[%l2]] */
225200914Smarius	ldx	[%l4], %l2
226145153Smarius	inc	%l2
227200914Smarius	stx	%l2, [%l4]
228117658Sjmg
229104074Sjake	ba,a	%xcc, 1b
230104074Sjake	 nop
231104075SjakeEND(intr_fast)
232