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 */