xref: /onnv-gate/usr/src/uts/sun4u/ml/mach_interrupt.s (revision 11172:a792f425ae2e)
10Sstevel@tonic-gate/*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52310Shyw * Common Development and Distribution License (the "License").
62310Shyw * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate/*
22*11172SHaik.Aftandilian@Sun.COM * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate#if defined(lint)
270Sstevel@tonic-gate#include <sys/types.h>
280Sstevel@tonic-gate#include <sys/thread.h>
290Sstevel@tonic-gate#else	/* lint */
300Sstevel@tonic-gate#include "assym.h"
310Sstevel@tonic-gate#endif	/* lint */
320Sstevel@tonic-gate
330Sstevel@tonic-gate#include <sys/asm_linkage.h>
340Sstevel@tonic-gate#include <sys/machthread.h>
350Sstevel@tonic-gate#include <sys/machcpuvar.h>
360Sstevel@tonic-gate#include <sys/mmu.h>
370Sstevel@tonic-gate#include <sys/intreg.h>
380Sstevel@tonic-gate#include <sys/dmv.h>
390Sstevel@tonic-gate
400Sstevel@tonic-gate#ifdef TRAPTRACE
410Sstevel@tonic-gate#include <sys/traptrace.h>
420Sstevel@tonic-gate#endif /* TRAPTRACE */
430Sstevel@tonic-gate
440Sstevel@tonic-gate
450Sstevel@tonic-gate#if defined(lint)
460Sstevel@tonic-gate
470Sstevel@tonic-gatevoid
480Sstevel@tonic-gatevec_interrupt(void)
490Sstevel@tonic-gate{}
500Sstevel@tonic-gate
510Sstevel@tonic-gate#else	/* lint */
520Sstevel@tonic-gate
530Sstevel@tonic-gatevec_uiii_irdr_tab:
540Sstevel@tonic-gate        .byte   UIII_IRDR_0, UIII_IRDR_1, UIII_IRDR_2, UIII_IRDR_3
550Sstevel@tonic-gate        .byte   UIII_IRDR_4, UIII_IRDR_5, UIII_IRDR_6, UIII_IRDR_7
560Sstevel@tonic-gate
570Sstevel@tonic-gate/*
580Sstevel@tonic-gate * (TT 0x60, TL>0) Interrupt Vector Handler
590Sstevel@tonic-gate *	Globals are the Interrupt Globals.
600Sstevel@tonic-gate */
610Sstevel@tonic-gate	ENTRY_NP(vec_interrupt)
620Sstevel@tonic-gate	!
630Sstevel@tonic-gate	! Load the interrupt receive data register 0.
640Sstevel@tonic-gate	! It could be a fast trap handler address (pc > KERNELBASE) at TL>0
650Sstevel@tonic-gate	! or an interrupt number.
660Sstevel@tonic-gate	!
670Sstevel@tonic-gate	mov	IRDR_0, %g2
680Sstevel@tonic-gate	ldxa	[%g2]ASI_INTR_RECEIVE, %g5	! %g5 = PC or Interrupt Number
690Sstevel@tonic-gate
700Sstevel@tonic-gate	! If the high bit of IRDR_0 is set, then this is a
710Sstevel@tonic-gate	! data bearing mondo vector.
720Sstevel@tonic-gate	brlz,pt %g5, dmv_vector
730Sstevel@tonic-gate	.empty
740Sstevel@tonic-gate
750Sstevel@tonic-gate
760Sstevel@tonic-gatevec_interrupt_resume:
770Sstevel@tonic-gate	set	KERNELBASE, %g4
780Sstevel@tonic-gate	cmp	%g5, %g4
790Sstevel@tonic-gate	bl,a,pt	%xcc, 0f			! an interrupt number found
800Sstevel@tonic-gate	  nop
810Sstevel@tonic-gate	!
820Sstevel@tonic-gate	! intercept OBP xcalls and set PCONTEXT=0
830Sstevel@tonic-gate	!
840Sstevel@tonic-gate	set	_end, %g4		! _end is highest kernel address
850Sstevel@tonic-gate	cmp	%g5, %g4
860Sstevel@tonic-gate	bl,a,pt	%xcc, 7f
870Sstevel@tonic-gate	  nop
885584Sjimand
895584Sjimand#ifndef _OPL
900Sstevel@tonic-gate	mov	MMU_PCONTEXT, %g1
910Sstevel@tonic-gate	ldxa	[%g1]ASI_DMMU, %g1
920Sstevel@tonic-gate	srlx	%g1, CTXREG_NEXT_SHIFT, %g3
930Sstevel@tonic-gate	brz,pt	%g3, 7f			! nucleus pgsz is 0, no problem
940Sstevel@tonic-gate	  sllx	%g3, CTXREG_NEXT_SHIFT, %g3
950Sstevel@tonic-gate	set	CTXREG_CTX_MASK, %g4	! check Pcontext
960Sstevel@tonic-gate	btst	%g4, %g1
970Sstevel@tonic-gate	bz,a,pt	%xcc, 6f
980Sstevel@tonic-gate	  clr	%g3			! kernel:  PCONTEXT=0
990Sstevel@tonic-gate	xor	%g3, %g1, %g3		! user:	clr N_pgsz0/1 bits
1000Sstevel@tonic-gate6:
1010Sstevel@tonic-gate	set	DEMAP_ALL_TYPE, %g1
1020Sstevel@tonic-gate	stxa	%g0, [%g1]ASI_DTLB_DEMAP
1030Sstevel@tonic-gate	stxa	%g0, [%g1]ASI_ITLB_DEMAP
1040Sstevel@tonic-gate	mov	MMU_PCONTEXT, %g1
1050Sstevel@tonic-gate	stxa	%g3, [%g1]ASI_DMMU
1060Sstevel@tonic-gate        membar  #Sync
1070Sstevel@tonic-gate	sethi	%hi(FLUSH_ADDR), %g1
1080Sstevel@tonic-gate	flush	%g1			! flush required by immu
1095584Sjimand#endif /* _OPL */
1105584Sjimand
1110Sstevel@tonic-gate7:
1120Sstevel@tonic-gate	!
1130Sstevel@tonic-gate	!  Cross-trap request case
1140Sstevel@tonic-gate	!
1150Sstevel@tonic-gate	! Load interrupt receive data registers 1 and 2 to fetch
1160Sstevel@tonic-gate	! the arguments for the fast trap handler.
1170Sstevel@tonic-gate	!
1180Sstevel@tonic-gate	! Register usage:
1190Sstevel@tonic-gate	!	g5: TL>0 handler
1200Sstevel@tonic-gate	!	g1: arg1
1210Sstevel@tonic-gate	!	g2: arg2
1220Sstevel@tonic-gate	!	g3: arg3
1230Sstevel@tonic-gate	!	g4: arg4
1240Sstevel@tonic-gate	!
1250Sstevel@tonic-gate	mov	IRDR_1, %g2
1260Sstevel@tonic-gate	ldxa	[%g2]ASI_INTR_RECEIVE, %g1
1270Sstevel@tonic-gate	mov	IRDR_2, %g2
1280Sstevel@tonic-gate	ldxa	[%g2]ASI_INTR_RECEIVE, %g2
1290Sstevel@tonic-gate#ifdef TRAPTRACE
1300Sstevel@tonic-gate	TRACE_PTR(%g4, %g6)
131*11172SHaik.Aftandilian@Sun.COM	GET_TRACE_TICK(%g6, %g3)
1320Sstevel@tonic-gate	stxa	%g6, [%g4 + TRAP_ENT_TICK]%asi
1330Sstevel@tonic-gate	rdpr	%tl, %g6
1340Sstevel@tonic-gate	stha	%g6, [%g4 + TRAP_ENT_TL]%asi
1350Sstevel@tonic-gate	rdpr	%tt, %g6
1360Sstevel@tonic-gate	stha	%g6, [%g4 + TRAP_ENT_TT]%asi
1370Sstevel@tonic-gate	rdpr	%tpc, %g6
1380Sstevel@tonic-gate	stna	%g6, [%g4 + TRAP_ENT_TPC]%asi
1390Sstevel@tonic-gate	rdpr	%tstate, %g6
1400Sstevel@tonic-gate	stxa	%g6, [%g4 + TRAP_ENT_TSTATE]%asi
1410Sstevel@tonic-gate	stna	%sp, [%g4 + TRAP_ENT_SP]%asi
1420Sstevel@tonic-gate	stna	%g5, [%g4 + TRAP_ENT_TR]%asi	! pc of the TL>0 handler
1430Sstevel@tonic-gate	stxa	%g1, [%g4 + TRAP_ENT_F1]%asi
1440Sstevel@tonic-gate	stxa	%g2, [%g4 + TRAP_ENT_F3]%asi
1450Sstevel@tonic-gate	stxa	%g0, [%g4 + TRAP_ENT_F2]%asi
1460Sstevel@tonic-gate	stxa	%g0, [%g4 + TRAP_ENT_F4]%asi
1470Sstevel@tonic-gate	TRACE_NEXT(%g4, %g6, %g3)
1480Sstevel@tonic-gate#endif /* TRAPTRACE */
1490Sstevel@tonic-gate	stxa	%g0, [%g0]ASI_INTR_RECEIVE_STATUS	! clear the BUSY bit
1500Sstevel@tonic-gate	membar	#Sync
1510Sstevel@tonic-gate#ifdef SF_ERRATA_51
1520Sstevel@tonic-gate	ba,pt	%icc, 1f
1530Sstevel@tonic-gate	nop
1540Sstevel@tonic-gate	.align 32
1550Sstevel@tonic-gate1:	jmp	%g5				! call the fast trap handler
1560Sstevel@tonic-gate	nop
1570Sstevel@tonic-gate#else
1580Sstevel@tonic-gate	jmp	%g5
1590Sstevel@tonic-gate	nop
1600Sstevel@tonic-gate#endif /* SF_ERRATA_51 */
1610Sstevel@tonic-gate	/* Never Reached */
1620Sstevel@tonic-gate
1630Sstevel@tonic-gate0:
1640Sstevel@tonic-gate	! We have an interrupt number.
1650Sstevel@tonic-gate        !
1660Sstevel@tonic-gate	! Register usage:
1670Sstevel@tonic-gate	!	%g5 - inum
1680Sstevel@tonic-gate	!	%g1 - temp
1690Sstevel@tonic-gate	!
1700Sstevel@tonic-gate        ! We don't bother to verify that the received inum is valid (it should
1712973Sgovinda        ! be < MAXIVNUM) since setvecint_tl1 will do that for us.
1720Sstevel@tonic-gate        !
1730Sstevel@tonic-gate	! clear BUSY bit
1740Sstevel@tonic-gate	!
1750Sstevel@tonic-gate	stxa	%g0, [%g0]ASI_INTR_RECEIVE_STATUS
1760Sstevel@tonic-gate	membar	#Sync
1770Sstevel@tonic-gate
1782973Sgovinda	! setvecint_tl1 will do all the work, and finish with a retry
1790Sstevel@tonic-gate	!
1802973Sgovinda	ba,pt	%xcc, setvecint_tl1
1812973Sgovinda	mov	%g5, %g1		! setvecint_tl1 expects inum in %g1
1820Sstevel@tonic-gate
1830Sstevel@tonic-gate	/* Never Reached */
1840Sstevel@tonic-gate	SET_SIZE(vec_interrupt)
1850Sstevel@tonic-gate
1860Sstevel@tonic-gate
1870Sstevel@tonic-gate!
1880Sstevel@tonic-gate!   See usr/src/uts/sun4u/sys/dmv.h for the Databearing Mondo Vector
1890Sstevel@tonic-gate!	 interrupt format
1900Sstevel@tonic-gate!
1910Sstevel@tonic-gate! Inputs:
1920Sstevel@tonic-gate!	g1: value of ASI_INTR_RECEIVE_STATUS
1930Sstevel@tonic-gate!	g5: word 0 of the interrupt data
1940Sstevel@tonic-gate! Register use:
1950Sstevel@tonic-gate!	g2: dmv inum
1960Sstevel@tonic-gate!	g3: scratch
1970Sstevel@tonic-gate!	g4: pointer to dmv_dispatch_table
1980Sstevel@tonic-gate!	g6: handler pointer from dispatch table
1990Sstevel@tonic-gate
2000Sstevel@tonic-gate
2010Sstevel@tonic-gate	DGDEF(dmv_spurious_cnt)
2020Sstevel@tonic-gate	.word	0
2030Sstevel@tonic-gate
2040Sstevel@tonic-gate	ENTRY_NP(dmv_vector)
2050Sstevel@tonic-gate	srlx	%g5, DMV_INUM_SHIFT, %g2
2060Sstevel@tonic-gate	set	DMV_INUM_MASK, %g3
2070Sstevel@tonic-gate	and	%g2, %g3, %g2		   ! %g2 = inum
2080Sstevel@tonic-gate
2090Sstevel@tonic-gate	set	dmv_totalints, %g3
2100Sstevel@tonic-gate	ld	[%g3], %g3
2110Sstevel@tonic-gate	cmp	%g2, %g3
2120Sstevel@tonic-gate	bge,pn	%xcc, 2f		   ! inum >= dmv_totalints
2130Sstevel@tonic-gate	nop
2140Sstevel@tonic-gate
2150Sstevel@tonic-gate	set	dmv_dispatch_table, %g3
2160Sstevel@tonic-gate	ldn	[%g3], %g4
2170Sstevel@tonic-gate	brz,pn	%g4, 2f
2180Sstevel@tonic-gate	sll	%g2, DMV_DISP_SHIFT, %g3   ! %g3 = inum*sizeof(struct dmv_disp)
2190Sstevel@tonic-gate
2200Sstevel@tonic-gate	add	%g4, %g3, %g4		! %g4 = &dmv_dispatch_table[inum]
2210Sstevel@tonic-gate#if (DMV_FUNC != 0) || (DMV_ARG != 8)
2220Sstevel@tonic-gate#error "DMV_FUNC or DMV_SIZE has changed"
2230Sstevel@tonic-gate#endif
2240Sstevel@tonic-gate	ldda	[%g4]ASI_NQUAD_LD, %g2  ! %g2=handler %g3=argument
2250Sstevel@tonic-gate	mov	%g3, %g1
2260Sstevel@tonic-gate	brz,pn  %g2, 2f
2270Sstevel@tonic-gate	nop
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate	! we have a handler, so call it
2300Sstevel@tonic-gate	! On entry to the handler, the %g registers are set as follows:
2310Sstevel@tonic-gate	!
2320Sstevel@tonic-gate	!	%g1	The argument (arg) passed to dmv_add_intr().
2330Sstevel@tonic-gate	!	%g2	Word 0 of the incoming mondo vector.
2340Sstevel@tonic-gate	!
2350Sstevel@tonic-gate	jmp	%g2
2360Sstevel@tonic-gate	mov	%g5, %g2
2370Sstevel@tonic-gate
2380Sstevel@tonic-gate	! No handler was listed in the table, so just record it
2390Sstevel@tonic-gate	! as an error condition and continue.  There is a race
2400Sstevel@tonic-gate	! window here updating the counter, but that's ok since
2410Sstevel@tonic-gate	! just knowing that spurious interrupts happened is enough,
2420Sstevel@tonic-gate	! we probably won't need to know exactly how many.
2430Sstevel@tonic-gate2:
2440Sstevel@tonic-gate	set	dmv_spurious_cnt, %g1
2450Sstevel@tonic-gate	ld	[%g1], %g2
2460Sstevel@tonic-gate	inc	%g2
2470Sstevel@tonic-gate	ba,pt	%xcc,3f
2480Sstevel@tonic-gate	st	%g2, [%g1]
2490Sstevel@tonic-gate
2500Sstevel@tonic-gate	!	When the handler's processing (which should be as quick as
2510Sstevel@tonic-gate	!	possible) is complete, the handler must exit by jumping to
2520Sstevel@tonic-gate	!	the label dmv_finish_intr.  The contents of %g1 at this time
2530Sstevel@tonic-gate	!	determine whether a software interrupt will be issued, as
2540Sstevel@tonic-gate	!	follows:
2550Sstevel@tonic-gate	!
2560Sstevel@tonic-gate	!		If %g1 is less than zero, no interrupt will be queued.
2570Sstevel@tonic-gate	!		Otherwise, %g1 will be used as the interrupt number
2580Sstevel@tonic-gate	!		to simulate; this means that the behavior of the
2590Sstevel@tonic-gate	!		interrupt system will be exactly that which would have
2600Sstevel@tonic-gate	!		occurred if the first word of the incoming interrupt
2610Sstevel@tonic-gate	!		vector had contained the contents of %g1.
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate	ENTRY_NP(dmv_finish_intr)
2640Sstevel@tonic-gate	brlz,pn %g1,3f
2650Sstevel@tonic-gate	nop
2660Sstevel@tonic-gate	!	generate an interrupt based on the contents of %g1
2670Sstevel@tonic-gate	ba,pt	%xcc,vec_interrupt_resume
2680Sstevel@tonic-gate	mov	%g1, %g5
2690Sstevel@tonic-gate	!	We are done
2700Sstevel@tonic-gate3:
2710Sstevel@tonic-gate	stxa	%g0, [%g0]ASI_INTR_RECEIVE_STATUS ! clear the busy bit
2720Sstevel@tonic-gate	retry
2730Sstevel@tonic-gate	SET_SIZE(dmv_vector)
2740Sstevel@tonic-gate
2750Sstevel@tonic-gate#endif	/* lint */
2760Sstevel@tonic-gate
2770Sstevel@tonic-gate#if defined(lint)
2780Sstevel@tonic-gate
2790Sstevel@tonic-gatevoid
2800Sstevel@tonic-gatevec_intr_spurious(void)
2810Sstevel@tonic-gate{}
2820Sstevel@tonic-gate
2830Sstevel@tonic-gate#else	/* lint */
2840Sstevel@tonic-gate
2850Sstevel@tonic-gate	DGDEF(vec_spurious_cnt)
2860Sstevel@tonic-gate	.word	0
2870Sstevel@tonic-gate
2880Sstevel@tonic-gate	ENTRY_NP(vec_intr_spurious)
2890Sstevel@tonic-gate	sethi	%hi(vec_spurious_cnt), %g2
2900Sstevel@tonic-gate	ld	[%g2 + %lo(vec_spurious_cnt)], %g2
2910Sstevel@tonic-gate#ifdef TRAPTRACE
2920Sstevel@tonic-gate	TRACE_PTR(%g4, %g6)
293*11172SHaik.Aftandilian@Sun.COM	GET_TRACE_TICK(%g6, %g3)
2940Sstevel@tonic-gate	stxa	%g6, [%g4 + TRAP_ENT_TICK]%asi
2950Sstevel@tonic-gate	rdpr	%tl, %g6
2960Sstevel@tonic-gate	stha	%g6, [%g4 + TRAP_ENT_TL]%asi
2970Sstevel@tonic-gate	rdpr	%tt, %g6
2980Sstevel@tonic-gate	or	%g6, TT_SPURIOUS_INT, %g6
2990Sstevel@tonic-gate	stha	%g6, [%g4 + TRAP_ENT_TT]%asi
3000Sstevel@tonic-gate	rdpr	%tpc, %g6
3010Sstevel@tonic-gate	stna	%g6, [%g4 + TRAP_ENT_TPC]%asi
3020Sstevel@tonic-gate	rdpr	%tstate, %g6
3030Sstevel@tonic-gate	stxa	%g6, [%g4 + TRAP_ENT_TSTATE]%asi
3040Sstevel@tonic-gate	stna	%sp, [%g4 + TRAP_ENT_SP]%asi
3050Sstevel@tonic-gate	stna	%g1, [%g4 + TRAP_ENT_TR]%asi	! irsr
3060Sstevel@tonic-gate	stna	%g2, [%g4 + TRAP_ENT_F1]%asi
3070Sstevel@tonic-gate	ldxa	[%g0]ASI_INTR_RECEIVE_STATUS, %g5
3080Sstevel@tonic-gate	stxa	%g5, [%g4 + TRAP_ENT_F2]%asi
3090Sstevel@tonic-gate	stxa	%g0, [%g4 + TRAP_ENT_F4]%asi
3100Sstevel@tonic-gate	TRACE_NEXT(%g4, %g6, %g3)
3110Sstevel@tonic-gate#endif /* TRAPTRACE */
3120Sstevel@tonic-gate	cmp	%g2, 16
3130Sstevel@tonic-gate	bl,a,pt	%xcc, 1f
3140Sstevel@tonic-gate	inc	%g2
3150Sstevel@tonic-gate	!
3160Sstevel@tonic-gate	! prepare for sys_trap()
3170Sstevel@tonic-gate	!	%g1 - sys_tl1_panic
3180Sstevel@tonic-gate	!	%g2 - panic message
3190Sstevel@tonic-gate	!	%g4 - current pil
3200Sstevel@tonic-gate	!
3212310Shyw#ifdef CLEAR_INTR_BUSYBIT_ON_SPURIOUS
3222310Shyw	/*
3232310Shyw	 * Certain processors (OPL) need to explicitly
3242310Shyw	 * clear the intr busy bit even though it is
3252310Shyw	 * not visibly set (spurious intrs)
3262310Shyw	 */
3272310Shyw	stxa	%g0, [%g0]ASI_INTR_RECEIVE_STATUS	! clear the BUSY bit
3282310Shyw	membar  #Sync
3292310Shyw#endif /* CLEAR_INTR_BUSYBIT_ON_SPURIOUS */
3300Sstevel@tonic-gate	sub	%g0, 1, %g4
3310Sstevel@tonic-gate	set	_not_ready, %g2
3320Sstevel@tonic-gate	sethi	%hi(sys_tl1_panic), %g1
3330Sstevel@tonic-gate	ba,pt	%xcc, sys_trap
3340Sstevel@tonic-gate	or	%g1, %lo(sys_tl1_panic), %g1
3350Sstevel@tonic-gate	!
3360Sstevel@tonic-gate1:	sethi	%hi(vec_spurious_cnt), %g1
3370Sstevel@tonic-gate	st	%g2, [%g1 + %lo(vec_spurious_cnt)]
3380Sstevel@tonic-gate	retry
3390Sstevel@tonic-gate	SET_SIZE(vec_intr_spurious)
3400Sstevel@tonic-gate
3410Sstevel@tonic-gate_not_ready:	.asciz	"Interrupt Vector Receive Register not READY"
3420Sstevel@tonic-gate
3430Sstevel@tonic-gate#endif	/* lint */
344