xref: /titanic_52/usr/src/uts/sun4/ml/interrupt.s (revision 25cf1a301a396c38e8adf52c15f537b80d2483f7)
17c478bd9Sstevel@tonic-gate/*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*25cf1a30Sjl139090 * Common Development and Distribution License (the "License").
6*25cf1a30Sjl139090 * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate/*
22*25cf1a30Sjl139090 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate#pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate#if defined(lint)
297c478bd9Sstevel@tonic-gate#include <sys/types.h>
307c478bd9Sstevel@tonic-gate#include <sys/thread.h>
317c478bd9Sstevel@tonic-gate#else	/* lint */
327c478bd9Sstevel@tonic-gate#include "assym.h"
337c478bd9Sstevel@tonic-gate#endif	/* lint */
347c478bd9Sstevel@tonic-gate
357c478bd9Sstevel@tonic-gate#include <sys/cmn_err.h>
367c478bd9Sstevel@tonic-gate#include <sys/ftrace.h>
377c478bd9Sstevel@tonic-gate#include <sys/asm_linkage.h>
387c478bd9Sstevel@tonic-gate#include <sys/machthread.h>
397c478bd9Sstevel@tonic-gate#include <sys/machcpuvar.h>
407c478bd9Sstevel@tonic-gate#include <sys/intreg.h>
417c478bd9Sstevel@tonic-gate
427c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE
437c478bd9Sstevel@tonic-gate#include <sys/traptrace.h>
447c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */
457c478bd9Sstevel@tonic-gate
467c478bd9Sstevel@tonic-gate
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate#if defined(lint)
497c478bd9Sstevel@tonic-gate
507c478bd9Sstevel@tonic-gate/* ARGSUSED */
517c478bd9Sstevel@tonic-gatevoid
527c478bd9Sstevel@tonic-gatepil_interrupt(int level)
537c478bd9Sstevel@tonic-gate{}
547c478bd9Sstevel@tonic-gate
557c478bd9Sstevel@tonic-gate#else	/* lint */
567c478bd9Sstevel@tonic-gate
577c478bd9Sstevel@tonic-gate
587c478bd9Sstevel@tonic-gate/*
597c478bd9Sstevel@tonic-gate * (TT 0x40..0x4F, TL>0) Interrupt Level N Handler (N == 1..15)
607c478bd9Sstevel@tonic-gate * 	Register passed from LEVEL_INTERRUPT(level)
617c478bd9Sstevel@tonic-gate *	%g4 - interrupt request level
627c478bd9Sstevel@tonic-gate */
637c478bd9Sstevel@tonic-gate	ENTRY_NP(pil_interrupt)
647c478bd9Sstevel@tonic-gate	!
657c478bd9Sstevel@tonic-gate	! Register usage
667c478bd9Sstevel@tonic-gate	!	%g1 - cpu
677c478bd9Sstevel@tonic-gate	!	%g3 - intr_req
687c478bd9Sstevel@tonic-gate	!	%g4 - pil
697c478bd9Sstevel@tonic-gate	!	%g2, %g5, %g6 - temps
707c478bd9Sstevel@tonic-gate	!
717c478bd9Sstevel@tonic-gate	! grab the 1st intr_req off the list
727c478bd9Sstevel@tonic-gate	! if the list is empty, clear %clear_softint
737c478bd9Sstevel@tonic-gate	!
747c478bd9Sstevel@tonic-gate	CPU_ADDR(%g1, %g5)
757c478bd9Sstevel@tonic-gate	!
767c478bd9Sstevel@tonic-gate	ALTENTRY(pil_interrupt_common)
777c478bd9Sstevel@tonic-gate	sll	%g4, CPTRSHIFT, %g5
787c478bd9Sstevel@tonic-gate	add	%g1, INTR_HEAD, %g6	! intr_head[0]
797c478bd9Sstevel@tonic-gate	add	%g6, %g5, %g6		! intr_head[pil]
807c478bd9Sstevel@tonic-gate	ldn	[%g6], %g3		! g3 = intr_req
817c478bd9Sstevel@tonic-gate
827c478bd9Sstevel@tonic-gate#ifndef DEBUG
837c478bd9Sstevel@tonic-gate	brnz,pt	%g3, 5f
847c478bd9Sstevel@tonic-gate	nop
857c478bd9Sstevel@tonic-gate#else
867c478bd9Sstevel@tonic-gate	!
877c478bd9Sstevel@tonic-gate	! Verify the address of intr_req; it should be within the
887c478bd9Sstevel@tonic-gate	! address range of intr_pool and intr_head
897c478bd9Sstevel@tonic-gate	! or the address range of intr_add_head and intr_add_tail.
907c478bd9Sstevel@tonic-gate	! The range of intr_add_head and intr_add_tail is subdivided
917c478bd9Sstevel@tonic-gate	! by cpu, but the subdivision is not verified here.
927c478bd9Sstevel@tonic-gate	!
937c478bd9Sstevel@tonic-gate	! Registers passed to sys_trap()
947c478bd9Sstevel@tonic-gate	!	%g1 - no_intr_req
957c478bd9Sstevel@tonic-gate	!	%g2 - intr_req
967c478bd9Sstevel@tonic-gate	!	%g3 - %pil
977c478bd9Sstevel@tonic-gate	!	%g4 - current pil
987c478bd9Sstevel@tonic-gate	!
997c478bd9Sstevel@tonic-gate	add	%g1, INTR_POOL, %g2
1007c478bd9Sstevel@tonic-gate	cmp	%g3, %g2
1017c478bd9Sstevel@tonic-gate	blu,pn	%xcc, 8f
1027c478bd9Sstevel@tonic-gate	nop
1037c478bd9Sstevel@tonic-gate	add	%g1, INTR_HEAD, %g2
1047c478bd9Sstevel@tonic-gate	cmp	%g2, %g3
1057c478bd9Sstevel@tonic-gate	bgeu,pt	%xcc, 5f
1067c478bd9Sstevel@tonic-gate	nop
1077c478bd9Sstevel@tonic-gate8:
1087c478bd9Sstevel@tonic-gate	sethi	%hi(intr_add_head), %g2
1097c478bd9Sstevel@tonic-gate	ldn	[%g2 + %lo(intr_add_head)], %g2
1107c478bd9Sstevel@tonic-gate	brz,pn	%g2, 4f			! intr_add_head can be NULL
1117c478bd9Sstevel@tonic-gate	cmp	%g3, %g2
1127c478bd9Sstevel@tonic-gate	blu,pn	%xcc, 4f
1137c478bd9Sstevel@tonic-gate	nop
1147c478bd9Sstevel@tonic-gate	sethi	%hi(intr_add_tail), %g2
1157c478bd9Sstevel@tonic-gate	ldn	[%g2 + %lo(intr_add_tail)], %g2
1167c478bd9Sstevel@tonic-gate	cmp	%g2, %g3
1177c478bd9Sstevel@tonic-gate	bgeu,pt	%xcc, 5f
1187c478bd9Sstevel@tonic-gate	nop
1197c478bd9Sstevel@tonic-gate4:
1207c478bd9Sstevel@tonic-gate#endif /* DEBUG */
1217c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE
1227c478bd9Sstevel@tonic-gate	TRACE_PTR(%g5, %g2)
1237c478bd9Sstevel@tonic-gate	GET_TRACE_TICK(%g2)
1247c478bd9Sstevel@tonic-gate	stxa	%g2, [%g5 + TRAP_ENT_TICK]%asi
1257c478bd9Sstevel@tonic-gate	TRACE_SAVE_TL_GL_REGS(%g5, %g2)
1267c478bd9Sstevel@tonic-gate	mov	0xbad, %g2
1277c478bd9Sstevel@tonic-gate	stha	%g2, [%g5 + TRAP_ENT_TT]%asi
1287c478bd9Sstevel@tonic-gate	rdpr	%tpc, %g2
1297c478bd9Sstevel@tonic-gate	stna	%g2, [%g5 + TRAP_ENT_TPC]%asi
1307c478bd9Sstevel@tonic-gate	rdpr	%tstate, %g2
1317c478bd9Sstevel@tonic-gate	stxa	%g2, [%g5 + TRAP_ENT_TSTATE]%asi
1327c478bd9Sstevel@tonic-gate	stna	%g0, [%g5 + TRAP_ENT_SP]%asi
1337c478bd9Sstevel@tonic-gate	stna	%g1, [%g5 + TRAP_ENT_TR]%asi
1347c478bd9Sstevel@tonic-gate	rd	SOFTINT, %g2
1357c478bd9Sstevel@tonic-gate	stna	%g2, [%g5 + TRAP_ENT_F1]%asi
1367c478bd9Sstevel@tonic-gate	stna	%g3, [%g5 + TRAP_ENT_F2]%asi
1377c478bd9Sstevel@tonic-gate	stna	%g4, [%g5 + TRAP_ENT_F3]%asi
1387c478bd9Sstevel@tonic-gate	stna	%g6, [%g5 + TRAP_ENT_F4]%asi
1397c478bd9Sstevel@tonic-gate	TRACE_NEXT(%g5, %g2, %g1)
1407c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */
1417c478bd9Sstevel@tonic-gate	ba	ptl1_panic
1427c478bd9Sstevel@tonic-gate	mov	PTL1_BAD_INTR_REQ, %g1
1437c478bd9Sstevel@tonic-gate5:
1447c478bd9Sstevel@tonic-gate	ldn	[%g3 + INTR_NEXT], %g2	! 2nd entry
1457c478bd9Sstevel@tonic-gate	brnz,pn	%g2, 1f			! branch if list not empty
1467c478bd9Sstevel@tonic-gate	stn	%g2, [%g6]
1477c478bd9Sstevel@tonic-gate	add	%g1, INTR_TAIL, %g6	! intr_tail[0]
1487c478bd9Sstevel@tonic-gate	stn	%g0, [%g5 + %g6]	! update intr_tail[pil]
1497c478bd9Sstevel@tonic-gate	mov	1, %g5
1507c478bd9Sstevel@tonic-gate	sll	%g5, %g4, %g5
1517c478bd9Sstevel@tonic-gate	wr	%g5, CLEAR_SOFTINT
1527c478bd9Sstevel@tonic-gate1:
1537c478bd9Sstevel@tonic-gate	!
1547c478bd9Sstevel@tonic-gate	! put intr_req on free list
1557c478bd9Sstevel@tonic-gate	!	%g2 - inumber
1567c478bd9Sstevel@tonic-gate	!
1577c478bd9Sstevel@tonic-gate	ldn	[%g1 + INTR_HEAD], %g5	! current head of free list
1587c478bd9Sstevel@tonic-gate	lduw	[%g3 + INTR_NUMBER], %g2
1597c478bd9Sstevel@tonic-gate	stn	%g3, [%g1 + INTR_HEAD]
1607c478bd9Sstevel@tonic-gate	stn	%g5, [%g3 + INTR_NEXT]
1617c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE
1627c478bd9Sstevel@tonic-gate	TRACE_PTR(%g5, %g6)
1637c478bd9Sstevel@tonic-gate	GET_TRACE_TICK(%g6)
1647c478bd9Sstevel@tonic-gate	stxa	%g6, [%g5 + TRAP_ENT_TICK]%asi
1657c478bd9Sstevel@tonic-gate	TRACE_SAVE_TL_GL_REGS(%g5, %g6)
1667c478bd9Sstevel@tonic-gate	rdpr	%tt, %g6
1677c478bd9Sstevel@tonic-gate	stha	%g6, [%g5 + TRAP_ENT_TT]%asi
1687c478bd9Sstevel@tonic-gate	rdpr	%tpc, %g6
1697c478bd9Sstevel@tonic-gate	stna	%g6, [%g5 + TRAP_ENT_TPC]%asi
1707c478bd9Sstevel@tonic-gate	rdpr	%tstate, %g6
1717c478bd9Sstevel@tonic-gate	stxa	%g6, [%g5 + TRAP_ENT_TSTATE]%asi
1727c478bd9Sstevel@tonic-gate	stna	%sp, [%g5 + TRAP_ENT_SP]%asi
1737c478bd9Sstevel@tonic-gate	stna	%g3, [%g5 + TRAP_ENT_TR]%asi
1747c478bd9Sstevel@tonic-gate	stna	%g2, [%g5 + TRAP_ENT_F1]%asi
1757c478bd9Sstevel@tonic-gate	sll	%g4, CPTRSHIFT, %g3
1767c478bd9Sstevel@tonic-gate	add	%g1, INTR_HEAD, %g6
1777c478bd9Sstevel@tonic-gate	ldn	[%g6 + %g3], %g6		! intr_head[pil]
1787c478bd9Sstevel@tonic-gate	stna	%g6, [%g5 + TRAP_ENT_F2]%asi
1797c478bd9Sstevel@tonic-gate	add	%g1, INTR_TAIL, %g6
1807c478bd9Sstevel@tonic-gate	ldn	[%g6 + %g3], %g6		! intr_tail[pil]
1817c478bd9Sstevel@tonic-gate	stna	%g4, [%g5 + TRAP_ENT_F3]%asi
1827c478bd9Sstevel@tonic-gate	stna	%g6, [%g5 + TRAP_ENT_F4]%asi
1837c478bd9Sstevel@tonic-gate	TRACE_NEXT(%g5, %g6, %g3)
1847c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */
1857c478bd9Sstevel@tonic-gate	!
1867c478bd9Sstevel@tonic-gate	! clear the iv_pending flag for this inum
1877c478bd9Sstevel@tonic-gate	!
1887c478bd9Sstevel@tonic-gate	set	intr_vector, %g5;
1897c478bd9Sstevel@tonic-gate	sll	%g2, INTR_VECTOR_SHIFT, %g6;
1907c478bd9Sstevel@tonic-gate	add	%g5, %g6, %g5;			! &intr_vector[inum]
1917c478bd9Sstevel@tonic-gate	sth	%g0, [%g5 + IV_PENDING]
1927c478bd9Sstevel@tonic-gate
1937c478bd9Sstevel@tonic-gate	!
1947c478bd9Sstevel@tonic-gate	! Prepare for sys_trap()
1957c478bd9Sstevel@tonic-gate	!
1967c478bd9Sstevel@tonic-gate	! Registers passed to sys_trap()
1977c478bd9Sstevel@tonic-gate	!	%g1 - interrupt handler at TL==0
1987c478bd9Sstevel@tonic-gate	!	%g2 - inumber
1997c478bd9Sstevel@tonic-gate	!	%g3 - pil
2007c478bd9Sstevel@tonic-gate	!	%g4 - initial pil for handler
2017c478bd9Sstevel@tonic-gate	!
2027c478bd9Sstevel@tonic-gate	! figure which handler to run and which %pil it starts at
2037c478bd9Sstevel@tonic-gate	! intr_thread starts at DISP_LEVEL to prevent preemption
2047c478bd9Sstevel@tonic-gate	! current_thread starts at PIL_MAX to protect cpu_intr_actv
2057c478bd9Sstevel@tonic-gate	!
2067c478bd9Sstevel@tonic-gate	mov	%g4, %g3
2077c478bd9Sstevel@tonic-gate	cmp	%g4, LOCK_LEVEL
2087c478bd9Sstevel@tonic-gate	bg,a,pt	%xcc, 4f		! branch if pil > LOCK_LEVEL
2097c478bd9Sstevel@tonic-gate	mov	PIL_MAX, %g4
2107c478bd9Sstevel@tonic-gate	sethi	%hi(intr_thread), %g1
2117c478bd9Sstevel@tonic-gate	mov	DISP_LEVEL, %g4
2127c478bd9Sstevel@tonic-gate	ba,pt	%xcc, sys_trap
2137c478bd9Sstevel@tonic-gate	or	%g1, %lo(intr_thread), %g1
2147c478bd9Sstevel@tonic-gate4:
2157c478bd9Sstevel@tonic-gate	sethi	%hi(current_thread), %g1
2167c478bd9Sstevel@tonic-gate	ba,pt	%xcc, sys_trap
2177c478bd9Sstevel@tonic-gate	or	%g1, %lo(current_thread), %g1
2187c478bd9Sstevel@tonic-gate	SET_SIZE(pil_interrupt_common)
2197c478bd9Sstevel@tonic-gate	SET_SIZE(pil_interrupt)
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate#endif	/* lint */
2227c478bd9Sstevel@tonic-gate
2237c478bd9Sstevel@tonic-gate
2247c478bd9Sstevel@tonic-gate#ifndef	lint
2257c478bd9Sstevel@tonic-gate_spurious:
2267c478bd9Sstevel@tonic-gate	.asciz	"!interrupt 0x%x at level %d not serviced"
2277c478bd9Sstevel@tonic-gate
2287c478bd9Sstevel@tonic-gate/*
2297c478bd9Sstevel@tonic-gate * SERVE_INTR_PRE is called once, just before the first invocation
2307c478bd9Sstevel@tonic-gate * of SERVE_INTR.
2317c478bd9Sstevel@tonic-gate *
2327c478bd9Sstevel@tonic-gate * Registers on entry:
2337c478bd9Sstevel@tonic-gate *
2347c478bd9Sstevel@tonic-gate * inum, cpu, regs: may be out-registers
2357c478bd9Sstevel@tonic-gate * ls1, ls2: local scratch registers
2367c478bd9Sstevel@tonic-gate * os1, os2, os3: scratch registers, may be out
2377c478bd9Sstevel@tonic-gate */
2387c478bd9Sstevel@tonic-gate
2397c478bd9Sstevel@tonic-gate#define SERVE_INTR_PRE(inum, cpu, ls1, ls2, os1, os2, os3, regs)	\
2407c478bd9Sstevel@tonic-gate	set	intr_vector, ls1;					\
2417c478bd9Sstevel@tonic-gate	sll	inum, INTR_VECTOR_SHIFT, os1;				\
2427c478bd9Sstevel@tonic-gate	add	ls1, os1, ls1;						\
2437c478bd9Sstevel@tonic-gate	SERVE_INTR_TRACE(inum, os1, os2, os3, regs);			\
2447c478bd9Sstevel@tonic-gate	mov	inum, ls2;
2457c478bd9Sstevel@tonic-gate
2467c478bd9Sstevel@tonic-gate/*
2477c478bd9Sstevel@tonic-gate * SERVE_INTR is called immediately after either SERVE_INTR_PRE or
2487c478bd9Sstevel@tonic-gate * SERVE_INTR_NEXT, without intervening code. No register values
2497c478bd9Sstevel@tonic-gate * may be modified.
2507c478bd9Sstevel@tonic-gate *
2517c478bd9Sstevel@tonic-gate * After calling SERVE_INTR, the caller must check if os3 is set. If
2527c478bd9Sstevel@tonic-gate * so, there is another interrupt to process. The caller must call
2537c478bd9Sstevel@tonic-gate * SERVE_INTR_NEXT, immediately followed by SERVE_INTR.
2547c478bd9Sstevel@tonic-gate *
2557c478bd9Sstevel@tonic-gate * Before calling SERVE_INTR_NEXT, the caller may perform accounting
2567c478bd9Sstevel@tonic-gate * and other actions which need to occur after invocation of an interrupt
2577c478bd9Sstevel@tonic-gate * handler. However, the values of ls1 and os3 *must* be preserved and
2587c478bd9Sstevel@tonic-gate * passed unmodified into SERVE_INTR_NEXT.
2597c478bd9Sstevel@tonic-gate *
2607c478bd9Sstevel@tonic-gate * Registers on return from SERVE_INTR:
2617c478bd9Sstevel@tonic-gate *
2627c478bd9Sstevel@tonic-gate * ls1 - the pil just processed
2637c478bd9Sstevel@tonic-gate * ls2 - the inum just processed
2647c478bd9Sstevel@tonic-gate * os3 - if set, another interrupt needs to be processed
2657c478bd9Sstevel@tonic-gate * cpu, ls1, os3 - must be preserved if os3 is set
2667c478bd9Sstevel@tonic-gate */
2677c478bd9Sstevel@tonic-gate
2687c478bd9Sstevel@tonic-gate#define	SERVE_INTR(os5, cpu, ls1, ls2, os1, os2, os3, os4)		\
2697c478bd9Sstevel@tonic-gate	ldn	[ls1 + IV_HANDLER], os2;				\
2707c478bd9Sstevel@tonic-gate	ldn	[ls1 + IV_ARG], %o0;					\
2717c478bd9Sstevel@tonic-gate	ldn	[ls1 + IV_SOFTINT_ARG2], %o1;					\
2727c478bd9Sstevel@tonic-gate	call	os2;							\
2737c478bd9Sstevel@tonic-gate	lduh	[ls1 + IV_PIL], ls1;					\
2747c478bd9Sstevel@tonic-gate	brnz,pt	%o0, 2f;						\
2757c478bd9Sstevel@tonic-gate	mov	CE_WARN, %o0;						\
2767c478bd9Sstevel@tonic-gate	set	_spurious, %o1;						\
2777c478bd9Sstevel@tonic-gate	mov	ls2, %o2;						\
2787c478bd9Sstevel@tonic-gate	call	cmn_err;						\
2797c478bd9Sstevel@tonic-gate	rdpr	%pil, %o3;						\
2807c478bd9Sstevel@tonic-gate2:	ldn	[THREAD_REG + T_CPU], cpu;				\
2817c478bd9Sstevel@tonic-gate	sll	ls1, 3, os1;						\
2827c478bd9Sstevel@tonic-gate	add	os1, CPU_STATS_SYS_INTR - 8, os2;			\
2837c478bd9Sstevel@tonic-gate	ldx	[cpu + os2], os3;					\
2847c478bd9Sstevel@tonic-gate	inc	os3;							\
2857c478bd9Sstevel@tonic-gate	stx	os3, [cpu + os2];					\
2867c478bd9Sstevel@tonic-gate	sll	ls1, CPTRSHIFT, os2;					\
2877c478bd9Sstevel@tonic-gate	add	cpu,  INTR_HEAD, os1;					\
2887c478bd9Sstevel@tonic-gate	add	os1, os2, os1;						\
2897c478bd9Sstevel@tonic-gate	ldn	[os1], os3;
2907c478bd9Sstevel@tonic-gate
2917c478bd9Sstevel@tonic-gate/*
2927c478bd9Sstevel@tonic-gate * Registers on entry:
2937c478bd9Sstevel@tonic-gate *
2947c478bd9Sstevel@tonic-gate * cpu			- cpu pointer (clobbered, set to cpu upon completion)
2957c478bd9Sstevel@tonic-gate * ls1, os3		- preserved from prior call to SERVE_INTR
2967c478bd9Sstevel@tonic-gate * ls2			- local scratch reg (not preserved)
2977c478bd9Sstevel@tonic-gate * os1, os2, os4, os5	- scratch reg, can be out (not preserved)
2987c478bd9Sstevel@tonic-gate */
2997c478bd9Sstevel@tonic-gate#define SERVE_INTR_NEXT(os5, cpu, ls1, ls2, os1, os2, os3, os4)		\
3007c478bd9Sstevel@tonic-gate	sll	ls1, CPTRSHIFT, os4;					\
3017c478bd9Sstevel@tonic-gate	add	cpu, INTR_HEAD, os1;					\
3027c478bd9Sstevel@tonic-gate	rdpr	%pstate, ls2;						\
3037c478bd9Sstevel@tonic-gate	wrpr	ls2, PSTATE_IE, %pstate;				\
3047c478bd9Sstevel@tonic-gate	ldn 	[os3 + INTR_NEXT], os2;					\
3057c478bd9Sstevel@tonic-gate	brnz,pn	os2, 4f;						\
3067c478bd9Sstevel@tonic-gate	stn	os2, [os1 + os4];					\
3077c478bd9Sstevel@tonic-gate	add	cpu, INTR_TAIL, os1;					\
3087c478bd9Sstevel@tonic-gate	stn	%g0, [os1 + os4];					\
3097c478bd9Sstevel@tonic-gate	mov	1, os1;							\
3107c478bd9Sstevel@tonic-gate	sll	os1, ls1, os1;						\
3117c478bd9Sstevel@tonic-gate	wr	os1, CLEAR_SOFTINT;					\
3127c478bd9Sstevel@tonic-gate4:	ldn	[cpu + INTR_HEAD], os1;					\
3137c478bd9Sstevel@tonic-gate	ld 	[os3 + INTR_NUMBER], os5;				\
3147c478bd9Sstevel@tonic-gate	stn	os3, [cpu + INTR_HEAD];					\
3157c478bd9Sstevel@tonic-gate	stn	os1, [os3 + INTR_NEXT];					\
3167c478bd9Sstevel@tonic-gate	set	intr_vector, ls1;					\
3177c478bd9Sstevel@tonic-gate	sll	os5, INTR_VECTOR_SHIFT, os1;				\
3187c478bd9Sstevel@tonic-gate	add	ls1, os1, ls1;						\
3197c478bd9Sstevel@tonic-gate	sth	%g0, [ls1 + IV_PENDING];				\
3207c478bd9Sstevel@tonic-gate	wrpr	%g0, ls2, %pstate;					\
3217c478bd9Sstevel@tonic-gate	SERVE_INTR_TRACE2(os5, os1, os2, os3, os4);			\
3227c478bd9Sstevel@tonic-gate	mov	os5, ls2;
3237c478bd9Sstevel@tonic-gate
3247c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE
3257c478bd9Sstevel@tonic-gate/*
3267c478bd9Sstevel@tonic-gate * inum - not modified, _spurious depends on it.
3277c478bd9Sstevel@tonic-gate */
3287c478bd9Sstevel@tonic-gate#define	SERVE_INTR_TRACE(inum, os1, os2, os3, os4)			\
3297c478bd9Sstevel@tonic-gate	rdpr	%pstate, os3;						\
3307c478bd9Sstevel@tonic-gate	andn	os3, PSTATE_IE | PSTATE_AM, os2;			\
3317c478bd9Sstevel@tonic-gate	wrpr	%g0, os2, %pstate;					\
3327c478bd9Sstevel@tonic-gate	TRACE_PTR(os1, os2);						\
3337c478bd9Sstevel@tonic-gate	ldn	[os4 + PC_OFF], os2;					\
3347c478bd9Sstevel@tonic-gate	stna	os2, [os1 + TRAP_ENT_TPC]%asi;				\
3357c478bd9Sstevel@tonic-gate	ldx	[os4 + TSTATE_OFF], os2;				\
3367c478bd9Sstevel@tonic-gate	stxa	os2, [os1 + TRAP_ENT_TSTATE]%asi;			\
3377c478bd9Sstevel@tonic-gate	mov	os3, os4;						\
3387c478bd9Sstevel@tonic-gate	GET_TRACE_TICK(os2); 						\
3397c478bd9Sstevel@tonic-gate	stxa	os2, [os1 + TRAP_ENT_TICK]%asi;				\
3407c478bd9Sstevel@tonic-gate	TRACE_SAVE_TL_GL_REGS(os1, os2);				\
3417c478bd9Sstevel@tonic-gate	set	TT_SERVE_INTR, os2;					\
3427c478bd9Sstevel@tonic-gate	rdpr	%pil, os3;						\
3437c478bd9Sstevel@tonic-gate	or	os2, os3, os2;						\
3447c478bd9Sstevel@tonic-gate	stha	os2, [os1 + TRAP_ENT_TT]%asi;				\
3457c478bd9Sstevel@tonic-gate	stna	%sp, [os1 + TRAP_ENT_SP]%asi;				\
3467c478bd9Sstevel@tonic-gate	stna	inum, [os1 + TRAP_ENT_TR]%asi;				\
3477c478bd9Sstevel@tonic-gate	stna	%g0, [os1 + TRAP_ENT_F1]%asi;				\
3487c478bd9Sstevel@tonic-gate	stna	%g0, [os1 + TRAP_ENT_F2]%asi;				\
3497c478bd9Sstevel@tonic-gate	stna	%g0, [os1 + TRAP_ENT_F3]%asi;				\
3507c478bd9Sstevel@tonic-gate	stna	%g0, [os1 + TRAP_ENT_F4]%asi;				\
3517c478bd9Sstevel@tonic-gate	TRACE_NEXT(os1, os2, os3);					\
3527c478bd9Sstevel@tonic-gate	wrpr	%g0, os4, %pstate
3537c478bd9Sstevel@tonic-gate#else	/* TRAPTRACE */
3547c478bd9Sstevel@tonic-gate#define SERVE_INTR_TRACE(inum, os1, os2, os3, os4)
3557c478bd9Sstevel@tonic-gate#endif	/* TRAPTRACE */
3567c478bd9Sstevel@tonic-gate
3577c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE
3587c478bd9Sstevel@tonic-gate/*
3597c478bd9Sstevel@tonic-gate * inum - not modified, _spurious depends on it.
3607c478bd9Sstevel@tonic-gate */
3617c478bd9Sstevel@tonic-gate#define	SERVE_INTR_TRACE2(inum, os1, os2, os3, os4)			\
3627c478bd9Sstevel@tonic-gate	rdpr	%pstate, os3;						\
3637c478bd9Sstevel@tonic-gate	andn	os3, PSTATE_IE | PSTATE_AM, os2;			\
3647c478bd9Sstevel@tonic-gate	wrpr	%g0, os2, %pstate;					\
3657c478bd9Sstevel@tonic-gate	TRACE_PTR(os1, os2);						\
3667c478bd9Sstevel@tonic-gate	stna	%g0, [os1 + TRAP_ENT_TPC]%asi;				\
3677c478bd9Sstevel@tonic-gate	stxa	%g0, [os1 + TRAP_ENT_TSTATE]%asi;			\
3687c478bd9Sstevel@tonic-gate	mov	os3, os4;						\
3697c478bd9Sstevel@tonic-gate	GET_TRACE_TICK(os2); 						\
3707c478bd9Sstevel@tonic-gate	stxa	os2, [os1 + TRAP_ENT_TICK]%asi;				\
3717c478bd9Sstevel@tonic-gate	TRACE_SAVE_TL_GL_REGS(os1, os2);				\
3727c478bd9Sstevel@tonic-gate	set	TT_SERVE_INTR, os2;					\
3737c478bd9Sstevel@tonic-gate	rdpr	%pil, os3;						\
3747c478bd9Sstevel@tonic-gate	or	os2, os3, os2;						\
3757c478bd9Sstevel@tonic-gate	stha	os2, [os1 + TRAP_ENT_TT]%asi;				\
3767c478bd9Sstevel@tonic-gate	stna	%sp, [os1 + TRAP_ENT_SP]%asi;				\
3777c478bd9Sstevel@tonic-gate	stna	inum, [os1 + TRAP_ENT_TR]%asi;				\
3787c478bd9Sstevel@tonic-gate	stna	%g0, [os1 + TRAP_ENT_F1]%asi;				\
3797c478bd9Sstevel@tonic-gate	stna	%g0, [os1 + TRAP_ENT_F2]%asi;				\
3807c478bd9Sstevel@tonic-gate	stna	%g0, [os1 + TRAP_ENT_F3]%asi;				\
3817c478bd9Sstevel@tonic-gate	stna	%g0, [os1 + TRAP_ENT_F4]%asi;				\
3827c478bd9Sstevel@tonic-gate	TRACE_NEXT(os1, os2, os3);					\
3837c478bd9Sstevel@tonic-gate	wrpr	%g0, os4, %pstate
3847c478bd9Sstevel@tonic-gate#else	/* TRAPTRACE */
3857c478bd9Sstevel@tonic-gate#define SERVE_INTR_TRACE2(inum, os1, os2, os3, os4)
3867c478bd9Sstevel@tonic-gate#endif	/* TRAPTRACE */
3877c478bd9Sstevel@tonic-gate
3887c478bd9Sstevel@tonic-gate#endif	/* lint */
3897c478bd9Sstevel@tonic-gate
3907c478bd9Sstevel@tonic-gate#if defined(lint)
3917c478bd9Sstevel@tonic-gate
3927c478bd9Sstevel@tonic-gate/*ARGSUSED*/
3937c478bd9Sstevel@tonic-gatevoid
3947c478bd9Sstevel@tonic-gateintr_thread(struct regs *regs, uint_t inumber, uint_t pil)
3957c478bd9Sstevel@tonic-gate{}
3967c478bd9Sstevel@tonic-gate
3977c478bd9Sstevel@tonic-gate#else	/* lint */
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate#define	INTRCNT_LIMIT 16
4007c478bd9Sstevel@tonic-gate
4017c478bd9Sstevel@tonic-gate/*
4027c478bd9Sstevel@tonic-gate * Handle an interrupt in a new thread.
4037c478bd9Sstevel@tonic-gate *	Entry:
4047c478bd9Sstevel@tonic-gate *		%o0       = pointer to regs structure
4057c478bd9Sstevel@tonic-gate *		%o1       = inumber
4067c478bd9Sstevel@tonic-gate *		%o2       = pil
4077c478bd9Sstevel@tonic-gate *		%sp       = on current thread's kernel stack
4087c478bd9Sstevel@tonic-gate *		%o7       = return linkage to trap code
4097c478bd9Sstevel@tonic-gate *		%g7       = current thread
4107c478bd9Sstevel@tonic-gate *		%pstate   = normal globals, interrupts enabled,
4117c478bd9Sstevel@tonic-gate *		            privileged, fp disabled
4127c478bd9Sstevel@tonic-gate *		%pil      = DISP_LEVEL
4137c478bd9Sstevel@tonic-gate *
4147c478bd9Sstevel@tonic-gate *	Register Usage
4157c478bd9Sstevel@tonic-gate *		%l0       = return linkage
4167c478bd9Sstevel@tonic-gate *		%l1       = pil
4177c478bd9Sstevel@tonic-gate *		%l2 - %l3 = scratch
4187c478bd9Sstevel@tonic-gate *		%l4 - %l7 = reserved for sys_trap
4197c478bd9Sstevel@tonic-gate *		%o2       = cpu
4207c478bd9Sstevel@tonic-gate *		%o3       = intr thread
4217c478bd9Sstevel@tonic-gate *		%o0       = scratch
4227c478bd9Sstevel@tonic-gate *		%o4 - %o5 = scratch
4237c478bd9Sstevel@tonic-gate */
4247c478bd9Sstevel@tonic-gate	ENTRY_NP(intr_thread)
4257c478bd9Sstevel@tonic-gate	mov	%o7, %l0
4267c478bd9Sstevel@tonic-gate	mov	%o2, %l1
4277c478bd9Sstevel@tonic-gate	!
4287c478bd9Sstevel@tonic-gate	! See if we are interrupting another interrupt thread.
4297c478bd9Sstevel@tonic-gate	!
4307c478bd9Sstevel@tonic-gate	lduh	[THREAD_REG + T_FLAGS], %o3
4317c478bd9Sstevel@tonic-gate	andcc	%o3, T_INTR_THREAD, %g0
4327c478bd9Sstevel@tonic-gate	bz,pt	%xcc, 1f
4337c478bd9Sstevel@tonic-gate	ldn	[THREAD_REG + T_CPU], %o2	! delay - load CPU pointer
4347c478bd9Sstevel@tonic-gate
4357c478bd9Sstevel@tonic-gate	! We have interrupted an interrupt thread. Take a timestamp,
4367c478bd9Sstevel@tonic-gate	! compute its interval, and update its cumulative counter.
4377c478bd9Sstevel@tonic-gate	add	THREAD_REG, T_INTR_START, %o5
4387c478bd9Sstevel@tonic-gate0:
4397c478bd9Sstevel@tonic-gate	ldx	[%o5], %o3
4407c478bd9Sstevel@tonic-gate	brz,pn	%o3, 1f
4417c478bd9Sstevel@tonic-gate	! We came in on top of an interrupt thread that had no timestamp.
4427c478bd9Sstevel@tonic-gate	! This could happen if, for instance, an interrupt thread which had
4437c478bd9Sstevel@tonic-gate	! previously blocked is being set up to run again in resume(), but
4447c478bd9Sstevel@tonic-gate	! resume() hasn't yet stored a timestamp for it. Or, it could be in
4457c478bd9Sstevel@tonic-gate	! swtch() after its slice has been accounted for.
4467c478bd9Sstevel@tonic-gate	! Only account for the time slice if the starting timestamp is non-zero.
4477c478bd9Sstevel@tonic-gate	rdpr	%tick, %o4			! delay
4487c478bd9Sstevel@tonic-gate	sllx	%o4, 1, %o4			! shift off NPT bit
4497c478bd9Sstevel@tonic-gate	srlx	%o4, 1, %o4
4507c478bd9Sstevel@tonic-gate	sub	%o4, %o3, %o4			! o4 has interval
4517c478bd9Sstevel@tonic-gate
4527c478bd9Sstevel@tonic-gate	! A high-level interrupt in current_thread() interrupting here
4537c478bd9Sstevel@tonic-gate	! will account for the interrupted thread's time slice, but
4547c478bd9Sstevel@tonic-gate	! only if t_intr_start is non-zero. Since this code is going to account
4557c478bd9Sstevel@tonic-gate	! for the time slice, we want to "atomically" load the thread's
4567c478bd9Sstevel@tonic-gate	! starting timestamp, calculate the interval with %tick, and zero
4577c478bd9Sstevel@tonic-gate	! its starting timestamp.
4587c478bd9Sstevel@tonic-gate	! To do this, we do a casx on the t_intr_start field, and store 0 to it.
4597c478bd9Sstevel@tonic-gate	! If it has changed since we loaded it above, we need to re-compute the
4607c478bd9Sstevel@tonic-gate	! interval, since a changed t_intr_start implies current_thread placed
4617c478bd9Sstevel@tonic-gate	! a new, later timestamp there after running a high-level interrupt,
4627c478bd9Sstevel@tonic-gate	! and the %tick val in %o4 had become stale.
4637c478bd9Sstevel@tonic-gate	mov	%g0, %l2
4647c478bd9Sstevel@tonic-gate	casx	[%o5], %o3, %l2
4657c478bd9Sstevel@tonic-gate
4667c478bd9Sstevel@tonic-gate	! If %l2 == %o3, our casx was successful. If not, the starting timestamp
4677c478bd9Sstevel@tonic-gate	! changed between loading it (after label 0b) and computing the
4687c478bd9Sstevel@tonic-gate	! interval above.
4697c478bd9Sstevel@tonic-gate	cmp	%l2, %o3
4707c478bd9Sstevel@tonic-gate	bne,pn	%xcc, 0b
4717c478bd9Sstevel@tonic-gate
4727c478bd9Sstevel@tonic-gate	! Check for Energy Star mode
4737c478bd9Sstevel@tonic-gate	lduh	[%o2 + CPU_DIVISOR], %l2	! delay -- %l2 = clock divisor
4747c478bd9Sstevel@tonic-gate	cmp	%l2, 1
4757c478bd9Sstevel@tonic-gate	bg,a,pn	%xcc, 2f
4767c478bd9Sstevel@tonic-gate	mulx	%o4, %l2, %o4	! multiply interval by clock divisor iff > 1
4777c478bd9Sstevel@tonic-gate2:
4787c478bd9Sstevel@tonic-gate	! We now know that a valid interval for the interrupted interrupt
4797c478bd9Sstevel@tonic-gate	! thread is in %o4. Update its cumulative counter.
4807c478bd9Sstevel@tonic-gate	ldub	[THREAD_REG + T_PIL], %l3	! load PIL
4817c478bd9Sstevel@tonic-gate	sllx	%l3, 4, %l3		! convert PIL index to byte offset
4827c478bd9Sstevel@tonic-gate	add	%l3, CPU_MCPU, %l3	! CPU_INTRSTAT is too big for use
4837c478bd9Sstevel@tonic-gate	add	%l3, MCPU_INTRSTAT, %l3	! as const, add offsets separately
4847c478bd9Sstevel@tonic-gate	ldx	[%o2 + %l3], %o5	! old counter in o5
4857c478bd9Sstevel@tonic-gate	add	%o5, %o4, %o5		! new counter in o5
4867c478bd9Sstevel@tonic-gate	stx	%o5, [%o2 + %l3]	! store new counter
4877c478bd9Sstevel@tonic-gate
488eda89462Sesolom	! Also update intracct[]
489eda89462Sesolom	lduh	[%o2 + CPU_MSTATE], %l3
490eda89462Sesolom	sllx	%l3, 3, %l3
491eda89462Sesolom	add	%l3, CPU_INTRACCT, %l3
492eda89462Sesolom	add	%l3, %o2, %l3
493eda89462Sesolom0:
494eda89462Sesolom	ldx	[%l3], %o5
495eda89462Sesolom	add	%o5, %o4, %o3
496eda89462Sesolom	casx	[%l3], %o5, %o3
497eda89462Sesolom	cmp	%o5, %o3
498eda89462Sesolom	bne,pn	%xcc, 0b
499eda89462Sesolom	nop
500eda89462Sesolom
5017c478bd9Sstevel@tonic-gate1:
5027c478bd9Sstevel@tonic-gate	!
5037c478bd9Sstevel@tonic-gate	! Get set to run interrupt thread.
5047c478bd9Sstevel@tonic-gate	! There should always be an interrupt thread since we allocate one
5057c478bd9Sstevel@tonic-gate	! for each level on the CPU.
5067c478bd9Sstevel@tonic-gate	!
5077c478bd9Sstevel@tonic-gate	! Note that the code in kcpc_overflow_intr -relies- on the ordering
5087c478bd9Sstevel@tonic-gate	! of events here -- in particular that t->t_lwp of the interrupt thread
5097c478bd9Sstevel@tonic-gate	! is set to the pinned thread *before* curthread is changed.
5107c478bd9Sstevel@tonic-gate	!
5117c478bd9Sstevel@tonic-gate	ldn	[%o2 + CPU_INTR_THREAD], %o3	! interrupt thread pool
5127c478bd9Sstevel@tonic-gate	ldn	[%o3 + T_LINK], %o4		! unlink thread from CPU's list
5137c478bd9Sstevel@tonic-gate	stn	%o4, [%o2 + CPU_INTR_THREAD]
5147c478bd9Sstevel@tonic-gate	!
5157c478bd9Sstevel@tonic-gate	! Set bit for this level in CPU's active interrupt bitmask.
5167c478bd9Sstevel@tonic-gate	!
5177c478bd9Sstevel@tonic-gate	ld	[%o2 + CPU_INTR_ACTV], %o5
5187c478bd9Sstevel@tonic-gate	mov	1, %o4
5197c478bd9Sstevel@tonic-gate	sll	%o4, %l1, %o4
5207c478bd9Sstevel@tonic-gate#ifdef DEBUG
5217c478bd9Sstevel@tonic-gate	!
5227c478bd9Sstevel@tonic-gate	! ASSERT(!(CPU->cpu_intr_actv & (1 << PIL)))
5237c478bd9Sstevel@tonic-gate	!
5247c478bd9Sstevel@tonic-gate	andcc	%o5, %o4, %g0
5257c478bd9Sstevel@tonic-gate	bz,pt	%xcc, 0f
5267c478bd9Sstevel@tonic-gate	nop
5277c478bd9Sstevel@tonic-gate	! Do not call panic if a panic is already in progress.
5287c478bd9Sstevel@tonic-gate	sethi	%hi(panic_quiesce), %l2
5297c478bd9Sstevel@tonic-gate	ld	[%l2 + %lo(panic_quiesce)], %l2
5307c478bd9Sstevel@tonic-gate	brnz,pn	%l2, 0f
5317c478bd9Sstevel@tonic-gate	nop
5327c478bd9Sstevel@tonic-gate	sethi	%hi(intr_thread_actv_bit_set), %o0
5337c478bd9Sstevel@tonic-gate	call	panic
5347c478bd9Sstevel@tonic-gate	or	%o0, %lo(intr_thread_actv_bit_set), %o0
5357c478bd9Sstevel@tonic-gate0:
5367c478bd9Sstevel@tonic-gate#endif /* DEBUG */
5377c478bd9Sstevel@tonic-gate	or	%o5, %o4, %o5
5387c478bd9Sstevel@tonic-gate	st	%o5, [%o2 + CPU_INTR_ACTV]
5397c478bd9Sstevel@tonic-gate	!
5407c478bd9Sstevel@tonic-gate	! Consider the new thread part of the same LWP so that
5417c478bd9Sstevel@tonic-gate	! window overflow code can find the PCB.
5427c478bd9Sstevel@tonic-gate	!
5437c478bd9Sstevel@tonic-gate	ldn	[THREAD_REG + T_LWP], %o4
5447c478bd9Sstevel@tonic-gate	stn	%o4, [%o3 + T_LWP]
5457c478bd9Sstevel@tonic-gate	!
5467c478bd9Sstevel@tonic-gate	! Threads on the interrupt thread free list could have state already
5477c478bd9Sstevel@tonic-gate	! set to TS_ONPROC, but it helps in debugging if they're TS_FREE
5487c478bd9Sstevel@tonic-gate	! Could eliminate the next two instructions with a little work.
5497c478bd9Sstevel@tonic-gate	!
5507c478bd9Sstevel@tonic-gate	mov	TS_ONPROC, %o4
5517c478bd9Sstevel@tonic-gate	st	%o4, [%o3 + T_STATE]
5527c478bd9Sstevel@tonic-gate	!
5537c478bd9Sstevel@tonic-gate	! Push interrupted thread onto list from new thread.
5547c478bd9Sstevel@tonic-gate	! Set the new thread as the current one.
5557c478bd9Sstevel@tonic-gate	! Set interrupted thread's T_SP because if it is the idle thread,
5567c478bd9Sstevel@tonic-gate	! resume may use that stack between threads.
5577c478bd9Sstevel@tonic-gate	!
5587c478bd9Sstevel@tonic-gate	stn	%o7, [THREAD_REG + T_PC]	! mark pc for resume
5597c478bd9Sstevel@tonic-gate	stn	%sp, [THREAD_REG + T_SP]	! mark stack for resume
5607c478bd9Sstevel@tonic-gate	stn	THREAD_REG, [%o3 + T_INTR]	! push old thread
5617c478bd9Sstevel@tonic-gate	stn	%o3, [%o2 + CPU_THREAD]		! set new thread
5627c478bd9Sstevel@tonic-gate	mov	%o3, THREAD_REG			! set global curthread register
5637c478bd9Sstevel@tonic-gate	ldn	[%o3 + T_STACK], %o4		! interrupt stack pointer
5647c478bd9Sstevel@tonic-gate	sub	%o4, STACK_BIAS, %sp
5657c478bd9Sstevel@tonic-gate	!
5667c478bd9Sstevel@tonic-gate	! Initialize thread priority level from intr_pri
5677c478bd9Sstevel@tonic-gate	!
5687c478bd9Sstevel@tonic-gate	sethi	%hi(intr_pri), %o4
5697c478bd9Sstevel@tonic-gate	ldsh	[%o4 + %lo(intr_pri)], %o4	! grab base interrupt priority
5707c478bd9Sstevel@tonic-gate	add	%l1, %o4, %o4		! convert level to dispatch priority
5717c478bd9Sstevel@tonic-gate	sth	%o4, [THREAD_REG + T_PRI]
5727c478bd9Sstevel@tonic-gate	stub	%l1, [THREAD_REG + T_PIL]	! save pil for intr_passivate
5737c478bd9Sstevel@tonic-gate
5747c478bd9Sstevel@tonic-gate	! Store starting timestamp in thread structure.
5757c478bd9Sstevel@tonic-gate	add	THREAD_REG, T_INTR_START, %o3
5767c478bd9Sstevel@tonic-gate1:
5777c478bd9Sstevel@tonic-gate	ldx	[%o3], %o5
5787c478bd9Sstevel@tonic-gate	rdpr	%tick, %o4
5797c478bd9Sstevel@tonic-gate	sllx	%o4, 1, %o4
5807c478bd9Sstevel@tonic-gate	srlx	%o4, 1, %o4			! shift off NPT bit
5817c478bd9Sstevel@tonic-gate	casx	[%o3], %o5, %o4
5827c478bd9Sstevel@tonic-gate	cmp	%o4, %o5
5837c478bd9Sstevel@tonic-gate	! If a high-level interrupt occurred while we were attempting to store
5847c478bd9Sstevel@tonic-gate	! the timestamp, try again.
5857c478bd9Sstevel@tonic-gate	bne,pn	%xcc, 1b
5867c478bd9Sstevel@tonic-gate	nop
5877c478bd9Sstevel@tonic-gate
5887c478bd9Sstevel@tonic-gate	wrpr	%g0, %l1, %pil			! lower %pil to new level
5897c478bd9Sstevel@tonic-gate	!
5907c478bd9Sstevel@tonic-gate	! Fast event tracing.
5917c478bd9Sstevel@tonic-gate	!
5927c478bd9Sstevel@tonic-gate	ld	[%o2 + CPU_FTRACE_STATE], %o4	! %o2 = curthread->t_cpu
5937c478bd9Sstevel@tonic-gate	btst	FTRACE_ENABLED, %o4
5947c478bd9Sstevel@tonic-gate	be,pt	%icc, 1f			! skip if ftrace disabled
5957c478bd9Sstevel@tonic-gate	  mov	%l1, %o5
5967c478bd9Sstevel@tonic-gate	!
5977c478bd9Sstevel@tonic-gate	! Tracing is enabled - write the trace entry.
5987c478bd9Sstevel@tonic-gate	!
5997c478bd9Sstevel@tonic-gate	save	%sp, -SA(MINFRAME), %sp
6007c478bd9Sstevel@tonic-gate	set	ftrace_intr_thread_format_str, %o0
6017c478bd9Sstevel@tonic-gate	mov	%i0, %o1
6027c478bd9Sstevel@tonic-gate	mov	%i1, %o2
6037c478bd9Sstevel@tonic-gate	call	ftrace_3
6047c478bd9Sstevel@tonic-gate	mov	%i5, %o3
6057c478bd9Sstevel@tonic-gate	restore
6067c478bd9Sstevel@tonic-gate1:
6077c478bd9Sstevel@tonic-gate	!
6087c478bd9Sstevel@tonic-gate	! call the handler
6097c478bd9Sstevel@tonic-gate	!
6107c478bd9Sstevel@tonic-gate	SERVE_INTR_PRE(%o1, %o2, %l1, %l3, %o4, %o5, %o3, %o0)
6117c478bd9Sstevel@tonic-gate	!
6127c478bd9Sstevel@tonic-gate	! %o0 and %o1 are now available as scratch registers.
6137c478bd9Sstevel@tonic-gate	!
6147c478bd9Sstevel@tonic-gate0:
6157c478bd9Sstevel@tonic-gate	SERVE_INTR(%o1, %o2, %l1, %l3, %o4, %o5, %o3, %o0)
6167c478bd9Sstevel@tonic-gate	!
6177c478bd9Sstevel@tonic-gate	! If %o3 is set, we must call serve_intr_post, and both %l1 and %o3
6187c478bd9Sstevel@tonic-gate	! must be preserved. %l1 holds our pil, %l3 holds our inum.
6197c478bd9Sstevel@tonic-gate	!
6207c478bd9Sstevel@tonic-gate	! Note: %l1 is the pil level we're processing, but we may have a
6217c478bd9Sstevel@tonic-gate	! higher effective pil because a higher-level interrupt may have
6227c478bd9Sstevel@tonic-gate	! blocked.
6237c478bd9Sstevel@tonic-gate	!
6247c478bd9Sstevel@tonic-gate	wrpr	%g0, DISP_LEVEL, %pil
6257c478bd9Sstevel@tonic-gate	!
6267c478bd9Sstevel@tonic-gate	! Take timestamp, compute interval, update cumulative counter.
6277c478bd9Sstevel@tonic-gate	!
6287c478bd9Sstevel@tonic-gate	add	THREAD_REG, T_INTR_START, %o5
6297c478bd9Sstevel@tonic-gate1:
6307c478bd9Sstevel@tonic-gate	ldx	[%o5], %o0
6317c478bd9Sstevel@tonic-gate#ifdef DEBUG
6327c478bd9Sstevel@tonic-gate	brnz	%o0, 9f
6337c478bd9Sstevel@tonic-gate	nop
6347c478bd9Sstevel@tonic-gate	! Do not call panic if a panic is already in progress.
6357c478bd9Sstevel@tonic-gate	sethi	%hi(panic_quiesce), %o1
6367c478bd9Sstevel@tonic-gate	ld	[%o1 + %lo(panic_quiesce)], %o1
6377c478bd9Sstevel@tonic-gate	brnz,pn	%o1, 9f
6387c478bd9Sstevel@tonic-gate	nop
6397c478bd9Sstevel@tonic-gate	sethi	%hi(intr_thread_t_intr_start_zero), %o0
6407c478bd9Sstevel@tonic-gate	call	panic
6417c478bd9Sstevel@tonic-gate	or	%o0, %lo(intr_thread_t_intr_start_zero), %o0
6427c478bd9Sstevel@tonic-gate9:
6437c478bd9Sstevel@tonic-gate#endif /* DEBUG */
6447c478bd9Sstevel@tonic-gate	rdpr	%tick, %o1
6457c478bd9Sstevel@tonic-gate	sllx	%o1, 1, %o1
6467c478bd9Sstevel@tonic-gate	srlx	%o1, 1, %o1			! shift off NPT bit
6477c478bd9Sstevel@tonic-gate	sub	%o1, %o0, %l2			! l2 has interval
6487c478bd9Sstevel@tonic-gate	!
6497c478bd9Sstevel@tonic-gate	! The general outline of what the code here does is:
6507c478bd9Sstevel@tonic-gate	! 1. load t_intr_start, %tick, and calculate the delta
6517c478bd9Sstevel@tonic-gate	! 2. replace t_intr_start with %tick (if %o3 is set) or 0.
6527c478bd9Sstevel@tonic-gate	!
6537c478bd9Sstevel@tonic-gate	! The problem is that a high-level interrupt could arrive at any time.
6547c478bd9Sstevel@tonic-gate	! It will account for (%tick - t_intr_start) for us when it starts,
6557c478bd9Sstevel@tonic-gate	! unless we have set t_intr_start to zero, and then set t_intr_start
6567c478bd9Sstevel@tonic-gate	! to a new %tick when it finishes. To account for this, our first step
6577c478bd9Sstevel@tonic-gate	! is to load t_intr_start and the last is to use casx to store the new
6587c478bd9Sstevel@tonic-gate	! t_intr_start. This guarantees atomicity in reading t_intr_start,
6597c478bd9Sstevel@tonic-gate	! reading %tick, and updating t_intr_start.
6607c478bd9Sstevel@tonic-gate	!
6617c478bd9Sstevel@tonic-gate	movrz	%o3, %g0, %o1
6627c478bd9Sstevel@tonic-gate	casx	[%o5], %o0, %o1
6637c478bd9Sstevel@tonic-gate	cmp	%o0, %o1
6647c478bd9Sstevel@tonic-gate	bne,pn	%xcc, 1b
6657c478bd9Sstevel@tonic-gate	!
6667c478bd9Sstevel@tonic-gate	! Check for Energy Star mode
6677c478bd9Sstevel@tonic-gate	!
6687c478bd9Sstevel@tonic-gate	lduh	[%o2 + CPU_DIVISOR], %o0	! delay -- %o0 = clock divisor
6697c478bd9Sstevel@tonic-gate	cmp	%o0, 1
6707c478bd9Sstevel@tonic-gate	bg,a,pn	%xcc, 2f
6717c478bd9Sstevel@tonic-gate	mulx	%l2, %o0, %l2	! multiply interval by clock divisor iff > 1
6727c478bd9Sstevel@tonic-gate2:
6737c478bd9Sstevel@tonic-gate	!
6747c478bd9Sstevel@tonic-gate	! Update cpu_intrstat. If o3 is set then we will be processing another
6757c478bd9Sstevel@tonic-gate	! interrupt. Above we have set t_intr_start to %tick, not 0. This
6767c478bd9Sstevel@tonic-gate	! means a high-level interrupt can arrive and update the same stats
6777c478bd9Sstevel@tonic-gate	! we're updating. Need to use casx.
6787c478bd9Sstevel@tonic-gate	!
6797c478bd9Sstevel@tonic-gate	sllx	%l1, 4, %o1			! delay - PIL as byte offset
6807c478bd9Sstevel@tonic-gate	add	%o1, CPU_MCPU, %o1		! CPU_INTRSTAT const too big
6817c478bd9Sstevel@tonic-gate	add	%o1, MCPU_INTRSTAT, %o1		! add parts separately
6827c478bd9Sstevel@tonic-gate	add	%o1, %o2, %o1
6837c478bd9Sstevel@tonic-gate1:
6847c478bd9Sstevel@tonic-gate	ldx	[%o1], %o5			! old counter in o5
6857c478bd9Sstevel@tonic-gate	add	%o5, %l2, %o0			! new counter in o0
6867c478bd9Sstevel@tonic-gate 	stx	%o0, [%o1 + 8]			! store into intrstat[pil][1]
6877c478bd9Sstevel@tonic-gate	casx	[%o1], %o5, %o0			! and into intrstat[pil][0]
6887c478bd9Sstevel@tonic-gate	cmp	%o5, %o0
6897c478bd9Sstevel@tonic-gate	bne,pn	%xcc, 1b
6907c478bd9Sstevel@tonic-gate	nop
691eda89462Sesolom
692eda89462Sesolom	! Also update intracct[]
693eda89462Sesolom	lduh	[%o2 + CPU_MSTATE], %o1
694eda89462Sesolom	sllx	%o1, 3, %o1
695eda89462Sesolom	add	%o1, CPU_INTRACCT, %o1
696eda89462Sesolom	add	%o1, %o2, %o1
697eda89462Sesolom1:
698eda89462Sesolom	ldx	[%o1], %o5
699eda89462Sesolom	add	%o5, %l2, %o0
700eda89462Sesolom	casx	[%o1], %o5, %o0
701eda89462Sesolom	cmp	%o5, %o0
702eda89462Sesolom	bne,pn	%xcc, 1b
703eda89462Sesolom	nop
704eda89462Sesolom
7057c478bd9Sstevel@tonic-gate	!
7067c478bd9Sstevel@tonic-gate	! Don't keep a pinned process pinned indefinitely. Bump cpu_intrcnt
7077c478bd9Sstevel@tonic-gate	! for each interrupt handler we invoke. If we hit INTRCNT_LIMIT, then
7087c478bd9Sstevel@tonic-gate	! we've crossed the threshold and we should unpin the pinned threads
7097c478bd9Sstevel@tonic-gate	! by preempt()ing ourselves, which will bubble up the t_intr chain
7107c478bd9Sstevel@tonic-gate	! until hitting the non-interrupt thread, which will then in turn
7117c478bd9Sstevel@tonic-gate	! preempt itself allowing the interrupt processing to resume. Finally,
7127c478bd9Sstevel@tonic-gate	! the scheduler takes over and picks the next thread to run.
7137c478bd9Sstevel@tonic-gate	!
7147c478bd9Sstevel@tonic-gate	! If our CPU is quiesced, we cannot preempt because the idle thread
7157c478bd9Sstevel@tonic-gate	! won't ever re-enter the scheduler, and the interrupt will be forever
7167c478bd9Sstevel@tonic-gate	! blocked.
7177c478bd9Sstevel@tonic-gate	!
7187c478bd9Sstevel@tonic-gate	! If t_intr is NULL, we're not pinning anyone, so we use a simpler
7197c478bd9Sstevel@tonic-gate	! algorithm. Just check for cpu_kprunrun, and if set then preempt.
7207c478bd9Sstevel@tonic-gate	! This insures we enter the scheduler if a higher-priority thread
7217c478bd9Sstevel@tonic-gate	! has become runnable.
7227c478bd9Sstevel@tonic-gate	!
7237c478bd9Sstevel@tonic-gate	lduh	[%o2 + CPU_FLAGS], %o5		! don't preempt if quiesced
7247c478bd9Sstevel@tonic-gate	andcc	%o5, CPU_QUIESCED, %g0
7257c478bd9Sstevel@tonic-gate	bnz,pn	%xcc, 1f
7267c478bd9Sstevel@tonic-gate
7277c478bd9Sstevel@tonic-gate	ldn     [THREAD_REG + T_INTR], %o5      ! pinning anything?
7287c478bd9Sstevel@tonic-gate	brz,pn  %o5, 3f				! if not, don't inc intrcnt
7297c478bd9Sstevel@tonic-gate
7307c478bd9Sstevel@tonic-gate	ldub	[%o2 + CPU_INTRCNT], %o5	! delay - %o5 = cpu_intrcnt
7317c478bd9Sstevel@tonic-gate	inc	%o5
7327c478bd9Sstevel@tonic-gate	cmp	%o5, INTRCNT_LIMIT		! have we hit the limit?
7337c478bd9Sstevel@tonic-gate	bl,a,pt	%xcc, 1f			! no preempt if < INTRCNT_LIMIT
7347c478bd9Sstevel@tonic-gate	stub	%o5, [%o2 + CPU_INTRCNT]	! delay annul - inc CPU_INTRCNT
7357c478bd9Sstevel@tonic-gate	bg,pn	%xcc, 2f			! don't inc stats again
7367c478bd9Sstevel@tonic-gate	!
7377c478bd9Sstevel@tonic-gate	! We've reached the limit. Set cpu_intrcnt and cpu_kprunrun, and do
7387c478bd9Sstevel@tonic-gate	! CPU_STATS_ADDQ(cp, sys, intrunpin, 1). Then call preempt.
7397c478bd9Sstevel@tonic-gate	!
7407c478bd9Sstevel@tonic-gate	mov	1, %o4				! delay
7417c478bd9Sstevel@tonic-gate	stub	%o4, [%o2 + CPU_KPRUNRUN]
7427c478bd9Sstevel@tonic-gate	ldx	[%o2 + CPU_STATS_SYS_INTRUNPIN], %o4
7437c478bd9Sstevel@tonic-gate	inc	%o4
7447c478bd9Sstevel@tonic-gate	stx	%o4, [%o2 + CPU_STATS_SYS_INTRUNPIN]
7457c478bd9Sstevel@tonic-gate	ba	2f
7467c478bd9Sstevel@tonic-gate	stub	%o5, [%o2 + CPU_INTRCNT]	! delay
7477c478bd9Sstevel@tonic-gate3:
7487c478bd9Sstevel@tonic-gate	! Code for t_intr == NULL
7497c478bd9Sstevel@tonic-gate	ldub	[%o2 + CPU_KPRUNRUN], %o5
7507c478bd9Sstevel@tonic-gate	brz,pt	%o5, 1f				! don't preempt unless kprunrun
7517c478bd9Sstevel@tonic-gate2:
7527c478bd9Sstevel@tonic-gate	! Time to call preempt
7537c478bd9Sstevel@tonic-gate	mov	%o2, %l3			! delay - save %o2
7547c478bd9Sstevel@tonic-gate	call	preempt
7557c478bd9Sstevel@tonic-gate	mov	%o3, %l2			! delay - save %o3.
7567c478bd9Sstevel@tonic-gate	mov	%l3, %o2			! restore %o2
7577c478bd9Sstevel@tonic-gate	mov	%l2, %o3			! restore %o3
7587c478bd9Sstevel@tonic-gate	wrpr	%g0, DISP_LEVEL, %pil		! up from cpu_base_spl
7597c478bd9Sstevel@tonic-gate1:
7607c478bd9Sstevel@tonic-gate	!
7617c478bd9Sstevel@tonic-gate	! Do we need to call serve_intr_post and do this again?
7627c478bd9Sstevel@tonic-gate	!
7637c478bd9Sstevel@tonic-gate	brz,a,pt %o3, 0f
7647c478bd9Sstevel@tonic-gate	ld	[%o2 + CPU_INTR_ACTV], %o5	! delay annulled
7657c478bd9Sstevel@tonic-gate	!
7667c478bd9Sstevel@tonic-gate	! Restore %pil before calling serve_intr() again. We must check
7677c478bd9Sstevel@tonic-gate	! CPU_BASE_SPL and set %pil to max(our-pil, CPU_BASE_SPL)
7687c478bd9Sstevel@tonic-gate	!
7697c478bd9Sstevel@tonic-gate	ld	[%o2 + CPU_BASE_SPL], %o4
7707c478bd9Sstevel@tonic-gate	cmp	%o4, %l1
7717c478bd9Sstevel@tonic-gate	movl	%xcc, %l1, %o4
7727c478bd9Sstevel@tonic-gate	wrpr	%g0, %o4, %pil
7737c478bd9Sstevel@tonic-gate	SERVE_INTR_NEXT(%o1, %o2, %l1, %l3, %o4, %o5, %o3, %o0)
7747c478bd9Sstevel@tonic-gate	ba	0b				! compute new stats
7757c478bd9Sstevel@tonic-gate	nop
7767c478bd9Sstevel@tonic-gate0:
7777c478bd9Sstevel@tonic-gate	!
7787c478bd9Sstevel@tonic-gate	! Clear bit for this level in CPU's interrupt active bitmask.
7797c478bd9Sstevel@tonic-gate	!
7807c478bd9Sstevel@tonic-gate	mov	1, %o4
7817c478bd9Sstevel@tonic-gate	sll	%o4, %l1, %o4
7827c478bd9Sstevel@tonic-gate#ifdef DEBUG
7837c478bd9Sstevel@tonic-gate	!
7847c478bd9Sstevel@tonic-gate	! ASSERT(CPU->cpu_intr_actv & (1 << PIL))
7857c478bd9Sstevel@tonic-gate	!
7867c478bd9Sstevel@tonic-gate	andcc	%o4, %o5, %g0
7877c478bd9Sstevel@tonic-gate	bnz,pt	%xcc, 0f
7887c478bd9Sstevel@tonic-gate	nop
7897c478bd9Sstevel@tonic-gate	! Do not call panic if a panic is already in progress.
7907c478bd9Sstevel@tonic-gate	sethi	%hi(panic_quiesce), %l2
7917c478bd9Sstevel@tonic-gate	ld	[%l2 + %lo(panic_quiesce)], %l2
7927c478bd9Sstevel@tonic-gate	brnz,pn	%l2, 0f
7937c478bd9Sstevel@tonic-gate	nop
7947c478bd9Sstevel@tonic-gate	sethi	%hi(intr_thread_actv_bit_not_set), %o0
7957c478bd9Sstevel@tonic-gate	call	panic
7967c478bd9Sstevel@tonic-gate	or	%o0, %lo(intr_thread_actv_bit_not_set), %o0
7977c478bd9Sstevel@tonic-gate0:
7987c478bd9Sstevel@tonic-gate#endif /* DEBUG */
7997c478bd9Sstevel@tonic-gate	andn	%o5, %o4, %o5
8007c478bd9Sstevel@tonic-gate	st	%o5, [%o2 + CPU_INTR_ACTV]
8017c478bd9Sstevel@tonic-gate	!
8027c478bd9Sstevel@tonic-gate	! If there is still an interrupted thread underneath this one,
8037c478bd9Sstevel@tonic-gate	! then the interrupt was never blocked and the return is fairly
8047c478bd9Sstevel@tonic-gate	! simple.  Otherwise jump to intr_thread_exit.
8057c478bd9Sstevel@tonic-gate	!
8067c478bd9Sstevel@tonic-gate	ldn	[THREAD_REG + T_INTR], %o4	! pinned thread
8077c478bd9Sstevel@tonic-gate	brz,pn	%o4, intr_thread_exit		! branch if none
8087c478bd9Sstevel@tonic-gate	nop
8097c478bd9Sstevel@tonic-gate	!
8107c478bd9Sstevel@tonic-gate	! link the thread back onto the interrupt thread pool
8117c478bd9Sstevel@tonic-gate	!
8127c478bd9Sstevel@tonic-gate	ldn	[%o2 + CPU_INTR_THREAD], %o3
8137c478bd9Sstevel@tonic-gate	stn	%o3, [THREAD_REG + T_LINK]
8147c478bd9Sstevel@tonic-gate	stn	THREAD_REG, [%o2 + CPU_INTR_THREAD]
8157c478bd9Sstevel@tonic-gate	!
8167c478bd9Sstevel@tonic-gate	! set the thread state to free so kernel debuggers don't see it
8177c478bd9Sstevel@tonic-gate	!
8187c478bd9Sstevel@tonic-gate	mov	TS_FREE, %o5
8197c478bd9Sstevel@tonic-gate	st	%o5, [THREAD_REG + T_STATE]
8207c478bd9Sstevel@tonic-gate	!
8217c478bd9Sstevel@tonic-gate	! Switch back to the interrupted thread and return
8227c478bd9Sstevel@tonic-gate	!
8237c478bd9Sstevel@tonic-gate	stn	%o4, [%o2 + CPU_THREAD]
824*25cf1a30Sjl139090	membar	#StoreLoad			! sync with mutex_exit()
8257c478bd9Sstevel@tonic-gate	mov	%o4, THREAD_REG
8267c478bd9Sstevel@tonic-gate
8277c478bd9Sstevel@tonic-gate	! If we pinned an interrupt thread, store its starting timestamp.
8287c478bd9Sstevel@tonic-gate	lduh	[THREAD_REG + T_FLAGS], %o5
8297c478bd9Sstevel@tonic-gate	andcc	%o5, T_INTR_THREAD, %g0
8307c478bd9Sstevel@tonic-gate	bz,pt	%xcc, 1f
8317c478bd9Sstevel@tonic-gate	ldn	[THREAD_REG + T_SP], %sp	! delay - restore %sp
8327c478bd9Sstevel@tonic-gate
8337c478bd9Sstevel@tonic-gate	add	THREAD_REG, T_INTR_START, %o3	! o3 has &curthread->t_intr_star
8347c478bd9Sstevel@tonic-gate0:
8357c478bd9Sstevel@tonic-gate	ldx	[%o3], %o4			! o4 = t_intr_start before
8367c478bd9Sstevel@tonic-gate	rdpr	%tick, %o5
8377c478bd9Sstevel@tonic-gate	sllx	%o5, 1, %o5
8387c478bd9Sstevel@tonic-gate	srlx	%o5, 1, %o5			! shift off NPT bit
8397c478bd9Sstevel@tonic-gate	casx	[%o3], %o4, %o5			! put o5 in ts if o4 == ts after
8407c478bd9Sstevel@tonic-gate	cmp	%o4, %o5
8417c478bd9Sstevel@tonic-gate	! If a high-level interrupt occurred while we were attempting to store
8427c478bd9Sstevel@tonic-gate	! the timestamp, try again.
8437c478bd9Sstevel@tonic-gate	bne,pn	%xcc, 0b
8447c478bd9Sstevel@tonic-gate	ldn	[THREAD_REG + T_SP], %sp	! delay - restore %sp
8457c478bd9Sstevel@tonic-gate1:
8467c478bd9Sstevel@tonic-gate	! If the thread being restarted isn't pinning anyone, and no interrupts
8477c478bd9Sstevel@tonic-gate	! are pending, zero out cpu_intrcnt
8487c478bd9Sstevel@tonic-gate	ldn	[THREAD_REG + T_INTR], %o4
8497c478bd9Sstevel@tonic-gate	brnz,pn	%o4, 2f
8507c478bd9Sstevel@tonic-gate	rd	SOFTINT, %o4			! delay
8517c478bd9Sstevel@tonic-gate	set	SOFTINT_MASK, %o5
8527c478bd9Sstevel@tonic-gate	andcc	%o4, %o5, %g0
8537c478bd9Sstevel@tonic-gate	bz,a,pt	%xcc, 2f
8547c478bd9Sstevel@tonic-gate	stub	%g0, [%o2 + CPU_INTRCNT]	! delay annul
8557c478bd9Sstevel@tonic-gate2:
8567c478bd9Sstevel@tonic-gate	jmp	%l0 + 8
8577c478bd9Sstevel@tonic-gate	nop
8587c478bd9Sstevel@tonic-gate	SET_SIZE(intr_thread)
8597c478bd9Sstevel@tonic-gate	/* Not Reached */
8607c478bd9Sstevel@tonic-gate
8617c478bd9Sstevel@tonic-gate	!
8627c478bd9Sstevel@tonic-gate	! An interrupt returned on what was once (and still might be)
8637c478bd9Sstevel@tonic-gate	! an interrupt thread stack, but the interrupted process is no longer
8647c478bd9Sstevel@tonic-gate	! there.  This means the interrupt must have blocked.
8657c478bd9Sstevel@tonic-gate	!
8667c478bd9Sstevel@tonic-gate	! There is no longer a thread under this one, so put this thread back
8677c478bd9Sstevel@tonic-gate	! on the CPU's free list and resume the idle thread which will dispatch
8687c478bd9Sstevel@tonic-gate	! the next thread to run.
8697c478bd9Sstevel@tonic-gate	!
8707c478bd9Sstevel@tonic-gate	! All traps below DISP_LEVEL are disabled here, but the mondo interrupt
8717c478bd9Sstevel@tonic-gate	! is enabled.
8727c478bd9Sstevel@tonic-gate	!
8737c478bd9Sstevel@tonic-gate	ENTRY_NP(intr_thread_exit)
8747c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE
8757c478bd9Sstevel@tonic-gate	rdpr	%pstate, %l2
8767c478bd9Sstevel@tonic-gate	andn	%l2, PSTATE_IE | PSTATE_AM, %o4
8777c478bd9Sstevel@tonic-gate	wrpr	%g0, %o4, %pstate			! cpu to known state
8787c478bd9Sstevel@tonic-gate	TRACE_PTR(%o4, %o5)
8797c478bd9Sstevel@tonic-gate	GET_TRACE_TICK(%o5)
8807c478bd9Sstevel@tonic-gate	stxa	%o5, [%o4 + TRAP_ENT_TICK]%asi
8817c478bd9Sstevel@tonic-gate	TRACE_SAVE_TL_GL_REGS(%o4, %o5)
8827c478bd9Sstevel@tonic-gate	set	TT_INTR_EXIT, %o5
8837c478bd9Sstevel@tonic-gate	stha	%o5, [%o4 + TRAP_ENT_TT]%asi
8847c478bd9Sstevel@tonic-gate	stna	%g0, [%o4 + TRAP_ENT_TPC]%asi
8857c478bd9Sstevel@tonic-gate	stxa	%g0, [%o4 + TRAP_ENT_TSTATE]%asi
8867c478bd9Sstevel@tonic-gate	stna	%sp, [%o4 + TRAP_ENT_SP]%asi
8877c478bd9Sstevel@tonic-gate	stna	THREAD_REG, [%o4 + TRAP_ENT_TR]%asi
8887c478bd9Sstevel@tonic-gate	ld	[%o2 + CPU_BASE_SPL], %o5
8897c478bd9Sstevel@tonic-gate	stna	%o5, [%o4 + TRAP_ENT_F1]%asi
8907c478bd9Sstevel@tonic-gate	stna	%g0, [%o4 + TRAP_ENT_F2]%asi
8917c478bd9Sstevel@tonic-gate	stna	%g0, [%o4 + TRAP_ENT_F3]%asi
8927c478bd9Sstevel@tonic-gate	stna	%g0, [%o4 + TRAP_ENT_F4]%asi
8937c478bd9Sstevel@tonic-gate	TRACE_NEXT(%o4, %o5, %o0)
8947c478bd9Sstevel@tonic-gate	wrpr	%g0, %l2, %pstate
8957c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */
8967c478bd9Sstevel@tonic-gate	! cpu_stats.sys.intrblk++
8977c478bd9Sstevel@tonic-gate        ldx	[%o2 + CPU_STATS_SYS_INTRBLK], %o4
8987c478bd9Sstevel@tonic-gate        inc     %o4
8997c478bd9Sstevel@tonic-gate        stx	%o4, [%o2 + CPU_STATS_SYS_INTRBLK]
9007c478bd9Sstevel@tonic-gate	!
9017c478bd9Sstevel@tonic-gate	! Put thread back on the interrupt thread list.
9027c478bd9Sstevel@tonic-gate	!
9037c478bd9Sstevel@tonic-gate
9047c478bd9Sstevel@tonic-gate	!
9057c478bd9Sstevel@tonic-gate	! Set the CPU's base SPL level.
9067c478bd9Sstevel@tonic-gate	!
9077c478bd9Sstevel@tonic-gate#ifdef DEBUG
9087c478bd9Sstevel@tonic-gate	!
9097c478bd9Sstevel@tonic-gate	! ASSERT(!(CPU->cpu_intr_actv & (1 << PIL)))
9107c478bd9Sstevel@tonic-gate	!
9117c478bd9Sstevel@tonic-gate	ld	[%o2 + CPU_INTR_ACTV], %o5
9127c478bd9Sstevel@tonic-gate	mov	1, %o4
9137c478bd9Sstevel@tonic-gate	sll	%o4, %l1, %o4
9147c478bd9Sstevel@tonic-gate	and	%o5, %o4, %o4
9157c478bd9Sstevel@tonic-gate	brz,pt	%o4, 0f
9167c478bd9Sstevel@tonic-gate	nop
9177c478bd9Sstevel@tonic-gate	! Do not call panic if a panic is already in progress.
9187c478bd9Sstevel@tonic-gate	sethi	%hi(panic_quiesce), %l2
9197c478bd9Sstevel@tonic-gate	ld	[%l2 + %lo(panic_quiesce)], %l2
9207c478bd9Sstevel@tonic-gate	brnz,pn	%l2, 0f
9217c478bd9Sstevel@tonic-gate	nop
9227c478bd9Sstevel@tonic-gate	sethi	%hi(intr_thread_exit_actv_bit_set), %o0
9237c478bd9Sstevel@tonic-gate	call	panic
9247c478bd9Sstevel@tonic-gate	or	%o0, %lo(intr_thread_exit_actv_bit_set), %o0
9257c478bd9Sstevel@tonic-gate0:
9267c478bd9Sstevel@tonic-gate#endif /* DEBUG */
9277c478bd9Sstevel@tonic-gate	call	_intr_set_spl			! set CPU's base SPL level
9287c478bd9Sstevel@tonic-gate	ld	[%o2 + CPU_INTR_ACTV], %o5	! delay - load active mask
9297c478bd9Sstevel@tonic-gate	!
9307c478bd9Sstevel@tonic-gate	! set the thread state to free so kernel debuggers don't see it
9317c478bd9Sstevel@tonic-gate	!
9327c478bd9Sstevel@tonic-gate	mov	TS_FREE, %o4
9337c478bd9Sstevel@tonic-gate	st	%o4, [THREAD_REG + T_STATE]
9347c478bd9Sstevel@tonic-gate	!
9357c478bd9Sstevel@tonic-gate	! Put thread on either the interrupt pool or the free pool and
9367c478bd9Sstevel@tonic-gate	! call swtch() to resume another thread.
9377c478bd9Sstevel@tonic-gate	!
9387c478bd9Sstevel@tonic-gate	ldn	[%o2 + CPU_INTR_THREAD], %o5	! get list pointer
9397c478bd9Sstevel@tonic-gate	stn	%o5, [THREAD_REG + T_LINK]
9407c478bd9Sstevel@tonic-gate	call	swtch				! switch to best thread
9417c478bd9Sstevel@tonic-gate	stn	THREAD_REG, [%o2 + CPU_INTR_THREAD] ! delay - put thread on list
9427c478bd9Sstevel@tonic-gate	ba,a,pt	%xcc, .				! swtch() shouldn't return
9437c478bd9Sstevel@tonic-gate	SET_SIZE(intr_thread_exit)
9447c478bd9Sstevel@tonic-gate
9457c478bd9Sstevel@tonic-gate	.global ftrace_intr_thread_format_str
9467c478bd9Sstevel@tonic-gateftrace_intr_thread_format_str:
9477c478bd9Sstevel@tonic-gate	.asciz	"intr_thread(): regs=0x%lx, int=0x%lx, pil=0x%lx"
9487c478bd9Sstevel@tonic-gate#ifdef DEBUG
9497c478bd9Sstevel@tonic-gateintr_thread_actv_bit_set:
9507c478bd9Sstevel@tonic-gate	.asciz	"intr_thread():	cpu_intr_actv bit already set for PIL"
9517c478bd9Sstevel@tonic-gateintr_thread_actv_bit_not_set:
9527c478bd9Sstevel@tonic-gate	.asciz	"intr_thread():	cpu_intr_actv bit not set for PIL"
9537c478bd9Sstevel@tonic-gateintr_thread_exit_actv_bit_set:
9547c478bd9Sstevel@tonic-gate	.asciz	"intr_thread_exit(): cpu_intr_actv bit erroneously set for PIL"
9557c478bd9Sstevel@tonic-gateintr_thread_t_intr_start_zero:
9567c478bd9Sstevel@tonic-gate	.asciz	"intr_thread():	t_intr_start zero upon handler return"
9577c478bd9Sstevel@tonic-gate#endif /* DEBUG */
9587c478bd9Sstevel@tonic-gate#endif	/* lint */
9597c478bd9Sstevel@tonic-gate
9607c478bd9Sstevel@tonic-gate#if defined(lint)
9617c478bd9Sstevel@tonic-gate
9627c478bd9Sstevel@tonic-gate/*
9637c478bd9Sstevel@tonic-gate * Handle an interrupt in the current thread
9647c478bd9Sstevel@tonic-gate *	Entry:
9657c478bd9Sstevel@tonic-gate *		%o0       = pointer to regs structure
9667c478bd9Sstevel@tonic-gate *		%o1       = inumber
9677c478bd9Sstevel@tonic-gate *		%o2       = pil
9687c478bd9Sstevel@tonic-gate *		%sp       = on current thread's kernel stack
9697c478bd9Sstevel@tonic-gate *		%o7       = return linkage to trap code
9707c478bd9Sstevel@tonic-gate *		%g7       = current thread
9717c478bd9Sstevel@tonic-gate *		%pstate   = normal globals, interrupts enabled,
9727c478bd9Sstevel@tonic-gate *		            privileged, fp disabled
9737c478bd9Sstevel@tonic-gate *		%pil      = PIL_MAX
9747c478bd9Sstevel@tonic-gate *
9757c478bd9Sstevel@tonic-gate *	Register Usage
9767c478bd9Sstevel@tonic-gate *		%l0       = return linkage
9777c478bd9Sstevel@tonic-gate *		%l1       = old stack
9787c478bd9Sstevel@tonic-gate *		%l2 - %l3 = scratch
9797c478bd9Sstevel@tonic-gate *		%l4 - %l7 = reserved for sys_trap
9807c478bd9Sstevel@tonic-gate *		%o3       = cpu
9817c478bd9Sstevel@tonic-gate *		%o0       = scratch
9827c478bd9Sstevel@tonic-gate *		%o4 - %o5 = scratch
9837c478bd9Sstevel@tonic-gate */
9847c478bd9Sstevel@tonic-gate/* ARGSUSED */
9857c478bd9Sstevel@tonic-gatevoid
9867c478bd9Sstevel@tonic-gatecurrent_thread(struct regs *regs, uint_t inumber, uint_t pil)
9877c478bd9Sstevel@tonic-gate{}
9887c478bd9Sstevel@tonic-gate
9897c478bd9Sstevel@tonic-gate#else	/* lint */
9907c478bd9Sstevel@tonic-gate
9917c478bd9Sstevel@tonic-gate	ENTRY_NP(current_thread)
9927c478bd9Sstevel@tonic-gate
9937c478bd9Sstevel@tonic-gate	mov	%o7, %l0
9947c478bd9Sstevel@tonic-gate	ldn	[THREAD_REG + T_CPU], %o3
9957c478bd9Sstevel@tonic-gate	!
9967c478bd9Sstevel@tonic-gate	! Set bit for this level in CPU's active interrupt bitmask.
9977c478bd9Sstevel@tonic-gate	!
9987c478bd9Sstevel@tonic-gate	ld	[%o3 + CPU_INTR_ACTV], %o5	! o5 has cpu_intr_actv b4 chng
9997c478bd9Sstevel@tonic-gate	mov	1, %o4
10007c478bd9Sstevel@tonic-gate	sll	%o4, %o2, %o4			! construct mask for level
10017c478bd9Sstevel@tonic-gate#ifdef DEBUG
10027c478bd9Sstevel@tonic-gate	!
10037c478bd9Sstevel@tonic-gate	! ASSERT(!(CPU->cpu_intr_actv & (1 << PIL)))
10047c478bd9Sstevel@tonic-gate	!
10057c478bd9Sstevel@tonic-gate	andcc	%o5, %o4, %g0
10067c478bd9Sstevel@tonic-gate	bz,pt	%xcc, 0f
10077c478bd9Sstevel@tonic-gate	nop
10087c478bd9Sstevel@tonic-gate	! Do not call panic if a panic is already in progress.
10097c478bd9Sstevel@tonic-gate	sethi	%hi(panic_quiesce), %l2
10107c478bd9Sstevel@tonic-gate	ld	[%l2 + %lo(panic_quiesce)], %l2
10117c478bd9Sstevel@tonic-gate	brnz,pn	%l2, 0f
10127c478bd9Sstevel@tonic-gate	nop
10137c478bd9Sstevel@tonic-gate	sethi	%hi(current_thread_actv_bit_set), %o0
10147c478bd9Sstevel@tonic-gate	call	panic
10157c478bd9Sstevel@tonic-gate	or	%o0, %lo(current_thread_actv_bit_set), %o0
10167c478bd9Sstevel@tonic-gate0:
10177c478bd9Sstevel@tonic-gate#endif /* DEBUG */
10187c478bd9Sstevel@tonic-gate	or	%o5, %o4, %o4
10197c478bd9Sstevel@tonic-gate	!
10207c478bd9Sstevel@tonic-gate	! See if we are interrupting another high-level interrupt.
10217c478bd9Sstevel@tonic-gate	!
10227c478bd9Sstevel@tonic-gate	srl	%o5, LOCK_LEVEL + 1, %o5	! only look at high-level bits
10237c478bd9Sstevel@tonic-gate	brz,pt	%o5, 1f
10247c478bd9Sstevel@tonic-gate	st	%o4, [%o3 + CPU_INTR_ACTV]	! delay - store active mask
10257c478bd9Sstevel@tonic-gate	!
10267c478bd9Sstevel@tonic-gate	! We have interrupted another high-level interrupt. Find its PIL,
10277c478bd9Sstevel@tonic-gate	! compute the interval it ran for, and update its cumulative counter.
10287c478bd9Sstevel@tonic-gate	!
10297c478bd9Sstevel@tonic-gate	! Register usage:
10307c478bd9Sstevel@tonic-gate
10317c478bd9Sstevel@tonic-gate	! o2 = PIL of this interrupt
10327c478bd9Sstevel@tonic-gate	! o5 = high PIL bits of INTR_ACTV (not including this PIL)
10337c478bd9Sstevel@tonic-gate	! l1 = bitmask used to find other active high-level PIL
10347c478bd9Sstevel@tonic-gate	! o4 = index of bit set in l1
10357c478bd9Sstevel@tonic-gate	! Use cpu_intr_actv to find the cpu_pil_high_start[] offset for the
10367c478bd9Sstevel@tonic-gate	! interrupted high-level interrupt.
10377c478bd9Sstevel@tonic-gate	! Create mask for cpu_intr_actv. Begin by looking for bits set
10387c478bd9Sstevel@tonic-gate	! at one level below the current PIL. Since %o5 contains the active
10397c478bd9Sstevel@tonic-gate	! mask already shifted right by (LOCK_LEVEL + 1), we start by looking
10407c478bd9Sstevel@tonic-gate	! at bit (current_pil - (LOCK_LEVEL + 2)).
10417c478bd9Sstevel@tonic-gate	sub	%o2, LOCK_LEVEL + 2, %o4
10427c478bd9Sstevel@tonic-gate	mov	1, %l1
10437c478bd9Sstevel@tonic-gate	sll	%l1, %o4, %l1
10447c478bd9Sstevel@tonic-gate2:
10457c478bd9Sstevel@tonic-gate#ifdef DEBUG
10467c478bd9Sstevel@tonic-gate	! ASSERT(%l1 != 0) (we didn't shift the bit off the right edge)
10477c478bd9Sstevel@tonic-gate	brnz,pt	%l1, 9f
10487c478bd9Sstevel@tonic-gate	nop
10497c478bd9Sstevel@tonic-gate
10507c478bd9Sstevel@tonic-gate	! Don't panic if a panic is already in progress.
10517c478bd9Sstevel@tonic-gate	sethi	%hi(panic_quiesce), %l3
10527c478bd9Sstevel@tonic-gate	ld	[%l3 + %lo(panic_quiesce)], %l3
10537c478bd9Sstevel@tonic-gate	brnz,pn	%l3, 9f
10547c478bd9Sstevel@tonic-gate	nop
10557c478bd9Sstevel@tonic-gate	sethi	%hi(current_thread_nested_PIL_not_found), %o0
10567c478bd9Sstevel@tonic-gate	call	panic
10577c478bd9Sstevel@tonic-gate	or	%o0, %lo(current_thread_nested_PIL_not_found), %o0
10587c478bd9Sstevel@tonic-gate9:
10597c478bd9Sstevel@tonic-gate#endif /* DEBUG */
10607c478bd9Sstevel@tonic-gate	andcc	%l1, %o5, %g0		! test mask against high-level bits of
10617c478bd9Sstevel@tonic-gate	bnz	%xcc, 3f		! cpu_intr_actv
10627c478bd9Sstevel@tonic-gate	nop
10637c478bd9Sstevel@tonic-gate	srl	%l1, 1, %l1		! No match. Try next lower PIL.
10647c478bd9Sstevel@tonic-gate	ba,pt	%xcc, 2b
10657c478bd9Sstevel@tonic-gate	sub	%o4, 1, %o4		! delay - decrement PIL
10667c478bd9Sstevel@tonic-gate3:
10677c478bd9Sstevel@tonic-gate	sll	%o4, 3, %o4			! index to byte offset
10687c478bd9Sstevel@tonic-gate	add	%o4, CPU_MCPU, %l1	! CPU_PIL_HIGH_START is too large
10697c478bd9Sstevel@tonic-gate	add	%l1, MCPU_PIL_HIGH_START, %l1
10707c478bd9Sstevel@tonic-gate	ldx	[%o3 + %l1], %l3		! load starting timestamp
10717c478bd9Sstevel@tonic-gate#ifdef DEBUG
10727c478bd9Sstevel@tonic-gate	brnz,pt	%l3, 9f
10737c478bd9Sstevel@tonic-gate	nop
10747c478bd9Sstevel@tonic-gate	! Don't panic if a panic is already in progress.
10757c478bd9Sstevel@tonic-gate	sethi	%hi(panic_quiesce), %l1
10767c478bd9Sstevel@tonic-gate	ld	[%l1 + %lo(panic_quiesce)], %l1
10777c478bd9Sstevel@tonic-gate	brnz,pn	%l1, 9f
10787c478bd9Sstevel@tonic-gate	nop
10797c478bd9Sstevel@tonic-gate	srl	%o4, 3, %o1			! Find interrupted PIL for panic
10807c478bd9Sstevel@tonic-gate	add	%o1, LOCK_LEVEL + 1, %o1
10817c478bd9Sstevel@tonic-gate	sethi	%hi(current_thread_nested_pil_zero), %o0
10827c478bd9Sstevel@tonic-gate	call	panic
10837c478bd9Sstevel@tonic-gate	or	%o0, %lo(current_thread_nested_pil_zero), %o0
10847c478bd9Sstevel@tonic-gate9:
10857c478bd9Sstevel@tonic-gate#endif /* DEBUG */
10867c478bd9Sstevel@tonic-gate	rdpr	%tick, %l1
10877c478bd9Sstevel@tonic-gate	sllx	%l1, 1, %l1
10887c478bd9Sstevel@tonic-gate	srlx	%l1, 1, %l1			! shake off NPT bit
10897c478bd9Sstevel@tonic-gate	sub	%l1, %l3, %l3			! interval in %l3
10907c478bd9Sstevel@tonic-gate	!
10917c478bd9Sstevel@tonic-gate	! Check for Energy Star mode
10927c478bd9Sstevel@tonic-gate	!
10937c478bd9Sstevel@tonic-gate	lduh	[%o3 + CPU_DIVISOR], %l1	! %l1 = clock divisor
10947c478bd9Sstevel@tonic-gate	cmp	%l1, 1
10957c478bd9Sstevel@tonic-gate	bg,a,pn	%xcc, 2f
10967c478bd9Sstevel@tonic-gate	mulx	%l3, %l1, %l3	! multiply interval by clock divisor iff > 1
10977c478bd9Sstevel@tonic-gate2:
10987c478bd9Sstevel@tonic-gate	!
10997c478bd9Sstevel@tonic-gate	! We need to find the CPU offset of the cumulative counter. We start
11007c478bd9Sstevel@tonic-gate	! with %o4, which has (PIL - (LOCK_LEVEL + 1)) * 8. We need PIL * 16,
11017c478bd9Sstevel@tonic-gate	! so we shift left 1, then add (LOCK_LEVEL + 1) * 16, which is
11027c478bd9Sstevel@tonic-gate	! CPU_INTRSTAT_LOW_PIL_OFFSET.
11037c478bd9Sstevel@tonic-gate	!
11047c478bd9Sstevel@tonic-gate	sll	%o4, 1, %o4
11057c478bd9Sstevel@tonic-gate	add	%o4, CPU_MCPU, %o4		! CPU_INTRSTAT const too large
11067c478bd9Sstevel@tonic-gate	add	%o4, MCPU_INTRSTAT, %o4		! add parts separately
11077c478bd9Sstevel@tonic-gate	add	%o4, CPU_INTRSTAT_LOW_PIL_OFFSET, %o4
11087c478bd9Sstevel@tonic-gate	ldx	[%o3 + %o4], %l1		! old counter in l1
11097c478bd9Sstevel@tonic-gate	add	%l1, %l3, %l1			! new counter in l1
1110eda89462Sesolom	stx	%l1, [%o3 + %o4]		! store new counter
1111eda89462Sesolom
1112eda89462Sesolom	! Also update intracct[]
1113eda89462Sesolom	lduh	[%o3 + CPU_MSTATE], %o4
1114eda89462Sesolom	sllx	%o4, 3, %o4
1115eda89462Sesolom	add	%o4, CPU_INTRACCT, %o4
1116eda89462Sesolom	ldx	[%o3 + %o4], %l1
1117eda89462Sesolom	add	%l1, %l3, %l1
11187c478bd9Sstevel@tonic-gate	! Another high-level interrupt is active below this one, so
11197c478bd9Sstevel@tonic-gate	! there is no need to check for an interrupt thread. That will be
11207c478bd9Sstevel@tonic-gate	! done by the lowest priority high-level interrupt active.
11217c478bd9Sstevel@tonic-gate	ba,pt	%xcc, 5f
11227c478bd9Sstevel@tonic-gate	stx	%l1, [%o3 + %o4]		! delay - store new counter
11237c478bd9Sstevel@tonic-gate1:
11247c478bd9Sstevel@tonic-gate	! If we haven't interrupted another high-level interrupt, we may be
11257c478bd9Sstevel@tonic-gate	! interrupting a low level interrupt thread. If so, compute its interval
11267c478bd9Sstevel@tonic-gate	! and update its cumulative counter.
11277c478bd9Sstevel@tonic-gate	lduh	[THREAD_REG + T_FLAGS], %o4
11287c478bd9Sstevel@tonic-gate	andcc	%o4, T_INTR_THREAD, %g0
11297c478bd9Sstevel@tonic-gate	bz,pt	%xcc, 4f
11307c478bd9Sstevel@tonic-gate	nop
11317c478bd9Sstevel@tonic-gate
11327c478bd9Sstevel@tonic-gate	! We have interrupted an interrupt thread. Take timestamp, compute
11337c478bd9Sstevel@tonic-gate	! interval, update cumulative counter.
11347c478bd9Sstevel@tonic-gate
11357c478bd9Sstevel@tonic-gate	! Check t_intr_start. If it is zero, either intr_thread() or
11367c478bd9Sstevel@tonic-gate	! current_thread() (at a lower PIL, of course) already did
11377c478bd9Sstevel@tonic-gate	! the accounting for the underlying interrupt thread.
11387c478bd9Sstevel@tonic-gate	ldx	[THREAD_REG + T_INTR_START], %o5
11397c478bd9Sstevel@tonic-gate	brz,pn	%o5, 4f
11407c478bd9Sstevel@tonic-gate	nop
11417c478bd9Sstevel@tonic-gate
11427c478bd9Sstevel@tonic-gate	stx	%g0, [THREAD_REG + T_INTR_START]
11437c478bd9Sstevel@tonic-gate	rdpr	%tick, %o4
11447c478bd9Sstevel@tonic-gate	sllx	%o4, 1, %o4
11457c478bd9Sstevel@tonic-gate	srlx	%o4, 1, %o4			! shake off NPT bit
11467c478bd9Sstevel@tonic-gate	sub	%o4, %o5, %o5			! o5 has the interval
11477c478bd9Sstevel@tonic-gate
11487c478bd9Sstevel@tonic-gate	! Check for Energy Star mode
11497c478bd9Sstevel@tonic-gate	lduh	[%o3 + CPU_DIVISOR], %o4	! %o4 = clock divisor
11507c478bd9Sstevel@tonic-gate	cmp	%o4, 1
11517c478bd9Sstevel@tonic-gate	bg,a,pn	%xcc, 2f
11527c478bd9Sstevel@tonic-gate	mulx	%o5, %o4, %o5	! multiply interval by clock divisor iff > 1
11537c478bd9Sstevel@tonic-gate2:
11547c478bd9Sstevel@tonic-gate	ldub	[THREAD_REG + T_PIL], %o4
11557c478bd9Sstevel@tonic-gate	sllx	%o4, 4, %o4			! PIL index to byte offset
11567c478bd9Sstevel@tonic-gate	add	%o4, CPU_MCPU, %o4		! CPU_INTRSTAT const too large
11577c478bd9Sstevel@tonic-gate	add	%o4, MCPU_INTRSTAT, %o4		! add parts separately
11587c478bd9Sstevel@tonic-gate	ldx	[%o3 + %o4], %l2		! old counter in l2
11597c478bd9Sstevel@tonic-gate	add	%l2, %o5, %l2			! new counter in l2
11607c478bd9Sstevel@tonic-gate	stx	%l2, [%o3 + %o4]		! store new counter
11617c478bd9Sstevel@tonic-gate
1162eda89462Sesolom	! Also update intracct[]
1163eda89462Sesolom	lduh	[%o3 + CPU_MSTATE], %o4
1164eda89462Sesolom	sllx	%o4, 3, %o4
1165eda89462Sesolom	add	%o4, CPU_INTRACCT, %o4
1166eda89462Sesolom	ldx	[%o3 + %o4], %l2
1167eda89462Sesolom	add	%l2, %o5, %l2
1168eda89462Sesolom	stx	%l2, [%o3 + %o4]
11697c478bd9Sstevel@tonic-gate4:
11707c478bd9Sstevel@tonic-gate	!
11717c478bd9Sstevel@tonic-gate	! Handle high-level interrupts on separate interrupt stack.
11727c478bd9Sstevel@tonic-gate	! No other high-level interrupts are active, so switch to int stack.
11737c478bd9Sstevel@tonic-gate	!
11747c478bd9Sstevel@tonic-gate	mov	%sp, %l1
11757c478bd9Sstevel@tonic-gate	ldn	[%o3 + CPU_INTR_STACK], %l3
11767c478bd9Sstevel@tonic-gate	sub	%l3, STACK_BIAS, %sp
11777c478bd9Sstevel@tonic-gate
11787c478bd9Sstevel@tonic-gate5:
11797c478bd9Sstevel@tonic-gate#ifdef DEBUG
11807c478bd9Sstevel@tonic-gate	!
11817c478bd9Sstevel@tonic-gate	! ASSERT(%o2 > LOCK_LEVEL)
11827c478bd9Sstevel@tonic-gate	!
11837c478bd9Sstevel@tonic-gate	cmp	%o2, LOCK_LEVEL
11847c478bd9Sstevel@tonic-gate	bg,pt	%xcc, 3f
11857c478bd9Sstevel@tonic-gate	nop
11867c478bd9Sstevel@tonic-gate	mov	CE_PANIC, %o0
11877c478bd9Sstevel@tonic-gate	sethi	%hi(current_thread_wrong_pil), %o1
11887c478bd9Sstevel@tonic-gate	call	cmn_err				! %o2 has the %pil already
11897c478bd9Sstevel@tonic-gate	or	%o1, %lo(current_thread_wrong_pil), %o1
11907c478bd9Sstevel@tonic-gate#endif
11917c478bd9Sstevel@tonic-gate3:
11927c478bd9Sstevel@tonic-gate	! Store starting timestamp for this PIL in CPU structure at
11937c478bd9Sstevel@tonic-gate	! cpu.cpu_m.pil_high_start[PIL - (LOCK_LEVEL + 1)]
11947c478bd9Sstevel@tonic-gate        sub     %o2, LOCK_LEVEL + 1, %o4	! convert PIL to array index
11957c478bd9Sstevel@tonic-gate	sllx    %o4, 3, %o4			! index to byte offset
11967c478bd9Sstevel@tonic-gate	add	%o4, CPU_MCPU, %o4	! CPU_PIL_HIGH_START is too large
11977c478bd9Sstevel@tonic-gate	add	%o4, MCPU_PIL_HIGH_START, %o4
11987c478bd9Sstevel@tonic-gate        rdpr    %tick, %o5
11997c478bd9Sstevel@tonic-gate	sllx	%o5, 1, %o5
12007c478bd9Sstevel@tonic-gate	srlx	%o5, 1, %o5
12017c478bd9Sstevel@tonic-gate        stx     %o5, [%o3 + %o4]
12027c478bd9Sstevel@tonic-gate
12037c478bd9Sstevel@tonic-gate	wrpr	%g0, %o2, %pil			! enable interrupts
12047c478bd9Sstevel@tonic-gate
12057c478bd9Sstevel@tonic-gate	!
12067c478bd9Sstevel@tonic-gate	! call the handler
12077c478bd9Sstevel@tonic-gate	!
12087c478bd9Sstevel@tonic-gate	SERVE_INTR_PRE(%o1, %o3, %l2, %l3, %o4, %o5, %o2, %o0)
12097c478bd9Sstevel@tonic-gate1:
12107c478bd9Sstevel@tonic-gate	SERVE_INTR(%o1, %o3, %l2, %l3, %o4, %o5, %o2, %o0)
12117c478bd9Sstevel@tonic-gate
12127c478bd9Sstevel@tonic-gate	brz,a,pt %o2, 0f			! if %o2, more intrs await
12137c478bd9Sstevel@tonic-gate	rdpr	%pil, %o2			! delay annulled
12147c478bd9Sstevel@tonic-gate	SERVE_INTR_NEXT(%o1, %o3, %l2, %l3, %o4, %o5, %o2, %o0)
12157c478bd9Sstevel@tonic-gate	ba	1b
12167c478bd9Sstevel@tonic-gate	nop
12177c478bd9Sstevel@tonic-gate0:
12187c478bd9Sstevel@tonic-gate	wrpr	%g0, PIL_MAX, %pil		! disable interrupts (1-15)
12197c478bd9Sstevel@tonic-gate
12207c478bd9Sstevel@tonic-gate	cmp	%o2, PIL_15
12217c478bd9Sstevel@tonic-gate	bne,pt	%xcc, 3f
12227c478bd9Sstevel@tonic-gate	nop
12237c478bd9Sstevel@tonic-gate
12247c478bd9Sstevel@tonic-gate	sethi	%hi(cpc_level15_inum), %o1
12257c478bd9Sstevel@tonic-gate	ld	[%o1 + %lo(cpc_level15_inum)], %o1 ! arg for intr_enqueue_req
12267c478bd9Sstevel@tonic-gate	brz	%o1, 3f
12277c478bd9Sstevel@tonic-gate	nop
12287c478bd9Sstevel@tonic-gate
12297c478bd9Sstevel@tonic-gate	rdpr 	%pstate, %g5
12307c478bd9Sstevel@tonic-gate	andn	%g5, PSTATE_IE, %g1
12317c478bd9Sstevel@tonic-gate	wrpr	%g0, %g1, %pstate		! Disable vec interrupts
12327c478bd9Sstevel@tonic-gate
12337c478bd9Sstevel@tonic-gate	call	intr_enqueue_req		! preserves %g5
12347c478bd9Sstevel@tonic-gate	mov	PIL_15, %o0
12357c478bd9Sstevel@tonic-gate
12367c478bd9Sstevel@tonic-gate	! clear perfcntr overflow
12377c478bd9Sstevel@tonic-gate	mov	1, %o0
12387c478bd9Sstevel@tonic-gate	sllx	%o0, PIL_15, %o0
12397c478bd9Sstevel@tonic-gate	wr	%o0, CLEAR_SOFTINT
12407c478bd9Sstevel@tonic-gate
12417c478bd9Sstevel@tonic-gate	wrpr	%g0, %g5, %pstate		! Enable vec interrupts
12427c478bd9Sstevel@tonic-gate
12437c478bd9Sstevel@tonic-gate3:
12447c478bd9Sstevel@tonic-gate	cmp	%o2, PIL_14
12457c478bd9Sstevel@tonic-gate	be	tick_rtt			!  cpu-specific tick processing
12467c478bd9Sstevel@tonic-gate	nop
12477c478bd9Sstevel@tonic-gate	.global	current_thread_complete
12487c478bd9Sstevel@tonic-gatecurrent_thread_complete:
12497c478bd9Sstevel@tonic-gate	!
12507c478bd9Sstevel@tonic-gate	! Register usage:
12517c478bd9Sstevel@tonic-gate	!
12527c478bd9Sstevel@tonic-gate	! %l1 = stack pointer
12537c478bd9Sstevel@tonic-gate	! %l2 = CPU_INTR_ACTV >> (LOCK_LEVEL + 1)
12547c478bd9Sstevel@tonic-gate	! %o2 = PIL
12557c478bd9Sstevel@tonic-gate	! %o3 = CPU pointer
12567c478bd9Sstevel@tonic-gate	! %o4, %o5, %l3, %l4, %l5 = scratch
12577c478bd9Sstevel@tonic-gate	!
12587c478bd9Sstevel@tonic-gate	ldn	[THREAD_REG + T_CPU], %o3
12597c478bd9Sstevel@tonic-gate	!
12607c478bd9Sstevel@tonic-gate	! Clear bit for this level in CPU's interrupt active bitmask.
12617c478bd9Sstevel@tonic-gate	!
12627c478bd9Sstevel@tonic-gate	ld	[%o3 + CPU_INTR_ACTV], %l2
12637c478bd9Sstevel@tonic-gate	mov	1, %o5
12647c478bd9Sstevel@tonic-gate	sll	%o5, %o2, %o5
12657c478bd9Sstevel@tonic-gate#ifdef DEBUG
12667c478bd9Sstevel@tonic-gate	!
12677c478bd9Sstevel@tonic-gate	! ASSERT(CPU->cpu_intr_actv & (1 << PIL))
12687c478bd9Sstevel@tonic-gate	!
12697c478bd9Sstevel@tonic-gate	andcc	%l2, %o5, %g0
12707c478bd9Sstevel@tonic-gate	bnz,pt	%xcc, 0f
12717c478bd9Sstevel@tonic-gate	nop
12727c478bd9Sstevel@tonic-gate	! Do not call panic if a panic is already in progress.
12737c478bd9Sstevel@tonic-gate	sethi	%hi(panic_quiesce), %l2
12747c478bd9Sstevel@tonic-gate	ld	[%l2 + %lo(panic_quiesce)], %l2
12757c478bd9Sstevel@tonic-gate	brnz,pn	%l2, 0f
12767c478bd9Sstevel@tonic-gate	nop
12777c478bd9Sstevel@tonic-gate	sethi	%hi(current_thread_actv_bit_not_set), %o0
12787c478bd9Sstevel@tonic-gate	call	panic
12797c478bd9Sstevel@tonic-gate	or	%o0, %lo(current_thread_actv_bit_not_set), %o0
12807c478bd9Sstevel@tonic-gate0:
12817c478bd9Sstevel@tonic-gate#endif /* DEBUG */
12827c478bd9Sstevel@tonic-gate	andn	%l2, %o5, %l2
12837c478bd9Sstevel@tonic-gate	st	%l2, [%o3 + CPU_INTR_ACTV]
12847c478bd9Sstevel@tonic-gate
12857c478bd9Sstevel@tonic-gate	! Take timestamp, compute interval, update cumulative counter.
12867c478bd9Sstevel@tonic-gate        sub     %o2, LOCK_LEVEL + 1, %o4	! PIL to array index
12877c478bd9Sstevel@tonic-gate	sllx    %o4, 3, %o4			! index to byte offset
12887c478bd9Sstevel@tonic-gate	add	%o4, CPU_MCPU, %o4	! CPU_PIL_HIGH_START is too large
12897c478bd9Sstevel@tonic-gate	add	%o4, MCPU_PIL_HIGH_START, %o4
12907c478bd9Sstevel@tonic-gate        rdpr    %tick, %o5
12917c478bd9Sstevel@tonic-gate	sllx	%o5, 1, %o5
12927c478bd9Sstevel@tonic-gate	srlx	%o5, 1, %o5
12937c478bd9Sstevel@tonic-gate	ldx     [%o3 + %o4], %o0
12947c478bd9Sstevel@tonic-gate#ifdef DEBUG
12957c478bd9Sstevel@tonic-gate	! ASSERT(cpu.cpu_m.pil_high_start[pil - (LOCK_LEVEL + 1)] != 0)
12967c478bd9Sstevel@tonic-gate	brnz,pt	%o0, 9f
12977c478bd9Sstevel@tonic-gate	nop
12987c478bd9Sstevel@tonic-gate	! Don't panic if a panic is already in progress.
12997c478bd9Sstevel@tonic-gate	sethi	%hi(panic_quiesce), %l2
13007c478bd9Sstevel@tonic-gate	ld	[%l2 + %lo(panic_quiesce)], %l2
13017c478bd9Sstevel@tonic-gate	brnz,pn	%l2, 9f
13027c478bd9Sstevel@tonic-gate	nop
13037c478bd9Sstevel@tonic-gate	sethi	%hi(current_thread_timestamp_zero), %o0
13047c478bd9Sstevel@tonic-gate	call	panic
13057c478bd9Sstevel@tonic-gate	or	%o0, %lo(current_thread_timestamp_zero), %o0
13067c478bd9Sstevel@tonic-gate9:
13077c478bd9Sstevel@tonic-gate#endif /* DEBUG */
13087c478bd9Sstevel@tonic-gate	stx	%g0, [%o3 + %o4]
13097c478bd9Sstevel@tonic-gate	sub	%o5, %o0, %o5			! interval in o5
13107c478bd9Sstevel@tonic-gate
13117c478bd9Sstevel@tonic-gate	! Check for Energy Star mode
13127c478bd9Sstevel@tonic-gate	lduh	[%o3 + CPU_DIVISOR], %o4	! %o4 = clock divisor
13137c478bd9Sstevel@tonic-gate	cmp	%o4, 1
13147c478bd9Sstevel@tonic-gate	bg,a,pn	%xcc, 2f
13157c478bd9Sstevel@tonic-gate	mulx	%o5, %o4, %o5	! multiply interval by clock divisor iff > 1
13167c478bd9Sstevel@tonic-gate2:
13177c478bd9Sstevel@tonic-gate	sllx	%o2, 4, %o4			! PIL index to byte offset
13187c478bd9Sstevel@tonic-gate	add	%o4, CPU_MCPU, %o4		! CPU_INTRSTAT too large
13197c478bd9Sstevel@tonic-gate	add	%o4, MCPU_INTRSTAT, %o4		! add parts separately
13207c478bd9Sstevel@tonic-gate	ldx	[%o3 + %o4], %o0		! old counter in o0
13217c478bd9Sstevel@tonic-gate	add	%o0, %o5, %o0			! new counter in o0
13227c478bd9Sstevel@tonic-gate	stx	%o0, [%o3 + %o4]		! store new counter
13237c478bd9Sstevel@tonic-gate
1324eda89462Sesolom	! Also update intracct[]
1325eda89462Sesolom	lduh	[%o3 + CPU_MSTATE], %o4
1326eda89462Sesolom	sllx	%o4, 3, %o4
1327eda89462Sesolom	add	%o4, CPU_INTRACCT, %o4
1328eda89462Sesolom	ldx	[%o3 + %o4], %o0
1329eda89462Sesolom	add	%o0, %o5, %o0
1330eda89462Sesolom	stx	%o0, [%o3 + %o4]
1331eda89462Sesolom
13327c478bd9Sstevel@tonic-gate	!
13337c478bd9Sstevel@tonic-gate	! get back on current thread's stack
13347c478bd9Sstevel@tonic-gate	!
13357c478bd9Sstevel@tonic-gate	srl	%l2, LOCK_LEVEL + 1, %l2
13367c478bd9Sstevel@tonic-gate	tst	%l2				! any more high-level ints?
13377c478bd9Sstevel@tonic-gate	movz	%xcc, %l1, %sp
13387c478bd9Sstevel@tonic-gate	!
13397c478bd9Sstevel@tonic-gate	! Current register usage:
13407c478bd9Sstevel@tonic-gate	! o2 = PIL
13417c478bd9Sstevel@tonic-gate	! o3 = CPU pointer
13427c478bd9Sstevel@tonic-gate	! l0 = return address
13437c478bd9Sstevel@tonic-gate	! l2 = intr_actv shifted right
13447c478bd9Sstevel@tonic-gate	!
13457c478bd9Sstevel@tonic-gate	bz,pt	%xcc, 3f			! if l2 was zero, no more ints
13467c478bd9Sstevel@tonic-gate	nop
13477c478bd9Sstevel@tonic-gate	!
13487c478bd9Sstevel@tonic-gate	! We found another high-level interrupt active below the one that just
13497c478bd9Sstevel@tonic-gate	! returned. Store a starting timestamp for it in the CPU structure.
13507c478bd9Sstevel@tonic-gate	!
13517c478bd9Sstevel@tonic-gate	! Use cpu_intr_actv to find the cpu_pil_high_start[] offset for the
13527c478bd9Sstevel@tonic-gate	! interrupted high-level interrupt.
13537c478bd9Sstevel@tonic-gate	! Create mask for cpu_intr_actv. Begin by looking for bits set
13547c478bd9Sstevel@tonic-gate	! at one level below the current PIL. Since %l2 contains the active
13557c478bd9Sstevel@tonic-gate	! mask already shifted right by (LOCK_LEVEL + 1), we start by looking
13567c478bd9Sstevel@tonic-gate	! at bit (current_pil - (LOCK_LEVEL + 2)).
13577c478bd9Sstevel@tonic-gate	! %l1 = mask, %o5 = index of bit set in mask
13587c478bd9Sstevel@tonic-gate	!
13597c478bd9Sstevel@tonic-gate	mov	1, %l1
13607c478bd9Sstevel@tonic-gate	sub	%o2, LOCK_LEVEL + 2, %o5
13617c478bd9Sstevel@tonic-gate	sll	%l1, %o5, %l1			! l1 = mask for level
13627c478bd9Sstevel@tonic-gate1:
13637c478bd9Sstevel@tonic-gate#ifdef DEBUG
13647c478bd9Sstevel@tonic-gate	! ASSERT(%l1 != 0) (we didn't shift the bit off the right edge)
13657c478bd9Sstevel@tonic-gate	brnz,pt	%l1, 9f
13667c478bd9Sstevel@tonic-gate	nop
13677c478bd9Sstevel@tonic-gate	sethi	%hi(current_thread_nested_PIL_not_found), %o0
13687c478bd9Sstevel@tonic-gate	call	panic
13697c478bd9Sstevel@tonic-gate	or	%o0, %lo(current_thread_nested_PIL_not_found), %o0
13707c478bd9Sstevel@tonic-gate9:
13717c478bd9Sstevel@tonic-gate#endif /* DEBUG */
13727c478bd9Sstevel@tonic-gate	andcc	%l1, %l2, %g0		! test mask against high-level bits of
13737c478bd9Sstevel@tonic-gate	bnz	%xcc, 2f		! cpu_intr_actv
13747c478bd9Sstevel@tonic-gate	nop
13757c478bd9Sstevel@tonic-gate	srl	%l1, 1, %l1		! No match. Try next lower PIL.
13767c478bd9Sstevel@tonic-gate	ba,pt	%xcc, 1b
13777c478bd9Sstevel@tonic-gate	sub	%o5, 1, %o5		! delay - decrement PIL
13787c478bd9Sstevel@tonic-gate2:
13797c478bd9Sstevel@tonic-gate	sll	%o5, 3, %o5		! convert array index to byte offset
13807c478bd9Sstevel@tonic-gate	add	%o5, CPU_MCPU, %o5	! CPU_PIL_HIGH_START is too large
13817c478bd9Sstevel@tonic-gate	add	%o5, MCPU_PIL_HIGH_START, %o5
13827c478bd9Sstevel@tonic-gate	rdpr	%tick, %o4
13837c478bd9Sstevel@tonic-gate	sllx	%o4, 1, %o4
13847c478bd9Sstevel@tonic-gate	srlx	%o4, 1, %o4
13857c478bd9Sstevel@tonic-gate	! Another high-level interrupt is active below this one, so
13867c478bd9Sstevel@tonic-gate	! there is no need to check for an interrupt thread. That will be
13877c478bd9Sstevel@tonic-gate	! done by the lowest priority high-level interrupt active.
13887c478bd9Sstevel@tonic-gate	ba,pt	%xcc, 1f
13897c478bd9Sstevel@tonic-gate	stx	%o4, [%o3 + %o5]	! delay - store timestamp
13907c478bd9Sstevel@tonic-gate3:
13917c478bd9Sstevel@tonic-gate	! If we haven't interrupted another high-level interrupt, we may have
13927c478bd9Sstevel@tonic-gate	! interrupted a low level interrupt thread. If so, store a starting
13937c478bd9Sstevel@tonic-gate	! timestamp in its thread structure.
13947c478bd9Sstevel@tonic-gate	lduh	[THREAD_REG + T_FLAGS], %o4
13957c478bd9Sstevel@tonic-gate	andcc	%o4, T_INTR_THREAD, %g0
13967c478bd9Sstevel@tonic-gate	bz,pt	%xcc, 1f
13977c478bd9Sstevel@tonic-gate	nop
13987c478bd9Sstevel@tonic-gate
13997c478bd9Sstevel@tonic-gate	rdpr	%tick, %o4
14007c478bd9Sstevel@tonic-gate	sllx	%o4, 1, %o4
14017c478bd9Sstevel@tonic-gate	srlx	%o4, 1, %o4			! Shake off NPT bit
14027c478bd9Sstevel@tonic-gate	stx	%o4, [THREAD_REG + T_INTR_START]
14037c478bd9Sstevel@tonic-gate1:
14047c478bd9Sstevel@tonic-gate	! Enable interrupts and return
14057c478bd9Sstevel@tonic-gate	jmp	%l0 + 8
14067c478bd9Sstevel@tonic-gate	wrpr	%g0, %o2, %pil			! enable interrupts
14077c478bd9Sstevel@tonic-gate	SET_SIZE(current_thread)
14087c478bd9Sstevel@tonic-gate
14097c478bd9Sstevel@tonic-gate
14107c478bd9Sstevel@tonic-gate#ifdef DEBUG
14117c478bd9Sstevel@tonic-gatecurrent_thread_wrong_pil:
14127c478bd9Sstevel@tonic-gate	.asciz	"current_thread: unexpected pil level: %d"
14137c478bd9Sstevel@tonic-gatecurrent_thread_actv_bit_set:
14147c478bd9Sstevel@tonic-gate	.asciz	"current_thread(): cpu_intr_actv bit already set for PIL"
14157c478bd9Sstevel@tonic-gatecurrent_thread_actv_bit_not_set:
14167c478bd9Sstevel@tonic-gate	.asciz	"current_thread(): cpu_intr_actv bit not set for PIL"
14177c478bd9Sstevel@tonic-gatecurrent_thread_nested_pil_zero:
14187c478bd9Sstevel@tonic-gate	.asciz	"current_thread(): timestamp zero for nested PIL %d"
14197c478bd9Sstevel@tonic-gatecurrent_thread_timestamp_zero:
14207c478bd9Sstevel@tonic-gate	.asciz	"current_thread(): timestamp zero upon handler return"
14217c478bd9Sstevel@tonic-gatecurrent_thread_nested_PIL_not_found:
14227c478bd9Sstevel@tonic-gate	.asciz	"current_thread: couldn't find nested high-level PIL"
14237c478bd9Sstevel@tonic-gate#endif /* DEBUG */
14247c478bd9Sstevel@tonic-gate#endif /* lint */
14257c478bd9Sstevel@tonic-gate
14267c478bd9Sstevel@tonic-gate/*
14277c478bd9Sstevel@tonic-gate * Return a thread's interrupt level.
14287c478bd9Sstevel@tonic-gate * Since this isn't saved anywhere but in %l4 on interrupt entry, we
14297c478bd9Sstevel@tonic-gate * must dig it out of the save area.
14307c478bd9Sstevel@tonic-gate *
14317c478bd9Sstevel@tonic-gate * Caller 'swears' that this really is an interrupt thread.
14327c478bd9Sstevel@tonic-gate *
14337c478bd9Sstevel@tonic-gate * int
14347c478bd9Sstevel@tonic-gate * intr_level(t)
14357c478bd9Sstevel@tonic-gate *	kthread_id_t	t;
14367c478bd9Sstevel@tonic-gate */
14377c478bd9Sstevel@tonic-gate
14387c478bd9Sstevel@tonic-gate#if defined(lint)
14397c478bd9Sstevel@tonic-gate
14407c478bd9Sstevel@tonic-gate/* ARGSUSED */
14417c478bd9Sstevel@tonic-gateint
14427c478bd9Sstevel@tonic-gateintr_level(kthread_id_t t)
14437c478bd9Sstevel@tonic-gate{ return (0); }
14447c478bd9Sstevel@tonic-gate
14457c478bd9Sstevel@tonic-gate#else	/* lint */
14467c478bd9Sstevel@tonic-gate
14477c478bd9Sstevel@tonic-gate	ENTRY_NP(intr_level)
14487c478bd9Sstevel@tonic-gate	retl
14497c478bd9Sstevel@tonic-gate	ldub	[%o0 + T_PIL], %o0		! return saved pil
14507c478bd9Sstevel@tonic-gate	SET_SIZE(intr_level)
14517c478bd9Sstevel@tonic-gate
14527c478bd9Sstevel@tonic-gate#endif	/* lint */
14537c478bd9Sstevel@tonic-gate
14547c478bd9Sstevel@tonic-gate#if defined(lint)
14557c478bd9Sstevel@tonic-gate
14567c478bd9Sstevel@tonic-gate/* ARGSUSED */
14577c478bd9Sstevel@tonic-gateint
14587c478bd9Sstevel@tonic-gatedisable_pil_intr()
14597c478bd9Sstevel@tonic-gate{ return (0); }
14607c478bd9Sstevel@tonic-gate
14617c478bd9Sstevel@tonic-gate#else	/* lint */
14627c478bd9Sstevel@tonic-gate
14637c478bd9Sstevel@tonic-gate	ENTRY_NP(disable_pil_intr)
14647c478bd9Sstevel@tonic-gate	rdpr	%pil, %o0
14657c478bd9Sstevel@tonic-gate	retl
14667c478bd9Sstevel@tonic-gate	wrpr	%g0, PIL_MAX, %pil		! disable interrupts (1-15)
14677c478bd9Sstevel@tonic-gate	SET_SIZE(disable_pil_intr)
14687c478bd9Sstevel@tonic-gate
14697c478bd9Sstevel@tonic-gate#endif	/* lint */
14707c478bd9Sstevel@tonic-gate
14717c478bd9Sstevel@tonic-gate#if defined(lint)
14727c478bd9Sstevel@tonic-gate
14737c478bd9Sstevel@tonic-gate/* ARGSUSED */
14747c478bd9Sstevel@tonic-gatevoid
14757c478bd9Sstevel@tonic-gateenable_pil_intr(int pil_save)
14767c478bd9Sstevel@tonic-gate{}
14777c478bd9Sstevel@tonic-gate
14787c478bd9Sstevel@tonic-gate#else	/* lint */
14797c478bd9Sstevel@tonic-gate
14807c478bd9Sstevel@tonic-gate	ENTRY_NP(enable_pil_intr)
14817c478bd9Sstevel@tonic-gate	retl
14827c478bd9Sstevel@tonic-gate	wrpr	%o0, %pil
14837c478bd9Sstevel@tonic-gate	SET_SIZE(enable_pil_intr)
14847c478bd9Sstevel@tonic-gate
14857c478bd9Sstevel@tonic-gate#endif	/* lint */
14867c478bd9Sstevel@tonic-gate
14877c478bd9Sstevel@tonic-gate#if defined(lint)
14887c478bd9Sstevel@tonic-gate
14897c478bd9Sstevel@tonic-gate/* ARGSUSED */
14907c478bd9Sstevel@tonic-gateuint_t
14917c478bd9Sstevel@tonic-gatedisable_vec_intr(void)
14927c478bd9Sstevel@tonic-gate{ return (0); }
14937c478bd9Sstevel@tonic-gate
14947c478bd9Sstevel@tonic-gate#else	/* lint */
14957c478bd9Sstevel@tonic-gate
14967c478bd9Sstevel@tonic-gate	ENTRY_NP(disable_vec_intr)
14977c478bd9Sstevel@tonic-gate	rdpr	%pstate, %o0
14987c478bd9Sstevel@tonic-gate	andn	%o0, PSTATE_IE, %g1
14997c478bd9Sstevel@tonic-gate	retl
15007c478bd9Sstevel@tonic-gate	wrpr	%g0, %g1, %pstate		! disable interrupt
15017c478bd9Sstevel@tonic-gate	SET_SIZE(disable_vec_intr)
15027c478bd9Sstevel@tonic-gate
15037c478bd9Sstevel@tonic-gate#endif	/* lint */
15047c478bd9Sstevel@tonic-gate
15057c478bd9Sstevel@tonic-gate#if defined(lint)
15067c478bd9Sstevel@tonic-gate
15077c478bd9Sstevel@tonic-gate/* ARGSUSED */
15087c478bd9Sstevel@tonic-gatevoid
15097c478bd9Sstevel@tonic-gateenable_vec_intr(uint_t pstate_save)
15107c478bd9Sstevel@tonic-gate{}
15117c478bd9Sstevel@tonic-gate
15127c478bd9Sstevel@tonic-gate#else	/* lint */
15137c478bd9Sstevel@tonic-gate
15147c478bd9Sstevel@tonic-gate	ENTRY_NP(enable_vec_intr)
15157c478bd9Sstevel@tonic-gate	retl
15167c478bd9Sstevel@tonic-gate	wrpr	%g0, %o0, %pstate
15177c478bd9Sstevel@tonic-gate	SET_SIZE(enable_vec_intr)
15187c478bd9Sstevel@tonic-gate
15197c478bd9Sstevel@tonic-gate#endif	/* lint */
15207c478bd9Sstevel@tonic-gate
15217c478bd9Sstevel@tonic-gate#if defined(lint)
15227c478bd9Sstevel@tonic-gate
15237c478bd9Sstevel@tonic-gatevoid
15247c478bd9Sstevel@tonic-gatecbe_level14(void)
15257c478bd9Sstevel@tonic-gate{}
15267c478bd9Sstevel@tonic-gate
15277c478bd9Sstevel@tonic-gate#else   /* lint */
15287c478bd9Sstevel@tonic-gate
15297c478bd9Sstevel@tonic-gate	ENTRY_NP(cbe_level14)
15307c478bd9Sstevel@tonic-gate	save    %sp, -SA(MINFRAME), %sp ! get a new window
15317c478bd9Sstevel@tonic-gate	!
15327c478bd9Sstevel@tonic-gate	! Make sure that this is from TICK_COMPARE; if not just return
15337c478bd9Sstevel@tonic-gate	!
15347c478bd9Sstevel@tonic-gate	rd	SOFTINT, %l1
15357c478bd9Sstevel@tonic-gate	set	(TICK_INT_MASK | STICK_INT_MASK), %o2
15367c478bd9Sstevel@tonic-gate	andcc	%l1, %o2, %g0
15377c478bd9Sstevel@tonic-gate	bz,pn	%icc, 2f
15387c478bd9Sstevel@tonic-gate	nop
15397c478bd9Sstevel@tonic-gate
15407c478bd9Sstevel@tonic-gate	CPU_ADDR(%o1, %o2)
15417c478bd9Sstevel@tonic-gate	call	cyclic_fire
15427c478bd9Sstevel@tonic-gate	mov	%o1, %o0
15437c478bd9Sstevel@tonic-gate2:
15447c478bd9Sstevel@tonic-gate	ret
15457c478bd9Sstevel@tonic-gate	restore	%g0, 1, %o0
15467c478bd9Sstevel@tonic-gate	SET_SIZE(cbe_level14)
15477c478bd9Sstevel@tonic-gate
15487c478bd9Sstevel@tonic-gate#endif  /* lint */
15497c478bd9Sstevel@tonic-gate
15507c478bd9Sstevel@tonic-gate
15517c478bd9Sstevel@tonic-gate#if defined(lint)
15527c478bd9Sstevel@tonic-gate
15537c478bd9Sstevel@tonic-gate/* ARGSUSED */
15547c478bd9Sstevel@tonic-gatevoid
15557c478bd9Sstevel@tonic-gatesetsoftint(uint_t inum)
15567c478bd9Sstevel@tonic-gate{}
15577c478bd9Sstevel@tonic-gate
15587c478bd9Sstevel@tonic-gate#else	/* lint */
15597c478bd9Sstevel@tonic-gate
15607c478bd9Sstevel@tonic-gate	ENTRY_NP(setsoftint)
15617c478bd9Sstevel@tonic-gate	save	%sp, -SA(MINFRAME), %sp	! get a new window
15627c478bd9Sstevel@tonic-gate	rdpr	%pstate, %l5
15637c478bd9Sstevel@tonic-gate	andn	%l5, PSTATE_IE, %l1
15647c478bd9Sstevel@tonic-gate	wrpr	%l1, %pstate		! disable interrupt
15657c478bd9Sstevel@tonic-gate	!
15667c478bd9Sstevel@tonic-gate	! Fetch data from intr_vector[] table according to the inum.
15677c478bd9Sstevel@tonic-gate	!
15687c478bd9Sstevel@tonic-gate	! We have an interrupt number.
15697c478bd9Sstevel@tonic-gate	! Put the request on the cpu's softint list,
15707c478bd9Sstevel@tonic-gate	! and set %set_softint.
15717c478bd9Sstevel@tonic-gate	!
15727c478bd9Sstevel@tonic-gate	! Register usage
15737c478bd9Sstevel@tonic-gate	!	%i0 - inumber
15747c478bd9Sstevel@tonic-gate	!	%l2 - requested pil
15757c478bd9Sstevel@tonic-gate	!	%l3 - intr_req
15767c478bd9Sstevel@tonic-gate	!	%l4 - *cpu
15777c478bd9Sstevel@tonic-gate	!	%l1, %l6 - temps
15787c478bd9Sstevel@tonic-gate	!
15797c478bd9Sstevel@tonic-gate	! check if a softint is pending for this inum already
15807c478bd9Sstevel@tonic-gate	! if one is pending, don't bother queuing another
15817c478bd9Sstevel@tonic-gate	!
15827c478bd9Sstevel@tonic-gate	set	intr_vector, %l1
15837c478bd9Sstevel@tonic-gate	sll	%i0, INTR_VECTOR_SHIFT, %l6
15847c478bd9Sstevel@tonic-gate	add	%l1, %l6, %l1			! %l1 = &intr_vector[inum]
15857c478bd9Sstevel@tonic-gate	lduh	[%l1 + IV_PENDING], %l6
15867c478bd9Sstevel@tonic-gate	brnz,pn	%l6, 4f				! branch, if pending
15877c478bd9Sstevel@tonic-gate	or	%g0, 1, %l2
15887c478bd9Sstevel@tonic-gate	sth	%l2, [%l1 + IV_PENDING]		! intr_vector[inum].pend = 1
15897c478bd9Sstevel@tonic-gate	!
15907c478bd9Sstevel@tonic-gate	! allocate an intr_req from the free list
15917c478bd9Sstevel@tonic-gate	!
15927c478bd9Sstevel@tonic-gate	CPU_ADDR(%l4, %l2)
15937c478bd9Sstevel@tonic-gate	ldn	[%l4 + INTR_HEAD], %l3
15947c478bd9Sstevel@tonic-gate	lduh	[%l1 + IV_PIL], %l2
15957c478bd9Sstevel@tonic-gate	!
15967c478bd9Sstevel@tonic-gate	! fixup free list
15977c478bd9Sstevel@tonic-gate	!
15987c478bd9Sstevel@tonic-gate	ldn	[%l3 + INTR_NEXT], %l6
15997c478bd9Sstevel@tonic-gate	stn	%l6, [%l4 + INTR_HEAD]
16007c478bd9Sstevel@tonic-gate	!
16017c478bd9Sstevel@tonic-gate	! fill up intr_req
16027c478bd9Sstevel@tonic-gate	!
16037c478bd9Sstevel@tonic-gate	st	%i0, [%l3 + INTR_NUMBER]
16047c478bd9Sstevel@tonic-gate	stn	%g0, [%l3 + INTR_NEXT]
16057c478bd9Sstevel@tonic-gate	!
16067c478bd9Sstevel@tonic-gate	! move intr_req to appropriate list
16077c478bd9Sstevel@tonic-gate	!
16087c478bd9Sstevel@tonic-gate	sll	%l2, CPTRSHIFT, %l0
16097c478bd9Sstevel@tonic-gate	add	%l4, INTR_TAIL, %l6
16107c478bd9Sstevel@tonic-gate	ldn	[%l6 + %l0], %l1	! current tail
16117c478bd9Sstevel@tonic-gate	brz,pt	%l1, 2f			! branch if list empty
16127c478bd9Sstevel@tonic-gate	stn	%l3, [%l6 + %l0]	! make intr_req new tail
16137c478bd9Sstevel@tonic-gate	!
16147c478bd9Sstevel@tonic-gate	! there's pending intr_req already
16157c478bd9Sstevel@tonic-gate	!
16167c478bd9Sstevel@tonic-gate	ba,pt	%xcc, 3f
16177c478bd9Sstevel@tonic-gate	stn	%l3, [%l1 + INTR_NEXT]	! update old tail
16187c478bd9Sstevel@tonic-gate2:
16197c478bd9Sstevel@tonic-gate	!
16207c478bd9Sstevel@tonic-gate	! no pending intr_req; make intr_req new head
16217c478bd9Sstevel@tonic-gate	!
16227c478bd9Sstevel@tonic-gate	add	%l4, INTR_HEAD, %l6
16237c478bd9Sstevel@tonic-gate	stn	%l3, [%l6 + %l0]
16247c478bd9Sstevel@tonic-gate3:
16257c478bd9Sstevel@tonic-gate	!
16267c478bd9Sstevel@tonic-gate	! Write %set_softint with (1<<pil) to cause a "pil" level trap
16277c478bd9Sstevel@tonic-gate	!
16287c478bd9Sstevel@tonic-gate	mov	1, %l1
16297c478bd9Sstevel@tonic-gate	sll	%l1, %l2, %l1
16307c478bd9Sstevel@tonic-gate	wr	%l1, SET_SOFTINT
16317c478bd9Sstevel@tonic-gate4:
16327c478bd9Sstevel@tonic-gate	wrpr	%g0, %l5, %pstate
16337c478bd9Sstevel@tonic-gate	ret
16347c478bd9Sstevel@tonic-gate	restore
16357c478bd9Sstevel@tonic-gate	SET_SIZE(setsoftint)
16367c478bd9Sstevel@tonic-gate
16377c478bd9Sstevel@tonic-gate#endif	/* lint */
16387c478bd9Sstevel@tonic-gate
16397c478bd9Sstevel@tonic-gate#if defined(lint)
16407c478bd9Sstevel@tonic-gate
16417c478bd9Sstevel@tonic-gate/*ARGSUSED*/
16427c478bd9Sstevel@tonic-gatevoid
16437c478bd9Sstevel@tonic-gatesetsoftint_tl1(uint64_t inum, uint64_t dummy)
16447c478bd9Sstevel@tonic-gate{}
16457c478bd9Sstevel@tonic-gate
16467c478bd9Sstevel@tonic-gate#else	/* lint */
16477c478bd9Sstevel@tonic-gate
16487c478bd9Sstevel@tonic-gate	!
16497c478bd9Sstevel@tonic-gate	! Register usage
16507c478bd9Sstevel@tonic-gate	!
16517c478bd9Sstevel@tonic-gate	! Arguments:
16527c478bd9Sstevel@tonic-gate	! %g1 - inumber
16537c478bd9Sstevel@tonic-gate	!
16547c478bd9Sstevel@tonic-gate	! Internal:
16557c478bd9Sstevel@tonic-gate	! %g2 - requested pil
16567c478bd9Sstevel@tonic-gate	! %g3 - intr_req
16577c478bd9Sstevel@tonic-gate	! %g4 - cpu pointer
16587c478bd9Sstevel@tonic-gate	! %g5,%g6,%g7 - temps
16597c478bd9Sstevel@tonic-gate	!
16607c478bd9Sstevel@tonic-gate	ENTRY_NP(setsoftint_tl1)
16617c478bd9Sstevel@tonic-gate	!
16627c478bd9Sstevel@tonic-gate	! Verify the inumber received (should be inum < MAXIVNUM).
16637c478bd9Sstevel@tonic-gate	!
16647c478bd9Sstevel@tonic-gate	set	MAXIVNUM, %g2
16657c478bd9Sstevel@tonic-gate	cmp	%g1, %g2
16667c478bd9Sstevel@tonic-gate	bgeu,pn	%xcc, .no_ivintr
16677c478bd9Sstevel@tonic-gate	clr	%g2			! expected in .no_ivintr
16687c478bd9Sstevel@tonic-gate	!
16697c478bd9Sstevel@tonic-gate	! Fetch data from intr_vector[] table according to the inum.
16707c478bd9Sstevel@tonic-gate	!
16717c478bd9Sstevel@tonic-gate	! We have an interrupt number. Put the request on the cpu's softint
16727c478bd9Sstevel@tonic-gate	! list, and set %set_softint.
16737c478bd9Sstevel@tonic-gate	!
16747c478bd9Sstevel@tonic-gate	set	intr_vector, %g5
16757c478bd9Sstevel@tonic-gate	sll	%g1, INTR_VECTOR_SHIFT, %g6
16767c478bd9Sstevel@tonic-gate	add	%g5, %g6, %g5			! %g5 = &intr_vector[inum]
16777c478bd9Sstevel@tonic-gate
16787c478bd9Sstevel@tonic-gate	!
16797c478bd9Sstevel@tonic-gate	! allocate an intr_req from the free list
16807c478bd9Sstevel@tonic-gate	!
16817c478bd9Sstevel@tonic-gate	CPU_ADDR(%g4, %g2)
16827c478bd9Sstevel@tonic-gate	ldn	[%g4 + INTR_HEAD], %g3
16837c478bd9Sstevel@tonic-gate
16847c478bd9Sstevel@tonic-gate	! load the pil so it can be used by .no_intr_pool/.no_ivintr
16857c478bd9Sstevel@tonic-gate	lduh	[%g5 + IV_PIL], %g2
16867c478bd9Sstevel@tonic-gate
16877c478bd9Sstevel@tonic-gate	! Verify that the free list is not exhausted.
16887c478bd9Sstevel@tonic-gate	brz,pn	%g3, .no_intr_pool
16897c478bd9Sstevel@tonic-gate	nop
16907c478bd9Sstevel@tonic-gate
16917c478bd9Sstevel@tonic-gate	! Verify the intr_vector[] entry according to the inumber.
16927c478bd9Sstevel@tonic-gate	! The iv_pil field should not be zero.  This used to be
16937c478bd9Sstevel@tonic-gate	! guarded by DEBUG but broken drivers can cause spurious
16947c478bd9Sstevel@tonic-gate	! tick interrupts when the softint register is programmed
16957c478bd9Sstevel@tonic-gate	! with 1 << 0 at the end of this routine.  Now we always
16967c478bd9Sstevel@tonic-gate	! check for an invalid pil.
16977c478bd9Sstevel@tonic-gate	brz,pn	%g2, .no_ivintr
16987c478bd9Sstevel@tonic-gate	nop
16997c478bd9Sstevel@tonic-gate
17007c478bd9Sstevel@tonic-gate	!
17017c478bd9Sstevel@tonic-gate	! fixup free list
17027c478bd9Sstevel@tonic-gate	!
17037c478bd9Sstevel@tonic-gate	ldn	[%g3 + INTR_NEXT], %g6
17047c478bd9Sstevel@tonic-gate	stn	%g6, [%g4 + INTR_HEAD]
17057c478bd9Sstevel@tonic-gate
17067c478bd9Sstevel@tonic-gate	!
17077c478bd9Sstevel@tonic-gate	! fill in intr_req
17087c478bd9Sstevel@tonic-gate	!
17097c478bd9Sstevel@tonic-gate	st	%g1, [%g3 + INTR_NUMBER]
17107c478bd9Sstevel@tonic-gate	stn	%g0, [%g3 + INTR_NEXT]
17117c478bd9Sstevel@tonic-gate	!
17127c478bd9Sstevel@tonic-gate	! move intr_req to appropriate list
17137c478bd9Sstevel@tonic-gate	!
17147c478bd9Sstevel@tonic-gate	sll	%g2, CPTRSHIFT, %g7
17157c478bd9Sstevel@tonic-gate	add	%g4, INTR_TAIL, %g6
17167c478bd9Sstevel@tonic-gate	ldn	[%g6 + %g7], %g5	! current tail
17177c478bd9Sstevel@tonic-gate	brz,pt	%g5, 2f			! branch if list empty
17187c478bd9Sstevel@tonic-gate	stn	%g3, [%g6 + %g7]	! make intr_req new tail
17197c478bd9Sstevel@tonic-gate	!
17207c478bd9Sstevel@tonic-gate	! there's pending intr_req already
17217c478bd9Sstevel@tonic-gate	!
17227c478bd9Sstevel@tonic-gate	ba,pt	%xcc, 3f
17237c478bd9Sstevel@tonic-gate	stn	%g3, [%g5 + INTR_NEXT]	! update old tail
17247c478bd9Sstevel@tonic-gate2:
17257c478bd9Sstevel@tonic-gate	!
17267c478bd9Sstevel@tonic-gate	! no pending intr_req; make intr_req new head
17277c478bd9Sstevel@tonic-gate	!
17287c478bd9Sstevel@tonic-gate	add	%g4, INTR_HEAD, %g6
17297c478bd9Sstevel@tonic-gate	stn	%g3, [%g6 + %g7]
17307c478bd9Sstevel@tonic-gate3:
17317c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE
17327c478bd9Sstevel@tonic-gate	TRACE_PTR(%g1, %g6)
17337c478bd9Sstevel@tonic-gate	GET_TRACE_TICK(%g6)
17347c478bd9Sstevel@tonic-gate	stxa	%g6, [%g1 + TRAP_ENT_TICK]%asi
17357c478bd9Sstevel@tonic-gate	TRACE_SAVE_TL_GL_REGS(%g1, %g6)
17367c478bd9Sstevel@tonic-gate	rdpr	%tt, %g6
17377c478bd9Sstevel@tonic-gate	stha	%g6, [%g1 + TRAP_ENT_TT]%asi
17387c478bd9Sstevel@tonic-gate	rdpr	%tpc, %g6
17397c478bd9Sstevel@tonic-gate	stna	%g6, [%g1 + TRAP_ENT_TPC]%asi
17407c478bd9Sstevel@tonic-gate	rdpr	%tstate, %g6
17417c478bd9Sstevel@tonic-gate	stxa	%g6, [%g1 + TRAP_ENT_TSTATE]%asi
17427c478bd9Sstevel@tonic-gate	stna	%sp, [%g1 + TRAP_ENT_SP]%asi
17437c478bd9Sstevel@tonic-gate	ld	[%g3 + INTR_NUMBER], %g6
17447c478bd9Sstevel@tonic-gate	stna	%g6, [%g1 + TRAP_ENT_TR]%asi
17457c478bd9Sstevel@tonic-gate	add	%g4, INTR_HEAD, %g6
17467c478bd9Sstevel@tonic-gate	ldn	[%g6 + %g7], %g6		! intr_head[pil]
17477c478bd9Sstevel@tonic-gate	stna	%g6, [%g1 + TRAP_ENT_F1]%asi
17487c478bd9Sstevel@tonic-gate	add	%g4, INTR_TAIL, %g6
17497c478bd9Sstevel@tonic-gate	ldn	[%g6 + %g7], %g6		! intr_tail[pil]
17507c478bd9Sstevel@tonic-gate	stna	%g6, [%g1 + TRAP_ENT_F2]%asi
17517c478bd9Sstevel@tonic-gate	stna	%g2, [%g1 + TRAP_ENT_F3]%asi	! pil
17527c478bd9Sstevel@tonic-gate	stna	%g3, [%g1 + TRAP_ENT_F4]%asi	! intr_req
17537c478bd9Sstevel@tonic-gate	TRACE_NEXT(%g1, %g6, %g5)
17547c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */
17557c478bd9Sstevel@tonic-gate	!
17567c478bd9Sstevel@tonic-gate	! Write %set_softint with (1<<pil) to cause a "pil" level trap
17577c478bd9Sstevel@tonic-gate	!
17587c478bd9Sstevel@tonic-gate	mov	1, %g5
17597c478bd9Sstevel@tonic-gate	sll	%g5, %g2, %g5
17607c478bd9Sstevel@tonic-gate	wr	%g5, SET_SOFTINT
17617c478bd9Sstevel@tonic-gate4:
17627c478bd9Sstevel@tonic-gate	retry
17637c478bd9Sstevel@tonic-gate
17647c478bd9Sstevel@tonic-gate.no_intr_pool:
17657c478bd9Sstevel@tonic-gate	! no_intr_pool: rp, inum (%g1), pil (%g2)
17667c478bd9Sstevel@tonic-gate	mov	%g2, %g3
17677c478bd9Sstevel@tonic-gate	mov	%g1, %g2
17687c478bd9Sstevel@tonic-gate	set	no_intr_pool, %g1
17697c478bd9Sstevel@tonic-gate	ba,pt	%xcc, sys_trap
17707c478bd9Sstevel@tonic-gate	mov	PIL_15, %g4
17717c478bd9Sstevel@tonic-gate
17727c478bd9Sstevel@tonic-gate.no_ivintr:
17737c478bd9Sstevel@tonic-gate	! no_ivintr: arguments: rp, inum (%g1), pil (%g2 == 0)
17747c478bd9Sstevel@tonic-gate	mov	%g2, %g3
17757c478bd9Sstevel@tonic-gate	mov	%g1, %g2
17767c478bd9Sstevel@tonic-gate	set	no_ivintr, %g1
17777c478bd9Sstevel@tonic-gate	ba,pt	%xcc, sys_trap
17787c478bd9Sstevel@tonic-gate	mov	PIL_15, %g4
17797c478bd9Sstevel@tonic-gate	SET_SIZE(setsoftint_tl1)
17807c478bd9Sstevel@tonic-gate
17817c478bd9Sstevel@tonic-gate#endif	/* lint */
17827c478bd9Sstevel@tonic-gate
17837c478bd9Sstevel@tonic-gate#if defined(lint)
17847c478bd9Sstevel@tonic-gate
17857c478bd9Sstevel@tonic-gate/*ARGSUSED*/
17867c478bd9Sstevel@tonic-gatevoid
17877c478bd9Sstevel@tonic-gatewr_clr_softint(uint_t value)
17887c478bd9Sstevel@tonic-gate{}
17897c478bd9Sstevel@tonic-gate
17907c478bd9Sstevel@tonic-gate#else
17917c478bd9Sstevel@tonic-gate
17927c478bd9Sstevel@tonic-gate	ENTRY_NP(wr_clr_softint)
17937c478bd9Sstevel@tonic-gate	retl
17947c478bd9Sstevel@tonic-gate	wr	%o0, CLEAR_SOFTINT
17957c478bd9Sstevel@tonic-gate	SET_SIZE(wr_clr_softint)
17967c478bd9Sstevel@tonic-gate
17977c478bd9Sstevel@tonic-gate#endif /* lint */
17987c478bd9Sstevel@tonic-gate
17997c478bd9Sstevel@tonic-gate#if defined(lint)
18007c478bd9Sstevel@tonic-gate
18017c478bd9Sstevel@tonic-gate/*ARGSUSED*/
18027c478bd9Sstevel@tonic-gatevoid
18037c478bd9Sstevel@tonic-gateintr_enqueue_req(uint_t pil, uint32_t inum)
18047c478bd9Sstevel@tonic-gate{}
18057c478bd9Sstevel@tonic-gate
18067c478bd9Sstevel@tonic-gate#else   /* lint */
18077c478bd9Sstevel@tonic-gate
18087c478bd9Sstevel@tonic-gate/*
18097c478bd9Sstevel@tonic-gate * intr_enqueue_req
18107c478bd9Sstevel@tonic-gate *
18117c478bd9Sstevel@tonic-gate * %o0 - pil
18127c478bd9Sstevel@tonic-gate * %o1 - inum
18137c478bd9Sstevel@tonic-gate * %o5 - preserved
18147c478bd9Sstevel@tonic-gate * %g5 - preserved
18157c478bd9Sstevel@tonic-gate */
18167c478bd9Sstevel@tonic-gate	ENTRY_NP(intr_enqueue_req)
18177c478bd9Sstevel@tonic-gate	! get intr_req free list
18187c478bd9Sstevel@tonic-gate	CPU_ADDR(%g4, %g1)
18197c478bd9Sstevel@tonic-gate	ldn	[%g4 + INTR_HEAD], %g3
18207c478bd9Sstevel@tonic-gate
18217c478bd9Sstevel@tonic-gate	! take intr_req from free list
18227c478bd9Sstevel@tonic-gate	ldn	[%g3 + INTR_NEXT], %g6
18237c478bd9Sstevel@tonic-gate	stn	%g6, [%g4 + INTR_HEAD]
18247c478bd9Sstevel@tonic-gate
18257c478bd9Sstevel@tonic-gate	! fill up intr_req
18267c478bd9Sstevel@tonic-gate	st	%o1, [%g3 + INTR_NUMBER]
18277c478bd9Sstevel@tonic-gate	stn	%g0, [%g3 + INTR_NEXT]
18287c478bd9Sstevel@tonic-gate
18297c478bd9Sstevel@tonic-gate	! add intr_req to proper pil list
18307c478bd9Sstevel@tonic-gate	sll	%o0, CPTRSHIFT, %o0
18317c478bd9Sstevel@tonic-gate	add	%g4, INTR_TAIL, %g6
18327c478bd9Sstevel@tonic-gate	ldn	[%o0 + %g6], %g1	! current tail
18337c478bd9Sstevel@tonic-gate	brz,pt	%g1, 2f			! branch if list is empty
18347c478bd9Sstevel@tonic-gate	stn	%g3, [%g6 + %o0]	! make intr_req the new tail
18357c478bd9Sstevel@tonic-gate
18367c478bd9Sstevel@tonic-gate	! an intr_req was already queued so update old tail
18377c478bd9Sstevel@tonic-gate	ba,pt	%xcc, 3f
18387c478bd9Sstevel@tonic-gate	stn	%g3, [%g1 + INTR_NEXT]
18397c478bd9Sstevel@tonic-gate2:
18407c478bd9Sstevel@tonic-gate	! no intr_req's queued so make intr_req the new head
18417c478bd9Sstevel@tonic-gate	add	%g4, INTR_HEAD, %g6
18427c478bd9Sstevel@tonic-gate	stn	%g3, [%g6 + %o0]
18437c478bd9Sstevel@tonic-gate3:
18447c478bd9Sstevel@tonic-gate	retl
18457c478bd9Sstevel@tonic-gate	nop
18467c478bd9Sstevel@tonic-gate	SET_SIZE(intr_enqueue_req)
18477c478bd9Sstevel@tonic-gate
18487c478bd9Sstevel@tonic-gate#endif  /* lint */
18497c478bd9Sstevel@tonic-gate
18507c478bd9Sstevel@tonic-gate/*
18517c478bd9Sstevel@tonic-gate * Set CPU's base SPL level, based on which interrupt levels are active.
18527c478bd9Sstevel@tonic-gate * 	Called at spl7 or above.
18537c478bd9Sstevel@tonic-gate */
18547c478bd9Sstevel@tonic-gate
18557c478bd9Sstevel@tonic-gate#if defined(lint)
18567c478bd9Sstevel@tonic-gate
18577c478bd9Sstevel@tonic-gatevoid
18587c478bd9Sstevel@tonic-gateset_base_spl(void)
18597c478bd9Sstevel@tonic-gate{}
18607c478bd9Sstevel@tonic-gate
18617c478bd9Sstevel@tonic-gate#else	/* lint */
18627c478bd9Sstevel@tonic-gate
18637c478bd9Sstevel@tonic-gate	ENTRY_NP(set_base_spl)
18647c478bd9Sstevel@tonic-gate	ldn	[THREAD_REG + T_CPU], %o2	! load CPU pointer
18657c478bd9Sstevel@tonic-gate	ld	[%o2 + CPU_INTR_ACTV], %o5	! load active interrupts mask
18667c478bd9Sstevel@tonic-gate
18677c478bd9Sstevel@tonic-gate/*
18687c478bd9Sstevel@tonic-gate * WARNING: non-standard callinq sequence; do not call from C
18697c478bd9Sstevel@tonic-gate *	%o2 = pointer to CPU
18707c478bd9Sstevel@tonic-gate *	%o5 = updated CPU_INTR_ACTV
18717c478bd9Sstevel@tonic-gate */
18727c478bd9Sstevel@tonic-gate_intr_set_spl:					! intr_thread_exit enters here
18737c478bd9Sstevel@tonic-gate	!
18747c478bd9Sstevel@tonic-gate	! Determine highest interrupt level active.  Several could be blocked
18757c478bd9Sstevel@tonic-gate	! at higher levels than this one, so must convert flags to a PIL
18767c478bd9Sstevel@tonic-gate	! Normally nothing will be blocked, so test this first.
18777c478bd9Sstevel@tonic-gate	!
18787c478bd9Sstevel@tonic-gate	brz,pt	%o5, 1f				! nothing active
18797c478bd9Sstevel@tonic-gate	sra	%o5, 11, %o3			! delay - set %o3 to bits 15-11
18807c478bd9Sstevel@tonic-gate	set	_intr_flag_table, %o1
18817c478bd9Sstevel@tonic-gate	tst	%o3				! see if any of the bits set
18827c478bd9Sstevel@tonic-gate	ldub	[%o1 + %o3], %o3		! load bit number
18837c478bd9Sstevel@tonic-gate	bnz,a,pn %xcc, 1f			! yes, add 10 and we're done
18847c478bd9Sstevel@tonic-gate	add	%o3, 11-1, %o3			! delay - add bit number - 1
18857c478bd9Sstevel@tonic-gate
18867c478bd9Sstevel@tonic-gate	sra	%o5, 6, %o3			! test bits 10-6
18877c478bd9Sstevel@tonic-gate	tst	%o3
18887c478bd9Sstevel@tonic-gate	ldub	[%o1 + %o3], %o3
18897c478bd9Sstevel@tonic-gate	bnz,a,pn %xcc, 1f
18907c478bd9Sstevel@tonic-gate	add	%o3, 6-1, %o3
18917c478bd9Sstevel@tonic-gate
18927c478bd9Sstevel@tonic-gate	sra	%o5, 1, %o3			! test bits 5-1
18937c478bd9Sstevel@tonic-gate	ldub	[%o1 + %o3], %o3
18947c478bd9Sstevel@tonic-gate
18957c478bd9Sstevel@tonic-gate	!
18967c478bd9Sstevel@tonic-gate	! highest interrupt level number active is in %l6
18977c478bd9Sstevel@tonic-gate	!
18987c478bd9Sstevel@tonic-gate1:
18997c478bd9Sstevel@tonic-gate	retl
19007c478bd9Sstevel@tonic-gate	st	%o3, [%o2 + CPU_BASE_SPL]	! delay - store base priority
19017c478bd9Sstevel@tonic-gate	SET_SIZE(set_base_spl)
19027c478bd9Sstevel@tonic-gate
19037c478bd9Sstevel@tonic-gate/*
19047c478bd9Sstevel@tonic-gate * Table that finds the most significant bit set in a five bit field.
19057c478bd9Sstevel@tonic-gate * Each entry is the high-order bit number + 1 of it's index in the table.
19067c478bd9Sstevel@tonic-gate * This read-only data is in the text segment.
19077c478bd9Sstevel@tonic-gate */
19087c478bd9Sstevel@tonic-gate_intr_flag_table:
19097c478bd9Sstevel@tonic-gate	.byte	0, 1, 2, 2,	3, 3, 3, 3,	4, 4, 4, 4,	4, 4, 4, 4
19107c478bd9Sstevel@tonic-gate	.byte	5, 5, 5, 5,	5, 5, 5, 5,	5, 5, 5, 5,	5, 5, 5, 5
19117c478bd9Sstevel@tonic-gate	.align	4
19127c478bd9Sstevel@tonic-gate
19137c478bd9Sstevel@tonic-gate#endif	/* lint */
19147c478bd9Sstevel@tonic-gate
19157c478bd9Sstevel@tonic-gate/*
19167c478bd9Sstevel@tonic-gate * int
19177c478bd9Sstevel@tonic-gate * intr_passivate(from, to)
19187c478bd9Sstevel@tonic-gate *	kthread_id_t	from;		interrupt thread
19197c478bd9Sstevel@tonic-gate *	kthread_id_t	to;		interrupted thread
19207c478bd9Sstevel@tonic-gate */
19217c478bd9Sstevel@tonic-gate
19227c478bd9Sstevel@tonic-gate#if defined(lint)
19237c478bd9Sstevel@tonic-gate
19247c478bd9Sstevel@tonic-gate/* ARGSUSED */
19257c478bd9Sstevel@tonic-gateint
19267c478bd9Sstevel@tonic-gateintr_passivate(kthread_id_t from, kthread_id_t to)
19277c478bd9Sstevel@tonic-gate{ return (0); }
19287c478bd9Sstevel@tonic-gate
19297c478bd9Sstevel@tonic-gate#else	/* lint */
19307c478bd9Sstevel@tonic-gate
19317c478bd9Sstevel@tonic-gate	ENTRY_NP(intr_passivate)
19327c478bd9Sstevel@tonic-gate	save	%sp, -SA(MINFRAME), %sp	! get a new window
19337c478bd9Sstevel@tonic-gate
19347c478bd9Sstevel@tonic-gate	flushw				! force register windows to stack
19357c478bd9Sstevel@tonic-gate	!
19367c478bd9Sstevel@tonic-gate	! restore registers from the base of the stack of the interrupt thread.
19377c478bd9Sstevel@tonic-gate	!
19387c478bd9Sstevel@tonic-gate	ldn	[%i0 + T_STACK], %i2	! get stack save area pointer
19397c478bd9Sstevel@tonic-gate	ldn	[%i2 + (0*GREGSIZE)], %l0	! load locals
19407c478bd9Sstevel@tonic-gate	ldn	[%i2 + (1*GREGSIZE)], %l1
19417c478bd9Sstevel@tonic-gate	ldn	[%i2 + (2*GREGSIZE)], %l2
19427c478bd9Sstevel@tonic-gate	ldn	[%i2 + (3*GREGSIZE)], %l3
19437c478bd9Sstevel@tonic-gate	ldn	[%i2 + (4*GREGSIZE)], %l4
19447c478bd9Sstevel@tonic-gate	ldn	[%i2 + (5*GREGSIZE)], %l5
19457c478bd9Sstevel@tonic-gate	ldn	[%i2 + (6*GREGSIZE)], %l6
19467c478bd9Sstevel@tonic-gate	ldn	[%i2 + (7*GREGSIZE)], %l7
19477c478bd9Sstevel@tonic-gate	ldn	[%i2 + (8*GREGSIZE)], %o0	! put ins from stack in outs
19487c478bd9Sstevel@tonic-gate	ldn	[%i2 + (9*GREGSIZE)], %o1
19497c478bd9Sstevel@tonic-gate	ldn	[%i2 + (10*GREGSIZE)], %o2
19507c478bd9Sstevel@tonic-gate	ldn	[%i2 + (11*GREGSIZE)], %o3
19517c478bd9Sstevel@tonic-gate	ldn	[%i2 + (12*GREGSIZE)], %o4
19527c478bd9Sstevel@tonic-gate	ldn	[%i2 + (13*GREGSIZE)], %o5
19537c478bd9Sstevel@tonic-gate	ldn	[%i2 + (14*GREGSIZE)], %i4
19547c478bd9Sstevel@tonic-gate					! copy stack/pointer without using %sp
19557c478bd9Sstevel@tonic-gate	ldn	[%i2 + (15*GREGSIZE)], %i5
19567c478bd9Sstevel@tonic-gate	!
19577c478bd9Sstevel@tonic-gate	! put registers into the save area at the top of the interrupted
19587c478bd9Sstevel@tonic-gate	! thread's stack, pointed to by %l7 in the save area just loaded.
19597c478bd9Sstevel@tonic-gate	!
19607c478bd9Sstevel@tonic-gate	ldn	[%i1 + T_SP], %i3	! get stack save area pointer
19617c478bd9Sstevel@tonic-gate	stn	%l0, [%i3 + STACK_BIAS + (0*GREGSIZE)]	! save locals
19627c478bd9Sstevel@tonic-gate	stn	%l1, [%i3 + STACK_BIAS + (1*GREGSIZE)]
19637c478bd9Sstevel@tonic-gate	stn	%l2, [%i3 + STACK_BIAS + (2*GREGSIZE)]
19647c478bd9Sstevel@tonic-gate	stn	%l3, [%i3 + STACK_BIAS + (3*GREGSIZE)]
19657c478bd9Sstevel@tonic-gate	stn	%l4, [%i3 + STACK_BIAS + (4*GREGSIZE)]
19667c478bd9Sstevel@tonic-gate	stn	%l5, [%i3 + STACK_BIAS + (5*GREGSIZE)]
19677c478bd9Sstevel@tonic-gate	stn	%l6, [%i3 + STACK_BIAS + (6*GREGSIZE)]
19687c478bd9Sstevel@tonic-gate	stn	%l7, [%i3 + STACK_BIAS + (7*GREGSIZE)]
19697c478bd9Sstevel@tonic-gate	stn	%o0, [%i3 + STACK_BIAS + (8*GREGSIZE)]	! save ins using outs
19707c478bd9Sstevel@tonic-gate	stn	%o1, [%i3 + STACK_BIAS + (9*GREGSIZE)]
19717c478bd9Sstevel@tonic-gate	stn	%o2, [%i3 + STACK_BIAS + (10*GREGSIZE)]
19727c478bd9Sstevel@tonic-gate	stn	%o3, [%i3 + STACK_BIAS + (11*GREGSIZE)]
19737c478bd9Sstevel@tonic-gate	stn	%o4, [%i3 + STACK_BIAS + (12*GREGSIZE)]
19747c478bd9Sstevel@tonic-gate	stn	%o5, [%i3 + STACK_BIAS + (13*GREGSIZE)]
19757c478bd9Sstevel@tonic-gate	stn	%i4, [%i3 + STACK_BIAS + (14*GREGSIZE)]
19767c478bd9Sstevel@tonic-gate						! fp, %i7 copied using %i4
19777c478bd9Sstevel@tonic-gate	stn	%i5, [%i3 + STACK_BIAS + (15*GREGSIZE)]
19787c478bd9Sstevel@tonic-gate	stn	%g0, [%i2 + ((8+6)*GREGSIZE)]
19797c478bd9Sstevel@tonic-gate						! clear fp in save area
19807c478bd9Sstevel@tonic-gate
19817c478bd9Sstevel@tonic-gate	! load saved pil for return
19827c478bd9Sstevel@tonic-gate	ldub	[%i0 + T_PIL], %i0
19837c478bd9Sstevel@tonic-gate	ret
19847c478bd9Sstevel@tonic-gate	restore
19857c478bd9Sstevel@tonic-gate	SET_SIZE(intr_passivate)
19867c478bd9Sstevel@tonic-gate
19877c478bd9Sstevel@tonic-gate#endif	/* lint */
19887c478bd9Sstevel@tonic-gate
19897c478bd9Sstevel@tonic-gate#if defined(lint)
19907c478bd9Sstevel@tonic-gate
19917c478bd9Sstevel@tonic-gate/*
19927c478bd9Sstevel@tonic-gate * intr_get_time() is a resource for interrupt handlers to determine how
19937c478bd9Sstevel@tonic-gate * much time has been spent handling the current interrupt. Such a function
19947c478bd9Sstevel@tonic-gate * is needed because higher level interrupts can arrive during the
19957c478bd9Sstevel@tonic-gate * processing of an interrupt, thus making direct comparisons of %tick by
19967c478bd9Sstevel@tonic-gate * the handler inaccurate. intr_get_time() only returns time spent in the
19977c478bd9Sstevel@tonic-gate * current interrupt handler.
19987c478bd9Sstevel@tonic-gate *
19997c478bd9Sstevel@tonic-gate * The caller must be calling from an interrupt handler running at a pil
20007c478bd9Sstevel@tonic-gate * below or at lock level. Timings are not provided for high-level
20017c478bd9Sstevel@tonic-gate * interrupts.
20027c478bd9Sstevel@tonic-gate *
20037c478bd9Sstevel@tonic-gate * The first time intr_get_time() is called while handling an interrupt,
20047c478bd9Sstevel@tonic-gate * it returns the time since the interrupt handler was invoked. Subsequent
20057c478bd9Sstevel@tonic-gate * calls will return the time since the prior call to intr_get_time(). Time
20067c478bd9Sstevel@tonic-gate * is returned as ticks, adjusted for any clock divisor due to power
20077c478bd9Sstevel@tonic-gate * management. Use tick2ns() to convert ticks to nsec. Warning: ticks may
20087c478bd9Sstevel@tonic-gate * not be the same across CPUs.
20097c478bd9Sstevel@tonic-gate *
20107c478bd9Sstevel@tonic-gate * Theory Of Intrstat[][]:
20117c478bd9Sstevel@tonic-gate *
20127c478bd9Sstevel@tonic-gate * uint64_t intrstat[pil][0..1] is an array indexed by pil level, with two
20137c478bd9Sstevel@tonic-gate * uint64_ts per pil.
20147c478bd9Sstevel@tonic-gate *
20157c478bd9Sstevel@tonic-gate * intrstat[pil][0] is a cumulative count of the number of ticks spent
20167c478bd9Sstevel@tonic-gate * handling all interrupts at the specified pil on this CPU. It is
20177c478bd9Sstevel@tonic-gate * exported via kstats to the user.
20187c478bd9Sstevel@tonic-gate *
20197c478bd9Sstevel@tonic-gate * intrstat[pil][1] is always a count of ticks less than or equal to the
20207c478bd9Sstevel@tonic-gate * value in [0]. The difference between [1] and [0] is the value returned
20217c478bd9Sstevel@tonic-gate * by a call to intr_get_time(). At the start of interrupt processing,
20227c478bd9Sstevel@tonic-gate * [0] and [1] will be equal (or nearly so). As the interrupt consumes
20237c478bd9Sstevel@tonic-gate * time, [0] will increase, but [1] will remain the same. A call to
20247c478bd9Sstevel@tonic-gate * intr_get_time() will return the difference, then update [1] to be the
20257c478bd9Sstevel@tonic-gate * same as [0]. Future calls will return the time since the last call.
20267c478bd9Sstevel@tonic-gate * Finally, when the interrupt completes, [1] is updated to the same as [0].
20277c478bd9Sstevel@tonic-gate *
20287c478bd9Sstevel@tonic-gate * Implementation:
20297c478bd9Sstevel@tonic-gate *
20307c478bd9Sstevel@tonic-gate * intr_get_time() works much like a higher level interrupt arriving. It
20317c478bd9Sstevel@tonic-gate * "checkpoints" the timing information by incrementing intrstat[pil][0]
20327c478bd9Sstevel@tonic-gate * to include elapsed running time, and by setting t_intr_start to %tick.
20337c478bd9Sstevel@tonic-gate * It then sets the return value to intrstat[pil][0] - intrstat[pil][1],
20347c478bd9Sstevel@tonic-gate * and updates intrstat[pil][1] to be the same as the new value of
20357c478bd9Sstevel@tonic-gate * intrstat[pil][0].
20367c478bd9Sstevel@tonic-gate *
20377c478bd9Sstevel@tonic-gate * In the normal handling of interrupts, after an interrupt handler returns
20387c478bd9Sstevel@tonic-gate * and the code in intr_thread() updates intrstat[pil][0], it then sets
20397c478bd9Sstevel@tonic-gate * intrstat[pil][1] to the new value of intrstat[pil][0]. When [0] == [1],
20407c478bd9Sstevel@tonic-gate * the timings are reset, i.e. intr_get_time() will return [0] - [1] which
20417c478bd9Sstevel@tonic-gate * is 0.
20427c478bd9Sstevel@tonic-gate *
20437c478bd9Sstevel@tonic-gate * Whenever interrupts arrive on a CPU which is handling a lower pil
20447c478bd9Sstevel@tonic-gate * interrupt, they update the lower pil's [0] to show time spent in the
20457c478bd9Sstevel@tonic-gate * handler that they've interrupted. This results in a growing discrepancy
20467c478bd9Sstevel@tonic-gate * between [0] and [1], which is returned the next time intr_get_time() is
20477c478bd9Sstevel@tonic-gate * called. Time spent in the higher-pil interrupt will not be returned in
20487c478bd9Sstevel@tonic-gate * the next intr_get_time() call from the original interrupt, because
20497c478bd9Sstevel@tonic-gate * the higher-pil interrupt's time is accumulated in intrstat[higherpil][].
20507c478bd9Sstevel@tonic-gate */
20517c478bd9Sstevel@tonic-gate
20527c478bd9Sstevel@tonic-gate/*ARGSUSED*/
20537c478bd9Sstevel@tonic-gateuint64_t
20547c478bd9Sstevel@tonic-gateintr_get_time(void)
20557c478bd9Sstevel@tonic-gate{ return 0; }
20567c478bd9Sstevel@tonic-gate#else	/* lint */
20577c478bd9Sstevel@tonic-gate
20587c478bd9Sstevel@tonic-gate	ENTRY_NP(intr_get_time)
20597c478bd9Sstevel@tonic-gate#ifdef DEBUG
20607c478bd9Sstevel@tonic-gate	!
20617c478bd9Sstevel@tonic-gate	! Lots of asserts, but just check panic_quiesce first.
20627c478bd9Sstevel@tonic-gate	! Don't bother with lots of tests if we're just ignoring them.
20637c478bd9Sstevel@tonic-gate	!
20647c478bd9Sstevel@tonic-gate	sethi	%hi(panic_quiesce), %o0
20657c478bd9Sstevel@tonic-gate	ld	[%o0 + %lo(panic_quiesce)], %o0
20667c478bd9Sstevel@tonic-gate	brnz,pn	%o0, 2f
20677c478bd9Sstevel@tonic-gate	nop
20687c478bd9Sstevel@tonic-gate	!
20697c478bd9Sstevel@tonic-gate	! ASSERT(%pil <= LOCK_LEVEL)
20707c478bd9Sstevel@tonic-gate	!
20717c478bd9Sstevel@tonic-gate	rdpr	%pil, %o1
20727c478bd9Sstevel@tonic-gate	cmp	%o1, LOCK_LEVEL
20737c478bd9Sstevel@tonic-gate	ble,pt	%xcc, 0f
20747c478bd9Sstevel@tonic-gate	sethi	%hi(intr_get_time_high_pil), %o0	! delay
20757c478bd9Sstevel@tonic-gate	call	panic
20767c478bd9Sstevel@tonic-gate	or	%o0, %lo(intr_get_time_high_pil), %o0
20777c478bd9Sstevel@tonic-gate0:
20787c478bd9Sstevel@tonic-gate	!
20797c478bd9Sstevel@tonic-gate	! ASSERT((t_flags & T_INTR_THREAD) != 0 && t_pil > 0)
20807c478bd9Sstevel@tonic-gate	!
20817c478bd9Sstevel@tonic-gate	lduh	[THREAD_REG + T_FLAGS], %o2
20827c478bd9Sstevel@tonic-gate	andcc	%o2, T_INTR_THREAD, %g0
20837c478bd9Sstevel@tonic-gate	bz,pn	%xcc, 1f
20847c478bd9Sstevel@tonic-gate	ldub	[THREAD_REG + T_PIL], %o1		! delay
20857c478bd9Sstevel@tonic-gate	brnz,pt	%o1, 0f
20867c478bd9Sstevel@tonic-gate1:
20877c478bd9Sstevel@tonic-gate	sethi	%hi(intr_get_time_not_intr), %o0
20887c478bd9Sstevel@tonic-gate	call	panic
20897c478bd9Sstevel@tonic-gate	or	%o0, %lo(intr_get_time_not_intr), %o0
20907c478bd9Sstevel@tonic-gate0:
20917c478bd9Sstevel@tonic-gate	!
20927c478bd9Sstevel@tonic-gate	! ASSERT(t_intr_start != 0)
20937c478bd9Sstevel@tonic-gate	!
20947c478bd9Sstevel@tonic-gate	ldx	[THREAD_REG + T_INTR_START], %o1
20957c478bd9Sstevel@tonic-gate	brnz,pt	%o1, 2f
20967c478bd9Sstevel@tonic-gate	sethi	%hi(intr_get_time_no_start_time), %o0	! delay
20977c478bd9Sstevel@tonic-gate	call	panic
20987c478bd9Sstevel@tonic-gate	or	%o0, %lo(intr_get_time_no_start_time), %o0
20997c478bd9Sstevel@tonic-gate2:
21007c478bd9Sstevel@tonic-gate#endif /* DEBUG */
21017c478bd9Sstevel@tonic-gate	!
21027c478bd9Sstevel@tonic-gate	! %o0 = elapsed time and return value
21037c478bd9Sstevel@tonic-gate	! %o1 = pil
21047c478bd9Sstevel@tonic-gate	! %o2 = scratch
21057c478bd9Sstevel@tonic-gate	! %o3 = scratch
21067c478bd9Sstevel@tonic-gate	! %o4 = scratch
21077c478bd9Sstevel@tonic-gate	! %o5 = cpu
21087c478bd9Sstevel@tonic-gate	!
21097c478bd9Sstevel@tonic-gate	wrpr	%g0, PIL_MAX, %pil	! make this easy -- block normal intrs
21107c478bd9Sstevel@tonic-gate	ldn	[THREAD_REG + T_CPU], %o5
21117c478bd9Sstevel@tonic-gate	ldub	[THREAD_REG + T_PIL], %o1
21127c478bd9Sstevel@tonic-gate	ldx	[THREAD_REG + T_INTR_START], %o3 ! %o3 = t_intr_start
21137c478bd9Sstevel@tonic-gate	!
21147c478bd9Sstevel@tonic-gate	! Calculate elapsed time since t_intr_start. Update t_intr_start,
21157c478bd9Sstevel@tonic-gate	! get delta, and multiply by cpu_divisor if necessary.
21167c478bd9Sstevel@tonic-gate	!
21177c478bd9Sstevel@tonic-gate	rdpr	%tick, %o2
21187c478bd9Sstevel@tonic-gate	sllx	%o2, 1, %o2
21197c478bd9Sstevel@tonic-gate	srlx	%o2, 1, %o2
21207c478bd9Sstevel@tonic-gate	stx	%o2, [THREAD_REG + T_INTR_START]
21217c478bd9Sstevel@tonic-gate	sub	%o2, %o3, %o0
21227c478bd9Sstevel@tonic-gate
21237c478bd9Sstevel@tonic-gate	lduh	[%o5 + CPU_DIVISOR], %o4
21247c478bd9Sstevel@tonic-gate	cmp	%o4, 1
21257c478bd9Sstevel@tonic-gate	bg,a,pn	%xcc, 1f
21267c478bd9Sstevel@tonic-gate	mulx	%o0, %o4, %o0	! multiply interval by clock divisor iff > 1
21277c478bd9Sstevel@tonic-gate1:
2128eda89462Sesolom	! Update intracct[]
2129eda89462Sesolom	lduh	[%o5 + CPU_MSTATE], %o4
2130eda89462Sesolom	sllx	%o4, 3, %o4
2131eda89462Sesolom	add	%o4, CPU_INTRACCT, %o4
2132eda89462Sesolom	ldx	[%o5 + %o4], %o2
2133eda89462Sesolom	add	%o2, %o0, %o2
2134eda89462Sesolom	stx	%o2, [%o5 + %o4]
2135eda89462Sesolom
21367c478bd9Sstevel@tonic-gate	!
21377c478bd9Sstevel@tonic-gate	! Increment cpu_m.intrstat[pil][0]. Calculate elapsed time since
21387c478bd9Sstevel@tonic-gate	! cpu_m.intrstat[pil][1], which is either when the interrupt was
21397c478bd9Sstevel@tonic-gate	! first entered, or the last time intr_get_time() was invoked. Then
21407c478bd9Sstevel@tonic-gate	! update cpu_m.intrstat[pil][1] to match [0].
21417c478bd9Sstevel@tonic-gate	!
21427c478bd9Sstevel@tonic-gate	sllx	%o1, 4, %o3
21437c478bd9Sstevel@tonic-gate	add	%o3, CPU_MCPU, %o3
21447c478bd9Sstevel@tonic-gate	add	%o3, MCPU_INTRSTAT, %o3
21457c478bd9Sstevel@tonic-gate	add	%o3, %o5, %o3		! %o3 = cpu_m.intrstat[pil][0]
21467c478bd9Sstevel@tonic-gate	ldx	[%o3], %o2
21477c478bd9Sstevel@tonic-gate	add	%o2, %o0, %o2		! %o2 = new value for intrstat
21487c478bd9Sstevel@tonic-gate	stx	%o2, [%o3]
21497c478bd9Sstevel@tonic-gate	ldx	[%o3 + 8], %o4		! %o4 = cpu_m.intrstat[pil][1]
21507c478bd9Sstevel@tonic-gate	sub	%o2, %o4, %o0		! %o0 is elapsed time since %o4
21517c478bd9Sstevel@tonic-gate	stx	%o2, [%o3 + 8]		! make [1] match [0], resetting time
21527c478bd9Sstevel@tonic-gate
21537c478bd9Sstevel@tonic-gate	ld	[%o5 + CPU_BASE_SPL], %o2	! restore %pil to the greater
21547c478bd9Sstevel@tonic-gate	cmp	%o2, %o1			! of either our pil %o1 or
21557c478bd9Sstevel@tonic-gate	movl	%xcc, %o1, %o2			! cpu_base_spl.
21567c478bd9Sstevel@tonic-gate	retl
21577c478bd9Sstevel@tonic-gate	wrpr	%g0, %o2, %pil
21587c478bd9Sstevel@tonic-gate	SET_SIZE(intr_get_time)
21597c478bd9Sstevel@tonic-gate
21607c478bd9Sstevel@tonic-gate#ifdef DEBUG
21617c478bd9Sstevel@tonic-gateintr_get_time_high_pil:
21627c478bd9Sstevel@tonic-gate	.asciz	"intr_get_time(): %pil > LOCK_LEVEL"
21637c478bd9Sstevel@tonic-gateintr_get_time_not_intr:
21647c478bd9Sstevel@tonic-gate	.asciz	"intr_get_time(): not called from an interrupt thread"
21657c478bd9Sstevel@tonic-gateintr_get_time_no_start_time:
21667c478bd9Sstevel@tonic-gate	.asciz	"intr_get_time(): t_intr_start == 0"
21677c478bd9Sstevel@tonic-gate#endif /* DEBUG */
21687c478bd9Sstevel@tonic-gate#endif  /* lint */
21697c478bd9Sstevel@tonic-gate
21707c478bd9Sstevel@tonic-gate
21717c478bd9Sstevel@tonic-gate#if !defined(lint)
21727c478bd9Sstevel@tonic-gate
21737c478bd9Sstevel@tonic-gate/*
21747c478bd9Sstevel@tonic-gate * Check shift value used for computing array offsets
21757c478bd9Sstevel@tonic-gate */
21767c478bd9Sstevel@tonic-gate#if INTR_VECTOR_SIZE != (1 << INTR_VECTOR_SHIFT)
21777c478bd9Sstevel@tonic-gate#error "INTR_VECTOR_SIZE has changed"
21787c478bd9Sstevel@tonic-gate#endif
21797c478bd9Sstevel@tonic-gate
21807c478bd9Sstevel@tonic-gate#endif  /* lint */
2181