Home | History | Annotate | Download | only in ml
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #if defined(lint)
     27 #include <sys/types.h>
     28 #include <sys/thread.h>
     29 #else	/* lint */
     30 #include "assym.h"
     31 #endif	/* lint */
     32 
     33 #include <sys/cmn_err.h>
     34 #include <sys/ftrace.h>
     35 #include <sys/asm_linkage.h>
     36 #include <sys/machthread.h>
     37 #include <sys/machcpuvar.h>
     38 #include <sys/intreg.h>
     39 #include <sys/ivintr.h>
     40 
     41 #ifdef TRAPTRACE
     42 #include <sys/traptrace.h>
     43 #endif /* TRAPTRACE */
     44 
     45 #if defined(lint)
     46 
     47 /* ARGSUSED */
     48 void
     49 pil_interrupt(int level)
     50 {}
     51 
     52 #else	/* lint */
     53 
     54 
     55 /*
     56  * (TT 0x40..0x4F, TL>0) Interrupt Level N Handler (N == 1..15)
     57  * 	Register passed from LEVEL_INTERRUPT(level)
     58  *	%g4 - interrupt request level
     59  */
     60 	ENTRY_NP(pil_interrupt)
     61 	!
     62 	! Register usage
     63 	!	%g1 - cpu
     64 	!	%g2 - pointer to intr_vec_t (iv)
     65 	!	%g4 - pil
     66 	!	%g3, %g5, %g6, %g7 - temps
     67 	!
     68 	! Grab the first or list head intr_vec_t off the intr_head[pil]
     69 	! and panic immediately if list head is NULL. Otherwise, update
     70 	! intr_head[pil] to next intr_vec_t on the list and clear softint
     71 	! %clear_softint, if next intr_vec_t is NULL.
     72 	!
     73 	CPU_ADDR(%g1, %g5)		! %g1 = cpu
     74 	!
     75 	ALTENTRY(pil_interrupt_common)
     76 	sll	%g4, CPTRSHIFT, %g5	! %g5 = offset to the pil entry
     77 	add	%g1, INTR_HEAD, %g6	! %g6 = &cpu->m_cpu.intr_head
     78 	add	%g6, %g5, %g6		! %g6 = &cpu->m_cpu.intr_head[pil]
     79 	ldn	[%g6], %g2		! %g2 = cpu->m_cpu.intr_head[pil]
     80 	brnz,pt	%g2, 0f			! check list head (iv) is NULL
     81 	nop
     82 	ba	ptl1_panic		! panic, list head (iv) is NULL
     83 	mov	PTL1_BAD_INTR_VEC, %g1
     84 0:
     85 	lduh	[%g2 + IV_FLAGS], %g7	! %g7 = iv->iv_flags
     86 	and	%g7, IV_SOFTINT_MT, %g3 ! %g3 = iv->iv_flags & IV_SOFTINT_MT
     87 	brz,pt	%g3, 1f			! check for multi target softint
     88 	add	%g2, IV_PIL_NEXT, %g7	! g7% = &iv->iv_pil_next
     89 	ld	[%g1 + CPU_ID], %g3	! for multi target softint, use cpuid
     90 	sll	%g3, CPTRSHIFT, %g3	! convert cpuid to offset address
     91 	add	%g7, %g3, %g7		! %g5 = &iv->iv_xpil_next[cpuid]
     92 1:
     93 	ldn	[%g7], %g3		! %g3 = next intr_vec_t
     94 	brnz,pn	%g3, 2f			! branch if next intr_vec_t non NULL
     95 	stn	%g3, [%g6]		! update cpu->m_cpu.intr_head[pil]
     96 	add	%g1, INTR_TAIL, %g6	! %g6 =  &cpu->m_cpu.intr_tail
     97 	stn	%g0, [%g5 + %g6]	! clear cpu->m_cpu.intr_tail[pil]
     98 	mov	1, %g5			! %g5 = 1
     99 	sll	%g5, %g4, %g5		! %g5 = 1 << pil
    100 	wr	%g5, CLEAR_SOFTINT	! clear interrupt on this pil
    101 2:
    102 #ifdef TRAPTRACE
    103 	TRACE_PTR(%g5, %g6)
    104 	TRACE_SAVE_TL_GL_REGS(%g5, %g6)
    105 	rdpr	%tt, %g6
    106 	stha	%g6, [%g5 + TRAP_ENT_TT]%asi	! trap_type = %tt
    107 	rdpr	%tpc, %g6
    108 	stna	%g6, [%g5 + TRAP_ENT_TPC]%asi	! trap_pc = %tpc
    109 	rdpr	%tstate, %g6
    110 	stxa	%g6, [%g5 + TRAP_ENT_TSTATE]%asi ! trap_tstate = %tstate
    111 	stna	%sp, [%g5 + TRAP_ENT_SP]%asi	! trap_sp = %sp
    112 	stna	%g2, [%g5 + TRAP_ENT_TR]%asi	! trap_tr = first intr_vec
    113 	stna	%g3, [%g5 + TRAP_ENT_F1]%asi	! trap_f1 = next intr_vec
    114 	GET_TRACE_TICK(%g6, %g3)
    115 	stxa	%g6, [%g5 + TRAP_ENT_TICK]%asi	! trap_tick = %tick
    116 	sll	%g4, CPTRSHIFT, %g3
    117 	add	%g1, INTR_HEAD, %g6
    118 	ldn	[%g6 + %g3], %g6		! %g6=cpu->m_cpu.intr_head[pil]
    119 	stna	%g6, [%g5 + TRAP_ENT_F2]%asi	! trap_f2 = intr_head[pil]
    120 	add	%g1, INTR_TAIL, %g6
    121 	ldn	[%g6 + %g3], %g6		! %g6=cpu->m_cpu.intr_tail[pil]
    122 	stna	%g6, [%g5 + TRAP_ENT_F3]%asi	! trap_f3 = intr_tail[pil]
    123 	stna	%g4, [%g5 + TRAP_ENT_F4]%asi	! trap_f4 = pil
    124 	TRACE_NEXT(%g5, %g6, %g3)
    125 #endif /* TRAPTRACE */
    126 	!
    127 	! clear the iv_pending flag for this interrupt request
    128 	!
    129 	lduh	[%g2 + IV_FLAGS], %g3		! %g3 = iv->iv_flags
    130 	andn	%g3, IV_SOFTINT_PEND, %g3	! %g3 = !(iv->iv_flags & PEND)
    131 	sth	%g3, [%g2 + IV_FLAGS]		! clear IV_SOFTINT_PEND flag
    132 	stn	%g0, [%g7]			! clear iv->iv_pil_next or
    133 						!       iv->iv_pil_xnext
    134 
    135 	!
    136 	! Prepare for sys_trap()
    137 	!
    138 	! Registers passed to sys_trap()
    139 	!	%g1 - interrupt handler at TL==0
    140 	!	%g2 - pointer to current intr_vec_t (iv),
    141 	!	      job queue for intr_thread or current_thread
    142 	!	%g3 - pil
    143 	!	%g4 - initial pil for handler
    144 	!
    145 	! figure which handler to run and which %pil it starts at
    146 	! intr_thread starts at DISP_LEVEL to prevent preemption
    147 	! current_thread starts at PIL_MAX to protect cpu_intr_actv
    148 	!
    149 	mov	%g4, %g3		! %g3 = %g4, pil
    150 	cmp	%g4, LOCK_LEVEL
    151 	bg,a,pt	%xcc, 3f		! branch if pil > LOCK_LEVEL
    152 	mov	PIL_MAX, %g4		! %g4 = PIL_MAX (15)
    153 	sethi	%hi(intr_thread), %g1	! %g1 = intr_thread
    154 	mov	DISP_LEVEL, %g4		! %g4 = DISP_LEVEL (11)
    155 	ba,pt	%xcc, sys_trap
    156 	or	%g1, %lo(intr_thread), %g1
    157 3:
    158 	sethi	%hi(current_thread), %g1 ! %g1 = current_thread
    159 	ba,pt	%xcc, sys_trap
    160 	or	%g1, %lo(current_thread), %g1
    161 	SET_SIZE(pil_interrupt_common)
    162 	SET_SIZE(pil_interrupt)
    163 
    164 #endif	/* lint */
    165 
    166 
    167 #ifndef	lint
    168 _spurious:
    169 	.asciz	"!interrupt 0x%x at level %d not serviced"
    170 
    171 /*
    172  * SERVE_INTR_PRE is called once, just before the first invocation
    173  * of SERVE_INTR.
    174  *
    175  * Registers on entry:
    176  *
    177  * iv_p, cpu, regs: may be out-registers
    178  * ls1, ls2: local scratch registers
    179  * os1, os2, os3: scratch registers, may be out
    180  */
    181 
    182 #define SERVE_INTR_PRE(iv_p, cpu, ls1, ls2, os1, os2, os3, regs)	\
    183 	mov	iv_p, ls1;						\
    184 	mov	iv_p, ls2;						\
    185 	SERVE_INTR_TRACE(iv_p, os1, os2, os3, regs);
    186 
    187 /*
    188  * SERVE_INTR is called immediately after either SERVE_INTR_PRE or
    189  * SERVE_INTR_NEXT, without intervening code. No register values
    190  * may be modified.
    191  *
    192  * After calling SERVE_INTR, the caller must check if os3 is set. If
    193  * so, there is another interrupt to process. The caller must call
    194  * SERVE_INTR_NEXT, immediately followed by SERVE_INTR.
    195  *
    196  * Before calling SERVE_INTR_NEXT, the caller may perform accounting
    197  * and other actions which need to occur after invocation of an interrupt
    198  * handler. However, the values of ls1 and os3 *must* be preserved and
    199  * passed unmodified into SERVE_INTR_NEXT.
    200  *
    201  * Registers on return from SERVE_INTR:
    202  *
    203  * ls1 - the pil just processed
    204  * ls2 - the pointer to intr_vec_t (iv) just processed
    205  * os3 - if set, another interrupt needs to be processed
    206  * cpu, ls1, os3 - must be preserved if os3 is set
    207  */
    208 
    209 #define	SERVE_INTR(os5, cpu, ls1, ls2, os1, os2, os3, os4)		\
    210 	ldn	[ls1 + IV_HANDLER], os2;				\
    211 	ldn	[ls1 + IV_ARG1], %o0;					\
    212 	ldn	[ls1 + IV_ARG2], %o1;					\
    213 	call	os2;							\
    214 	lduh	[ls1 + IV_PIL], ls1;					\
    215 	brnz,pt	%o0, 2f;						\
    216 	mov	CE_WARN, %o0;						\
    217 	set	_spurious, %o1;						\
    218 	mov	ls2, %o2;						\
    219 	call	cmn_err;						\
    220 	rdpr	%pil, %o3;						\
    221 2:	ldn	[THREAD_REG + T_CPU], cpu;				\
    222 	sll	ls1, 3, os1;						\
    223 	add	os1, CPU_STATS_SYS_INTR - 8, os2;			\
    224 	ldx	[cpu + os2], os3;					\
    225 	inc	os3;							\
    226 	stx	os3, [cpu + os2];					\
    227 	sll	ls1, CPTRSHIFT, os2;					\
    228 	add	cpu,  INTR_HEAD, os1;					\
    229 	add	os1, os2, os1;						\
    230 	ldn	[os1], os3;
    231 
    232 /*
    233  * Registers on entry:
    234  *
    235  * cpu			- cpu pointer (clobbered, set to cpu upon completion)
    236  * ls1, os3		- preserved from prior call to SERVE_INTR
    237  * ls2			- local scratch reg (not preserved)
    238  * os1, os2, os4, os5	- scratch reg, can be out (not preserved)
    239  */
    240 #define SERVE_INTR_NEXT(os5, cpu, ls1, ls2, os1, os2, os3, os4)		\
    241 	sll	ls1, CPTRSHIFT, os4;					\
    242 	add	cpu, INTR_HEAD, os1;					\
    243 	rdpr	%pstate, ls2;						\
    244 	wrpr	ls2, PSTATE_IE, %pstate;				\
    245 	lduh	[os3 + IV_FLAGS], os2;					\
    246 	and	os2, IV_SOFTINT_MT, os2;				\
    247 	brz,pt	os2, 4f;						\
    248 	add	os3, IV_PIL_NEXT, os2;					\
    249 	ld	[cpu + CPU_ID], os5;					\
    250 	sll	os5, CPTRSHIFT, os5;					\
    251 	add	os2, os5, os2;						\
    252 4:	ldn	[os2], os5;						\
    253 	brnz,pn	os5, 5f;						\
    254 	stn	os5, [os1 + os4];					\
    255 	add	cpu, INTR_TAIL, os1;					\
    256 	stn	%g0, [os1 + os4];					\
    257 	mov	1, os1;							\
    258 	sll	os1, ls1, os1;						\
    259 	wr	os1, CLEAR_SOFTINT;					\
    260 5:	lduh	[os3 + IV_FLAGS], ls1;                                  \
    261 	andn	ls1, IV_SOFTINT_PEND, ls1;				\
    262 	sth	ls1, [os3 + IV_FLAGS];				        \
    263 	stn	%g0, [os2];						\
    264 	wrpr	%g0, ls2, %pstate;					\
    265 	mov	os3, ls1;						\
    266 	mov	os3, ls2;						\
    267 	SERVE_INTR_TRACE2(os5, os1, os2, os3, os4);
    268 
    269 #ifdef TRAPTRACE
    270 /*
    271  * inum - not modified, _spurious depends on it.
    272  */
    273 #define	SERVE_INTR_TRACE(inum, os1, os2, os3, os4)			\
    274 	rdpr	%pstate, os3;						\
    275 	andn	os3, PSTATE_IE | PSTATE_AM, os2;			\
    276 	wrpr	%g0, os2, %pstate;					\
    277 	TRACE_PTR(os1, os2); 						\
    278 	ldn	[os4 + PC_OFF], os2;					\
    279 	stna	os2, [os1 + TRAP_ENT_TPC]%asi;				\
    280 	ldx	[os4 + TSTATE_OFF], os2;				\
    281 	stxa	os2, [os1 + TRAP_ENT_TSTATE]%asi;			\
    282 	mov	os3, os4;						\
    283 	GET_TRACE_TICK(os2, os3);					\
    284 	stxa	os2, [os1 + TRAP_ENT_TICK]%asi;				\
    285 	TRACE_SAVE_TL_GL_REGS(os1, os2);				\
    286 	set	TT_SERVE_INTR, os2;					\
    287 	rdpr	%pil, os3;						\
    288 	or	os2, os3, os2;						\
    289 	stha	os2, [os1 + TRAP_ENT_TT]%asi;				\
    290 	stna	%sp, [os1 + TRAP_ENT_SP]%asi;				\
    291 	stna	inum, [os1 + TRAP_ENT_TR]%asi;				\
    292 	stna	%g0, [os1 + TRAP_ENT_F1]%asi;				\
    293 	stna	%g0, [os1 + TRAP_ENT_F2]%asi;				\
    294 	stna	%g0, [os1 + TRAP_ENT_F3]%asi;				\
    295 	stna	%g0, [os1 + TRAP_ENT_F4]%asi;				\
    296 	TRACE_NEXT(os1, os2, os3);					\
    297 	wrpr	%g0, os4, %pstate
    298 #else	/* TRAPTRACE */
    299 #define SERVE_INTR_TRACE(inum, os1, os2, os3, os4)
    300 #endif	/* TRAPTRACE */
    301 
    302 #ifdef TRAPTRACE
    303 /*
    304  * inum - not modified, _spurious depends on it.
    305  */
    306 #define	SERVE_INTR_TRACE2(inum, os1, os2, os3, os4)			\
    307 	rdpr	%pstate, os3;						\
    308 	andn	os3, PSTATE_IE | PSTATE_AM, os2;			\
    309 	wrpr	%g0, os2, %pstate;					\
    310 	TRACE_PTR(os1, os2); 						\
    311 	stna	%g0, [os1 + TRAP_ENT_TPC]%asi;				\
    312 	stxa	%g0, [os1 + TRAP_ENT_TSTATE]%asi;			\
    313 	mov	os3, os4;						\
    314 	GET_TRACE_TICK(os2, os3);					\
    315 	stxa	os2, [os1 + TRAP_ENT_TICK]%asi;				\
    316 	TRACE_SAVE_TL_GL_REGS(os1, os2);				\
    317 	set	TT_SERVE_INTR, os2;					\
    318 	rdpr	%pil, os3;						\
    319 	or	os2, os3, os2;						\
    320 	stha	os2, [os1 + TRAP_ENT_TT]%asi;				\
    321 	stna	%sp, [os1 + TRAP_ENT_SP]%asi;				\
    322 	stna	inum, [os1 + TRAP_ENT_TR]%asi;				\
    323 	stna	%g0, [os1 + TRAP_ENT_F1]%asi;				\
    324 	stna	%g0, [os1 + TRAP_ENT_F2]%asi;				\
    325 	stna	%g0, [os1 + TRAP_ENT_F3]%asi;				\
    326 	stna	%g0, [os1 + TRAP_ENT_F4]%asi;				\
    327 	TRACE_NEXT(os1, os2, os3);					\
    328 	wrpr	%g0, os4, %pstate
    329 #else	/* TRAPTRACE */
    330 #define SERVE_INTR_TRACE2(inum, os1, os2, os3, os4)
    331 #endif	/* TRAPTRACE */
    332 
    333 #endif	/* lint */
    334 
    335 #if defined(lint)
    336 
    337 /*ARGSUSED*/
    338 void
    339 intr_thread(struct regs *regs, uint64_t iv_p, uint_t pil)
    340 {}
    341 
    342 #else	/* lint */
    343 
    344 #define	INTRCNT_LIMIT 16
    345 
    346 /*
    347  * Handle an interrupt in a new thread.
    348  *	Entry:
    349  *		%o0       = pointer to regs structure
    350  *		%o1       = pointer to current intr_vec_t (iv) to be processed
    351  *		%o2       = pil
    352  *		%sp       = on current thread's kernel stack
    353  *		%o7       = return linkage to trap code
    354  *		%g7       = current thread
    355  *		%pstate   = normal globals, interrupts enabled,
    356  *		            privileged, fp disabled
    357  *		%pil      = DISP_LEVEL
    358  *
    359  *	Register Usage
    360  *		%l0       = return linkage
    361  *		%l1       = pil
    362  *		%l2 - %l3 = scratch
    363  *		%l4 - %l7 = reserved for sys_trap
    364  *		%o2       = cpu
    365  *		%o3       = intr thread
    366  *		%o0       = scratch
    367  *		%o4 - %o5 = scratch
    368  */
    369 	ENTRY_NP(intr_thread)
    370 	mov	%o7, %l0
    371 	mov	%o2, %l1
    372 	!
    373 	! See if we are interrupting another interrupt thread.
    374 	!
    375 	lduh	[THREAD_REG + T_FLAGS], %o3
    376 	andcc	%o3, T_INTR_THREAD, %g0
    377 	bz,pt	%xcc, 1f
    378 	ldn	[THREAD_REG + T_CPU], %o2	! delay - load CPU pointer
    379 
    380 	! We have interrupted an interrupt thread. Take a timestamp,
    381 	! compute its interval, and update its cumulative counter.
    382 	add	THREAD_REG, T_INTR_START, %o5
    383 0:
    384 	ldx	[%o5], %o3
    385 	brz,pn	%o3, 1f
    386 	! We came in on top of an interrupt thread that had no timestamp.
    387 	! This could happen if, for instance, an interrupt thread which had
    388 	! previously blocked is being set up to run again in resume(), but
    389 	! resume() hasn't yet stored a timestamp for it. Or, it could be in
    390 	! swtch() after its slice has been accounted for.
    391 	! Only account for the time slice if the starting timestamp is non-zero.
    392 	RD_TICK(%o4,%l2,%l3,__LINE__)
    393 	sub	%o4, %o3, %o4			! o4 has interval
    394 
    395 	! A high-level interrupt in current_thread() interrupting here
    396 	! will account for the interrupted thread's time slice, but
    397 	! only if t_intr_start is non-zero. Since this code is going to account
    398 	! for the time slice, we want to "atomically" load the thread's
    399 	! starting timestamp, calculate the interval with %tick, and zero
    400 	! its starting timestamp.
    401 	! To do this, we do a casx on the t_intr_start field, and store 0 to it.
    402 	! If it has changed since we loaded it above, we need to re-compute the
    403 	! interval, since a changed t_intr_start implies current_thread placed
    404 	! a new, later timestamp there after running a high-level interrupt,
    405 	! and the %tick val in %o4 had become stale.
    406 	mov	%g0, %l2
    407 	casx	[%o5], %o3, %l2
    408 
    409 	! If %l2 == %o3, our casx was successful. If not, the starting timestamp
    410 	! changed between loading it (after label 0b) and computing the
    411 	! interval above.
    412 	cmp	%l2, %o3
    413 	bne,pn	%xcc, 0b
    414 
    415 	! Check for Energy Star mode
    416 	lduh	[%o2 + CPU_DIVISOR], %l2	! delay -- %l2 = clock divisor
    417 	cmp	%l2, 1
    418 	bg,a,pn	%xcc, 2f
    419 	mulx	%o4, %l2, %o4	! multiply interval by clock divisor iff > 1
    420 2:
    421 	! We now know that a valid interval for the interrupted interrupt
    422 	! thread is in %o4. Update its cumulative counter.
    423 	ldub	[THREAD_REG + T_PIL], %l3	! load PIL
    424 	sllx	%l3, 4, %l3		! convert PIL index to byte offset
    425 	add	%l3, CPU_MCPU, %l3	! CPU_INTRSTAT is too big for use
    426 	add	%l3, MCPU_INTRSTAT, %l3	! as const, add offsets separately
    427 	ldx	[%o2 + %l3], %o5	! old counter in o5
    428 	add	%o5, %o4, %o5		! new counter in o5
    429 	stx	%o5, [%o2 + %l3]	! store new counter
    430 
    431 	! Also update intracct[]
    432 	lduh	[%o2 + CPU_MSTATE], %l3
    433 	sllx	%l3, 3, %l3
    434 	add	%l3, CPU_INTRACCT, %l3
    435 	add	%l3, %o2, %l3
    436 0:
    437 	ldx	[%l3], %o5
    438 	add	%o5, %o4, %o3
    439 	casx	[%l3], %o5, %o3
    440 	cmp	%o5, %o3
    441 	bne,pn	%xcc, 0b
    442 	nop
    443 
    444 1:
    445 	!
    446 	! Get set to run interrupt thread.
    447 	! There should always be an interrupt thread since we allocate one
    448 	! for each level on the CPU.
    449 	!
    450 	! Note that the code in kcpc_overflow_intr -relies- on the ordering
    451 	! of events here -- in particular that t->t_lwp of the interrupt thread
    452 	! is set to the pinned thread *before* curthread is changed.
    453 	!
    454 	ldn	[%o2 + CPU_INTR_THREAD], %o3	! interrupt thread pool
    455 	ldn	[%o3 + T_LINK], %o4		! unlink thread from CPU's list
    456 	stn	%o4, [%o2 + CPU_INTR_THREAD]
    457 	!
    458 	! Set bit for this level in CPU's active interrupt bitmask.
    459 	!
    460 	ld	[%o2 + CPU_INTR_ACTV], %o5
    461 	mov	1, %o4
    462 	sll	%o4, %l1, %o4
    463 #ifdef DEBUG
    464 	!
    465 	! ASSERT(!(CPU->cpu_intr_actv & (1 << PIL)))
    466 	!
    467 	andcc	%o5, %o4, %g0
    468 	bz,pt	%xcc, 0f
    469 	nop
    470 	! Do not call panic if a panic is already in progress.
    471 	sethi	%hi(panic_quiesce), %l2
    472 	ld	[%l2 + %lo(panic_quiesce)], %l2
    473 	brnz,pn	%l2, 0f
    474 	nop
    475 	sethi	%hi(intr_thread_actv_bit_set), %o0
    476 	call	panic
    477 	or	%o0, %lo(intr_thread_actv_bit_set), %o0
    478 0:
    479 #endif /* DEBUG */
    480 	or	%o5, %o4, %o5
    481 	st	%o5, [%o2 + CPU_INTR_ACTV]
    482 	!
    483 	! Consider the new thread part of the same LWP so that
    484 	! window overflow code can find the PCB.
    485 	!
    486 	ldn	[THREAD_REG + T_LWP], %o4
    487 	stn	%o4, [%o3 + T_LWP]
    488 	!
    489 	! Threads on the interrupt thread free list could have state already
    490 	! set to TS_ONPROC, but it helps in debugging if they're TS_FREE
    491 	! Could eliminate the next two instructions with a little work.
    492 	!
    493 	mov	TS_ONPROC, %o4
    494 	st	%o4, [%o3 + T_STATE]
    495 	!
    496 	! Push interrupted thread onto list from new thread.
    497 	! Set the new thread as the current one.
    498 	! Set interrupted thread's T_SP because if it is the idle thread,
    499 	! resume may use that stack between threads.
    500 	!
    501 	stn	%o7, [THREAD_REG + T_PC]	! mark pc for resume
    502 	stn	%sp, [THREAD_REG + T_SP]	! mark stack for resume
    503 	stn	THREAD_REG, [%o3 + T_INTR]	! push old thread
    504 	stn	%o3, [%o2 + CPU_THREAD]		! set new thread
    505 	mov	%o3, THREAD_REG			! set global curthread register
    506 	ldn	[%o3 + T_STACK], %o4		! interrupt stack pointer
    507 	sub	%o4, STACK_BIAS, %sp
    508 	!
    509 	! Initialize thread priority level from intr_pri
    510 	!
    511 	sethi	%hi(intr_pri), %o4
    512 	ldsh	[%o4 + %lo(intr_pri)], %o4	! grab base interrupt priority
    513 	add	%l1, %o4, %o4		! convert level to dispatch priority
    514 	sth	%o4, [THREAD_REG + T_PRI]
    515 	stub	%l1, [THREAD_REG + T_PIL]	! save pil for intr_passivate
    516 
    517 	! Store starting timestamp in thread structure.
    518 	add	THREAD_REG, T_INTR_START, %o3
    519 1:
    520 	ldx	[%o3], %o5
    521 	RD_TICK(%o4,%l2,%l3,__LINE__)
    522 	casx	[%o3], %o5, %o4
    523 	cmp	%o4, %o5
    524 	! If a high-level interrupt occurred while we were attempting to store
    525 	! the timestamp, try again.
    526 	bne,pn	%xcc, 1b
    527 	nop
    528 
    529 	wrpr	%g0, %l1, %pil			! lower %pil to new level
    530 	!
    531 	! Fast event tracing.
    532 	!
    533 	ld	[%o2 + CPU_FTRACE_STATE], %o4	! %o2 = curthread->t_cpu
    534 	btst	FTRACE_ENABLED, %o4
    535 	be,pt	%icc, 1f			! skip if ftrace disabled
    536 	  mov	%l1, %o5
    537 	!
    538 	! Tracing is enabled - write the trace entry.
    539 	!
    540 	save	%sp, -SA(MINFRAME), %sp
    541 	set	ftrace_intr_thread_format_str, %o0
    542 	mov	%i0, %o1
    543 	mov	%i1, %o2
    544 	mov	%i5, %o3
    545 	call	ftrace_3
    546 	ldn	[%i0 + PC_OFF], %o4
    547 	restore
    548 1:
    549 	!
    550 	! call the handler
    551 	!
    552 	SERVE_INTR_PRE(%o1, %o2, %l1, %l3, %o4, %o5, %o3, %o0)
    553 	!
    554 	! %o0 and %o1 are now available as scratch registers.
    555 	!
    556 0:
    557 	SERVE_INTR(%o1, %o2, %l1, %l3, %o4, %o5, %o3, %o0)
    558 	!
    559 	! If %o3 is set, we must call serve_intr_next, and both %l1 and %o3
    560 	! must be preserved. %l1 holds our pil, %l3 holds our inum.
    561 	!
    562 	! Note: %l1 is the pil level we're processing, but we may have a
    563 	! higher effective pil because a higher-level interrupt may have
    564 	! blocked.
    565 	!
    566 	wrpr	%g0, DISP_LEVEL, %pil
    567 	!
    568 	! Take timestamp, compute interval, update cumulative counter.
    569 	!
    570 	add	THREAD_REG, T_INTR_START, %o5
    571 1:
    572 	ldx	[%o5], %o0
    573 #ifdef DEBUG
    574 	brnz	%o0, 9f
    575 	nop
    576 	! Do not call panic if a panic is already in progress.
    577 	sethi	%hi(panic_quiesce), %o1
    578 	ld	[%o1 + %lo(panic_quiesce)], %o1
    579 	brnz,pn	%o1, 9f
    580 	nop
    581 	sethi	%hi(intr_thread_t_intr_start_zero), %o0
    582 	call	panic
    583 	or	%o0, %lo(intr_thread_t_intr_start_zero), %o0
    584 9:
    585 #endif /* DEBUG */
    586 	RD_TICK(%o1,%l2,%l3,__LINE__)
    587 	sub	%o1, %o0, %l2			! l2 has interval
    588 	!
    589 	! The general outline of what the code here does is:
    590 	! 1. load t_intr_start, %tick, and calculate the delta
    591 	! 2. replace t_intr_start with %tick (if %o3 is set) or 0.
    592 	!
    593 	! The problem is that a high-level interrupt could arrive at any time.
    594 	! It will account for (%tick - t_intr_start) for us when it starts,
    595 	! unless we have set t_intr_start to zero, and then set t_intr_start
    596 	! to a new %tick when it finishes. To account for this, our first step
    597 	! is to load t_intr_start and the last is to use casx to store the new
    598 	! t_intr_start. This guarantees atomicity in reading t_intr_start,
    599 	! reading %tick, and updating t_intr_start.
    600 	!
    601 	movrz	%o3, %g0, %o1
    602 	casx	[%o5], %o0, %o1
    603 	cmp	%o0, %o1
    604 	bne,pn	%xcc, 1b
    605 	!
    606 	! Check for Energy Star mode
    607 	!
    608 	lduh	[%o2 + CPU_DIVISOR], %o0	! delay -- %o0 = clock divisor
    609 	cmp	%o0, 1
    610 	bg,a,pn	%xcc, 2f
    611 	mulx	%l2, %o0, %l2	! multiply interval by clock divisor iff > 1
    612 2:
    613 	!
    614 	! Update cpu_intrstat. If o3 is set then we will be processing another
    615 	! interrupt. Above we have set t_intr_start to %tick, not 0. This
    616 	! means a high-level interrupt can arrive and update the same stats
    617 	! we're updating. Need to use casx.
    618 	!
    619 	sllx	%l1, 4, %o1			! delay - PIL as byte offset
    620 	add	%o1, CPU_MCPU, %o1		! CPU_INTRSTAT const too big
    621 	add	%o1, MCPU_INTRSTAT, %o1		! add parts separately
    622 	add	%o1, %o2, %o1
    623 1:
    624 	ldx	[%o1], %o5			! old counter in o5
    625 	add	%o5, %l2, %o0			! new counter in o0
    626  	stx	%o0, [%o1 + 8]			! store into intrstat[pil][1]
    627 	casx	[%o1], %o5, %o0			! and into intrstat[pil][0]
    628 	cmp	%o5, %o0
    629 	bne,pn	%xcc, 1b
    630 	nop
    631 
    632 	! Also update intracct[]
    633 	lduh	[%o2 + CPU_MSTATE], %o1
    634 	sllx	%o1, 3, %o1
    635 	add	%o1, CPU_INTRACCT, %o1
    636 	add	%o1, %o2, %o1
    637 1:
    638 	ldx	[%o1], %o5
    639 	add	%o5, %l2, %o0
    640 	casx	[%o1], %o5, %o0
    641 	cmp	%o5, %o0
    642 	bne,pn	%xcc, 1b
    643 	nop
    644 
    645 	!
    646 	! Don't keep a pinned process pinned indefinitely. Bump cpu_intrcnt
    647 	! for each interrupt handler we invoke. If we hit INTRCNT_LIMIT, then
    648 	! we've crossed the threshold and we should unpin the pinned threads
    649 	! by preempt()ing ourselves, which will bubble up the t_intr chain
    650 	! until hitting the non-interrupt thread, which will then in turn
    651 	! preempt itself allowing the interrupt processing to resume. Finally,
    652 	! the scheduler takes over and picks the next thread to run.
    653 	!
    654 	! If our CPU is quiesced, we cannot preempt because the idle thread
    655 	! won't ever re-enter the scheduler, and the interrupt will be forever
    656 	! blocked.
    657 	!
    658 	! If t_intr is NULL, we're not pinning anyone, so we use a simpler
    659 	! algorithm. Just check for cpu_kprunrun, and if set then preempt.
    660 	! This insures we enter the scheduler if a higher-priority thread
    661 	! has become runnable.
    662 	!
    663 	lduh	[%o2 + CPU_FLAGS], %o5		! don't preempt if quiesced
    664 	andcc	%o5, CPU_QUIESCED, %g0
    665 	bnz,pn	%xcc, 1f
    666 
    667 	ldn     [THREAD_REG + T_INTR], %o5      ! pinning anything?
    668 	brz,pn  %o5, 3f				! if not, don't inc intrcnt
    669 
    670 	ldub	[%o2 + CPU_INTRCNT], %o5	! delay - %o5 = cpu_intrcnt
    671 	inc	%o5
    672 	cmp	%o5, INTRCNT_LIMIT		! have we hit the limit?
    673 	bl,a,pt	%xcc, 1f			! no preempt if < INTRCNT_LIMIT
    674 	stub	%o5, [%o2 + CPU_INTRCNT]	! delay annul - inc CPU_INTRCNT
    675 	bg,pn	%xcc, 2f			! don't inc stats again
    676 	!
    677 	! We've reached the limit. Set cpu_intrcnt and cpu_kprunrun, and do
    678 	! CPU_STATS_ADDQ(cp, sys, intrunpin, 1). Then call preempt.
    679 	!
    680 	mov	1, %o4				! delay
    681 	stub	%o4, [%o2 + CPU_KPRUNRUN]
    682 	ldx	[%o2 + CPU_STATS_SYS_INTRUNPIN], %o4
    683 	inc	%o4
    684 	stx	%o4, [%o2 + CPU_STATS_SYS_INTRUNPIN]
    685 	ba	2f
    686 	stub	%o5, [%o2 + CPU_INTRCNT]	! delay
    687 3:
    688 	! Code for t_intr == NULL
    689 	ldub	[%o2 + CPU_KPRUNRUN], %o5
    690 	brz,pt	%o5, 1f				! don't preempt unless kprunrun
    691 2:
    692 	! Time to call preempt
    693 	mov	%o2, %l3			! delay - save %o2
    694 	call	preempt
    695 	mov	%o3, %l2			! delay - save %o3.
    696 	mov	%l3, %o2			! restore %o2
    697 	mov	%l2, %o3			! restore %o3
    698 	wrpr	%g0, DISP_LEVEL, %pil		! up from cpu_base_spl
    699 1:
    700 	!
    701 	! Do we need to call serve_intr_next and do this again?
    702 	!
    703 	brz,a,pt %o3, 0f
    704 	ld	[%o2 + CPU_INTR_ACTV], %o5	! delay annulled
    705 	!
    706 	! Restore %pil before calling serve_intr() again. We must check
    707 	! CPU_BASE_SPL and set %pil to max(our-pil, CPU_BASE_SPL)
    708 	!
    709 	ld	[%o2 + CPU_BASE_SPL], %o4
    710 	cmp	%o4, %l1
    711 	movl	%xcc, %l1, %o4
    712 	wrpr	%g0, %o4, %pil
    713 	SERVE_INTR_NEXT(%o1, %o2, %l1, %l3, %o4, %o5, %o3, %o0)
    714 	ba	0b				! compute new stats
    715 	nop
    716 0:
    717 	!
    718 	! Clear bit for this level in CPU's interrupt active bitmask.
    719 	!
    720 	mov	1, %o4
    721 	sll	%o4, %l1, %o4
    722 #ifdef DEBUG
    723 	!
    724 	! ASSERT(CPU->cpu_intr_actv & (1 << PIL))
    725 	!
    726 	andcc	%o4, %o5, %g0
    727 	bnz,pt	%xcc, 0f
    728 	nop
    729 	! Do not call panic if a panic is already in progress.
    730 	sethi	%hi(panic_quiesce), %l2
    731 	ld	[%l2 + %lo(panic_quiesce)], %l2
    732 	brnz,pn	%l2, 0f
    733 	nop
    734 	sethi	%hi(intr_thread_actv_bit_not_set), %o0
    735 	call	panic
    736 	or	%o0, %lo(intr_thread_actv_bit_not_set), %o0
    737 0:
    738 #endif /* DEBUG */
    739 	andn	%o5, %o4, %o5
    740 	st	%o5, [%o2 + CPU_INTR_ACTV]
    741 	!
    742 	! If there is still an interrupted thread underneath this one,
    743 	! then the interrupt was never blocked and the return is fairly
    744 	! simple.  Otherwise jump to intr_thread_exit.
    745 	!
    746 	ldn	[THREAD_REG + T_INTR], %o4	! pinned thread
    747 	brz,pn	%o4, intr_thread_exit		! branch if none
    748 	nop
    749 	!
    750 	! link the thread back onto the interrupt thread pool
    751 	!
    752 	ldn	[%o2 + CPU_INTR_THREAD], %o3
    753 	stn	%o3, [THREAD_REG + T_LINK]
    754 	stn	THREAD_REG, [%o2 + CPU_INTR_THREAD]
    755 	!
    756 	! set the thread state to free so kernel debuggers don't see it
    757 	!
    758 	mov	TS_FREE, %o5
    759 	st	%o5, [THREAD_REG + T_STATE]
    760 	!
    761 	! Switch back to the interrupted thread and return
    762 	!
    763 	stn	%o4, [%o2 + CPU_THREAD]
    764 	membar	#StoreLoad			! sync with mutex_exit()
    765 	mov	%o4, THREAD_REG
    766 
    767 	! If we pinned an interrupt thread, store its starting timestamp.
    768 	lduh	[THREAD_REG + T_FLAGS], %o5
    769 	andcc	%o5, T_INTR_THREAD, %g0
    770 	bz,pt	%xcc, 1f
    771 	ldn	[THREAD_REG + T_SP], %sp	! delay - restore %sp
    772 
    773 	add	THREAD_REG, T_INTR_START, %o3	! o3 has &curthread->t_intr_star
    774 0:
    775 	ldx	[%o3], %o4			! o4 = t_intr_start before
    776 	RD_TICK(%o5,%l2,%l3,__LINE__)
    777 	casx	[%o3], %o4, %o5			! put o5 in ts if o4 == ts after
    778 	cmp	%o4, %o5
    779 	! If a high-level interrupt occurred while we were attempting to store
    780 	! the timestamp, try again.
    781 	bne,pn	%xcc, 0b
    782 	ldn	[THREAD_REG + T_SP], %sp	! delay - restore %sp
    783 1:
    784 	! If the thread being restarted isn't pinning anyone, and no interrupts
    785 	! are pending, zero out cpu_intrcnt
    786 	ldn	[THREAD_REG + T_INTR], %o4
    787 	brnz,pn	%o4, 2f
    788 	rd	SOFTINT, %o4			! delay
    789 	set	SOFTINT_MASK, %o5
    790 	andcc	%o4, %o5, %g0
    791 	bz,a,pt	%xcc, 2f
    792 	stub	%g0, [%o2 + CPU_INTRCNT]	! delay annul
    793 2:
    794 	jmp	%l0 + 8
    795 	nop
    796 	SET_SIZE(intr_thread)
    797 	/* Not Reached */
    798 
    799 	!
    800 	! An interrupt returned on what was once (and still might be)
    801 	! an interrupt thread stack, but the interrupted process is no longer
    802 	! there.  This means the interrupt must have blocked.
    803 	!
    804 	! There is no longer a thread under this one, so put this thread back
    805 	! on the CPU's free list and resume the idle thread which will dispatch
    806 	! the next thread to run.
    807 	!
    808 	! All traps below DISP_LEVEL are disabled here, but the mondo interrupt
    809 	! is enabled.
    810 	!
    811 	ENTRY_NP(intr_thread_exit)
    812 #ifdef TRAPTRACE
    813 	rdpr	%pstate, %l2
    814 	andn	%l2, PSTATE_IE | PSTATE_AM, %o4
    815 	wrpr	%g0, %o4, %pstate			! cpu to known state
    816 	TRACE_PTR(%o4, %o5)
    817 	GET_TRACE_TICK(%o5, %o0)
    818 	stxa	%o5, [%o4 + TRAP_ENT_TICK]%asi
    819 	TRACE_SAVE_TL_GL_REGS(%o4, %o5)
    820 	set	TT_INTR_EXIT, %o5
    821 	stha	%o5, [%o4 + TRAP_ENT_TT]%asi
    822 	stna	%g0, [%o4 + TRAP_ENT_TPC]%asi
    823 	stxa	%g0, [%o4 + TRAP_ENT_TSTATE]%asi
    824 	stna	%sp, [%o4 + TRAP_ENT_SP]%asi
    825 	stna	THREAD_REG, [%o4 + TRAP_ENT_TR]%asi
    826 	ld	[%o2 + CPU_BASE_SPL], %o5
    827 	stna	%o5, [%o4 + TRAP_ENT_F1]%asi
    828 	stna	%g0, [%o4 + TRAP_ENT_F2]%asi
    829 	stna	%g0, [%o4 + TRAP_ENT_F3]%asi
    830 	stna	%g0, [%o4 + TRAP_ENT_F4]%asi
    831 	TRACE_NEXT(%o4, %o5, %o0)
    832 	wrpr	%g0, %l2, %pstate
    833 #endif /* TRAPTRACE */
    834 	! cpu_stats.sys.intrblk++
    835         ldx	[%o2 + CPU_STATS_SYS_INTRBLK], %o4
    836         inc     %o4
    837         stx	%o4, [%o2 + CPU_STATS_SYS_INTRBLK]
    838 	!
    839 	! Put thread back on the interrupt thread list.
    840 	!
    841 
    842 	!
    843 	! Set the CPU's base SPL level.
    844 	!
    845 #ifdef DEBUG
    846 	!
    847 	! ASSERT(!(CPU->cpu_intr_actv & (1 << PIL)))
    848 	!
    849 	ld	[%o2 + CPU_INTR_ACTV], %o5
    850 	mov	1, %o4
    851 	sll	%o4, %l1, %o4
    852 	and	%o5, %o4, %o4
    853 	brz,pt	%o4, 0f
    854 	nop
    855 	! Do not call panic if a panic is already in progress.
    856 	sethi	%hi(panic_quiesce), %l2
    857 	ld	[%l2 + %lo(panic_quiesce)], %l2
    858 	brnz,pn	%l2, 0f
    859 	nop
    860 	sethi	%hi(intr_thread_exit_actv_bit_set), %o0
    861 	call	panic
    862 	or	%o0, %lo(intr_thread_exit_actv_bit_set), %o0
    863 0:
    864 #endif /* DEBUG */
    865 	call	_intr_set_spl			! set CPU's base SPL level
    866 	ld	[%o2 + CPU_INTR_ACTV], %o5	! delay - load active mask
    867 	!
    868 	! set the thread state to free so kernel debuggers don't see it
    869 	!
    870 	mov	TS_FREE, %o4
    871 	st	%o4, [THREAD_REG + T_STATE]
    872 	!
    873 	! Put thread on either the interrupt pool or the free pool and
    874 	! call swtch() to resume another thread.
    875 	!
    876 	ldn	[%o2 + CPU_INTR_THREAD], %o5	! get list pointer
    877 	stn	%o5, [THREAD_REG + T_LINK]
    878 	call	swtch				! switch to best thread
    879 	stn	THREAD_REG, [%o2 + CPU_INTR_THREAD] ! delay - put thread on list
    880 	ba,a,pt	%xcc, .				! swtch() shouldn't return
    881 	SET_SIZE(intr_thread_exit)
    882 
    883 	.global ftrace_intr_thread_format_str
    884 ftrace_intr_thread_format_str:
    885 	.asciz	"intr_thread(): regs=0x%lx, int=0x%lx, pil=0x%lx"
    886 #ifdef DEBUG
    887 intr_thread_actv_bit_set:
    888 	.asciz	"intr_thread():	cpu_intr_actv bit already set for PIL"
    889 intr_thread_actv_bit_not_set:
    890 	.asciz	"intr_thread():	cpu_intr_actv bit not set for PIL"
    891 intr_thread_exit_actv_bit_set:
    892 	.asciz	"intr_thread_exit(): cpu_intr_actv bit erroneously set for PIL"
    893 intr_thread_t_intr_start_zero:
    894 	.asciz	"intr_thread():	t_intr_start zero upon handler return"
    895 #endif /* DEBUG */
    896 #endif	/* lint */
    897 
    898 #if defined(lint)
    899 
    900 /*
    901  * Handle an interrupt in the current thread
    902  *	Entry:
    903  *		%o0       = pointer to regs structure
    904  *		%o1       = pointer to current intr_vec_t (iv) to be processed
    905  *		%o2       = pil
    906  *		%sp       = on current thread's kernel stack
    907  *		%o7       = return linkage to trap code
    908  *		%g7       = current thread
    909  *		%pstate   = normal globals, interrupts enabled,
    910  *		            privileged, fp disabled
    911  *		%pil      = PIL_MAX
    912  *
    913  *	Register Usage
    914  *		%l0       = return linkage
    915  *		%l1       = old stack
    916  *		%l2 - %l3 = scratch
    917  *		%l4 - %l7 = reserved for sys_trap
    918  *		%o3       = cpu
    919  *		%o0       = scratch
    920  *		%o4 - %o5 = scratch
    921  */
    922 /* ARGSUSED */
    923 void
    924 current_thread(struct regs *regs, uint64_t iv_p, uint_t pil)
    925 {}
    926 
    927 #else	/* lint */
    928 
    929 	ENTRY_NP(current_thread)
    930 
    931 	mov	%o7, %l0
    932 	ldn	[THREAD_REG + T_CPU], %o3
    933 
    934 	ldn	[THREAD_REG + T_ONFAULT], %l2
    935 	brz,pt	%l2, no_onfault		! branch if no onfault label set
    936 	nop
    937 	stn	%g0, [THREAD_REG + T_ONFAULT]! clear onfault label
    938 	ldn	[THREAD_REG + T_LOFAULT], %l3
    939 	stn	%g0, [THREAD_REG + T_LOFAULT]! clear lofault data
    940 
    941 	sub	%o2, LOCK_LEVEL + 1, %o5
    942 	sll	%o5, CPTRSHIFT, %o5
    943 	add	%o5, CPU_OFD, %o4	! %o4 has on_fault data offset
    944 	stn	%l2, [%o3 + %o4]	! save onfault label for pil %o2
    945 	add	%o5, CPU_LFD, %o4	! %o4 has lofault data offset
    946 	stn	%l3, [%o3 + %o4]	! save lofault data for pil %o2
    947 
    948 no_onfault:
    949 	ldn	[THREAD_REG + T_ONTRAP], %l2
    950 	brz,pt	%l2, 6f			! branch if no on_trap protection
    951 	nop
    952 	stn	%g0, [THREAD_REG + T_ONTRAP]! clear on_trap protection
    953 	sub	%o2, LOCK_LEVEL + 1, %o5
    954 	sll	%o5, CPTRSHIFT, %o5
    955 	add	%o5, CPU_OTD, %o4	! %o4 has on_trap data offset
    956 	stn	%l2, [%o3 + %o4]	! save on_trap label for pil %o2
    957 
    958 	!
    959 	! Set bit for this level in CPU's active interrupt bitmask.
    960 	!
    961 6:	ld	[%o3 + CPU_INTR_ACTV], %o5	! o5 has cpu_intr_actv b4 chng
    962 	mov	1, %o4
    963 	sll	%o4, %o2, %o4			! construct mask for level
    964 #ifdef DEBUG
    965 	!
    966 	! ASSERT(!(CPU->cpu_intr_actv & (1 << PIL)))
    967 	!
    968 	andcc	%o5, %o4, %g0
    969 	bz,pt	%xcc, 0f
    970 	nop
    971 	! Do not call panic if a panic is already in progress.
    972 	sethi	%hi(panic_quiesce), %l2
    973 	ld	[%l2 + %lo(panic_quiesce)], %l2
    974 	brnz,pn	%l2, 0f
    975 	nop
    976 	sethi	%hi(current_thread_actv_bit_set), %o0
    977 	call	panic
    978 	or	%o0, %lo(current_thread_actv_bit_set), %o0
    979 0:
    980 #endif /* DEBUG */
    981 	or	%o5, %o4, %o4
    982 	!
    983 	! See if we are interrupting another high-level interrupt.
    984 	!
    985 	srl	%o5, LOCK_LEVEL + 1, %o5	! only look at high-level bits
    986 	brz,pt	%o5, 1f
    987 	st	%o4, [%o3 + CPU_INTR_ACTV]	! delay - store active mask
    988 	!
    989 	! We have interrupted another high-level interrupt. Find its PIL,
    990 	! compute the interval it ran for, and update its cumulative counter.
    991 	!
    992 	! Register usage:
    993 
    994 	! o2 = PIL of this interrupt
    995 	! o5 = high PIL bits of INTR_ACTV (not including this PIL)
    996 	! l1 = bitmask used to find other active high-level PIL
    997 	! o4 = index of bit set in l1
    998 	! Use cpu_intr_actv to find the cpu_pil_high_start[] offset for the
    999 	! interrupted high-level interrupt.
   1000 	! Create mask for cpu_intr_actv. Begin by looking for bits set
   1001 	! at one level below the current PIL. Since %o5 contains the active
   1002 	! mask already shifted right by (LOCK_LEVEL + 1), we start by looking
   1003 	! at bit (current_pil - (LOCK_LEVEL + 2)).
   1004 	sub	%o2, LOCK_LEVEL + 2, %o4
   1005 	mov	1, %l1
   1006 	sll	%l1, %o4, %l1
   1007 2:
   1008 #ifdef DEBUG
   1009 	! ASSERT(%l1 != 0) (we didn't shift the bit off the right edge)
   1010 	brnz,pt	%l1, 9f
   1011 	nop
   1012 
   1013 	! Don't panic if a panic is already in progress.
   1014 	sethi	%hi(panic_quiesce), %l3
   1015 	ld	[%l3 + %lo(panic_quiesce)], %l3
   1016 	brnz,pn	%l3, 9f
   1017 	nop
   1018 	sethi	%hi(current_thread_nested_PIL_not_found), %o0
   1019 	call	panic
   1020 	or	%o0, %lo(current_thread_nested_PIL_not_found), %o0
   1021 9:
   1022 #endif /* DEBUG */
   1023 	andcc	%l1, %o5, %g0		! test mask against high-level bits of
   1024 	bnz	%xcc, 3f		! cpu_intr_actv
   1025 	nop
   1026 	srl	%l1, 1, %l1		! No match. Try next lower PIL.
   1027 	ba,pt	%xcc, 2b
   1028 	sub	%o4, 1, %o4		! delay - decrement PIL
   1029 3:
   1030 	sll	%o4, 3, %o4			! index to byte offset
   1031 	add	%o4, CPU_MCPU, %l1	! CPU_PIL_HIGH_START is too large
   1032 	add	%l1, MCPU_PIL_HIGH_START, %l1
   1033 	ldx	[%o3 + %l1], %l3		! load starting timestamp
   1034 #ifdef DEBUG
   1035 	brnz,pt	%l3, 9f
   1036 	nop
   1037 	! Don't panic if a panic is already in progress.
   1038 	sethi	%hi(panic_quiesce), %l1
   1039 	ld	[%l1 + %lo(panic_quiesce)], %l1
   1040 	brnz,pn	%l1, 9f
   1041 	nop
   1042 	srl	%o4, 3, %o1			! Find interrupted PIL for panic
   1043 	add	%o1, LOCK_LEVEL + 1, %o1
   1044 	sethi	%hi(current_thread_nested_pil_zero), %o0
   1045 	call	panic
   1046 	or	%o0, %lo(current_thread_nested_pil_zero), %o0
   1047 9:
   1048 #endif /* DEBUG */
   1049 	RD_TICK_NO_SUSPEND_CHECK(%l1, %l2)
   1050 	sub	%l1, %l3, %l3			! interval in %l3
   1051 	!
   1052 	! Check for Energy Star mode
   1053 	!
   1054 	lduh	[%o3 + CPU_DIVISOR], %l1	! %l1 = clock divisor
   1055 	cmp	%l1, 1
   1056 	bg,a,pn	%xcc, 2f
   1057 	mulx	%l3, %l1, %l3	! multiply interval by clock divisor iff > 1
   1058 2:
   1059 	!
   1060 	! We need to find the CPU offset of the cumulative counter. We start
   1061 	! with %o4, which has (PIL - (LOCK_LEVEL + 1)) * 8. We need PIL * 16,
   1062 	! so we shift left 1, then add (LOCK_LEVEL + 1) * 16, which is
   1063 	! CPU_INTRSTAT_LOW_PIL_OFFSET.
   1064 	!
   1065 	sll	%o4, 1, %o4
   1066 	add	%o4, CPU_MCPU, %o4		! CPU_INTRSTAT const too large
   1067 	add	%o4, MCPU_INTRSTAT, %o4		! add parts separately
   1068 	add	%o4, CPU_INTRSTAT_LOW_PIL_OFFSET, %o4
   1069 	ldx	[%o3 + %o4], %l1		! old counter in l1
   1070 	add	%l1, %l3, %l1			! new counter in l1
   1071 	stx	%l1, [%o3 + %o4]		! store new counter
   1072 
   1073 	! Also update intracct[]
   1074 	lduh	[%o3 + CPU_MSTATE], %o4
   1075 	sllx	%o4, 3, %o4
   1076 	add	%o4, CPU_INTRACCT, %o4
   1077 	ldx	[%o3 + %o4], %l1
   1078 	add	%l1, %l3, %l1
   1079 	! Another high-level interrupt is active below this one, so
   1080 	! there is no need to check for an interrupt thread. That will be
   1081 	! done by the lowest priority high-level interrupt active.
   1082 	ba,pt	%xcc, 5f
   1083 	stx	%l1, [%o3 + %o4]		! delay - store new counter
   1084 1:
   1085 	! If we haven't interrupted another high-level interrupt, we may be
   1086 	! interrupting a low level interrupt thread. If so, compute its interval
   1087 	! and update its cumulative counter.
   1088 	lduh	[THREAD_REG + T_FLAGS], %o4
   1089 	andcc	%o4, T_INTR_THREAD, %g0
   1090 	bz,pt	%xcc, 4f
   1091 	nop
   1092 
   1093 	! We have interrupted an interrupt thread. Take timestamp, compute
   1094 	! interval, update cumulative counter.
   1095 
   1096 	! Check t_intr_start. If it is zero, either intr_thread() or
   1097 	! current_thread() (at a lower PIL, of course) already did
   1098 	! the accounting for the underlying interrupt thread.
   1099 	ldx	[THREAD_REG + T_INTR_START], %o5
   1100 	brz,pn	%o5, 4f
   1101 	nop
   1102 
   1103 	stx	%g0, [THREAD_REG + T_INTR_START]
   1104 	RD_TICK_NO_SUSPEND_CHECK(%o4, %l2)
   1105 	sub	%o4, %o5, %o5			! o5 has the interval
   1106 
   1107 	! Check for Energy Star mode
   1108 	lduh	[%o3 + CPU_DIVISOR], %o4	! %o4 = clock divisor
   1109 	cmp	%o4, 1
   1110 	bg,a,pn	%xcc, 2f
   1111 	mulx	%o5, %o4, %o5	! multiply interval by clock divisor iff > 1
   1112 2:
   1113 	ldub	[THREAD_REG + T_PIL], %o4
   1114 	sllx	%o4, 4, %o4			! PIL index to byte offset
   1115 	add	%o4, CPU_MCPU, %o4		! CPU_INTRSTAT const too large
   1116 	add	%o4, MCPU_INTRSTAT, %o4		! add parts separately
   1117 	ldx	[%o3 + %o4], %l2		! old counter in l2
   1118 	add	%l2, %o5, %l2			! new counter in l2
   1119 	stx	%l2, [%o3 + %o4]		! store new counter
   1120 
   1121 	! Also update intracct[]
   1122 	lduh	[%o3 + CPU_MSTATE], %o4
   1123 	sllx	%o4, 3, %o4
   1124 	add	%o4, CPU_INTRACCT, %o4
   1125 	ldx	[%o3 + %o4], %l2
   1126 	add	%l2, %o5, %l2
   1127 	stx	%l2, [%o3 + %o4]
   1128 4:
   1129 	!
   1130 	! Handle high-level interrupts on separate interrupt stack.
   1131 	! No other high-level interrupts are active, so switch to int stack.
   1132 	!
   1133 	mov	%sp, %l1
   1134 	ldn	[%o3 + CPU_INTR_STACK], %l3
   1135 	sub	%l3, STACK_BIAS, %sp
   1136 
   1137 5:
   1138 #ifdef DEBUG
   1139 	!
   1140 	! ASSERT(%o2 > LOCK_LEVEL)
   1141 	!
   1142 	cmp	%o2, LOCK_LEVEL
   1143 	bg,pt	%xcc, 3f
   1144 	nop
   1145 	mov	CE_PANIC, %o0
   1146 	sethi	%hi(current_thread_wrong_pil), %o1
   1147 	call	cmn_err				! %o2 has the %pil already
   1148 	or	%o1, %lo(current_thread_wrong_pil), %o1
   1149 #endif
   1150 3:
   1151 	! Store starting timestamp for this PIL in CPU structure at
   1152 	! cpu.cpu_m.pil_high_start[PIL - (LOCK_LEVEL + 1)]
   1153         sub     %o2, LOCK_LEVEL + 1, %o4	! convert PIL to array index
   1154 	sllx    %o4, 3, %o4			! index to byte offset
   1155 	add	%o4, CPU_MCPU, %o4	! CPU_PIL_HIGH_START is too large
   1156 	add	%o4, MCPU_PIL_HIGH_START, %o4
   1157 	RD_TICK_NO_SUSPEND_CHECK(%o5, %l2)
   1158         stx     %o5, [%o3 + %o4]
   1159 
   1160 	wrpr	%g0, %o2, %pil			! enable interrupts
   1161 
   1162 	!
   1163 	! call the handler
   1164 	!
   1165 	SERVE_INTR_PRE(%o1, %o3, %l2, %l3, %o4, %o5, %o2, %o0)
   1166 1:
   1167 	SERVE_INTR(%o1, %o3, %l2, %l3, %o4, %o5, %o2, %o0)
   1168 
   1169 	brz,a,pt %o2, 0f			! if %o2, more intrs await
   1170 	rdpr	%pil, %o2			! delay annulled
   1171 	SERVE_INTR_NEXT(%o1, %o3, %l2, %l3, %o4, %o5, %o2, %o0)
   1172 	ba	1b
   1173 	nop
   1174 0:
   1175 	wrpr	%g0, PIL_MAX, %pil		! disable interrupts (1-15)
   1176 
   1177 	cmp	%o2, PIL_15
   1178 	bne,pt	%xcc, 3f
   1179 	nop
   1180 
   1181 	sethi	%hi(cpc_level15_inum), %o1
   1182 	ldx	[%o1 + %lo(cpc_level15_inum)], %o1 ! arg for intr_enqueue_req
   1183 	brz	%o1, 3f
   1184 	nop
   1185 
   1186 	rdpr 	%pstate, %g5
   1187 	andn	%g5, PSTATE_IE, %g1
   1188 	wrpr	%g0, %g1, %pstate		! Disable vec interrupts
   1189 
   1190 	call	intr_enqueue_req		! preserves %g5
   1191 	mov	PIL_15, %o0
   1192 
   1193 	! clear perfcntr overflow
   1194 	mov	1, %o0
   1195 	sllx	%o0, PIL_15, %o0
   1196 	wr	%o0, CLEAR_SOFTINT
   1197 
   1198 	wrpr	%g0, %g5, %pstate		! Enable vec interrupts
   1199 
   1200 3:
   1201 	cmp	%o2, PIL_14
   1202 	be	tick_rtt			!  cpu-specific tick processing
   1203 	nop
   1204 	.global	current_thread_complete
   1205 current_thread_complete:
   1206 	!
   1207 	! Register usage:
   1208 	!
   1209 	! %l1 = stack pointer
   1210 	! %l2 = CPU_INTR_ACTV >> (LOCK_LEVEL + 1)
   1211 	! %o2 = PIL
   1212 	! %o3 = CPU pointer
   1213 	! %o4, %o5, %l3, %l4, %l5 = scratch
   1214 	!
   1215 	ldn	[THREAD_REG + T_CPU], %o3
   1216 	!
   1217 	! Clear bit for this level in CPU's interrupt active bitmask.
   1218 	!
   1219 	ld	[%o3 + CPU_INTR_ACTV], %l2
   1220 	mov	1, %o5
   1221 	sll	%o5, %o2, %o5
   1222 #ifdef DEBUG
   1223 	!
   1224 	! ASSERT(CPU->cpu_intr_actv & (1 << PIL))
   1225 	!
   1226 	andcc	%l2, %o5, %g0
   1227 	bnz,pt	%xcc, 0f
   1228 	nop
   1229 	! Do not call panic if a panic is already in progress.
   1230 	sethi	%hi(panic_quiesce), %l2
   1231 	ld	[%l2 + %lo(panic_quiesce)], %l2
   1232 	brnz,pn	%l2, 0f
   1233 	nop
   1234 	sethi	%hi(current_thread_actv_bit_not_set), %o0
   1235 	call	panic
   1236 	or	%o0, %lo(current_thread_actv_bit_not_set), %o0
   1237 0:
   1238 #endif /* DEBUG */
   1239 	andn	%l2, %o5, %l2
   1240 	st	%l2, [%o3 + CPU_INTR_ACTV]
   1241 
   1242 	! Take timestamp, compute interval, update cumulative counter.
   1243         sub     %o2, LOCK_LEVEL + 1, %o4	! PIL to array index
   1244 	sllx    %o4, 3, %o4			! index to byte offset
   1245 	add	%o4, CPU_MCPU, %o4	! CPU_PIL_HIGH_START is too large
   1246 	add	%o4, MCPU_PIL_HIGH_START, %o4
   1247 	RD_TICK_NO_SUSPEND_CHECK(%o5, %o0)
   1248 	ldx     [%o3 + %o4], %o0
   1249 #ifdef DEBUG
   1250 	! ASSERT(cpu.cpu_m.pil_high_start[pil - (LOCK_LEVEL + 1)] != 0)
   1251 	brnz,pt	%o0, 9f
   1252 	nop
   1253 	! Don't panic if a panic is already in progress.
   1254 	sethi	%hi(panic_quiesce), %l2
   1255 	ld	[%l2 + %lo(panic_quiesce)], %l2
   1256 	brnz,pn	%l2, 9f
   1257 	nop
   1258 	sethi	%hi(current_thread_timestamp_zero), %o0
   1259 	call	panic
   1260 	or	%o0, %lo(current_thread_timestamp_zero), %o0
   1261 9:
   1262 #endif /* DEBUG */
   1263 	stx	%g0, [%o3 + %o4]
   1264 	sub	%o5, %o0, %o5			! interval in o5
   1265 
   1266 	! Check for Energy Star mode
   1267 	lduh	[%o3 + CPU_DIVISOR], %o4	! %o4 = clock divisor
   1268 	cmp	%o4, 1
   1269 	bg,a,pn	%xcc, 2f
   1270 	mulx	%o5, %o4, %o5	! multiply interval by clock divisor iff > 1
   1271 2:
   1272 	sllx	%o2, 4, %o4			! PIL index to byte offset
   1273 	add	%o4, CPU_MCPU, %o4		! CPU_INTRSTAT too large
   1274 	add	%o4, MCPU_INTRSTAT, %o4		! add parts separately
   1275 	ldx	[%o3 + %o4], %o0		! old counter in o0
   1276 	add	%o0, %o5, %o0			! new counter in o0
   1277 	stx	%o0, [%o3 + %o4]		! store new counter
   1278 
   1279 	! Also update intracct[]
   1280 	lduh	[%o3 + CPU_MSTATE], %o4
   1281 	sllx	%o4, 3, %o4
   1282 	add	%o4, CPU_INTRACCT, %o4
   1283 	ldx	[%o3 + %o4], %o0
   1284 	add	%o0, %o5, %o0
   1285 	stx	%o0, [%o3 + %o4]
   1286 
   1287 	!
   1288 	! get back on current thread's stack
   1289 	!
   1290 	srl	%l2, LOCK_LEVEL + 1, %l2
   1291 	tst	%l2				! any more high-level ints?
   1292 	movz	%xcc, %l1, %sp
   1293 	!
   1294 	! Current register usage:
   1295 	! o2 = PIL
   1296 	! o3 = CPU pointer
   1297 	! l0 = return address
   1298 	! l2 = intr_actv shifted right
   1299 	!
   1300 	bz,pt	%xcc, 3f			! if l2 was zero, no more ints
   1301 	nop
   1302 	!
   1303 	! We found another high-level interrupt active below the one that just
   1304 	! returned. Store a starting timestamp for it in the CPU structure.
   1305 	!
   1306 	! Use cpu_intr_actv to find the cpu_pil_high_start[] offset for the
   1307 	! interrupted high-level interrupt.
   1308 	! Create mask for cpu_intr_actv. Begin by looking for bits set
   1309 	! at one level below the current PIL. Since %l2 contains the active
   1310 	! mask already shifted right by (LOCK_LEVEL + 1), we start by looking
   1311 	! at bit (current_pil - (LOCK_LEVEL + 2)).
   1312 	! %l1 = mask, %o5 = index of bit set in mask
   1313 	!
   1314 	mov	1, %l1
   1315 	sub	%o2, LOCK_LEVEL + 2, %o5
   1316 	sll	%l1, %o5, %l1			! l1 = mask for level
   1317 1:
   1318 #ifdef DEBUG
   1319 	! ASSERT(%l1 != 0) (we didn't shift the bit off the right edge)
   1320 	brnz,pt	%l1, 9f
   1321 	nop
   1322 	sethi	%hi(current_thread_nested_PIL_not_found), %o0
   1323 	call	panic
   1324 	or	%o0, %lo(current_thread_nested_PIL_not_found), %o0
   1325 9:
   1326 #endif /* DEBUG */
   1327 	andcc	%l1, %l2, %g0		! test mask against high-level bits of
   1328 	bnz	%xcc, 2f		! cpu_intr_actv
   1329 	nop
   1330 	srl	%l1, 1, %l1		! No match. Try next lower PIL.
   1331 	ba,pt	%xcc, 1b
   1332 	sub	%o5, 1, %o5		! delay - decrement PIL
   1333 2:
   1334 	sll	%o5, 3, %o5		! convert array index to byte offset
   1335 	add	%o5, CPU_MCPU, %o5	! CPU_PIL_HIGH_START is too large
   1336 	add	%o5, MCPU_PIL_HIGH_START, %o5
   1337 	RD_TICK_NO_SUSPEND_CHECK(%o4, %l2)
   1338 	! Another high-level interrupt is active below this one, so
   1339 	! there is no need to check for an interrupt thread. That will be
   1340 	! done by the lowest priority high-level interrupt active.
   1341 	ba,pt	%xcc, 7f
   1342 	stx	%o4, [%o3 + %o5]	! delay - store timestamp
   1343 3:
   1344 	! If we haven't interrupted another high-level interrupt, we may have
   1345 	! interrupted a low level interrupt thread. If so, store a starting
   1346 	! timestamp in its thread structure.
   1347 	lduh	[THREAD_REG + T_FLAGS], %o4
   1348 	andcc	%o4, T_INTR_THREAD, %g0
   1349 	bz,pt	%xcc, 7f
   1350 	nop
   1351 
   1352 	RD_TICK_NO_SUSPEND_CHECK(%o4, %l2)
   1353 	stx	%o4, [THREAD_REG + T_INTR_START]
   1354 
   1355 7:
   1356 	sub	%o2, LOCK_LEVEL + 1, %o4
   1357 	sll	%o4, CPTRSHIFT, %o5
   1358 
   1359 	! Check on_trap saved area and restore as needed
   1360 	add	%o5, CPU_OTD, %o4
   1361 	ldn	[%o3 + %o4], %l2
   1362 	brz,pt %l2, no_ontrp_restore
   1363 	nop
   1364 	stn	%l2, [THREAD_REG + T_ONTRAP] ! restore
   1365 	stn	%g0, [%o3 + %o4]	! clear
   1366 
   1367 no_ontrp_restore:
   1368 	! Check on_fault saved area and restore as needed
   1369 	add	%o5, CPU_OFD, %o4
   1370 	ldn	[%o3 + %o4], %l2
   1371 	brz,pt %l2, 8f
   1372 	nop
   1373 	stn	%l2, [THREAD_REG + T_ONFAULT] ! restore
   1374 	stn	%g0, [%o3 + %o4]	! clear
   1375 	add	%o5, CPU_LFD, %o4
   1376 	ldn	[%o3 + %o4], %l2
   1377 	stn	%l2, [THREAD_REG + T_LOFAULT] ! restore
   1378 	stn	%g0, [%o3 + %o4]	! clear
   1379 
   1380 
   1381 8:
   1382 	! Enable interrupts and return
   1383 	jmp	%l0 + 8
   1384 	wrpr	%g0, %o2, %pil			! enable interrupts
   1385 	SET_SIZE(current_thread)
   1386 
   1387 
   1388 #ifdef DEBUG
   1389 current_thread_wrong_pil:
   1390 	.asciz	"current_thread: unexpected pil level: %d"
   1391 current_thread_actv_bit_set:
   1392 	.asciz	"current_thread(): cpu_intr_actv bit already set for PIL"
   1393 current_thread_actv_bit_not_set:
   1394 	.asciz	"current_thread(): cpu_intr_actv bit not set for PIL"
   1395 current_thread_nested_pil_zero:
   1396 	.asciz	"current_thread(): timestamp zero for nested PIL %d"
   1397 current_thread_timestamp_zero:
   1398 	.asciz	"current_thread(): timestamp zero upon handler return"
   1399 current_thread_nested_PIL_not_found:
   1400 	.asciz	"current_thread: couldn't find nested high-level PIL"
   1401 #endif /* DEBUG */
   1402 #endif /* lint */
   1403 
   1404 /*
   1405  * Return a thread's interrupt level.
   1406  * Since this isn't saved anywhere but in %l4 on interrupt entry, we
   1407  * must dig it out of the save area.
   1408  *
   1409  * Caller 'swears' that this really is an interrupt thread.
   1410  *
   1411  * int
   1412  * intr_level(t)
   1413  *	kthread_id_t	t;
   1414  */
   1415 
   1416 #if defined(lint)
   1417 
   1418 /* ARGSUSED */
   1419 int
   1420 intr_level(kthread_id_t t)
   1421 { return (0); }
   1422 
   1423 #else	/* lint */
   1424 
   1425 	ENTRY_NP(intr_level)
   1426 	retl
   1427 	ldub	[%o0 + T_PIL], %o0		! return saved pil
   1428 	SET_SIZE(intr_level)
   1429 
   1430 #endif	/* lint */
   1431 
   1432 #if defined(lint)
   1433 
   1434 /* ARGSUSED */
   1435 int
   1436 disable_pil_intr()
   1437 { return (0); }
   1438 
   1439 #else	/* lint */
   1440 
   1441 	ENTRY_NP(disable_pil_intr)
   1442 	rdpr	%pil, %o0
   1443 	retl
   1444 	wrpr	%g0, PIL_MAX, %pil		! disable interrupts (1-15)
   1445 	SET_SIZE(disable_pil_intr)
   1446 
   1447 #endif	/* lint */
   1448 
   1449 #if defined(lint)
   1450 
   1451 /* ARGSUSED */
   1452 void
   1453 enable_pil_intr(int pil_save)
   1454 {}
   1455 
   1456 #else	/* lint */
   1457 
   1458 	ENTRY_NP(enable_pil_intr)
   1459 	retl
   1460 	wrpr	%o0, %pil
   1461 	SET_SIZE(enable_pil_intr)
   1462 
   1463 #endif	/* lint */
   1464 
   1465 #if defined(lint)
   1466 
   1467 /* ARGSUSED */
   1468 uint_t
   1469 disable_vec_intr(void)
   1470 { return (0); }
   1471 
   1472 #else	/* lint */
   1473 
   1474 	ENTRY_NP(disable_vec_intr)
   1475 	rdpr	%pstate, %o0
   1476 	andn	%o0, PSTATE_IE, %g1
   1477 	retl
   1478 	wrpr	%g0, %g1, %pstate		! disable interrupt
   1479 	SET_SIZE(disable_vec_intr)
   1480 
   1481 #endif	/* lint */
   1482 
   1483 #if defined(lint)
   1484 
   1485 /* ARGSUSED */
   1486 void
   1487 enable_vec_intr(uint_t pstate_save)
   1488 {}
   1489 
   1490 #else	/* lint */
   1491 
   1492 	ENTRY_NP(enable_vec_intr)
   1493 	retl
   1494 	wrpr	%g0, %o0, %pstate
   1495 	SET_SIZE(enable_vec_intr)
   1496 
   1497 #endif	/* lint */
   1498 
   1499 #if defined(lint)
   1500 
   1501 void
   1502 cbe_level14(void)
   1503 {}
   1504 
   1505 #else   /* lint */
   1506 
   1507 	ENTRY_NP(cbe_level14)
   1508 	save    %sp, -SA(MINFRAME), %sp ! get a new window
   1509 	!
   1510 	! Make sure that this is from TICK_COMPARE; if not just return
   1511 	!
   1512 	rd	SOFTINT, %l1
   1513 	set	(TICK_INT_MASK | STICK_INT_MASK), %o2
   1514 	andcc	%l1, %o2, %g0
   1515 	bz,pn	%icc, 2f
   1516 	nop
   1517 
   1518 	CPU_ADDR(%o1, %o2)
   1519 	call	cyclic_fire
   1520 	mov	%o1, %o0
   1521 2:
   1522 	ret
   1523 	restore	%g0, 1, %o0
   1524 	SET_SIZE(cbe_level14)
   1525 
   1526 #endif  /* lint */
   1527 
   1528 
   1529 #if defined(lint)
   1530 
   1531 /* ARGSUSED */
   1532 void
   1533 kdi_setsoftint(uint64_t iv_p)
   1534 {}
   1535 
   1536 #else	/* lint */
   1537 
   1538 	ENTRY_NP(kdi_setsoftint)
   1539 	save	%sp, -SA(MINFRAME), %sp	! get a new window
   1540 	rdpr	%pstate, %l5
   1541 	andn	%l5, PSTATE_IE, %l1
   1542 	wrpr	%l1, %pstate		! disable interrupt
   1543 	!
   1544 	! We have a pointer to an interrupt vector data structure.
   1545 	! Put the request on the cpu's softint priority list and
   1546 	! set %set_softint.
   1547 	!
   1548 	! Register usage
   1549 	! 	%i0 - pointer to intr_vec_t (iv)
   1550 	!	%l2 - requested pil
   1551 	!	%l4 - cpu
   1552 	!	%l5 - pstate
   1553 	!	%l1, %l3, %l6 - temps
   1554 	!
   1555 	! check if a softint is pending for this softint,
   1556 	! if one is pending, don't bother queuing another.
   1557 	!
   1558 	lduh	[%i0 + IV_FLAGS], %l1	! %l1 = iv->iv_flags
   1559 	and	%l1, IV_SOFTINT_PEND, %l6 ! %l6 = iv->iv_flags & IV_SOFTINT_PEND
   1560 	brnz,pn	%l6, 4f			! branch if softint is already pending
   1561 	or	%l1, IV_SOFTINT_PEND, %l2
   1562 	sth	%l2, [%i0 + IV_FLAGS]	! Set IV_SOFTINT_PEND flag
   1563 
   1564 	CPU_ADDR(%l4, %l2)		! %l4 = cpu
   1565 	lduh	[%i0 + IV_PIL], %l2	! %l2 = iv->iv_pil
   1566 
   1567 	!
   1568 	! Insert intr_vec_t (iv) to appropriate cpu's softint priority list
   1569 	!
   1570 	sll	%l2, CPTRSHIFT, %l0	! %l0 = offset to pil entry
   1571 	add	%l4, INTR_TAIL, %l6	! %l6 = &cpu->m_cpu.intr_tail
   1572 	ldn	[%l6 + %l0], %l1	! %l1 = cpu->m_cpu.intr_tail[pil]
   1573 					!       current tail (ct)
   1574 	brz,pt	%l1, 2f			! branch if current tail is NULL
   1575 	stn	%i0, [%l6 + %l0]	! make intr_vec_t (iv) as new tail
   1576 	!
   1577 	! there's pending intr_vec_t already
   1578 	!
   1579 	lduh	[%l1 + IV_FLAGS], %l6	! %l6 = ct->iv_flags
   1580 	and	%l6, IV_SOFTINT_MT, %l6	! %l6 = ct->iv_flags & IV_SOFTINT_MT
   1581 	brz,pt	%l6, 1f			! check for Multi target softint flag
   1582 	add	%l1, IV_PIL_NEXT, %l3	! %l3 = &ct->iv_pil_next
   1583 	ld	[%l4 + CPU_ID], %l6	! for multi target softint, use cpuid
   1584 	sll	%l6, CPTRSHIFT, %l6	! calculate offset address from cpuid
   1585 	add	%l3, %l6, %l3		! %l3 =  &ct->iv_xpil_next[cpuid]
   1586 1:
   1587 	!
   1588 	! update old tail
   1589 	!
   1590 	ba,pt	%xcc, 3f
   1591 	stn	%i0, [%l3]		! [%l3] = iv, set pil_next field
   1592 2:
   1593 	!
   1594 	! no pending intr_vec_t; make intr_vec_t as new head
   1595 	!
   1596 	add	%l4, INTR_HEAD, %l6	! %l6 = &cpu->m_cpu.intr_head[pil]
   1597 	stn	%i0, [%l6 + %l0]	! cpu->m_cpu.intr_head[pil] = iv
   1598 3:
   1599 	!
   1600 	! Write %set_softint with (1<<pil) to cause a "pil" level trap
   1601 	!
   1602 	mov	1, %l1			! %l1 = 1
   1603 	sll	%l1, %l2, %l1		! %l1 = 1 << pil
   1604 	wr	%l1, SET_SOFTINT	! trigger required pil softint
   1605 4:
   1606 	wrpr	%g0, %l5, %pstate	! %pstate = saved %pstate (in %l5)
   1607 	ret
   1608 	restore
   1609 	SET_SIZE(kdi_setsoftint)
   1610 
   1611 #endif	/* lint */
   1612 
   1613 #if defined(lint)
   1614 
   1615 /*ARGSUSED*/
   1616 void
   1617 setsoftint_tl1(uint64_t iv_p, uint64_t dummy)
   1618 {}
   1619 
   1620 #else	/* lint */
   1621 
   1622 	!
   1623 	! Register usage
   1624 	!	Arguments:
   1625 	! 	%g1 - Pointer to intr_vec_t (iv)
   1626 	!
   1627 	!	Internal:
   1628 	!	%g2 - pil
   1629 	!	%g4 - cpu
   1630 	!	%g3,%g5-g7 - temps
   1631 	!
   1632 	ENTRY_NP(setsoftint_tl1)
   1633 	!
   1634 	! We have a pointer to an interrupt vector data structure.
   1635 	! Put the request on the cpu's softint priority list and
   1636 	! set %set_softint.
   1637 	!
   1638 	CPU_ADDR(%g4, %g2)		! %g4 = cpu
   1639 	lduh	[%g1 + IV_PIL], %g2	! %g2 = iv->iv_pil
   1640 
   1641 	!
   1642 	! Insert intr_vec_t (iv) to appropriate cpu's softint priority list
   1643 	!
   1644 	sll	%g2, CPTRSHIFT, %g7	! %g7 = offset to pil entry
   1645 	add	%g4, INTR_TAIL, %g6	! %g6 = &cpu->m_cpu.intr_tail
   1646 	ldn	[%g6 + %g7], %g5	! %g5 = cpu->m_cpu.intr_tail[pil]
   1647 					!       current tail (ct)
   1648 	brz,pt	%g5, 1f			! branch if current tail is NULL
   1649 	stn	%g1, [%g6 + %g7]	! make intr_rec_t (iv) as new tail
   1650 	!
   1651 	! there's pending intr_vec_t already
   1652 	!
   1653 	lduh	[%g5 + IV_FLAGS], %g6	! %g6 = ct->iv_flags
   1654 	and	%g6, IV_SOFTINT_MT, %g6	! %g6 = ct->iv_flags & IV_SOFTINT_MT
   1655 	brz,pt	%g6, 0f			! check for Multi target softint flag
   1656 	add	%g5, IV_PIL_NEXT, %g3	! %g3 = &ct->iv_pil_next
   1657 	ld	[%g4 + CPU_ID], %g6	! for multi target softint, use cpuid
   1658 	sll	%g6, CPTRSHIFT, %g6	! calculate offset address from cpuid
   1659 	add	%g3, %g6, %g3		! %g3 = &ct->iv_xpil_next[cpuid]
   1660 0:
   1661 	!
   1662 	! update old tail
   1663 	!
   1664 	ba,pt	%xcc, 2f
   1665 	stn	%g1, [%g3]		! [%g3] = iv, set pil_next field
   1666 1:
   1667 	!
   1668 	! no pending intr_vec_t; make intr_vec_t as new head
   1669 	!
   1670 	add	%g4, INTR_HEAD, %g6	! %g6 = &cpu->m_cpu.intr_head[pil]
   1671 	stn	%g1, [%g6 + %g7]	! cpu->m_cpu.intr_head[pil] = iv
   1672 2:
   1673 #ifdef TRAPTRACE
   1674 	TRACE_PTR(%g5, %g6)
   1675 	GET_TRACE_TICK(%g6, %g3)
   1676 	stxa	%g6, [%g5 + TRAP_ENT_TICK]%asi	! trap_tick = %tick
   1677 	TRACE_SAVE_TL_GL_REGS(%g5, %g6)
   1678 	rdpr	%tt, %g6
   1679 	stha	%g6, [%g5 + TRAP_ENT_TT]%asi	! trap_type = %tt
   1680 	rdpr	%tpc, %g6
   1681 	stna	%g6, [%g5 + TRAP_ENT_TPC]%asi	! trap_pc = %tpc
   1682 	rdpr	%tstate, %g6
   1683 	stxa	%g6, [%g5 + TRAP_ENT_TSTATE]%asi ! trap_tstate = %tstate
   1684 	stna	%sp, [%g5 + TRAP_ENT_SP]%asi	! trap_sp = %sp
   1685 	stna	%g1, [%g5 + TRAP_ENT_TR]%asi	! trap_tr = iv
   1686 	ldn	[%g1 + IV_PIL_NEXT], %g6	!
   1687 	stna	%g6, [%g5 + TRAP_ENT_F1]%asi	! trap_f1 = iv->iv_pil_next
   1688 	add	%g4, INTR_HEAD, %g6
   1689 	ldn	[%g6 + %g7], %g6		! %g6=cpu->m_cpu.intr_head[pil]
   1690 	stna	%g6, [%g5 + TRAP_ENT_F2]%asi	! trap_f2 = intr_head[pil]
   1691 	add	%g4, INTR_TAIL, %g6
   1692 	ldn	[%g6 + %g7], %g6		! %g6=cpu->m_cpu.intr_tail[pil]
   1693 	stna	%g6, [%g5 + TRAP_ENT_F3]%asi	! trap_f3 = intr_tail[pil]
   1694 	stna	%g2, [%g5 + TRAP_ENT_F4]%asi	! trap_f4 = pil
   1695 	TRACE_NEXT(%g5, %g6, %g3)
   1696 #endif /* TRAPTRACE */
   1697 	!
   1698 	! Write %set_softint with (1<<pil) to cause a "pil" level trap
   1699 	!
   1700 	mov	1, %g5			! %g5 = 1
   1701 	sll	%g5, %g2, %g5		! %g5 = 1 << pil
   1702 	wr	%g5, SET_SOFTINT	! trigger required pil softint
   1703 	retry
   1704 	SET_SIZE(setsoftint_tl1)
   1705 
   1706 #endif	/* lint */
   1707 
   1708 #if defined(lint)
   1709 
   1710 /*ARGSUSED*/
   1711 void
   1712 setvecint_tl1(uint64_t inum, uint64_t dummy)
   1713 {}
   1714 
   1715 #else	/* lint */
   1716 
   1717 	!
   1718 	! Register usage
   1719 	!	Arguments:
   1720 	! 	%g1 - inumber
   1721 	!
   1722 	!	Internal:
   1723 	! 	%g1 - softint pil mask
   1724 	!	%g2 - pil of intr_vec_t
   1725 	!	%g3 - pointer to current intr_vec_t (iv)
   1726 	!	%g4 - cpu
   1727 	!	%g5, %g6,%g7 - temps
   1728 	!
   1729 	ENTRY_NP(setvecint_tl1)
   1730 	!
   1731 	! Verify the inumber received (should be inum < MAXIVNUM).
   1732 	!
   1733 	set	MAXIVNUM, %g2
   1734 	cmp	%g1, %g2
   1735 	bgeu,pn	%xcc, .no_ivintr
   1736 	clr	%g2			! expected in .no_ivintr
   1737 
   1738 	!
   1739 	! Fetch data from intr_vec_table according to the inum.
   1740 	!
   1741 	! We have an interrupt number. Fetch the interrupt vector requests
   1742 	! from the interrupt vector table for a given interrupt number and
   1743 	! insert them into cpu's softint priority lists and set %set_softint.
   1744 	!
   1745 	set	intr_vec_table, %g5	! %g5 = intr_vec_table
   1746 	sll	%g1, CPTRSHIFT, %g6	! %g6 = offset to inum entry in table
   1747 	add	%g5, %g6, %g5		! %g5 = &intr_vec_table[inum]
   1748 	ldn	[%g5], %g3		! %g3 = pointer to first entry of
   1749 					!       intr_vec_t list
   1750 
   1751 	! Verify the first intr_vec_t pointer for a given inum and it should
   1752 	! not be NULL. This used to be guarded by DEBUG but broken drivers can
   1753 	! cause spurious tick interrupts when the softint register is programmed
   1754 	! with 1 << 0 at the end of this routine. Now we always check for a
   1755 	! valid intr_vec_t pointer.
   1756 	brz,pn	%g3, .no_ivintr
   1757 	nop
   1758 
   1759 	!
   1760 	! Traverse the intr_vec_t link list, put each item on to corresponding
   1761 	! CPU softint priority queue, and compose the final softint pil mask.
   1762 	!
   1763 	! At this point:
   1764 	!	%g3 = intr_vec_table[inum]
   1765 	!
   1766 	CPU_ADDR(%g4, %g2)		! %g4 = cpu
   1767 	mov	%g0, %g1		! %g1 = 0, initialize pil mask to 0
   1768 0:
   1769 	!
   1770 	! Insert next intr_vec_t (iv) to appropriate cpu's softint priority list
   1771 	!
   1772 	! At this point:
   1773 	!	%g1 = softint pil mask
   1774 	!	%g3 = pointer to next intr_vec_t (iv)
   1775 	!	%g4 = cpu
   1776 	!
   1777 	lduh	[%g3 + IV_PIL], %g2	! %g2 = iv->iv_pil
   1778 	sll	%g2, CPTRSHIFT, %g7	! %g7 = offset to pil entry
   1779 	add	%g4, INTR_TAIL, %g6	! %g6 = &cpu->m_cpu.intr_tail
   1780 	ldn	[%g6 + %g7], %g5	! %g5 = cpu->m_cpu.intr_tail[pil]
   1781 					! 	current tail (ct)
   1782 	brz,pt	%g5, 2f			! branch if current tail is NULL
   1783 	stn	%g3, [%g6 + %g7]	! make intr_vec_t (iv) as new tail
   1784 					! cpu->m_cpu.intr_tail[pil] = iv
   1785 	!
   1786 	! there's pending intr_vec_t already
   1787 	!
   1788 	lduh	[%g5 + IV_FLAGS], %g6	! %g6 = ct->iv_flags
   1789 	and	%g6, IV_SOFTINT_MT, %g6	! %g6 = ct->iv_flags & IV_SOFTINT_MT
   1790 	brz,pt	%g6, 1f			! check for Multi target softint flag
   1791 	add	%g5, IV_PIL_NEXT, %g5	! %g5 = &ct->iv_pil_next
   1792 	ld	[%g4 + CPU_ID], %g6	! for multi target softint, use cpuid
   1793 	sll	%g6, CPTRSHIFT, %g6	! calculate offset address from cpuid
   1794 	add	%g5, %g6, %g5		! %g5 = &ct->iv_xpil_next[cpuid]
   1795 1:
   1796 	!
   1797 	! update old tail
   1798 	!
   1799 	ba,pt	%xcc, 3f
   1800 	stn	%g3, [%g5]		! [%g5] = iv, set pil_next field
   1801 2:
   1802 	!
   1803 	! no pending intr_vec_t; make intr_vec_t as new head
   1804 	!
   1805 	add	%g4, INTR_HEAD, %g6	!  %g6 = &cpu->m_cpu.intr_head[pil]
   1806 	stn	%g3, [%g6 + %g7]	!  cpu->m_cpu.intr_head[pil] = iv
   1807 3:
   1808 #ifdef TRAPTRACE
   1809 	TRACE_PTR(%g5, %g6)
   1810 	TRACE_SAVE_TL_GL_REGS(%g5, %g6)
   1811 	rdpr	%tt, %g6
   1812 	stha	%g6, [%g5 + TRAP_ENT_TT]%asi	! trap_type = %tt`
   1813 	rdpr	%tpc, %g6
   1814 	stna	%g6, [%g5 + TRAP_ENT_TPC]%asi	! trap_pc = %tpc
   1815 	rdpr	%tstate, %g6
   1816 	stxa	%g6, [%g5 + TRAP_ENT_TSTATE]%asi ! trap_tstate = %tstate
   1817 	stna	%sp, [%g5 + TRAP_ENT_SP]%asi	! trap_sp = %sp
   1818 	stna	%g3, [%g5 + TRAP_ENT_TR]%asi	! trap_tr = iv
   1819 	stna	%g1, [%g5 + TRAP_ENT_F1]%asi	! trap_f1 = pil mask
   1820 	add	%g4, INTR_HEAD, %g6
   1821 	ldn	[%g6 + %g7], %g6		! %g6=cpu->m_cpu.intr_head[pil]
   1822 	stna	%g6, [%g5 + TRAP_ENT_F2]%asi	! trap_f2 = intr_head[pil]
   1823 	add	%g4, INTR_TAIL, %g6
   1824 	ldn	[%g6 + %g7], %g6		! %g6=cpu->m_cpu.intr_tail[pil]
   1825 	stna	%g6, [%g5 + TRAP_ENT_F3]%asi	! trap_f3 = intr_tail[pil]
   1826 	stna	%g2, [%g5 + TRAP_ENT_F4]%asi	! trap_f4 = pil
   1827 	GET_TRACE_TICK(%g6, %g7)
   1828 	stxa	%g6, [%g5 + TRAP_ENT_TICK]%asi	! trap_tick = %tick
   1829 	TRACE_NEXT(%g5, %g6, %g7)
   1830 #endif /* TRAPTRACE */
   1831 	mov	1, %g6			! %g6 = 1
   1832 	sll	%g6, %g2, %g6		! %g6 = 1 << pil
   1833 	or	%g1, %g6, %g1		! %g1 |= (1 << pil), pil mask
   1834 	ldn	[%g3 + IV_VEC_NEXT], %g3 ! %g3 = pointer to next intr_vec_t (iv)
   1835 	brnz,pn	%g3, 0b			! iv->iv_vec_next is non NULL, goto 0b
   1836 	nop
   1837 	wr	%g1, SET_SOFTINT	! triggered one or more pil softints
   1838 	retry
   1839 
   1840 .no_ivintr:
   1841 	! no_ivintr: arguments: rp, inum (%g1), pil (%g2 == 0)
   1842 	mov	%g2, %g3
   1843 	mov	%g1, %g2
   1844 	set	no_ivintr, %g1
   1845 	ba,pt	%xcc, sys_trap
   1846 	mov	PIL_15, %g4
   1847 	SET_SIZE(setvecint_tl1)
   1848 
   1849 #endif	/* lint */
   1850 
   1851 #if defined(lint)
   1852 
   1853 /*ARGSUSED*/
   1854 void
   1855 wr_clr_softint(uint_t value)
   1856 {}
   1857 
   1858 #else
   1859 
   1860 	ENTRY_NP(wr_clr_softint)
   1861 	retl
   1862 	wr	%o0, CLEAR_SOFTINT
   1863 	SET_SIZE(wr_clr_softint)
   1864 
   1865 #endif /* lint */
   1866 
   1867 #if defined(lint)
   1868 
   1869 /*ARGSUSED*/
   1870 void
   1871 intr_enqueue_req(uint_t pil, uint64_t inum)
   1872 {}
   1873 
   1874 #else   /* lint */
   1875 
   1876 /*
   1877  * intr_enqueue_req
   1878  *
   1879  * %o0 - pil
   1880  * %o1 - pointer to intr_vec_t (iv)
   1881  * %o5 - preserved
   1882  * %g5 - preserved
   1883  */
   1884 	ENTRY_NP(intr_enqueue_req)
   1885 	!
   1886 	CPU_ADDR(%g4, %g1)		! %g4 = cpu
   1887 
   1888 	!
   1889 	! Insert intr_vec_t (iv) to appropriate cpu's softint priority list
   1890 	!
   1891 	sll	%o0, CPTRSHIFT, %o0	! %o0 = offset to pil entry
   1892 	add	%g4, INTR_TAIL, %g6	! %g6 = &cpu->m_cpu.intr_tail
   1893 	ldn	[%o0 + %g6], %g1	! %g1 = cpu->m_cpu.intr_tail[pil]
   1894 					!       current tail (ct)
   1895 	brz,pt	%g1, 2f			! branch if current tail is NULL
   1896 	stn	%o1, [%g6 + %o0]	! make intr_vec_t (iv) as new tail
   1897 
   1898 	!
   1899 	! there's pending intr_vec_t already
   1900 	!
   1901 	lduh	[%g1 + IV_FLAGS], %g6	! %g6 = ct->iv_flags
   1902 	and	%g6, IV_SOFTINT_MT, %g6	! %g6 = ct->iv_flags & IV_SOFTINT_MT
   1903 	brz,pt	%g6, 1f			! check for Multi target softint flag
   1904 	add	%g1, IV_PIL_NEXT, %g3	! %g3 = &ct->iv_pil_next
   1905 	ld	[%g4 + CPU_ID], %g6	! for multi target softint, use cpuid
   1906 	sll	%g6, CPTRSHIFT, %g6	! calculate offset address from cpuid
   1907 	add	%g3, %g6, %g3		! %g3 = &ct->iv_xpil_next[cpuid]
   1908 1:
   1909 	!
   1910 	! update old tail
   1911 	!
   1912 	ba,pt	%xcc, 3f
   1913 	stn	%o1, [%g3]		! {%g5] = iv, set pil_next field
   1914 2:
   1915 	!
   1916 	! no intr_vec_t's queued so make intr_vec_t as new head
   1917 	!
   1918 	add	%g4, INTR_HEAD, %g6	! %g6 = &cpu->m_cpu.intr_head[pil]
   1919 	stn	%o1, [%g6 + %o0]	! cpu->m_cpu.intr_head[pil] = iv
   1920 3:
   1921 	retl
   1922 	nop
   1923 	SET_SIZE(intr_enqueue_req)
   1924 
   1925 #endif  /* lint */
   1926 
   1927 /*
   1928  * Set CPU's base SPL level, based on which interrupt levels are active.
   1929  * 	Called at spl7 or above.
   1930  */
   1931 
   1932 #if defined(lint)
   1933 
   1934 void
   1935 set_base_spl(void)
   1936 {}
   1937 
   1938 #else	/* lint */
   1939 
   1940 	ENTRY_NP(set_base_spl)
   1941 	ldn	[THREAD_REG + T_CPU], %o2	! load CPU pointer
   1942 	ld	[%o2 + CPU_INTR_ACTV], %o5	! load active interrupts mask
   1943 
   1944 /*
   1945  * WARNING: non-standard callinq sequence; do not call from C
   1946  *	%o2 = pointer to CPU
   1947  *	%o5 = updated CPU_INTR_ACTV
   1948  */
   1949 _intr_set_spl:					! intr_thread_exit enters here
   1950 	!
   1951 	! Determine highest interrupt level active.  Several could be blocked
   1952 	! at higher levels than this one, so must convert flags to a PIL
   1953 	! Normally nothing will be blocked, so test this first.
   1954 	!
   1955 	brz,pt	%o5, 1f				! nothing active
   1956 	sra	%o5, 11, %o3			! delay - set %o3 to bits 15-11
   1957 	set	_intr_flag_table, %o1
   1958 	tst	%o3				! see if any of the bits set
   1959 	ldub	[%o1 + %o3], %o3		! load bit number
   1960 	bnz,a,pn %xcc, 1f			! yes, add 10 and we're done
   1961 	add	%o3, 11-1, %o3			! delay - add bit number - 1
   1962 
   1963 	sra	%o5, 6, %o3			! test bits 10-6
   1964 	tst	%o3
   1965 	ldub	[%o1 + %o3], %o3
   1966 	bnz,a,pn %xcc, 1f
   1967 	add	%o3, 6-1, %o3
   1968 
   1969 	sra	%o5, 1, %o3			! test bits 5-1
   1970 	ldub	[%o1 + %o3], %o3
   1971 
   1972 	!
   1973 	! highest interrupt level number active is in %l6
   1974 	!
   1975 1:
   1976 	retl
   1977 	st	%o3, [%o2 + CPU_BASE_SPL]	! delay - store base priority
   1978 	SET_SIZE(set_base_spl)
   1979 
   1980 /*
   1981  * Table that finds the most significant bit set in a five bit field.
   1982  * Each entry is the high-order bit number + 1 of it's index in the table.
   1983  * This read-only data is in the text segment.
   1984  */
   1985 _intr_flag_table:
   1986 	.byte	0, 1, 2, 2,	3, 3, 3, 3,	4, 4, 4, 4,	4, 4, 4, 4
   1987 	.byte	5, 5, 5, 5,	5, 5, 5, 5,	5, 5, 5, 5,	5, 5, 5, 5
   1988 	.align	4
   1989 
   1990 #endif	/* lint */
   1991 
   1992 /*
   1993  * int
   1994  * intr_passivate(from, to)
   1995  *	kthread_id_t	from;		interrupt thread
   1996  *	kthread_id_t	to;		interrupted thread
   1997  */
   1998 
   1999 #if defined(lint)
   2000 
   2001 /* ARGSUSED */
   2002 int
   2003 intr_passivate(kthread_id_t from, kthread_id_t to)
   2004 { return (0); }
   2005 
   2006 #else	/* lint */
   2007 
   2008 	ENTRY_NP(intr_passivate)
   2009 	save	%sp, -SA(MINFRAME), %sp	! get a new window
   2010 
   2011 	flushw				! force register windows to stack
   2012 	!
   2013 	! restore registers from the base of the stack of the interrupt thread.
   2014 	!
   2015 	ldn	[%i0 + T_STACK], %i2	! get stack save area pointer
   2016 	ldn	[%i2 + (0*GREGSIZE)], %l0	! load locals
   2017 	ldn	[%i2 + (1*GREGSIZE)], %l1
   2018 	ldn	[%i2 + (2*GREGSIZE)], %l2
   2019 	ldn	[%i2 + (3*GREGSIZE)], %l3
   2020 	ldn	[%i2 + (4*GREGSIZE)], %l4
   2021 	ldn	[%i2 + (5*GREGSIZE)], %l5
   2022 	ldn	[%i2 + (6*GREGSIZE)], %l6
   2023 	ldn	[%i2 + (7*GREGSIZE)], %l7
   2024 	ldn	[%i2 + (8*GREGSIZE)], %o0	! put ins from stack in outs
   2025 	ldn	[%i2 + (9*GREGSIZE)], %o1
   2026 	ldn	[%i2 + (10*GREGSIZE)], %o2
   2027 	ldn	[%i2 + (11*GREGSIZE)], %o3
   2028 	ldn	[%i2 + (12*GREGSIZE)], %o4
   2029 	ldn	[%i2 + (13*GREGSIZE)], %o5
   2030 	ldn	[%i2 + (14*GREGSIZE)], %i4
   2031 					! copy stack/pointer without using %sp
   2032 	ldn	[%i2 + (15*GREGSIZE)], %i5
   2033 	!
   2034 	! put registers into the save area at the top of the interrupted
   2035 	! thread's stack, pointed to by %l7 in the save area just loaded.
   2036 	!
   2037 	ldn	[%i1 + T_SP], %i3	! get stack save area pointer
   2038 	stn	%l0, [%i3 + STACK_BIAS + (0*GREGSIZE)]	! save locals
   2039 	stn	%l1, [%i3 + STACK_BIAS + (1*GREGSIZE)]
   2040 	stn	%l2, [%i3 + STACK_BIAS + (2*GREGSIZE)]
   2041 	stn	%l3, [%i3 + STACK_BIAS + (3*GREGSIZE)]
   2042 	stn	%l4, [%i3 + STACK_BIAS + (4*GREGSIZE)]
   2043 	stn	%l5, [%i3 + STACK_BIAS + (5*GREGSIZE)]
   2044 	stn	%l6, [%i3 + STACK_BIAS + (6*GREGSIZE)]
   2045 	stn	%l7, [%i3 + STACK_BIAS + (7*GREGSIZE)]
   2046 	stn	%o0, [%i3 + STACK_BIAS + (8*GREGSIZE)]	! save ins using outs
   2047 	stn	%o1, [%i3 + STACK_BIAS + (9*GREGSIZE)]
   2048 	stn	%o2, [%i3 + STACK_BIAS + (10*GREGSIZE)]
   2049 	stn	%o3, [%i3 + STACK_BIAS + (11*GREGSIZE)]
   2050 	stn	%o4, [%i3 + STACK_BIAS + (12*GREGSIZE)]
   2051 	stn	%o5, [%i3 + STACK_BIAS + (13*GREGSIZE)]
   2052 	stn	%i4, [%i3 + STACK_BIAS + (14*GREGSIZE)]
   2053 						! fp, %i7 copied using %i4
   2054 	stn	%i5, [%i3 + STACK_BIAS + (15*GREGSIZE)]
   2055 	stn	%g0, [%i2 + ((8+6)*GREGSIZE)]
   2056 						! clear fp in save area
   2057 
   2058 	! load saved pil for return
   2059 	ldub	[%i0 + T_PIL], %i0
   2060 	ret
   2061 	restore
   2062 	SET_SIZE(intr_passivate)
   2063 
   2064 #endif	/* lint */
   2065 
   2066 #if defined(lint)
   2067 
   2068 /*
   2069  * intr_get_time() is a resource for interrupt handlers to determine how
   2070  * much time has been spent handling the current interrupt. Such a function
   2071  * is needed because higher level interrupts can arrive during the
   2072  * processing of an interrupt, thus making direct comparisons of %tick by
   2073  * the handler inaccurate. intr_get_time() only returns time spent in the
   2074  * current interrupt handler.
   2075  *
   2076  * The caller must be calling from an interrupt handler running at a pil
   2077  * below or at lock level. Timings are not provided for high-level
   2078  * interrupts.
   2079  *
   2080  * The first time intr_get_time() is called while handling an interrupt,
   2081  * it returns the time since the interrupt handler was invoked. Subsequent
   2082  * calls will return the time since the prior call to intr_get_time(). Time
   2083  * is returned as ticks, adjusted for any clock divisor due to power
   2084  * management. Use tick2ns() to convert ticks to nsec. Warning: ticks may
   2085  * not be the same across CPUs.
   2086  *
   2087  * Theory Of Intrstat[][]:
   2088  *
   2089  * uint64_t intrstat[pil][0..1] is an array indexed by pil level, with two
   2090  * uint64_ts per pil.
   2091  *
   2092  * intrstat[pil][0] is a cumulative count of the number of ticks spent
   2093  * handling all interrupts at the specified pil on this CPU. It is
   2094  * exported via kstats to the user.
   2095  *
   2096  * intrstat[pil][1] is always a count of ticks less than or equal to the
   2097  * value in [0]. The difference between [1] and [0] is the value returned
   2098  * by a call to intr_get_time(). At the start of interrupt processing,
   2099  * [0] and [1] will be equal (or nearly so). As the interrupt consumes
   2100  * time, [0] will increase, but [1] will remain the same. A call to
   2101  * intr_get_time() will return the difference, then update [1] to be the
   2102  * same as [0]. Future calls will return the time since the last call.
   2103  * Finally, when the interrupt completes, [1] is updated to the same as [0].
   2104  *
   2105  * Implementation:
   2106  *
   2107  * intr_get_time() works much like a higher level interrupt arriving. It
   2108  * "checkpoints" the timing information by incrementing intrstat[pil][0]
   2109  * to include elapsed running time, and by setting t_intr_start to %tick.
   2110  * It then sets the return value to intrstat[pil][0] - intrstat[pil][1],
   2111  * and updates intrstat[pil][1] to be the same as the new value of
   2112  * intrstat[pil][0].
   2113  *
   2114  * In the normal handling of interrupts, after an interrupt handler returns
   2115  * and the code in intr_thread() updates intrstat[pil][0], it then sets
   2116  * intrstat[pil][1] to the new value of intrstat[pil][0]. When [0] == [1],
   2117  * the timings are reset, i.e. intr_get_time() will return [0] - [1] which
   2118  * is 0.
   2119  *
   2120  * Whenever interrupts arrive on a CPU which is handling a lower pil
   2121  * interrupt, they update the lower pil's [0] to show time spent in the
   2122  * handler that they've interrupted. This results in a growing discrepancy
   2123  * between [0] and [1], which is returned the next time intr_get_time() is
   2124  * called. Time spent in the higher-pil interrupt will not be returned in
   2125  * the next intr_get_time() call from the original interrupt, because
   2126  * the higher-pil interrupt's time is accumulated in intrstat[higherpil][].
   2127  */
   2128 
   2129 /*ARGSUSED*/
   2130 uint64_t
   2131 intr_get_time(void)
   2132 { return 0; }
   2133 #else	/* lint */
   2134 
   2135 	ENTRY_NP(intr_get_time)
   2136 #ifdef DEBUG
   2137 	!
   2138 	! Lots of asserts, but just check panic_quiesce first.
   2139 	! Don't bother with lots of tests if we're just ignoring them.
   2140 	!
   2141 	sethi	%hi(panic_quiesce), %o0
   2142 	ld	[%o0 + %lo(panic_quiesce)], %o0
   2143 	brnz,pn	%o0, 2f
   2144 	nop
   2145 	!
   2146 	! ASSERT(%pil <= LOCK_LEVEL)
   2147 	!
   2148 	rdpr	%pil, %o1
   2149 	cmp	%o1, LOCK_LEVEL
   2150 	ble,pt	%xcc, 0f
   2151 	sethi	%hi(intr_get_time_high_pil), %o0	! delay
   2152 	call	panic
   2153 	or	%o0, %lo(intr_get_time_high_pil), %o0
   2154 0:
   2155 	!
   2156 	! ASSERT((t_flags & T_INTR_THREAD) != 0 && t_pil > 0)
   2157 	!
   2158 	lduh	[THREAD_REG + T_FLAGS], %o2
   2159 	andcc	%o2, T_INTR_THREAD, %g0
   2160 	bz,pn	%xcc, 1f
   2161 	ldub	[THREAD_REG + T_PIL], %o1		! delay
   2162 	brnz,pt	%o1, 0f
   2163 1:
   2164 	sethi	%hi(intr_get_time_not_intr), %o0
   2165 	call	panic
   2166 	or	%o0, %lo(intr_get_time_not_intr), %o0
   2167 0:
   2168 	!
   2169 	! ASSERT(t_intr_start != 0)
   2170 	!
   2171 	ldx	[THREAD_REG + T_INTR_START], %o1
   2172 	brnz,pt	%o1, 2f
   2173 	sethi	%hi(intr_get_time_no_start_time), %o0	! delay
   2174 	call	panic
   2175 	or	%o0, %lo(intr_get_time_no_start_time), %o0
   2176 2:
   2177 #endif /* DEBUG */
   2178 	!
   2179 	! %o0 = elapsed time and return value
   2180 	! %o1 = pil
   2181 	! %o2 = scratch
   2182 	! %o3 = scratch
   2183 	! %o4 = scratch
   2184 	! %o5 = cpu
   2185 	!
   2186 	wrpr	%g0, PIL_MAX, %pil	! make this easy -- block normal intrs
   2187 	ldn	[THREAD_REG + T_CPU], %o5
   2188 	ldub	[THREAD_REG + T_PIL], %o1
   2189 	ldx	[THREAD_REG + T_INTR_START], %o3 ! %o3 = t_intr_start
   2190 	!
   2191 	! Calculate elapsed time since t_intr_start. Update t_intr_start,
   2192 	! get delta, and multiply by cpu_divisor if necessary.
   2193 	!
   2194 	RD_TICK_NO_SUSPEND_CHECK(%o2, %o0)
   2195 	stx	%o2, [THREAD_REG + T_INTR_START]
   2196 	sub	%o2, %o3, %o0
   2197 
   2198 	lduh	[%o5 + CPU_DIVISOR], %o4
   2199 	cmp	%o4, 1
   2200 	bg,a,pn	%xcc, 1f
   2201 	mulx	%o0, %o4, %o0	! multiply interval by clock divisor iff > 1
   2202 1:
   2203 	! Update intracct[]
   2204 	lduh	[%o5 + CPU_MSTATE], %o4
   2205 	sllx	%o4, 3, %o4
   2206 	add	%o4, CPU_INTRACCT, %o4
   2207 	ldx	[%o5 + %o4], %o2
   2208 	add	%o2, %o0, %o2
   2209 	stx	%o2, [%o5 + %o4]
   2210 
   2211 	!
   2212 	! Increment cpu_m.intrstat[pil][0]. Calculate elapsed time since
   2213 	! cpu_m.intrstat[pil][1], which is either when the interrupt was
   2214 	! first entered, or the last time intr_get_time() was invoked. Then
   2215 	! update cpu_m.intrstat[pil][1] to match [0].
   2216 	!
   2217 	sllx	%o1, 4, %o3
   2218 	add	%o3, CPU_MCPU, %o3
   2219 	add	%o3, MCPU_INTRSTAT, %o3
   2220 	add	%o3, %o5, %o3		! %o3 = cpu_m.intrstat[pil][0]
   2221 	ldx	[%o3], %o2
   2222 	add	%o2, %o0, %o2		! %o2 = new value for intrstat
   2223 	stx	%o2, [%o3]
   2224 	ldx	[%o3 + 8], %o4		! %o4 = cpu_m.intrstat[pil][1]
   2225 	sub	%o2, %o4, %o0		! %o0 is elapsed time since %o4
   2226 	stx	%o2, [%o3 + 8]		! make [1] match [0], resetting time
   2227 
   2228 	ld	[%o5 + CPU_BASE_SPL], %o2	! restore %pil to the greater
   2229 	cmp	%o2, %o1			! of either our pil %o1 or
   2230 	movl	%xcc, %o1, %o2			! cpu_base_spl.
   2231 	retl
   2232 	wrpr	%g0, %o2, %pil
   2233 	SET_SIZE(intr_get_time)
   2234 
   2235 #ifdef DEBUG
   2236 intr_get_time_high_pil:
   2237 	.asciz	"intr_get_time(): %pil > LOCK_LEVEL"
   2238 intr_get_time_not_intr:
   2239 	.asciz	"intr_get_time(): not called from an interrupt thread"
   2240 intr_get_time_no_start_time:
   2241 	.asciz	"intr_get_time(): t_intr_start == 0"
   2242 #endif /* DEBUG */
   2243 #endif  /* lint */
   2244