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