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