1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#include "assym.h"
27
28#include <sys/asm_linkage.h>
29#include <sys/machthread.h>
30#include <sys/machcpuvar.h>
31#include <sys/mmu.h>
32#include <sys/intreg.h>
33#include <sys/dmv.h>
34
35#ifdef TRAPTRACE
36#include <sys/traptrace.h>
37#endif /* TRAPTRACE */
38
39
40vec_uiii_irdr_tab:
41        .byte   UIII_IRDR_0, UIII_IRDR_1, UIII_IRDR_2, UIII_IRDR_3
42        .byte   UIII_IRDR_4, UIII_IRDR_5, UIII_IRDR_6, UIII_IRDR_7
43
44/*
45 * (TT 0x60, TL>0) Interrupt Vector Handler
46 *	Globals are the Interrupt Globals.
47 */
48	ENTRY_NP(vec_interrupt)
49	!
50	! Load the interrupt receive data register 0.
51	! It could be a fast trap handler address (pc > KERNELBASE) at TL>0
52	! or an interrupt number.
53	!
54	mov	IRDR_0, %g2
55	ldxa	[%g2]ASI_INTR_RECEIVE, %g5	! %g5 = PC or Interrupt Number
56
57	! If the high bit of IRDR_0 is set, then this is a
58	! data bearing mondo vector.
59	brlz,pt %g5, dmv_vector
60	.empty
61
62
63vec_interrupt_resume:
64	set	KERNELBASE, %g4
65	cmp	%g5, %g4
66	bl,a,pt	%xcc, 0f			! an interrupt number found
67	  nop
68	!
69	! intercept OBP xcalls and set PCONTEXT=0
70	!
71	set	_end, %g4		! _end is highest kernel address
72	cmp	%g5, %g4
73	bl,a,pt	%xcc, 7f
74	  nop
75
76#ifndef _OPL
77	mov	MMU_PCONTEXT, %g1
78	ldxa	[%g1]ASI_DMMU, %g1
79	srlx	%g1, CTXREG_NEXT_SHIFT, %g3
80	brz,pt	%g3, 7f			! nucleus pgsz is 0, no problem
81	  sllx	%g3, CTXREG_NEXT_SHIFT, %g3
82	set	CTXREG_CTX_MASK, %g4	! check Pcontext
83	btst	%g4, %g1
84	bz,a,pt	%xcc, 6f
85	  clr	%g3			! kernel:  PCONTEXT=0
86	xor	%g3, %g1, %g3		! user:	clr N_pgsz0/1 bits
876:
88	set	DEMAP_ALL_TYPE, %g1
89	stxa	%g0, [%g1]ASI_DTLB_DEMAP
90	stxa	%g0, [%g1]ASI_ITLB_DEMAP
91	mov	MMU_PCONTEXT, %g1
92	stxa	%g3, [%g1]ASI_DMMU
93        membar  #Sync
94	sethi	%hi(FLUSH_ADDR), %g1
95	flush	%g1			! flush required by immu
96#endif /* _OPL */
97
987:
99	!
100	!  Cross-trap request case
101	!
102	! Load interrupt receive data registers 1 and 2 to fetch
103	! the arguments for the fast trap handler.
104	!
105	! Register usage:
106	!	g5: TL>0 handler
107	!	g1: arg1
108	!	g2: arg2
109	!	g3: arg3
110	!	g4: arg4
111	!
112	mov	IRDR_1, %g2
113	ldxa	[%g2]ASI_INTR_RECEIVE, %g1
114	mov	IRDR_2, %g2
115	ldxa	[%g2]ASI_INTR_RECEIVE, %g2
116#ifdef TRAPTRACE
117	TRACE_PTR(%g4, %g6)
118	GET_TRACE_TICK(%g6, %g3)
119	stxa	%g6, [%g4 + TRAP_ENT_TICK]%asi
120	rdpr	%tl, %g6
121	stha	%g6, [%g4 + TRAP_ENT_TL]%asi
122	rdpr	%tt, %g6
123	stha	%g6, [%g4 + TRAP_ENT_TT]%asi
124	rdpr	%tpc, %g6
125	stna	%g6, [%g4 + TRAP_ENT_TPC]%asi
126	rdpr	%tstate, %g6
127	stxa	%g6, [%g4 + TRAP_ENT_TSTATE]%asi
128	stna	%sp, [%g4 + TRAP_ENT_SP]%asi
129	stna	%g5, [%g4 + TRAP_ENT_TR]%asi	! pc of the TL>0 handler
130	stxa	%g1, [%g4 + TRAP_ENT_F1]%asi
131	stxa	%g2, [%g4 + TRAP_ENT_F3]%asi
132	stxa	%g0, [%g4 + TRAP_ENT_F2]%asi
133	stxa	%g0, [%g4 + TRAP_ENT_F4]%asi
134	TRACE_NEXT(%g4, %g6, %g3)
135#endif /* TRAPTRACE */
136	stxa	%g0, [%g0]ASI_INTR_RECEIVE_STATUS	! clear the BUSY bit
137	membar	#Sync
138#ifdef SF_ERRATA_51
139	ba,pt	%icc, 1f
140	nop
141	.align 32
1421:	jmp	%g5				! call the fast trap handler
143	nop
144#else
145	jmp	%g5
146	nop
147#endif /* SF_ERRATA_51 */
148	/* Never Reached */
149
1500:
151	! We have an interrupt number.
152        !
153	! Register usage:
154	!	%g5 - inum
155	!	%g1 - temp
156	!
157        ! We don't bother to verify that the received inum is valid (it should
158        ! be < MAXIVNUM) since setvecint_tl1 will do that for us.
159        !
160	! clear BUSY bit
161	!
162	stxa	%g0, [%g0]ASI_INTR_RECEIVE_STATUS
163	membar	#Sync
164
165	! setvecint_tl1 will do all the work, and finish with a retry
166	!
167	ba,pt	%xcc, setvecint_tl1
168	mov	%g5, %g1		! setvecint_tl1 expects inum in %g1
169
170	/* Never Reached */
171	SET_SIZE(vec_interrupt)
172
173
174!
175!   See usr/src/uts/sun4u/sys/dmv.h for the Databearing Mondo Vector
176!	 interrupt format
177!
178! Inputs:
179!	g1: value of ASI_INTR_RECEIVE_STATUS
180!	g5: word 0 of the interrupt data
181! Register use:
182!	g2: dmv inum
183!	g3: scratch
184!	g4: pointer to dmv_dispatch_table
185!	g6: handler pointer from dispatch table
186
187
188	DGDEF(dmv_spurious_cnt)
189	.word	0
190
191	ENTRY_NP(dmv_vector)
192	srlx	%g5, DMV_INUM_SHIFT, %g2
193	set	DMV_INUM_MASK, %g3
194	and	%g2, %g3, %g2		   ! %g2 = inum
195
196	set	dmv_totalints, %g3
197	ld	[%g3], %g3
198	cmp	%g2, %g3
199	bge,pn	%xcc, 2f		   ! inum >= dmv_totalints
200	nop
201
202	set	dmv_dispatch_table, %g3
203	ldn	[%g3], %g4
204	brz,pn	%g4, 2f
205	sll	%g2, DMV_DISP_SHIFT, %g3   ! %g3 = inum*sizeof(struct dmv_disp)
206
207	add	%g4, %g3, %g4		! %g4 = &dmv_dispatch_table[inum]
208#if (DMV_FUNC != 0) || (DMV_ARG != 8)
209#error "DMV_FUNC or DMV_SIZE has changed"
210#endif
211	ldda	[%g4]ASI_NQUAD_LD, %g2  ! %g2=handler %g3=argument
212	mov	%g3, %g1
213	brz,pn  %g2, 2f
214	nop
215
216	! we have a handler, so call it
217	! On entry to the handler, the %g registers are set as follows:
218	!
219	!	%g1	The argument (arg) passed to dmv_add_intr().
220	!	%g2	Word 0 of the incoming mondo vector.
221	!
222	jmp	%g2
223	mov	%g5, %g2
224
225	! No handler was listed in the table, so just record it
226	! as an error condition and continue.  There is a race
227	! window here updating the counter, but that's ok since
228	! just knowing that spurious interrupts happened is enough,
229	! we probably won't need to know exactly how many.
2302:
231	set	dmv_spurious_cnt, %g1
232	ld	[%g1], %g2
233	inc	%g2
234	ba,pt	%xcc,3f
235	st	%g2, [%g1]
236
237	!	When the handler's processing (which should be as quick as
238	!	possible) is complete, the handler must exit by jumping to
239	!	the label dmv_finish_intr.  The contents of %g1 at this time
240	!	determine whether a software interrupt will be issued, as
241	!	follows:
242	!
243	!		If %g1 is less than zero, no interrupt will be queued.
244	!		Otherwise, %g1 will be used as the interrupt number
245	!		to simulate; this means that the behavior of the
246	!		interrupt system will be exactly that which would have
247	!		occurred if the first word of the incoming interrupt
248	!		vector had contained the contents of %g1.
249
250	ENTRY_NP(dmv_finish_intr)
251	brlz,pn %g1,3f
252	nop
253	!	generate an interrupt based on the contents of %g1
254	ba,pt	%xcc,vec_interrupt_resume
255	mov	%g1, %g5
256	!	We are done
2573:
258	stxa	%g0, [%g0]ASI_INTR_RECEIVE_STATUS ! clear the busy bit
259	retry
260	SET_SIZE(dmv_vector)
261
262	DGDEF(vec_spurious_cnt)
263	.word	0
264
265	ENTRY_NP(vec_intr_spurious)
266	sethi	%hi(vec_spurious_cnt), %g2
267	ld	[%g2 + %lo(vec_spurious_cnt)], %g2
268#ifdef TRAPTRACE
269	TRACE_PTR(%g4, %g6)
270	GET_TRACE_TICK(%g6, %g3)
271	stxa	%g6, [%g4 + TRAP_ENT_TICK]%asi
272	rdpr	%tl, %g6
273	stha	%g6, [%g4 + TRAP_ENT_TL]%asi
274	rdpr	%tt, %g6
275	or	%g6, TT_SPURIOUS_INT, %g6
276	stha	%g6, [%g4 + TRAP_ENT_TT]%asi
277	rdpr	%tpc, %g6
278	stna	%g6, [%g4 + TRAP_ENT_TPC]%asi
279	rdpr	%tstate, %g6
280	stxa	%g6, [%g4 + TRAP_ENT_TSTATE]%asi
281	stna	%sp, [%g4 + TRAP_ENT_SP]%asi
282	stna	%g1, [%g4 + TRAP_ENT_TR]%asi	! irsr
283	stna	%g2, [%g4 + TRAP_ENT_F1]%asi
284	ldxa	[%g0]ASI_INTR_RECEIVE_STATUS, %g5
285	stxa	%g5, [%g4 + TRAP_ENT_F2]%asi
286	stxa	%g0, [%g4 + TRAP_ENT_F4]%asi
287	TRACE_NEXT(%g4, %g6, %g3)
288#endif /* TRAPTRACE */
289	cmp	%g2, 16
290	bl,a,pt	%xcc, 1f
291	inc	%g2
292	!
293	! prepare for sys_trap()
294	!	%g1 - sys_tl1_panic
295	!	%g2 - panic message
296	!	%g4 - current pil
297	!
298#ifdef CLEAR_INTR_BUSYBIT_ON_SPURIOUS
299	/*
300	 * Certain processors (OPL) need to explicitly
301	 * clear the intr busy bit even though it is
302	 * not visibly set (spurious intrs)
303	 */
304	stxa	%g0, [%g0]ASI_INTR_RECEIVE_STATUS	! clear the BUSY bit
305	membar  #Sync
306#endif /* CLEAR_INTR_BUSYBIT_ON_SPURIOUS */
307	sub	%g0, 1, %g4
308	set	_not_ready, %g2
309	sethi	%hi(sys_tl1_panic), %g1
310	ba,pt	%xcc, sys_trap
311	or	%g1, %lo(sys_tl1_panic), %g1
312	!
3131:	sethi	%hi(vec_spurious_cnt), %g1
314	st	%g2, [%g1 + %lo(vec_spurious_cnt)]
315	retry
316	SET_SIZE(vec_intr_spurious)
317
318_not_ready:	.asciz	"Interrupt Vector Receive Register not READY"
319
320