xref: /titanic_44/usr/src/uts/sun4u/ml/mach_interrupt.s (revision 21bf64a78855d076f09716ea1c06175d954e934c)
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 2007 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
91#ifndef _OPL
92	mov	MMU_PCONTEXT, %g1
93	ldxa	[%g1]ASI_DMMU, %g1
94	srlx	%g1, CTXREG_NEXT_SHIFT, %g3
95	brz,pt	%g3, 7f			! nucleus pgsz is 0, no problem
96	  sllx	%g3, CTXREG_NEXT_SHIFT, %g3
97	set	CTXREG_CTX_MASK, %g4	! check Pcontext
98	btst	%g4, %g1
99	bz,a,pt	%xcc, 6f
100	  clr	%g3			! kernel:  PCONTEXT=0
101	xor	%g3, %g1, %g3		! user:	clr N_pgsz0/1 bits
1026:
103	set	DEMAP_ALL_TYPE, %g1
104	stxa	%g0, [%g1]ASI_DTLB_DEMAP
105	stxa	%g0, [%g1]ASI_ITLB_DEMAP
106	mov	MMU_PCONTEXT, %g1
107	stxa	%g3, [%g1]ASI_DMMU
108        membar  #Sync
109	sethi	%hi(FLUSH_ADDR), %g1
110	flush	%g1			! flush required by immu
111#endif /* _OPL */
112
1137:
114	!
115	!  Cross-trap request case
116	!
117	! Load interrupt receive data registers 1 and 2 to fetch
118	! the arguments for the fast trap handler.
119	!
120	! Register usage:
121	!	g5: TL>0 handler
122	!	g1: arg1
123	!	g2: arg2
124	!	g3: arg3
125	!	g4: arg4
126	!
127	mov	IRDR_1, %g2
128	ldxa	[%g2]ASI_INTR_RECEIVE, %g1
129	mov	IRDR_2, %g2
130	ldxa	[%g2]ASI_INTR_RECEIVE, %g2
131#ifdef TRAPTRACE
132	TRACE_PTR(%g4, %g6)
133	GET_TRACE_TICK(%g6)
134	stxa	%g6, [%g4 + TRAP_ENT_TICK]%asi
135	rdpr	%tl, %g6
136	stha	%g6, [%g4 + TRAP_ENT_TL]%asi
137	rdpr	%tt, %g6
138	stha	%g6, [%g4 + TRAP_ENT_TT]%asi
139	rdpr	%tpc, %g6
140	stna	%g6, [%g4 + TRAP_ENT_TPC]%asi
141	rdpr	%tstate, %g6
142	stxa	%g6, [%g4 + TRAP_ENT_TSTATE]%asi
143	stna	%sp, [%g4 + TRAP_ENT_SP]%asi
144	stna	%g5, [%g4 + TRAP_ENT_TR]%asi	! pc of the TL>0 handler
145	stxa	%g1, [%g4 + TRAP_ENT_F1]%asi
146	stxa	%g2, [%g4 + TRAP_ENT_F3]%asi
147	stxa	%g0, [%g4 + TRAP_ENT_F2]%asi
148	stxa	%g0, [%g4 + TRAP_ENT_F4]%asi
149	TRACE_NEXT(%g4, %g6, %g3)
150#endif /* TRAPTRACE */
151	stxa	%g0, [%g0]ASI_INTR_RECEIVE_STATUS	! clear the BUSY bit
152	membar	#Sync
153#ifdef SF_ERRATA_51
154	ba,pt	%icc, 1f
155	nop
156	.align 32
1571:	jmp	%g5				! call the fast trap handler
158	nop
159#else
160	jmp	%g5
161	nop
162#endif /* SF_ERRATA_51 */
163	/* Never Reached */
164
1650:
166	! We have an interrupt number.
167        !
168	! Register usage:
169	!	%g5 - inum
170	!	%g1 - temp
171	!
172        ! We don't bother to verify that the received inum is valid (it should
173        ! be < MAXIVNUM) since setvecint_tl1 will do that for us.
174        !
175	! clear BUSY bit
176	!
177	stxa	%g0, [%g0]ASI_INTR_RECEIVE_STATUS
178	membar	#Sync
179
180	! setvecint_tl1 will do all the work, and finish with a retry
181	!
182	ba,pt	%xcc, setvecint_tl1
183	mov	%g5, %g1		! setvecint_tl1 expects inum in %g1
184
185	/* Never Reached */
186	SET_SIZE(vec_interrupt)
187
188
189!
190!   See usr/src/uts/sun4u/sys/dmv.h for the Databearing Mondo Vector
191!	 interrupt format
192!
193! Inputs:
194!	g1: value of ASI_INTR_RECEIVE_STATUS
195!	g5: word 0 of the interrupt data
196! Register use:
197!	g2: dmv inum
198!	g3: scratch
199!	g4: pointer to dmv_dispatch_table
200!	g6: handler pointer from dispatch table
201
202
203	DGDEF(dmv_spurious_cnt)
204	.word	0
205
206	ENTRY_NP(dmv_vector)
207	srlx	%g5, DMV_INUM_SHIFT, %g2
208	set	DMV_INUM_MASK, %g3
209	and	%g2, %g3, %g2		   ! %g2 = inum
210
211	set	dmv_totalints, %g3
212	ld	[%g3], %g3
213	cmp	%g2, %g3
214	bge,pn	%xcc, 2f		   ! inum >= dmv_totalints
215	nop
216
217	set	dmv_dispatch_table, %g3
218	ldn	[%g3], %g4
219	brz,pn	%g4, 2f
220	sll	%g2, DMV_DISP_SHIFT, %g3   ! %g3 = inum*sizeof(struct dmv_disp)
221
222	add	%g4, %g3, %g4		! %g4 = &dmv_dispatch_table[inum]
223#if (DMV_FUNC != 0) || (DMV_ARG != 8)
224#error "DMV_FUNC or DMV_SIZE has changed"
225#endif
226	ldda	[%g4]ASI_NQUAD_LD, %g2  ! %g2=handler %g3=argument
227	mov	%g3, %g1
228	brz,pn  %g2, 2f
229	nop
230
231	! we have a handler, so call it
232	! On entry to the handler, the %g registers are set as follows:
233	!
234	!	%g1	The argument (arg) passed to dmv_add_intr().
235	!	%g2	Word 0 of the incoming mondo vector.
236	!
237	jmp	%g2
238	mov	%g5, %g2
239
240	! No handler was listed in the table, so just record it
241	! as an error condition and continue.  There is a race
242	! window here updating the counter, but that's ok since
243	! just knowing that spurious interrupts happened is enough,
244	! we probably won't need to know exactly how many.
2452:
246	set	dmv_spurious_cnt, %g1
247	ld	[%g1], %g2
248	inc	%g2
249	ba,pt	%xcc,3f
250	st	%g2, [%g1]
251
252	!	When the handler's processing (which should be as quick as
253	!	possible) is complete, the handler must exit by jumping to
254	!	the label dmv_finish_intr.  The contents of %g1 at this time
255	!	determine whether a software interrupt will be issued, as
256	!	follows:
257	!
258	!		If %g1 is less than zero, no interrupt will be queued.
259	!		Otherwise, %g1 will be used as the interrupt number
260	!		to simulate; this means that the behavior of the
261	!		interrupt system will be exactly that which would have
262	!		occurred if the first word of the incoming interrupt
263	!		vector had contained the contents of %g1.
264
265	ENTRY_NP(dmv_finish_intr)
266	brlz,pn %g1,3f
267	nop
268	!	generate an interrupt based on the contents of %g1
269	ba,pt	%xcc,vec_interrupt_resume
270	mov	%g1, %g5
271	!	We are done
2723:
273	stxa	%g0, [%g0]ASI_INTR_RECEIVE_STATUS ! clear the busy bit
274	retry
275	SET_SIZE(dmv_vector)
276
277#endif	/* lint */
278
279#if defined(lint)
280
281void
282vec_intr_spurious(void)
283{}
284
285#else	/* lint */
286
287	DGDEF(vec_spurious_cnt)
288	.word	0
289
290	ENTRY_NP(vec_intr_spurious)
291	sethi	%hi(vec_spurious_cnt), %g2
292	ld	[%g2 + %lo(vec_spurious_cnt)], %g2
293#ifdef TRAPTRACE
294	TRACE_PTR(%g4, %g6)
295	GET_TRACE_TICK(%g6)
296	stxa	%g6, [%g4 + TRAP_ENT_TICK]%asi
297	rdpr	%tl, %g6
298	stha	%g6, [%g4 + TRAP_ENT_TL]%asi
299	rdpr	%tt, %g6
300	or	%g6, TT_SPURIOUS_INT, %g6
301	stha	%g6, [%g4 + TRAP_ENT_TT]%asi
302	rdpr	%tpc, %g6
303	stna	%g6, [%g4 + TRAP_ENT_TPC]%asi
304	rdpr	%tstate, %g6
305	stxa	%g6, [%g4 + TRAP_ENT_TSTATE]%asi
306	stna	%sp, [%g4 + TRAP_ENT_SP]%asi
307	stna	%g1, [%g4 + TRAP_ENT_TR]%asi	! irsr
308	stna	%g2, [%g4 + TRAP_ENT_F1]%asi
309	ldxa	[%g0]ASI_INTR_RECEIVE_STATUS, %g5
310	stxa	%g5, [%g4 + TRAP_ENT_F2]%asi
311	stxa	%g0, [%g4 + TRAP_ENT_F4]%asi
312	TRACE_NEXT(%g4, %g6, %g3)
313#endif /* TRAPTRACE */
314	cmp	%g2, 16
315	bl,a,pt	%xcc, 1f
316	inc	%g2
317	!
318	! prepare for sys_trap()
319	!	%g1 - sys_tl1_panic
320	!	%g2 - panic message
321	!	%g4 - current pil
322	!
323#ifdef CLEAR_INTR_BUSYBIT_ON_SPURIOUS
324	/*
325	 * Certain processors (OPL) need to explicitly
326	 * clear the intr busy bit even though it is
327	 * not visibly set (spurious intrs)
328	 */
329	stxa	%g0, [%g0]ASI_INTR_RECEIVE_STATUS	! clear the BUSY bit
330	membar  #Sync
331#endif /* CLEAR_INTR_BUSYBIT_ON_SPURIOUS */
332	sub	%g0, 1, %g4
333	set	_not_ready, %g2
334	sethi	%hi(sys_tl1_panic), %g1
335	ba,pt	%xcc, sys_trap
336	or	%g1, %lo(sys_tl1_panic), %g1
337	!
3381:	sethi	%hi(vec_spurious_cnt), %g1
339	st	%g2, [%g1 + %lo(vec_spurious_cnt)]
340	retry
341	SET_SIZE(vec_intr_spurious)
342
343_not_ready:	.asciz	"Interrupt Vector Receive Register not READY"
344
345#endif	/* lint */
346