xref: /onnv-gate/usr/src/uts/sun4v/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
52973Sgovinda * Common Development and Distribution License (the "License").
62973Sgovinda * 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/*
2210271SJason.Beloro@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/intreg.h>
370Sstevel@tonic-gate#include <sys/cmn_err.h>
380Sstevel@tonic-gate#include <sys/ftrace.h>
390Sstevel@tonic-gate#include <sys/machasi.h>
401457Swh94709#include <sys/scb.h>
410Sstevel@tonic-gate#include <sys/error.h>
424528Spaulsan#include <sys/mmu.h>
434528Spaulsan#include <vm/hat_sfmmu.h>
440Sstevel@tonic-gate#define	INTR_REPORT_SIZE	64
450Sstevel@tonic-gate
460Sstevel@tonic-gate#ifdef TRAPTRACE
470Sstevel@tonic-gate#include <sys/traptrace.h>
480Sstevel@tonic-gate#endif /* TRAPTRACE */
490Sstevel@tonic-gate
500Sstevel@tonic-gate#if defined(lint)
510Sstevel@tonic-gate
520Sstevel@tonic-gatevoid
530Sstevel@tonic-gatecpu_mondo(void)
540Sstevel@tonic-gate{}
550Sstevel@tonic-gate
560Sstevel@tonic-gate#else	/* lint */
570Sstevel@tonic-gate
580Sstevel@tonic-gate
590Sstevel@tonic-gate/*
600Sstevel@tonic-gate * (TT 0x7c, TL>0) CPU Mondo Queue Handler
610Sstevel@tonic-gate *	Globals are the Interrupt Globals.
620Sstevel@tonic-gate */
630Sstevel@tonic-gate	ENTRY_NP(cpu_mondo)
640Sstevel@tonic-gate	!
650Sstevel@tonic-gate	!	Register Usage:-
660Sstevel@tonic-gate	!	%g5	PC for fasttrap TL>0 handler
670Sstevel@tonic-gate	!	%g1	arg 1
680Sstevel@tonic-gate	!	%g2	arg 2
690Sstevel@tonic-gate	!	%g3	queue base VA
700Sstevel@tonic-gate	!	%g4 	queue size mask
710Sstevel@tonic-gate	!	%g6	head ptr
720Sstevel@tonic-gate	!	%g7	tail ptr
730Sstevel@tonic-gate	mov	CPU_MONDO_Q_HD, %g3
740Sstevel@tonic-gate	ldxa	[%g3]ASI_QUEUE, %g6	! %g6 = head ptr
750Sstevel@tonic-gate	mov	CPU_MONDO_Q_TL, %g4
760Sstevel@tonic-gate	ldxa	[%g4]ASI_QUEUE, %g7	! %g7 = tail ptr
770Sstevel@tonic-gate	cmp	%g6, %g7
784528Spaulsan	be,pn	%xcc, 3f		! head == tail
790Sstevel@tonic-gate	nop
800Sstevel@tonic-gate
810Sstevel@tonic-gate	CPU_ADDR(%g1,%g2)
820Sstevel@tonic-gate	add	%g1, CPU_MCPU, %g2
830Sstevel@tonic-gate	ldx	[%g2 + MCPU_CPU_Q_BASE], %g3	! %g3 = queue base PA
840Sstevel@tonic-gate	ldx	[%g2 + MCPU_CPU_Q_SIZE], %g4	! queue size
850Sstevel@tonic-gate	sub	%g4, 1, %g4		! %g4 = queue size mask
860Sstevel@tonic-gate
870Sstevel@tonic-gate	! Load interrupt receive data registers 1 and 2 to fetch
880Sstevel@tonic-gate	! the arguments for the fast trap handler.
890Sstevel@tonic-gate	!
900Sstevel@tonic-gate	! XXX - Since the data words in the interrupt report are not defined yet
910Sstevel@tonic-gate	! we assume that the consective words contain valid data and preserve
920Sstevel@tonic-gate	! sun4u's xcall mondo arguments.
930Sstevel@tonic-gate	! Register usage:
940Sstevel@tonic-gate	!	%g5	PC for fasttrap TL>0 handler
950Sstevel@tonic-gate	!	%g1	arg 1
960Sstevel@tonic-gate	!	%g2	arg 2
970Sstevel@tonic-gate
980Sstevel@tonic-gate	ldxa	[%g3 + %g6]ASI_MEM, %g5	! get PC from q base + head
990Sstevel@tonic-gate	add	%g6, 0x8, %g6		! inc head
1000Sstevel@tonic-gate	ldxa	[%g3 + %g6]ASI_MEM, %g1 ! read data word 1
1010Sstevel@tonic-gate	add	%g6, 0x8, %g6		! inc head
1020Sstevel@tonic-gate	ldxa	[%g3 + %g6]ASI_MEM, %g2	! read data word 2
1030Sstevel@tonic-gate	add	%g6, (INTR_REPORT_SIZE - 16) , %g6 ! inc head to next record
1040Sstevel@tonic-gate	and	%g6, %g4, %g6 		! and size mask for wrap around
1050Sstevel@tonic-gate	mov	CPU_MONDO_Q_HD, %g3
1060Sstevel@tonic-gate	stxa	%g6, [%g3]ASI_QUEUE	! store head pointer
1070Sstevel@tonic-gate	membar	#Sync
1080Sstevel@tonic-gate
1090Sstevel@tonic-gate#ifdef TRAPTRACE
1100Sstevel@tonic-gate	TRACE_PTR(%g4, %g6)
111*11172SHaik.Aftandilian@Sun.COM	GET_TRACE_TICK(%g6, %g3)
1120Sstevel@tonic-gate	stxa	%g6, [%g4 + TRAP_ENT_TICK]%asi
1130Sstevel@tonic-gate	TRACE_SAVE_TL_GL_REGS(%g4, %g6)
1140Sstevel@tonic-gate	rdpr	%tt, %g6
1150Sstevel@tonic-gate	stha	%g6, [%g4 + TRAP_ENT_TT]%asi
1160Sstevel@tonic-gate	rdpr	%tpc, %g6
1170Sstevel@tonic-gate	stna	%g6, [%g4 + TRAP_ENT_TPC]%asi
1180Sstevel@tonic-gate	rdpr	%tstate, %g6
1190Sstevel@tonic-gate	stxa	%g6, [%g4 + TRAP_ENT_TSTATE]%asi
1200Sstevel@tonic-gate	stna	%sp, [%g4 + TRAP_ENT_SP]%asi
1210Sstevel@tonic-gate	stna	%g5, [%g4 + TRAP_ENT_TR]%asi	! pc of the TL>0 handler
1220Sstevel@tonic-gate	stna	%g1, [%g4 + TRAP_ENT_F1]%asi	! arg1
1230Sstevel@tonic-gate	stna	%g2, [%g4 + TRAP_ENT_F3]%asi	! arg2
1240Sstevel@tonic-gate	mov	CPU_MONDO_Q_HD, %g6
1250Sstevel@tonic-gate	ldxa	[%g6]ASI_QUEUE, %g6		! new head offset
1260Sstevel@tonic-gate	stna	%g6, [%g4 + TRAP_ENT_F2]%asi
1270Sstevel@tonic-gate	stna	%g7, [%g4 + TRAP_ENT_F4]%asi	! tail offset
1280Sstevel@tonic-gate	TRACE_NEXT(%g4, %g6, %g3)
1290Sstevel@tonic-gate#endif /* TRAPTRACE */
1300Sstevel@tonic-gate
1310Sstevel@tonic-gate	/*
1320Sstevel@tonic-gate	 * For now catch invalid PC being passed via cpu_mondo queue
1330Sstevel@tonic-gate	 */
1340Sstevel@tonic-gate	set	KERNELBASE, %g4
1350Sstevel@tonic-gate	cmp	%g5, %g4
1364528Spaulsan	bl,pn	%xcc, 2f		! branch if bad %pc
1374528Spaulsan	  nop
1384528Spaulsan
1390Sstevel@tonic-gate
1404528Spaulsan	/*
1414528Spaulsan	 * If this platform supports shared contexts and we are jumping
1424528Spaulsan	 * to OBP code, then we need to invalidate both contexts to prevent OBP
1434528Spaulsan	 * from corrupting the shared context registers.
1444528Spaulsan	 *
1454528Spaulsan	 * If shared contexts are not supported then the next two instructions
1464528Spaulsan	 * will be patched with:
1474528Spaulsan	 *
1484528Spaulsan	 * jmp       %g5
1494528Spaulsan	 * nop
1504528Spaulsan	 *
1514528Spaulsan	 */
1524528Spaulsan	.global sfmmu_shctx_cpu_mondo_patch
1534528Spaulsansfmmu_shctx_cpu_mondo_patch:
1544528Spaulsan	set	OFW_START_ADDR, %g4	! Check if this a call into OBP?
1554528Spaulsan	cmp	%g5, %g4
1564528Spaulsan	bl,pt %xcc, 1f
1574528Spaulsan	  nop
1584528Spaulsan	set	OFW_END_ADDR, %g4
1594528Spaulsan	cmp	%g5, %g4
1604528Spaulsan	bg,pn %xcc, 1f
1614528Spaulsan	  nop
1624528Spaulsan	mov	MMU_PCONTEXT, %g3
1634528Spaulsan	ldxa	[%g3]ASI_MMU_CTX, %g4
1644528Spaulsan	cmp	%g4, INVALID_CONTEXT	! Check if we are in kernel mode
1654528Spaulsan	ble,pn %xcc, 1f			! or the primary context is invalid
1664528Spaulsan	  nop
1674528Spaulsan	set	INVALID_CONTEXT, %g4	! Invalidate contexts - compatability
1684528Spaulsan	stxa    %g4, [%g3]ASI_MMU_CTX	! mode ensures shared contexts are also
1694528Spaulsan	mov     MMU_SCONTEXT, %g3	! invalidated.
1704528Spaulsan	stxa    %g4, [%g3]ASI_MMU_CTX
1714528Spaulsan	membar  #Sync
1724528Spaulsan	mov	%o0, %g3		! save output regs
1734528Spaulsan	mov	%o1, %g4
1744528Spaulsan	mov	%o5, %g6
1754528Spaulsan	clr	%o0			! Invalidate tsbs, set ntsb = 0
1764528Spaulsan	clr	%o1			! and HV_TSB_INFO_PA = 0
1774528Spaulsan	mov	MMU_TSB_CTXNON0, %o5
1784528Spaulsan	ta	FAST_TRAP		! set TSB info for user process
1794528Spaulsan	brnz,a,pn %o0, ptl1_panic
1804528Spaulsan	  mov	PTL1_BAD_HCALL, %g1
1814528Spaulsan	mov	%g3, %o0		! restore output regs
1824528Spaulsan	mov	%g4, %o1
1834528Spaulsan	mov	%g6, %o5
1844528Spaulsan1:
1850Sstevel@tonic-gate	jmp	%g5			! jump to traphandler
1860Sstevel@tonic-gate	nop
1874528Spaulsan2:
1880Sstevel@tonic-gate	! invalid trap handler, discard it for now
1890Sstevel@tonic-gate	set	cpu_mondo_inval, %g4
1900Sstevel@tonic-gate	ldx	[%g4], %g5
1910Sstevel@tonic-gate	inc	%g5
1920Sstevel@tonic-gate	stx	%g5, [%g4]
1934528Spaulsan3:
1940Sstevel@tonic-gate	retry
1950Sstevel@tonic-gate	/* Never Reached */
1960Sstevel@tonic-gate	SET_SIZE(cpu_mondo)
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate#endif /* lint */
1990Sstevel@tonic-gate
2000Sstevel@tonic-gate#if defined(lint)
2010Sstevel@tonic-gate
2020Sstevel@tonic-gatevoid
2030Sstevel@tonic-gatedev_mondo(void)
2040Sstevel@tonic-gate{}
2050Sstevel@tonic-gate
2060Sstevel@tonic-gate#else	/* lint */
2070Sstevel@tonic-gate
2080Sstevel@tonic-gate
2090Sstevel@tonic-gate/*
2100Sstevel@tonic-gate * (TT 0x7d, TL>0) Dev Mondo Queue Handler
2110Sstevel@tonic-gate *	Globals are the Interrupt Globals.
2120Sstevel@tonic-gate * We only process one interrupt at a time causing us to keep
2130Sstevel@tonic-gate * taking this trap till the queue is empty.
2140Sstevel@tonic-gate * We really should drain the whole queue for better performance
2150Sstevel@tonic-gate * but this will do for now.
2160Sstevel@tonic-gate */
2170Sstevel@tonic-gate	ENTRY_NP(dev_mondo)
2180Sstevel@tonic-gate	!
2190Sstevel@tonic-gate	!	Register Usage:-
2200Sstevel@tonic-gate	!	%g5	PC for fasttrap TL>0 handler
2210Sstevel@tonic-gate	!	%g1	arg 1
2220Sstevel@tonic-gate	!	%g2	arg 2
2230Sstevel@tonic-gate	!	%g3	queue base PA
2240Sstevel@tonic-gate	!	%g4 	queue size mask
2250Sstevel@tonic-gate	!	%g6	head ptr
2260Sstevel@tonic-gate	!	%g7	tail ptr
2270Sstevel@tonic-gate	mov	DEV_MONDO_Q_HD, %g3
2280Sstevel@tonic-gate	ldxa	[%g3]ASI_QUEUE, %g6	! %g6 = head ptr
2290Sstevel@tonic-gate	mov	DEV_MONDO_Q_TL, %g4
2300Sstevel@tonic-gate	ldxa	[%g4]ASI_QUEUE, %g7	! %g7 = tail ptr
2310Sstevel@tonic-gate	cmp	%g6, %g7
2320Sstevel@tonic-gate	be,pn	%xcc, 0f		! head == tail
2330Sstevel@tonic-gate	nop
2340Sstevel@tonic-gate
2350Sstevel@tonic-gate	CPU_ADDR(%g1,%g2)
2360Sstevel@tonic-gate	add	%g1, CPU_MCPU, %g2
2370Sstevel@tonic-gate	ldx	[%g2 + MCPU_DEV_Q_BASE], %g3	! %g3 = queue base PA
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate	! Register usage:
2400Sstevel@tonic-gate	!	%g5 - inum
2410Sstevel@tonic-gate	!	%g1 - cpu struct pointer used below in TRAPTRACE
2420Sstevel@tonic-gate	!
2430Sstevel@tonic-gate	ldxa	[%g3 + %g6]ASI_MEM, %g5	! get inum from q base + head
2440Sstevel@tonic-gate
2450Sstevel@tonic-gate	!
2460Sstevel@tonic-gate	! We verify that inum is valid ( < MAXVNUM). If it is greater
2472973Sgovinda	! than MAXVNUM, we let setvecint_tl1 take care of it.
2480Sstevel@tonic-gate	!
2490Sstevel@tonic-gate	set	MAXIVNUM, %g4
2500Sstevel@tonic-gate	cmp	%g5, %g4
2510Sstevel@tonic-gate	bgeu,a,pn	%xcc, 1f
2520Sstevel@tonic-gate	ldx	[%g2 + MCPU_DEV_Q_SIZE], %g4	! queue size - delay slot
2530Sstevel@tonic-gate
2540Sstevel@tonic-gate	!
2550Sstevel@tonic-gate	!	Copy 64-byte payload to the *iv_payload if it is not NULL
2560Sstevel@tonic-gate	!
2572973Sgovinda	set	intr_vec_table, %g1		! %g1 = intr_vec_table
2582973Sgovinda	sll	%g5, CPTRSHIFT, %g7		! %g7 = offset to inum entry
2592973Sgovinda						!       in the intr_vec_table
2602973Sgovinda	add	%g1, %g7, %g7			! %g7 = &intr_vec_table[inum]
2612973Sgovinda	ldn	[%g7], %g1			! %g1 = ptr to intr_vec_t (iv)
2623200Sgovinda
2633200Sgovinda	!
2643200Sgovinda	! Verify the pointer to first intr_vec_t for a given inum and
2653200Sgovinda	! it should not be NULL. If this pointer is NULL, then it is a
2663200Sgovinda	! spurious interrupt. In this case, just call setvecint_tl1 and
2673200Sgovinda	! it will handle this spurious interrupt.
2683200Sgovinda	!
2693200Sgovinda	brz,a,pn	%g1, 1f			! if %g1 is NULL
2703200Sgovinda	ldx	[%g2 + MCPU_DEV_Q_SIZE], %g4	! queue size - delay slot
2713200Sgovinda
2722973Sgovinda	ldx	[%g1 + IV_PAYLOAD_BUF], %g1	! %g1 = iv->iv_payload_buf
2730Sstevel@tonic-gate	brz,a,pt	%g1, 1f			! if it is NULL
2740Sstevel@tonic-gate	ldx	[%g2 + MCPU_DEV_Q_SIZE], %g4	! queue size - delay slot
2750Sstevel@tonic-gate
2760Sstevel@tonic-gate	!
2770Sstevel@tonic-gate	!	Now move 64 byte payload from mondo queue to buf
2780Sstevel@tonic-gate	!
2790Sstevel@tonic-gate	mov	%g6, %g7			! %g7 = head ptr
2800Sstevel@tonic-gate	ldxa	[%g3 + %g7]ASI_MEM, %g4
2810Sstevel@tonic-gate	stx	%g4, [%g1 + 0]			! byte 0 - 7
2820Sstevel@tonic-gate	add	%g7, 8, %g7
2830Sstevel@tonic-gate	ldxa	[%g3 + %g7]ASI_MEM, %g4
2840Sstevel@tonic-gate	stx	%g4, [%g1 + 8]			! byte 8 - 15
2850Sstevel@tonic-gate	add	%g7, 8, %g7
2860Sstevel@tonic-gate	ldxa	[%g3 + %g7]ASI_MEM, %g4
2870Sstevel@tonic-gate	stx	%g4, [%g1 + 16]			! byte 16 - 23
2880Sstevel@tonic-gate	add	%g7, 8, %g7
2890Sstevel@tonic-gate	ldxa	[%g3 + %g7]ASI_MEM, %g4
2900Sstevel@tonic-gate	stx	%g4, [%g1 + 24]			! byte 24 - 31
2910Sstevel@tonic-gate	add	%g7, 8, %g7
2920Sstevel@tonic-gate	ldxa	[%g3 + %g7]ASI_MEM, %g4
2930Sstevel@tonic-gate	stx	%g4, [%g1 + 32]			! byte 32 - 39
2940Sstevel@tonic-gate	add	%g7, 8, %g7
2950Sstevel@tonic-gate	ldxa	[%g3 + %g7]ASI_MEM, %g4
2960Sstevel@tonic-gate	stx	%g4, [%g1 + 40]			! byte 40 - 47
2970Sstevel@tonic-gate	add	%g7, 8, %g7
2980Sstevel@tonic-gate	ldxa	[%g3 + %g7]ASI_MEM, %g4
2990Sstevel@tonic-gate	stx	%g4, [%g1 + 48]			! byte 48 - 55
3000Sstevel@tonic-gate	add	%g7, 8, %g7
3010Sstevel@tonic-gate	ldxa	[%g3 + %g7]ASI_MEM, %g4
3020Sstevel@tonic-gate	stx	%g4, [%g1 + 56]			! byte 56 - 63
3030Sstevel@tonic-gate	ldx	[%g2 + MCPU_DEV_Q_SIZE], %g4	! queue size
3040Sstevel@tonic-gate
3050Sstevel@tonic-gate1:	sub	%g4, 1, %g4		! %g4 = queue size mask
3060Sstevel@tonic-gate	add	%g6, INTR_REPORT_SIZE , %g6 ! inc head to next record
3070Sstevel@tonic-gate	and	%g6, %g4, %g6 		! and mask for wrap around
3080Sstevel@tonic-gate	mov	DEV_MONDO_Q_HD, %g3
3090Sstevel@tonic-gate	stxa	%g6, [%g3]ASI_QUEUE	! increment head offset
3100Sstevel@tonic-gate	membar	#Sync
3110Sstevel@tonic-gate
3120Sstevel@tonic-gate#ifdef TRAPTRACE
3130Sstevel@tonic-gate	TRACE_PTR(%g4, %g6)
314*11172SHaik.Aftandilian@Sun.COM	GET_TRACE_TICK(%g6, %g3)
3150Sstevel@tonic-gate	stxa	%g6, [%g4 + TRAP_ENT_TICK]%asi
3160Sstevel@tonic-gate	TRACE_SAVE_TL_GL_REGS(%g4, %g6)
3170Sstevel@tonic-gate	rdpr	%tt, %g6
3180Sstevel@tonic-gate	stha	%g6, [%g4 + TRAP_ENT_TT]%asi
3190Sstevel@tonic-gate	rdpr	%tpc, %g6
3200Sstevel@tonic-gate	stna	%g6, [%g4 + TRAP_ENT_TPC]%asi
3210Sstevel@tonic-gate	rdpr	%tstate, %g6
3220Sstevel@tonic-gate	stxa	%g6, [%g4 + TRAP_ENT_TSTATE]%asi
3230Sstevel@tonic-gate	! move head to sp
3240Sstevel@tonic-gate	ldx	[%g2 + MCPU_DEV_Q_BASE], %g6
3250Sstevel@tonic-gate	stna	%g6, [%g4 + TRAP_ENT_SP]%asi	! Device Queue Base PA
3260Sstevel@tonic-gate	stna	%g5, [%g4 + TRAP_ENT_TR]%asi	! Inum
3270Sstevel@tonic-gate	mov	DEV_MONDO_Q_HD, %g6
3280Sstevel@tonic-gate	ldxa	[%g6]ASI_QUEUE, %g6		! New head offset
3290Sstevel@tonic-gate	stna	%g6, [%g4 + TRAP_ENT_F1]%asi
3300Sstevel@tonic-gate	ldx	[%g2 + MCPU_DEV_Q_SIZE], %g6
3310Sstevel@tonic-gate	stna	%g6, [%g4 + TRAP_ENT_F2]%asi	! Q Size
3320Sstevel@tonic-gate	stna	%g7, [%g4 + TRAP_ENT_F3]%asi	! tail offset
3330Sstevel@tonic-gate	stna	%g0, [%g4 + TRAP_ENT_F4]%asi
3340Sstevel@tonic-gate	TRACE_NEXT(%g4, %g6, %g3)
3350Sstevel@tonic-gate#endif /* TRAPTRACE */
3360Sstevel@tonic-gate
3370Sstevel@tonic-gate	!
3382973Sgovinda	! setvecint_tl1 will do all the work, and finish with a retry
3390Sstevel@tonic-gate	!
3402973Sgovinda	ba,pt	%xcc, setvecint_tl1
3412973Sgovinda	mov	%g5, %g1		! setvecint_tl1 expects inum in %g1
3420Sstevel@tonic-gate
3430Sstevel@tonic-gate0:	retry
3440Sstevel@tonic-gate
3450Sstevel@tonic-gate	/* Never Reached */
3460Sstevel@tonic-gate	SET_SIZE(dev_mondo)
3470Sstevel@tonic-gate#endif /* lint */
3480Sstevel@tonic-gate
3490Sstevel@tonic-gate#if defined(lint)
3500Sstevel@tonic-gateuint64_t cpu_mondo_inval;
3510Sstevel@tonic-gate#else /* lint */
3520Sstevel@tonic-gate	.seg	".data"
3530Sstevel@tonic-gate	.global	cpu_mondo_inval
3540Sstevel@tonic-gate	.align	8
3550Sstevel@tonic-gatecpu_mondo_inval:
3560Sstevel@tonic-gate	.skip	8
3570Sstevel@tonic-gate
3580Sstevel@tonic-gate	.seg	".text"
3590Sstevel@tonic-gate#endif	/* lint */
3600Sstevel@tonic-gate
3610Sstevel@tonic-gate
3620Sstevel@tonic-gate#if defined(lint)
3630Sstevel@tonic-gate
3640Sstevel@tonic-gatevoid
3650Sstevel@tonic-gateresumable_error(void)
3660Sstevel@tonic-gate{}
3670Sstevel@tonic-gate
3680Sstevel@tonic-gate#else	/* lint */
3690Sstevel@tonic-gate
3700Sstevel@tonic-gate/*
3710Sstevel@tonic-gate * (TT 0x7e, TL>0) Resumeable Error Queue Handler
3720Sstevel@tonic-gate *	We keep a shadow copy of the queue in kernel buf.
3730Sstevel@tonic-gate *	Read the resumable queue head and tail offset
3740Sstevel@tonic-gate *	If there are entries on the queue, move them to
3750Sstevel@tonic-gate *	the kernel buf, which is next to the resumable
3760Sstevel@tonic-gate *	queue in the memory. Call C routine to process.
3770Sstevel@tonic-gate */
3780Sstevel@tonic-gate	ENTRY_NP(resumable_error)
3790Sstevel@tonic-gate	mov	CPU_RQ_HD, %g4
3800Sstevel@tonic-gate	ldxa	[%g4]ASI_QUEUE, %g2		! %g2 = Q head offset
3810Sstevel@tonic-gate	mov	CPU_RQ_TL, %g4
3820Sstevel@tonic-gate	ldxa	[%g4]ASI_QUEUE, %g3		! %g3 = Q tail offset
3830Sstevel@tonic-gate	mov	%g2, %g6			! save head in %g2
3840Sstevel@tonic-gate
3850Sstevel@tonic-gate	cmp	%g6, %g3
3860Sstevel@tonic-gate	be,pn	%xcc, 0f			! head == tail
3870Sstevel@tonic-gate	nop
3880Sstevel@tonic-gate
3890Sstevel@tonic-gate	CPU_ADDR(%g1, %g4)			! %g1 = cpu struct addr
3900Sstevel@tonic-gate
3910Sstevel@tonic-gate2:	set	CPU_RQ_BASE_OFF, %g4
3920Sstevel@tonic-gate	ldx	[%g1 + %g4], %g4		! %g4 = queue base PA
3930Sstevel@tonic-gate	add	%g6, %g4, %g4			! %g4 = PA of ER in Q
3940Sstevel@tonic-gate	set	CPU_RQ_SIZE, %g7
3950Sstevel@tonic-gate	add	%g4, %g7, %g7			! %g7=PA of ER in kernel buf
3960Sstevel@tonic-gate
3970Sstevel@tonic-gate	ldxa	[%g7]ASI_MEM, %g5		! %g5=first 8 byte of ER buf
3980Sstevel@tonic-gate	cmp	0, %g5
3990Sstevel@tonic-gate	bne,pn	%xcc, 1f			! first 8 byte is not 0
4000Sstevel@tonic-gate	nop
4010Sstevel@tonic-gate
4020Sstevel@tonic-gate	/* Now we can move 64 bytes from queue to buf */
4030Sstevel@tonic-gate	set	0, %g5
4040Sstevel@tonic-gate	ldxa	[%g4 + %g5]ASI_MEM, %g1
4050Sstevel@tonic-gate	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 0 - 7
4060Sstevel@tonic-gate	add	%g5, 8, %g5
4070Sstevel@tonic-gate	ldxa	[%g4 + %g5]ASI_MEM, %g1
4080Sstevel@tonic-gate	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 8 - 15
4090Sstevel@tonic-gate	add	%g5, 8, %g5
4100Sstevel@tonic-gate	ldxa	[%g4 + %g5]ASI_MEM, %g1
4110Sstevel@tonic-gate	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 16 - 23
4120Sstevel@tonic-gate	add	%g5, 8, %g5
4130Sstevel@tonic-gate	ldxa	[%g4 + %g5]ASI_MEM, %g1
4140Sstevel@tonic-gate	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 24 - 31
4150Sstevel@tonic-gate	add	%g5, 8, %g5
4160Sstevel@tonic-gate	ldxa	[%g4 + %g5]ASI_MEM, %g1
4170Sstevel@tonic-gate	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 32 - 39
4180Sstevel@tonic-gate	add	%g5, 8, %g5
4190Sstevel@tonic-gate	ldxa	[%g4 + %g5]ASI_MEM, %g1
4200Sstevel@tonic-gate	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 40 - 47
4210Sstevel@tonic-gate	add	%g5, 8, %g5
4220Sstevel@tonic-gate	ldxa	[%g4 + %g5]ASI_MEM, %g1
4230Sstevel@tonic-gate	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 48 - 55
4240Sstevel@tonic-gate	add	%g5, 8, %g5
4250Sstevel@tonic-gate	ldxa	[%g4 + %g5]ASI_MEM, %g1
4260Sstevel@tonic-gate	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 56 - 63
4270Sstevel@tonic-gate
4280Sstevel@tonic-gate	set	CPU_RQ_SIZE, %g5		! %g5 = queue size
4290Sstevel@tonic-gate	sub	%g5, 1, %g5			! %g5 = queu size mask
4300Sstevel@tonic-gate
4310Sstevel@tonic-gate	add	%g6, Q_ENTRY_SIZE, %g6		! increment q head to next
4320Sstevel@tonic-gate	and	%g6, %g5, %g6			! size mask for warp around
4330Sstevel@tonic-gate	cmp	%g6, %g3			! head == tail ??
4340Sstevel@tonic-gate
4350Sstevel@tonic-gate	bne,pn	%xcc, 2b			! still have more to process
4360Sstevel@tonic-gate	nop
4370Sstevel@tonic-gate
4380Sstevel@tonic-gate	/*
4390Sstevel@tonic-gate	 * head equals to tail now, we can update the queue head
4400Sstevel@tonic-gate	 * and call sys_trap
4410Sstevel@tonic-gate	 */
4420Sstevel@tonic-gate	mov	CPU_RQ_HD, %g4
4430Sstevel@tonic-gate	stxa	%g6, [%g4]ASI_QUEUE		! update head offset
4447718SJason.Beloro@Sun.COM	membar	#Sync
4450Sstevel@tonic-gate
4460Sstevel@tonic-gate	/*
447623Sdavemq	 * Call sys_trap at PIL 14 unless we're already at PIL 15. %g2.l is
448623Sdavemq	 * head offset(arg2) and %g3 is tail
4490Sstevel@tonic-gate	 * offset(arg3).
4500Sstevel@tonic-gate	 */
4510Sstevel@tonic-gate	set	process_resumable_error, %g1
452623Sdavemq	rdpr	%pil, %g4
453623Sdavemq	cmp	%g4, PIL_14
4540Sstevel@tonic-gate	ba	sys_trap
455623Sdavemq	  movl	%icc, PIL_14, %g4
4560Sstevel@tonic-gate
4570Sstevel@tonic-gate	/*
4580Sstevel@tonic-gate	 * We are here because the C routine is not able to process
4590Sstevel@tonic-gate	 * errors in time. So the first 8 bytes of ER in buf has not
4600Sstevel@tonic-gate	 * been cleared. We update head to tail and call sys_trap to
4610Sstevel@tonic-gate	 * print out an error message
4620Sstevel@tonic-gate	 */
4630Sstevel@tonic-gate
4640Sstevel@tonic-gate1:	mov	CPU_RQ_HD, %g4
4650Sstevel@tonic-gate	stxa	%g3, [%g4]ASI_QUEUE		! set head equal to tail
4667718SJason.Beloro@Sun.COM	membar	#Sync
4670Sstevel@tonic-gate
4680Sstevel@tonic-gate	/*
4690Sstevel@tonic-gate	 * Set %g2 to %g6, which is current head offset. %g2
4700Sstevel@tonic-gate	 * is arg2 of the C routine. %g3 is the tail offset,
4710Sstevel@tonic-gate	 * which is arg3 of the C routine.
472623Sdavemq	 * Call rq_overflow at PIL 14 unless we're already at PIL 15.
4730Sstevel@tonic-gate	 */
4740Sstevel@tonic-gate	mov	%g6, %g2
4750Sstevel@tonic-gate	set	rq_overflow, %g1
476623Sdavemq	rdpr	%pil, %g4
477623Sdavemq	cmp	%g4, PIL_14
4780Sstevel@tonic-gate	ba	sys_trap
479623Sdavemq	  movl	%icc, PIL_14, %g4
4800Sstevel@tonic-gate
4810Sstevel@tonic-gate0:	retry
4820Sstevel@tonic-gate
4830Sstevel@tonic-gate	/*NOTREACHED*/
4840Sstevel@tonic-gate	SET_SIZE(resumable_error)
4850Sstevel@tonic-gate#endif /* lint */
4860Sstevel@tonic-gate
4870Sstevel@tonic-gate#if defined(lint)
4880Sstevel@tonic-gate
4890Sstevel@tonic-gatevoid
4900Sstevel@tonic-gatenonresumable_error(void)
4910Sstevel@tonic-gate{}
4920Sstevel@tonic-gate
4930Sstevel@tonic-gate#else	/* lint */
4940Sstevel@tonic-gate
4950Sstevel@tonic-gate/*
4960Sstevel@tonic-gate * (TT 0x7f, TL>0) Non-resumeable Error Queue Handler
4970Sstevel@tonic-gate *	We keep a shadow copy of the queue in kernel buf.
4980Sstevel@tonic-gate *	Read non-resumable queue head and tail offset
4990Sstevel@tonic-gate *	If there are entries on the queue, move them to
5000Sstevel@tonic-gate *	the kernel buf, which is next to the non-resumable
5010Sstevel@tonic-gate *	queue in the memory. Call C routine to process.
5020Sstevel@tonic-gate */
5030Sstevel@tonic-gate	ENTRY_NP(nonresumable_error)
5040Sstevel@tonic-gate	mov	CPU_NRQ_HD, %g4
5050Sstevel@tonic-gate	ldxa	[%g4]ASI_QUEUE, %g2		! %g2 = Q head offset
5060Sstevel@tonic-gate	mov	CPU_NRQ_TL, %g4
5070Sstevel@tonic-gate	ldxa	[%g4]ASI_QUEUE, %g3		! %g3 = Q tail offset
5080Sstevel@tonic-gate
509817Swh94709	cmp	%g2, %g3
5100Sstevel@tonic-gate	be,pn	%xcc, 0f			! head == tail
5110Sstevel@tonic-gate	nop
5120Sstevel@tonic-gate
513817Swh94709	/* force %gl to 1 as sys_trap requires */
514817Swh94709	wrpr	%g0, 1, %gl
515817Swh94709	mov	CPU_NRQ_HD, %g4
516817Swh94709	ldxa	[%g4]ASI_QUEUE, %g2		! %g2 = Q head offset
517817Swh94709	mov	CPU_NRQ_TL, %g4
518817Swh94709	ldxa	[%g4]ASI_QUEUE, %g3		! %g3 = Q tail offset
519817Swh94709	mov	%g2, %g6			! save head in %g2
520817Swh94709
521817Swh94709	CPU_PADDR(%g1, %g4)			! %g1 = cpu struct paddr
5220Sstevel@tonic-gate
5230Sstevel@tonic-gate2:	set	CPU_NRQ_BASE_OFF, %g4
524817Swh94709	ldxa	[%g1 + %g4]ASI_MEM, %g4		! %g4 = queue base PA
5250Sstevel@tonic-gate	add	%g6, %g4, %g4			! %g4 = PA of ER in Q
5260Sstevel@tonic-gate	set	CPU_NRQ_SIZE, %g7
5270Sstevel@tonic-gate	add	%g4, %g7, %g7			! %g7 = PA of ER in kernel buf
5280Sstevel@tonic-gate
5290Sstevel@tonic-gate	ldxa	[%g7]ASI_MEM, %g5		! %g5 = first 8 byte of ER buf
5300Sstevel@tonic-gate	cmp	0, %g5
5310Sstevel@tonic-gate	bne,pn	%xcc, 1f			! first 8 byte is not 0
5320Sstevel@tonic-gate	nop
5330Sstevel@tonic-gate
53410271SJason.Beloro@Sun.COM	/* Now we can move 64 bytes from queue to buf */
5350Sstevel@tonic-gate	set	0, %g5
5360Sstevel@tonic-gate	ldxa	[%g4 + %g5]ASI_MEM, %g1
5370Sstevel@tonic-gate	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 0 - 7
5380Sstevel@tonic-gate	add	%g5, 8, %g5
5390Sstevel@tonic-gate	ldxa	[%g4 + %g5]ASI_MEM, %g1
5400Sstevel@tonic-gate	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 8 - 15
5410Sstevel@tonic-gate	add	%g5, 8, %g5
5420Sstevel@tonic-gate	ldxa	[%g4 + %g5]ASI_MEM, %g1
5430Sstevel@tonic-gate	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 16 - 23
54410271SJason.Beloro@Sun.COM	add	%g5, 8, %g5
5450Sstevel@tonic-gate	ldxa	[%g4 + %g5]ASI_MEM, %g1
5460Sstevel@tonic-gate	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 24 - 31
5470Sstevel@tonic-gate	add	%g5, 8, %g5
5480Sstevel@tonic-gate	ldxa	[%g4 + %g5]ASI_MEM, %g1
5490Sstevel@tonic-gate	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 32 - 39
5500Sstevel@tonic-gate	add	%g5, 8, %g5
5510Sstevel@tonic-gate	ldxa	[%g4 + %g5]ASI_MEM, %g1
5520Sstevel@tonic-gate	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 40 - 47
55310271SJason.Beloro@Sun.COM	add	%g5, 8, %g5
5540Sstevel@tonic-gate	ldxa	[%g4 + %g5]ASI_MEM, %g1
5550Sstevel@tonic-gate	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 48 - 55
5560Sstevel@tonic-gate	add	%g5, 8, %g5
5570Sstevel@tonic-gate	ldxa	[%g4 + %g5]ASI_MEM, %g1
5580Sstevel@tonic-gate	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 56 - 63
5590Sstevel@tonic-gate
5600Sstevel@tonic-gate	set	CPU_NRQ_SIZE, %g5		! %g5 = queue size
5610Sstevel@tonic-gate	sub	%g5, 1, %g5			! %g5 = queu size mask
5620Sstevel@tonic-gate
5630Sstevel@tonic-gate	add	%g6, Q_ENTRY_SIZE, %g6		! increment q head to next
5640Sstevel@tonic-gate	and	%g6, %g5, %g6			! size mask for warp around
5650Sstevel@tonic-gate	cmp	%g6, %g3			! head == tail ??
5660Sstevel@tonic-gate
5670Sstevel@tonic-gate	bne,pn	%xcc, 2b			! still have more to process
5680Sstevel@tonic-gate	nop
5690Sstevel@tonic-gate
5700Sstevel@tonic-gate	/*
5710Sstevel@tonic-gate	 * head equals to tail now, we can update the queue head
5720Sstevel@tonic-gate	 * and call sys_trap
5730Sstevel@tonic-gate	 */
5740Sstevel@tonic-gate	mov	CPU_NRQ_HD, %g4
5750Sstevel@tonic-gate	stxa	%g6, [%g4]ASI_QUEUE		! update head offset
5767718SJason.Beloro@Sun.COM	membar	#Sync
5777718SJason.Beloro@Sun.COM
5787718SJason.Beloro@Sun.COM	/*
5790Sstevel@tonic-gate	 * Call sys_trap. %g2 is TL(arg2), %g3 is head and tail
5800Sstevel@tonic-gate	 * offset(arg3).
5810Sstevel@tonic-gate	 * %g3 looks like following:
5820Sstevel@tonic-gate	 *	+--------------------+--------------------+
5830Sstevel@tonic-gate	 *	|   tail offset      |    head offset     |
5840Sstevel@tonic-gate	 *	+--------------------+--------------------+
5850Sstevel@tonic-gate	 *	63                 32 31                 0
586623Sdavemq	 *
587623Sdavemq	 * Run at PIL 14 unless we're already at PIL 15.
5880Sstevel@tonic-gate	 */
58910271SJason.Beloro@Sun.COM	sllx	%g3, 32, %g3			! %g3.h = tail offset
5900Sstevel@tonic-gate	or	%g3, %g2, %g3			! %g3.l = head offset
5910Sstevel@tonic-gate	rdpr	%tl, %g2			! %g2 = current tl
5921457Swh94709
5931457Swh94709	/*
5941457Swh94709	 * Now check if the first error that sent us here was caused
5951457Swh94709	 * in user's SPILL/FILL trap. If it was, we call sys_trap to
5961457Swh94709	 * kill the user process. Several considerations:
5971457Swh94709	 * - If multiple nonresumable errors happen, we only check the
5981457Swh94709	 *   first one. Nonresumable errors cause system either panic
5991457Swh94709	 *   or kill the user process. So the system has already
6001457Swh94709	 *   panic'ed or killed user process after processing the first
6011457Swh94709	 *   error. Therefore, no need to check if other error packet
6021457Swh94709	 *   for this type of error.
6031457Swh94709	 * - Errors happen in user's SPILL/FILL trap will bring us at
6041457Swh94709	 *   TL = 2.
6051457Swh94709	 * - We need to lower TL to 1 to get the trap type and tstate.
6061457Swh94709	 *   We don't go back to TL = 2 so no need to save states.
6071457Swh94709	 */
6081457Swh94709	cmp	%g2, 2
6091457Swh94709	bne,pt	%xcc, 3f			! if tl != 2
6101457Swh94709	nop
6111457Swh94709	/* Check to see if the trap pc is in a window spill/fill handling */
6121457Swh94709	rdpr	%tpc, %g4
6131457Swh94709	/* tpc should be in the trap table */
6141457Swh94709	set	trap_table, %g5
6151457Swh94709	cmp	%g4, %g5
6161457Swh94709	blu,pt	%xcc, 3f
6171457Swh94709	nop
6181457Swh94709	set	etrap_table, %g5
6191457Swh94709	cmp	%g4, %g5
6201457Swh94709	bgeu,pt	%xcc, 3f
6211457Swh94709	nop
6221457Swh94709	/* Set tl to 1 in order to read tt[1] and tstate[1] */
6231457Swh94709	wrpr	%g0, 1, %tl
6241457Swh94709	rdpr	%tt, %g4			! %g4 = tt[1]
6251457Swh94709	/* Check if tt[1] is a window trap */
6261457Swh94709	and	%g4, WTRAP_TTMASK, %g4
6271457Swh94709	cmp	%g4, WTRAP_TYPE
6281457Swh94709	bne,pt	%xcc, 3f
6291457Swh94709	nop
6301457Swh94709	rdpr	%tstate, %g5			! %g5 = tstate[1]
6311457Swh94709	btst	TSTATE_PRIV, %g5
6321457Swh94709	bnz	%xcc, 3f			! Is it from user code?
6331457Swh94709	nop
6341457Swh94709	/*
6351457Swh94709	 * Now we know the error happened in user's SPILL/FILL trap.
6361457Swh94709	 * Turn on the user spill/fill flag in %g2
6371457Swh94709	 */
6381457Swh94709	mov	1, %g4
6391457Swh94709	sllx	%g4, ERRH_U_SPILL_FILL_SHIFT, %g4
6401457Swh94709	or	%g2, %g4, %g2			! turn on flag in %g2
6411457Swh94709
6421457Swh947093:	sub	%g2, 1, %g2			! %g2.l = previous tl
6430Sstevel@tonic-gate
6440Sstevel@tonic-gate	set	process_nonresumable_error, %g1
645623Sdavemq	rdpr	%pil, %g4
646623Sdavemq	cmp	%g4, PIL_14
6470Sstevel@tonic-gate	ba	sys_trap
648623Sdavemq	  movl	%icc, PIL_14, %g4
6490Sstevel@tonic-gate
6500Sstevel@tonic-gate	/*
6510Sstevel@tonic-gate	 * We are here because the C routine is not able to process
6520Sstevel@tonic-gate	 * errors in time. So the first 8 bytes of ER in buf has not
653817Swh94709	 * been cleared. We call sys_trap to panic.
654817Swh94709	 * Run at PIL 14 unless we're already at PIL 15.
6550Sstevel@tonic-gate	 */
656817Swh947091:	set	nrq_overflow, %g1
657817Swh94709	rdpr	%pil, %g4
658817Swh94709	cmp	%g4, PIL_14
659817Swh94709	ba	sys_trap
660817Swh94709	  movl	%icc, PIL_14, %g4
6610Sstevel@tonic-gate
6620Sstevel@tonic-gate0:	retry
6630Sstevel@tonic-gate
6640Sstevel@tonic-gate	/*NOTREACHED*/
6650Sstevel@tonic-gate	SET_SIZE(nonresumable_error)
6660Sstevel@tonic-gate#endif /* lint */
667