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