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