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