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