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