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