17c478bd9Sstevel@tonic-gate/* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 525cf1a30Sjl139090 * Common Development and Distribution License (the "License"). 625cf1a30Sjl139090 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate/* 2225cf1a30Sjl139090 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate#pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate#if defined(lint) 297c478bd9Sstevel@tonic-gate#include <sys/types.h> 307c478bd9Sstevel@tonic-gate#include <sys/thread.h> 317c478bd9Sstevel@tonic-gate#else /* lint */ 327c478bd9Sstevel@tonic-gate#include "assym.h" 337c478bd9Sstevel@tonic-gate#endif /* lint */ 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate#include <sys/cmn_err.h> 367c478bd9Sstevel@tonic-gate#include <sys/ftrace.h> 377c478bd9Sstevel@tonic-gate#include <sys/asm_linkage.h> 387c478bd9Sstevel@tonic-gate#include <sys/machthread.h> 397c478bd9Sstevel@tonic-gate#include <sys/machcpuvar.h> 407c478bd9Sstevel@tonic-gate#include <sys/intreg.h> 41*b0fc0e77Sgovinda#include <sys/ivintr.h> 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE 447c478bd9Sstevel@tonic-gate#include <sys/traptrace.h> 457c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */ 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate#if defined(lint) 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate/* ARGSUSED */ 507c478bd9Sstevel@tonic-gatevoid 517c478bd9Sstevel@tonic-gatepil_interrupt(int level) 527c478bd9Sstevel@tonic-gate{} 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate#else /* lint */ 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate/* 587c478bd9Sstevel@tonic-gate * (TT 0x40..0x4F, TL>0) Interrupt Level N Handler (N == 1..15) 597c478bd9Sstevel@tonic-gate * Register passed from LEVEL_INTERRUPT(level) 607c478bd9Sstevel@tonic-gate * %g4 - interrupt request level 617c478bd9Sstevel@tonic-gate */ 627c478bd9Sstevel@tonic-gate ENTRY_NP(pil_interrupt) 637c478bd9Sstevel@tonic-gate ! 647c478bd9Sstevel@tonic-gate ! Register usage 657c478bd9Sstevel@tonic-gate ! %g1 - cpu 66*b0fc0e77Sgovinda ! %g2 - pointer to intr_vec_t (iv) 677c478bd9Sstevel@tonic-gate ! %g4 - pil 68*b0fc0e77Sgovinda ! %g3, %g5, %g6, %g7 - temps 697c478bd9Sstevel@tonic-gate ! 70*b0fc0e77Sgovinda ! Grab the first or list head intr_vec_t off the intr_head[pil] 71*b0fc0e77Sgovinda ! and panic immediately if list head is NULL. Otherwise, update 72*b0fc0e77Sgovinda ! intr_head[pil] to next intr_vec_t on the list and clear softint 73*b0fc0e77Sgovinda ! %clear_softint, if next intr_vec_t is NULL. 747c478bd9Sstevel@tonic-gate ! 75*b0fc0e77Sgovinda CPU_ADDR(%g1, %g5) ! %g1 = cpu 767c478bd9Sstevel@tonic-gate ! 777c478bd9Sstevel@tonic-gate ALTENTRY(pil_interrupt_common) 78*b0fc0e77Sgovinda sll %g4, CPTRSHIFT, %g5 ! %g5 = offset to the pil entry 79*b0fc0e77Sgovinda add %g1, INTR_HEAD, %g6 ! %g6 = &cpu->m_cpu.intr_head 80*b0fc0e77Sgovinda add %g6, %g5, %g6 ! %g6 = &cpu->m_cpu.intr_head[pil] 81*b0fc0e77Sgovinda ldn [%g6], %g2 ! %g2 = cpu->m_cpu.intr_head[pil] 82*b0fc0e77Sgovinda brnz,pt %g2, 0f ! check list head (iv) is NULL 837c478bd9Sstevel@tonic-gate nop 84*b0fc0e77Sgovinda ba ptl1_panic ! panic, list head (iv) is NULL 85*b0fc0e77Sgovinda mov PTL1_BAD_INTR_VEC, %g1 86*b0fc0e77Sgovinda0: 87*b0fc0e77Sgovinda lduh [%g2 + IV_FLAGS], %g7 ! %g7 = iv->iv_flags 88*b0fc0e77Sgovinda and %g7, IV_SOFTINT_MT, %g3 ! %g3 = iv->iv_flags & IV_SOFTINT_MT 89*b0fc0e77Sgovinda brz,pt %g3, 1f ! check for multi target softint 90*b0fc0e77Sgovinda add %g2, IV_PIL_NEXT, %g7 ! g7% = &iv->iv_pil_next 91*b0fc0e77Sgovinda ld [%g1 + CPU_ID], %g3 ! for multi target softint, use cpuid 92*b0fc0e77Sgovinda sll %g3, CPTRSHIFT, %g3 ! convert cpuid to offset address 93*b0fc0e77Sgovinda add %g7, %g3, %g7 ! %g5 = &iv->iv_xpil_next[cpuid] 947c478bd9Sstevel@tonic-gate1: 95*b0fc0e77Sgovinda ldn [%g7], %g3 ! %g3 = next intr_vec_t 96*b0fc0e77Sgovinda brnz,pn %g3, 2f ! branch if next intr_vec_t non NULL 97*b0fc0e77Sgovinda stn %g3, [%g6] ! update cpu->m_cpu.intr_head[pil] 98*b0fc0e77Sgovinda add %g1, INTR_TAIL, %g6 ! %g6 = &cpu->m_cpu.intr_tail 99*b0fc0e77Sgovinda stn %g0, [%g5 + %g6] ! clear cpu->m_cpu.intr_tail[pil] 100*b0fc0e77Sgovinda mov 1, %g5 ! %g5 = 1 101*b0fc0e77Sgovinda sll %g5, %g4, %g5 ! %g5 = 1 << pil 102*b0fc0e77Sgovinda wr %g5, CLEAR_SOFTINT ! clear interrupt on this pil 103*b0fc0e77Sgovinda2: 1047c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE 1057c478bd9Sstevel@tonic-gate TRACE_PTR(%g5, %g6) 1067c478bd9Sstevel@tonic-gate GET_TRACE_TICK(%g6) 107*b0fc0e77Sgovinda stxa %g6, [%g5 + TRAP_ENT_TICK]%asi ! trap_tick = %tick 1087c478bd9Sstevel@tonic-gate TRACE_SAVE_TL_GL_REGS(%g5, %g6) 1097c478bd9Sstevel@tonic-gate rdpr %tt, %g6 110*b0fc0e77Sgovinda stha %g6, [%g5 + TRAP_ENT_TT]%asi ! trap_type = %tt 1117c478bd9Sstevel@tonic-gate rdpr %tpc, %g6 112*b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_TPC]%asi ! trap_pc = %tpc 1137c478bd9Sstevel@tonic-gate rdpr %tstate, %g6 114*b0fc0e77Sgovinda stxa %g6, [%g5 + TRAP_ENT_TSTATE]%asi ! trap_tstate = %tstate 115*b0fc0e77Sgovinda stna %sp, [%g5 + TRAP_ENT_SP]%asi ! trap_sp = %sp 116*b0fc0e77Sgovinda stna %g2, [%g5 + TRAP_ENT_TR]%asi ! trap_tr = first intr_vec 117*b0fc0e77Sgovinda stna %g3, [%g5 + TRAP_ENT_F1]%asi ! trap_f1 = next intr_vec 1187c478bd9Sstevel@tonic-gate sll %g4, CPTRSHIFT, %g3 1197c478bd9Sstevel@tonic-gate add %g1, INTR_HEAD, %g6 120*b0fc0e77Sgovinda ldn [%g6 + %g3], %g6 ! %g6=cpu->m_cpu.intr_head[pil] 121*b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_F2]%asi ! trap_f2 = intr_head[pil] 1227c478bd9Sstevel@tonic-gate add %g1, INTR_TAIL, %g6 123*b0fc0e77Sgovinda ldn [%g6 + %g3], %g6 ! %g6=cpu->m_cpu.intr_tail[pil] 124*b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_F3]%asi ! trap_f3 = intr_tail[pil] 125*b0fc0e77Sgovinda stna %g4, [%g5 + TRAP_ENT_F4]%asi ! trap_f4 = pil 1267c478bd9Sstevel@tonic-gate TRACE_NEXT(%g5, %g6, %g3) 1277c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */ 1287c478bd9Sstevel@tonic-gate ! 129*b0fc0e77Sgovinda ! clear the iv_pending flag for this interrupt request 1307c478bd9Sstevel@tonic-gate ! 131*b0fc0e77Sgovinda lduh [%g2 + IV_FLAGS], %g3 ! %g3 = iv->iv_flags 132*b0fc0e77Sgovinda andn %g3, IV_SOFTINT_PEND, %g3 ! %g3 = !(iv->iv_flags & PEND) 133*b0fc0e77Sgovinda sth %g3, [%g2 + IV_FLAGS] ! clear IV_SOFTINT_PEND flag 134*b0fc0e77Sgovinda stn %g0, [%g7] ! clear iv->iv_pil_next or 135*b0fc0e77Sgovinda ! iv->iv_pil_xnext 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate ! 1387c478bd9Sstevel@tonic-gate ! Prepare for sys_trap() 1397c478bd9Sstevel@tonic-gate ! 1407c478bd9Sstevel@tonic-gate ! Registers passed to sys_trap() 1417c478bd9Sstevel@tonic-gate ! %g1 - interrupt handler at TL==0 142*b0fc0e77Sgovinda ! %g2 - pointer to current intr_vec_t (iv), 143*b0fc0e77Sgovinda ! job queue for intr_thread or current_thread 1447c478bd9Sstevel@tonic-gate ! %g3 - pil 1457c478bd9Sstevel@tonic-gate ! %g4 - initial pil for handler 1467c478bd9Sstevel@tonic-gate ! 1477c478bd9Sstevel@tonic-gate ! figure which handler to run and which %pil it starts at 1487c478bd9Sstevel@tonic-gate ! intr_thread starts at DISP_LEVEL to prevent preemption 1497c478bd9Sstevel@tonic-gate ! current_thread starts at PIL_MAX to protect cpu_intr_actv 1507c478bd9Sstevel@tonic-gate ! 151*b0fc0e77Sgovinda mov %g4, %g3 ! %g3 = %g4, pil 1527c478bd9Sstevel@tonic-gate cmp %g4, LOCK_LEVEL 153*b0fc0e77Sgovinda bg,a,pt %xcc, 3f ! branch if pil > LOCK_LEVEL 154*b0fc0e77Sgovinda mov PIL_MAX, %g4 ! %g4 = PIL_MAX (15) 155*b0fc0e77Sgovinda sethi %hi(intr_thread), %g1 ! %g1 = intr_thread 156*b0fc0e77Sgovinda mov DISP_LEVEL, %g4 ! %g4 = DISP_LEVEL (11) 1577c478bd9Sstevel@tonic-gate ba,pt %xcc, sys_trap 1587c478bd9Sstevel@tonic-gate or %g1, %lo(intr_thread), %g1 159*b0fc0e77Sgovinda3: 160*b0fc0e77Sgovinda sethi %hi(current_thread), %g1 ! %g1 = current_thread 1617c478bd9Sstevel@tonic-gate ba,pt %xcc, sys_trap 1627c478bd9Sstevel@tonic-gate or %g1, %lo(current_thread), %g1 1637c478bd9Sstevel@tonic-gate SET_SIZE(pil_interrupt_common) 1647c478bd9Sstevel@tonic-gate SET_SIZE(pil_interrupt) 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate#endif /* lint */ 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate#ifndef lint 1707c478bd9Sstevel@tonic-gate_spurious: 1717c478bd9Sstevel@tonic-gate .asciz "!interrupt 0x%x at level %d not serviced" 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate/* 1747c478bd9Sstevel@tonic-gate * SERVE_INTR_PRE is called once, just before the first invocation 1757c478bd9Sstevel@tonic-gate * of SERVE_INTR. 1767c478bd9Sstevel@tonic-gate * 1777c478bd9Sstevel@tonic-gate * Registers on entry: 1787c478bd9Sstevel@tonic-gate * 179*b0fc0e77Sgovinda * iv_p, cpu, regs: may be out-registers 1807c478bd9Sstevel@tonic-gate * ls1, ls2: local scratch registers 1817c478bd9Sstevel@tonic-gate * os1, os2, os3: scratch registers, may be out 1827c478bd9Sstevel@tonic-gate */ 1837c478bd9Sstevel@tonic-gate 184*b0fc0e77Sgovinda#define SERVE_INTR_PRE(iv_p, cpu, ls1, ls2, os1, os2, os3, regs) \ 185*b0fc0e77Sgovinda mov iv_p, ls1; \ 186*b0fc0e77Sgovinda mov iv_p, ls2; \ 187*b0fc0e77Sgovinda SERVE_INTR_TRACE(iv_p, os1, os2, os3, regs); 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate/* 1907c478bd9Sstevel@tonic-gate * SERVE_INTR is called immediately after either SERVE_INTR_PRE or 1917c478bd9Sstevel@tonic-gate * SERVE_INTR_NEXT, without intervening code. No register values 1927c478bd9Sstevel@tonic-gate * may be modified. 1937c478bd9Sstevel@tonic-gate * 1947c478bd9Sstevel@tonic-gate * After calling SERVE_INTR, the caller must check if os3 is set. If 1957c478bd9Sstevel@tonic-gate * so, there is another interrupt to process. The caller must call 1967c478bd9Sstevel@tonic-gate * SERVE_INTR_NEXT, immediately followed by SERVE_INTR. 1977c478bd9Sstevel@tonic-gate * 1987c478bd9Sstevel@tonic-gate * Before calling SERVE_INTR_NEXT, the caller may perform accounting 1997c478bd9Sstevel@tonic-gate * and other actions which need to occur after invocation of an interrupt 2007c478bd9Sstevel@tonic-gate * handler. However, the values of ls1 and os3 *must* be preserved and 2017c478bd9Sstevel@tonic-gate * passed unmodified into SERVE_INTR_NEXT. 2027c478bd9Sstevel@tonic-gate * 2037c478bd9Sstevel@tonic-gate * Registers on return from SERVE_INTR: 2047c478bd9Sstevel@tonic-gate * 2057c478bd9Sstevel@tonic-gate * ls1 - the pil just processed 206*b0fc0e77Sgovinda * ls2 - the pointer to intr_vec_t (iv) just processed 2077c478bd9Sstevel@tonic-gate * os3 - if set, another interrupt needs to be processed 2087c478bd9Sstevel@tonic-gate * cpu, ls1, os3 - must be preserved if os3 is set 2097c478bd9Sstevel@tonic-gate */ 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate#define SERVE_INTR(os5, cpu, ls1, ls2, os1, os2, os3, os4) \ 2127c478bd9Sstevel@tonic-gate ldn [ls1 + IV_HANDLER], os2; \ 213*b0fc0e77Sgovinda ldn [ls1 + IV_ARG1], %o0; \ 214*b0fc0e77Sgovinda ldn [ls1 + IV_ARG2], %o1; \ 2157c478bd9Sstevel@tonic-gate call os2; \ 2167c478bd9Sstevel@tonic-gate lduh [ls1 + IV_PIL], ls1; \ 2177c478bd9Sstevel@tonic-gate brnz,pt %o0, 2f; \ 2187c478bd9Sstevel@tonic-gate mov CE_WARN, %o0; \ 2197c478bd9Sstevel@tonic-gate set _spurious, %o1; \ 2207c478bd9Sstevel@tonic-gate mov ls2, %o2; \ 2217c478bd9Sstevel@tonic-gate call cmn_err; \ 2227c478bd9Sstevel@tonic-gate rdpr %pil, %o3; \ 2237c478bd9Sstevel@tonic-gate2: ldn [THREAD_REG + T_CPU], cpu; \ 2247c478bd9Sstevel@tonic-gate sll ls1, 3, os1; \ 2257c478bd9Sstevel@tonic-gate add os1, CPU_STATS_SYS_INTR - 8, os2; \ 2267c478bd9Sstevel@tonic-gate ldx [cpu + os2], os3; \ 2277c478bd9Sstevel@tonic-gate inc os3; \ 2287c478bd9Sstevel@tonic-gate stx os3, [cpu + os2]; \ 2297c478bd9Sstevel@tonic-gate sll ls1, CPTRSHIFT, os2; \ 2307c478bd9Sstevel@tonic-gate add cpu, INTR_HEAD, os1; \ 2317c478bd9Sstevel@tonic-gate add os1, os2, os1; \ 2327c478bd9Sstevel@tonic-gate ldn [os1], os3; 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate/* 2357c478bd9Sstevel@tonic-gate * Registers on entry: 2367c478bd9Sstevel@tonic-gate * 2377c478bd9Sstevel@tonic-gate * cpu - cpu pointer (clobbered, set to cpu upon completion) 2387c478bd9Sstevel@tonic-gate * ls1, os3 - preserved from prior call to SERVE_INTR 2397c478bd9Sstevel@tonic-gate * ls2 - local scratch reg (not preserved) 2407c478bd9Sstevel@tonic-gate * os1, os2, os4, os5 - scratch reg, can be out (not preserved) 2417c478bd9Sstevel@tonic-gate */ 2427c478bd9Sstevel@tonic-gate#define SERVE_INTR_NEXT(os5, cpu, ls1, ls2, os1, os2, os3, os4) \ 2437c478bd9Sstevel@tonic-gate sll ls1, CPTRSHIFT, os4; \ 2447c478bd9Sstevel@tonic-gate add cpu, INTR_HEAD, os1; \ 2457c478bd9Sstevel@tonic-gate rdpr %pstate, ls2; \ 2467c478bd9Sstevel@tonic-gate wrpr ls2, PSTATE_IE, %pstate; \ 247*b0fc0e77Sgovinda lduh [os3 + IV_FLAGS], os2; \ 248*b0fc0e77Sgovinda and os2, IV_SOFTINT_MT, os2; \ 249*b0fc0e77Sgovinda brz,pt os2, 4f; \ 250*b0fc0e77Sgovinda add os3, IV_PIL_NEXT, os2; \ 251*b0fc0e77Sgovinda ld [cpu + CPU_ID], os5; \ 252*b0fc0e77Sgovinda sll os5, CPTRSHIFT, os5; \ 253*b0fc0e77Sgovinda add os2, os5, os2; \ 254*b0fc0e77Sgovinda4: ldn [os2], os5; \ 255*b0fc0e77Sgovinda brnz,pn os5, 5f; \ 256*b0fc0e77Sgovinda stn os5, [os1 + os4]; \ 2577c478bd9Sstevel@tonic-gate add cpu, INTR_TAIL, os1; \ 2587c478bd9Sstevel@tonic-gate stn %g0, [os1 + os4]; \ 2597c478bd9Sstevel@tonic-gate mov 1, os1; \ 2607c478bd9Sstevel@tonic-gate sll os1, ls1, os1; \ 2617c478bd9Sstevel@tonic-gate wr os1, CLEAR_SOFTINT; \ 262*b0fc0e77Sgovinda5: lduh [os3 + IV_FLAGS], ls1; \ 263*b0fc0e77Sgovinda andn ls1, IV_SOFTINT_PEND, ls1; \ 264*b0fc0e77Sgovinda sth ls1, [os3 + IV_FLAGS]; \ 265*b0fc0e77Sgovinda stn %g0, [os2]; \ 2667c478bd9Sstevel@tonic-gate wrpr %g0, ls2, %pstate; \ 267*b0fc0e77Sgovinda mov os3, ls1; \ 268*b0fc0e77Sgovinda mov os3, ls2; \ 269*b0fc0e77Sgovinda SERVE_INTR_TRACE2(os5, os1, os2, os3, os4); 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE 2727c478bd9Sstevel@tonic-gate/* 2737c478bd9Sstevel@tonic-gate * inum - not modified, _spurious depends on it. 2747c478bd9Sstevel@tonic-gate */ 2757c478bd9Sstevel@tonic-gate#define SERVE_INTR_TRACE(inum, os1, os2, os3, os4) \ 2767c478bd9Sstevel@tonic-gate rdpr %pstate, os3; \ 2777c478bd9Sstevel@tonic-gate andn os3, PSTATE_IE | PSTATE_AM, os2; \ 2787c478bd9Sstevel@tonic-gate wrpr %g0, os2, %pstate; \ 2797c478bd9Sstevel@tonic-gate TRACE_PTR(os1, os2); \ 2807c478bd9Sstevel@tonic-gate ldn [os4 + PC_OFF], os2; \ 2817c478bd9Sstevel@tonic-gate stna os2, [os1 + TRAP_ENT_TPC]%asi; \ 2827c478bd9Sstevel@tonic-gate ldx [os4 + TSTATE_OFF], os2; \ 2837c478bd9Sstevel@tonic-gate stxa os2, [os1 + TRAP_ENT_TSTATE]%asi; \ 2847c478bd9Sstevel@tonic-gate mov os3, os4; \ 2857c478bd9Sstevel@tonic-gate GET_TRACE_TICK(os2); \ 2867c478bd9Sstevel@tonic-gate stxa os2, [os1 + TRAP_ENT_TICK]%asi; \ 2877c478bd9Sstevel@tonic-gate TRACE_SAVE_TL_GL_REGS(os1, os2); \ 2887c478bd9Sstevel@tonic-gate set TT_SERVE_INTR, os2; \ 2897c478bd9Sstevel@tonic-gate rdpr %pil, os3; \ 2907c478bd9Sstevel@tonic-gate or os2, os3, os2; \ 2917c478bd9Sstevel@tonic-gate stha os2, [os1 + TRAP_ENT_TT]%asi; \ 2927c478bd9Sstevel@tonic-gate stna %sp, [os1 + TRAP_ENT_SP]%asi; \ 2937c478bd9Sstevel@tonic-gate stna inum, [os1 + TRAP_ENT_TR]%asi; \ 2947c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_F1]%asi; \ 2957c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_F2]%asi; \ 2967c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_F3]%asi; \ 2977c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_F4]%asi; \ 2987c478bd9Sstevel@tonic-gate TRACE_NEXT(os1, os2, os3); \ 2997c478bd9Sstevel@tonic-gate wrpr %g0, os4, %pstate 3007c478bd9Sstevel@tonic-gate#else /* TRAPTRACE */ 3017c478bd9Sstevel@tonic-gate#define SERVE_INTR_TRACE(inum, os1, os2, os3, os4) 3027c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */ 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE 3057c478bd9Sstevel@tonic-gate/* 3067c478bd9Sstevel@tonic-gate * inum - not modified, _spurious depends on it. 3077c478bd9Sstevel@tonic-gate */ 3087c478bd9Sstevel@tonic-gate#define SERVE_INTR_TRACE2(inum, os1, os2, os3, os4) \ 3097c478bd9Sstevel@tonic-gate rdpr %pstate, os3; \ 3107c478bd9Sstevel@tonic-gate andn os3, PSTATE_IE | PSTATE_AM, os2; \ 3117c478bd9Sstevel@tonic-gate wrpr %g0, os2, %pstate; \ 3127c478bd9Sstevel@tonic-gate TRACE_PTR(os1, os2); \ 3137c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_TPC]%asi; \ 3147c478bd9Sstevel@tonic-gate stxa %g0, [os1 + TRAP_ENT_TSTATE]%asi; \ 3157c478bd9Sstevel@tonic-gate mov os3, os4; \ 3167c478bd9Sstevel@tonic-gate GET_TRACE_TICK(os2); \ 3177c478bd9Sstevel@tonic-gate stxa os2, [os1 + TRAP_ENT_TICK]%asi; \ 3187c478bd9Sstevel@tonic-gate TRACE_SAVE_TL_GL_REGS(os1, os2); \ 3197c478bd9Sstevel@tonic-gate set TT_SERVE_INTR, os2; \ 3207c478bd9Sstevel@tonic-gate rdpr %pil, os3; \ 3217c478bd9Sstevel@tonic-gate or os2, os3, os2; \ 3227c478bd9Sstevel@tonic-gate stha os2, [os1 + TRAP_ENT_TT]%asi; \ 3237c478bd9Sstevel@tonic-gate stna %sp, [os1 + TRAP_ENT_SP]%asi; \ 3247c478bd9Sstevel@tonic-gate stna inum, [os1 + TRAP_ENT_TR]%asi; \ 3257c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_F1]%asi; \ 3267c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_F2]%asi; \ 3277c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_F3]%asi; \ 3287c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_F4]%asi; \ 3297c478bd9Sstevel@tonic-gate TRACE_NEXT(os1, os2, os3); \ 3307c478bd9Sstevel@tonic-gate wrpr %g0, os4, %pstate 3317c478bd9Sstevel@tonic-gate#else /* TRAPTRACE */ 3327c478bd9Sstevel@tonic-gate#define SERVE_INTR_TRACE2(inum, os1, os2, os3, os4) 3337c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */ 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate#endif /* lint */ 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate#if defined(lint) 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate/*ARGSUSED*/ 3407c478bd9Sstevel@tonic-gatevoid 341*b0fc0e77Sgovindaintr_thread(struct regs *regs, uint64_t iv_p, uint_t pil) 3427c478bd9Sstevel@tonic-gate{} 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate#else /* lint */ 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate#define INTRCNT_LIMIT 16 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate/* 3497c478bd9Sstevel@tonic-gate * Handle an interrupt in a new thread. 3507c478bd9Sstevel@tonic-gate * Entry: 3517c478bd9Sstevel@tonic-gate * %o0 = pointer to regs structure 352*b0fc0e77Sgovinda * %o1 = pointer to current intr_vec_t (iv) to be processed 3537c478bd9Sstevel@tonic-gate * %o2 = pil 3547c478bd9Sstevel@tonic-gate * %sp = on current thread's kernel stack 3557c478bd9Sstevel@tonic-gate * %o7 = return linkage to trap code 3567c478bd9Sstevel@tonic-gate * %g7 = current thread 3577c478bd9Sstevel@tonic-gate * %pstate = normal globals, interrupts enabled, 3587c478bd9Sstevel@tonic-gate * privileged, fp disabled 3597c478bd9Sstevel@tonic-gate * %pil = DISP_LEVEL 3607c478bd9Sstevel@tonic-gate * 3617c478bd9Sstevel@tonic-gate * Register Usage 3627c478bd9Sstevel@tonic-gate * %l0 = return linkage 3637c478bd9Sstevel@tonic-gate * %l1 = pil 3647c478bd9Sstevel@tonic-gate * %l2 - %l3 = scratch 3657c478bd9Sstevel@tonic-gate * %l4 - %l7 = reserved for sys_trap 3667c478bd9Sstevel@tonic-gate * %o2 = cpu 3677c478bd9Sstevel@tonic-gate * %o3 = intr thread 3687c478bd9Sstevel@tonic-gate * %o0 = scratch 3697c478bd9Sstevel@tonic-gate * %o4 - %o5 = scratch 3707c478bd9Sstevel@tonic-gate */ 3717c478bd9Sstevel@tonic-gate ENTRY_NP(intr_thread) 3727c478bd9Sstevel@tonic-gate mov %o7, %l0 3737c478bd9Sstevel@tonic-gate mov %o2, %l1 3747c478bd9Sstevel@tonic-gate ! 3757c478bd9Sstevel@tonic-gate ! See if we are interrupting another interrupt thread. 3767c478bd9Sstevel@tonic-gate ! 3777c478bd9Sstevel@tonic-gate lduh [THREAD_REG + T_FLAGS], %o3 3787c478bd9Sstevel@tonic-gate andcc %o3, T_INTR_THREAD, %g0 3797c478bd9Sstevel@tonic-gate bz,pt %xcc, 1f 3807c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CPU], %o2 ! delay - load CPU pointer 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate ! We have interrupted an interrupt thread. Take a timestamp, 3837c478bd9Sstevel@tonic-gate ! compute its interval, and update its cumulative counter. 3847c478bd9Sstevel@tonic-gate add THREAD_REG, T_INTR_START, %o5 3857c478bd9Sstevel@tonic-gate0: 3867c478bd9Sstevel@tonic-gate ldx [%o5], %o3 3877c478bd9Sstevel@tonic-gate brz,pn %o3, 1f 3887c478bd9Sstevel@tonic-gate ! We came in on top of an interrupt thread that had no timestamp. 3897c478bd9Sstevel@tonic-gate ! This could happen if, for instance, an interrupt thread which had 3907c478bd9Sstevel@tonic-gate ! previously blocked is being set up to run again in resume(), but 3917c478bd9Sstevel@tonic-gate ! resume() hasn't yet stored a timestamp for it. Or, it could be in 3927c478bd9Sstevel@tonic-gate ! swtch() after its slice has been accounted for. 3937c478bd9Sstevel@tonic-gate ! Only account for the time slice if the starting timestamp is non-zero. 3947c478bd9Sstevel@tonic-gate rdpr %tick, %o4 ! delay 3957c478bd9Sstevel@tonic-gate sllx %o4, 1, %o4 ! shift off NPT bit 3967c478bd9Sstevel@tonic-gate srlx %o4, 1, %o4 3977c478bd9Sstevel@tonic-gate sub %o4, %o3, %o4 ! o4 has interval 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate ! A high-level interrupt in current_thread() interrupting here 4007c478bd9Sstevel@tonic-gate ! will account for the interrupted thread's time slice, but 4017c478bd9Sstevel@tonic-gate ! only if t_intr_start is non-zero. Since this code is going to account 4027c478bd9Sstevel@tonic-gate ! for the time slice, we want to "atomically" load the thread's 4037c478bd9Sstevel@tonic-gate ! starting timestamp, calculate the interval with %tick, and zero 4047c478bd9Sstevel@tonic-gate ! its starting timestamp. 4057c478bd9Sstevel@tonic-gate ! To do this, we do a casx on the t_intr_start field, and store 0 to it. 4067c478bd9Sstevel@tonic-gate ! If it has changed since we loaded it above, we need to re-compute the 4077c478bd9Sstevel@tonic-gate ! interval, since a changed t_intr_start implies current_thread placed 4087c478bd9Sstevel@tonic-gate ! a new, later timestamp there after running a high-level interrupt, 4097c478bd9Sstevel@tonic-gate ! and the %tick val in %o4 had become stale. 4107c478bd9Sstevel@tonic-gate mov %g0, %l2 4117c478bd9Sstevel@tonic-gate casx [%o5], %o3, %l2 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate ! If %l2 == %o3, our casx was successful. If not, the starting timestamp 4147c478bd9Sstevel@tonic-gate ! changed between loading it (after label 0b) and computing the 4157c478bd9Sstevel@tonic-gate ! interval above. 4167c478bd9Sstevel@tonic-gate cmp %l2, %o3 4177c478bd9Sstevel@tonic-gate bne,pn %xcc, 0b 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate ! Check for Energy Star mode 4207c478bd9Sstevel@tonic-gate lduh [%o2 + CPU_DIVISOR], %l2 ! delay -- %l2 = clock divisor 4217c478bd9Sstevel@tonic-gate cmp %l2, 1 4227c478bd9Sstevel@tonic-gate bg,a,pn %xcc, 2f 4237c478bd9Sstevel@tonic-gate mulx %o4, %l2, %o4 ! multiply interval by clock divisor iff > 1 4247c478bd9Sstevel@tonic-gate2: 4257c478bd9Sstevel@tonic-gate ! We now know that a valid interval for the interrupted interrupt 4267c478bd9Sstevel@tonic-gate ! thread is in %o4. Update its cumulative counter. 4277c478bd9Sstevel@tonic-gate ldub [THREAD_REG + T_PIL], %l3 ! load PIL 4287c478bd9Sstevel@tonic-gate sllx %l3, 4, %l3 ! convert PIL index to byte offset 4297c478bd9Sstevel@tonic-gate add %l3, CPU_MCPU, %l3 ! CPU_INTRSTAT is too big for use 4307c478bd9Sstevel@tonic-gate add %l3, MCPU_INTRSTAT, %l3 ! as const, add offsets separately 4317c478bd9Sstevel@tonic-gate ldx [%o2 + %l3], %o5 ! old counter in o5 4327c478bd9Sstevel@tonic-gate add %o5, %o4, %o5 ! new counter in o5 4337c478bd9Sstevel@tonic-gate stx %o5, [%o2 + %l3] ! store new counter 4347c478bd9Sstevel@tonic-gate 435eda89462Sesolom ! Also update intracct[] 436eda89462Sesolom lduh [%o2 + CPU_MSTATE], %l3 437eda89462Sesolom sllx %l3, 3, %l3 438eda89462Sesolom add %l3, CPU_INTRACCT, %l3 439eda89462Sesolom add %l3, %o2, %l3 440eda89462Sesolom0: 441eda89462Sesolom ldx [%l3], %o5 442eda89462Sesolom add %o5, %o4, %o3 443eda89462Sesolom casx [%l3], %o5, %o3 444eda89462Sesolom cmp %o5, %o3 445eda89462Sesolom bne,pn %xcc, 0b 446eda89462Sesolom nop 447eda89462Sesolom 4487c478bd9Sstevel@tonic-gate1: 4497c478bd9Sstevel@tonic-gate ! 4507c478bd9Sstevel@tonic-gate ! Get set to run interrupt thread. 4517c478bd9Sstevel@tonic-gate ! There should always be an interrupt thread since we allocate one 4527c478bd9Sstevel@tonic-gate ! for each level on the CPU. 4537c478bd9Sstevel@tonic-gate ! 4547c478bd9Sstevel@tonic-gate ! Note that the code in kcpc_overflow_intr -relies- on the ordering 4557c478bd9Sstevel@tonic-gate ! of events here -- in particular that t->t_lwp of the interrupt thread 4567c478bd9Sstevel@tonic-gate ! is set to the pinned thread *before* curthread is changed. 4577c478bd9Sstevel@tonic-gate ! 4587c478bd9Sstevel@tonic-gate ldn [%o2 + CPU_INTR_THREAD], %o3 ! interrupt thread pool 4597c478bd9Sstevel@tonic-gate ldn [%o3 + T_LINK], %o4 ! unlink thread from CPU's list 4607c478bd9Sstevel@tonic-gate stn %o4, [%o2 + CPU_INTR_THREAD] 4617c478bd9Sstevel@tonic-gate ! 4627c478bd9Sstevel@tonic-gate ! Set bit for this level in CPU's active interrupt bitmask. 4637c478bd9Sstevel@tonic-gate ! 4647c478bd9Sstevel@tonic-gate ld [%o2 + CPU_INTR_ACTV], %o5 4657c478bd9Sstevel@tonic-gate mov 1, %o4 4667c478bd9Sstevel@tonic-gate sll %o4, %l1, %o4 4677c478bd9Sstevel@tonic-gate#ifdef DEBUG 4687c478bd9Sstevel@tonic-gate ! 4697c478bd9Sstevel@tonic-gate ! ASSERT(!(CPU->cpu_intr_actv & (1 << PIL))) 4707c478bd9Sstevel@tonic-gate ! 4717c478bd9Sstevel@tonic-gate andcc %o5, %o4, %g0 4727c478bd9Sstevel@tonic-gate bz,pt %xcc, 0f 4737c478bd9Sstevel@tonic-gate nop 4747c478bd9Sstevel@tonic-gate ! Do not call panic if a panic is already in progress. 4757c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l2 4767c478bd9Sstevel@tonic-gate ld [%l2 + %lo(panic_quiesce)], %l2 4777c478bd9Sstevel@tonic-gate brnz,pn %l2, 0f 4787c478bd9Sstevel@tonic-gate nop 4797c478bd9Sstevel@tonic-gate sethi %hi(intr_thread_actv_bit_set), %o0 4807c478bd9Sstevel@tonic-gate call panic 4817c478bd9Sstevel@tonic-gate or %o0, %lo(intr_thread_actv_bit_set), %o0 4827c478bd9Sstevel@tonic-gate0: 4837c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 4847c478bd9Sstevel@tonic-gate or %o5, %o4, %o5 4857c478bd9Sstevel@tonic-gate st %o5, [%o2 + CPU_INTR_ACTV] 4867c478bd9Sstevel@tonic-gate ! 4877c478bd9Sstevel@tonic-gate ! Consider the new thread part of the same LWP so that 4887c478bd9Sstevel@tonic-gate ! window overflow code can find the PCB. 4897c478bd9Sstevel@tonic-gate ! 4907c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_LWP], %o4 4917c478bd9Sstevel@tonic-gate stn %o4, [%o3 + T_LWP] 4927c478bd9Sstevel@tonic-gate ! 4937c478bd9Sstevel@tonic-gate ! Threads on the interrupt thread free list could have state already 4947c478bd9Sstevel@tonic-gate ! set to TS_ONPROC, but it helps in debugging if they're TS_FREE 4957c478bd9Sstevel@tonic-gate ! Could eliminate the next two instructions with a little work. 4967c478bd9Sstevel@tonic-gate ! 4977c478bd9Sstevel@tonic-gate mov TS_ONPROC, %o4 4987c478bd9Sstevel@tonic-gate st %o4, [%o3 + T_STATE] 4997c478bd9Sstevel@tonic-gate ! 5007c478bd9Sstevel@tonic-gate ! Push interrupted thread onto list from new thread. 5017c478bd9Sstevel@tonic-gate ! Set the new thread as the current one. 5027c478bd9Sstevel@tonic-gate ! Set interrupted thread's T_SP because if it is the idle thread, 5037c478bd9Sstevel@tonic-gate ! resume may use that stack between threads. 5047c478bd9Sstevel@tonic-gate ! 5057c478bd9Sstevel@tonic-gate stn %o7, [THREAD_REG + T_PC] ! mark pc for resume 5067c478bd9Sstevel@tonic-gate stn %sp, [THREAD_REG + T_SP] ! mark stack for resume 5077c478bd9Sstevel@tonic-gate stn THREAD_REG, [%o3 + T_INTR] ! push old thread 5087c478bd9Sstevel@tonic-gate stn %o3, [%o2 + CPU_THREAD] ! set new thread 5097c478bd9Sstevel@tonic-gate mov %o3, THREAD_REG ! set global curthread register 5107c478bd9Sstevel@tonic-gate ldn [%o3 + T_STACK], %o4 ! interrupt stack pointer 5117c478bd9Sstevel@tonic-gate sub %o4, STACK_BIAS, %sp 5127c478bd9Sstevel@tonic-gate ! 5137c478bd9Sstevel@tonic-gate ! Initialize thread priority level from intr_pri 5147c478bd9Sstevel@tonic-gate ! 5157c478bd9Sstevel@tonic-gate sethi %hi(intr_pri), %o4 5167c478bd9Sstevel@tonic-gate ldsh [%o4 + %lo(intr_pri)], %o4 ! grab base interrupt priority 5177c478bd9Sstevel@tonic-gate add %l1, %o4, %o4 ! convert level to dispatch priority 5187c478bd9Sstevel@tonic-gate sth %o4, [THREAD_REG + T_PRI] 5197c478bd9Sstevel@tonic-gate stub %l1, [THREAD_REG + T_PIL] ! save pil for intr_passivate 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate ! Store starting timestamp in thread structure. 5227c478bd9Sstevel@tonic-gate add THREAD_REG, T_INTR_START, %o3 5237c478bd9Sstevel@tonic-gate1: 5247c478bd9Sstevel@tonic-gate ldx [%o3], %o5 5257c478bd9Sstevel@tonic-gate rdpr %tick, %o4 5267c478bd9Sstevel@tonic-gate sllx %o4, 1, %o4 5277c478bd9Sstevel@tonic-gate srlx %o4, 1, %o4 ! shift off NPT bit 5287c478bd9Sstevel@tonic-gate casx [%o3], %o5, %o4 5297c478bd9Sstevel@tonic-gate cmp %o4, %o5 5307c478bd9Sstevel@tonic-gate ! If a high-level interrupt occurred while we were attempting to store 5317c478bd9Sstevel@tonic-gate ! the timestamp, try again. 5327c478bd9Sstevel@tonic-gate bne,pn %xcc, 1b 5337c478bd9Sstevel@tonic-gate nop 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate wrpr %g0, %l1, %pil ! lower %pil to new level 5367c478bd9Sstevel@tonic-gate ! 5377c478bd9Sstevel@tonic-gate ! Fast event tracing. 5387c478bd9Sstevel@tonic-gate ! 5397c478bd9Sstevel@tonic-gate ld [%o2 + CPU_FTRACE_STATE], %o4 ! %o2 = curthread->t_cpu 5407c478bd9Sstevel@tonic-gate btst FTRACE_ENABLED, %o4 5417c478bd9Sstevel@tonic-gate be,pt %icc, 1f ! skip if ftrace disabled 5427c478bd9Sstevel@tonic-gate mov %l1, %o5 5437c478bd9Sstevel@tonic-gate ! 5447c478bd9Sstevel@tonic-gate ! Tracing is enabled - write the trace entry. 5457c478bd9Sstevel@tonic-gate ! 5467c478bd9Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp 5477c478bd9Sstevel@tonic-gate set ftrace_intr_thread_format_str, %o0 5487c478bd9Sstevel@tonic-gate mov %i0, %o1 5497c478bd9Sstevel@tonic-gate mov %i1, %o2 5507c478bd9Sstevel@tonic-gate call ftrace_3 5517c478bd9Sstevel@tonic-gate mov %i5, %o3 5527c478bd9Sstevel@tonic-gate restore 5537c478bd9Sstevel@tonic-gate1: 5547c478bd9Sstevel@tonic-gate ! 5557c478bd9Sstevel@tonic-gate ! call the handler 5567c478bd9Sstevel@tonic-gate ! 5577c478bd9Sstevel@tonic-gate SERVE_INTR_PRE(%o1, %o2, %l1, %l3, %o4, %o5, %o3, %o0) 5587c478bd9Sstevel@tonic-gate ! 5597c478bd9Sstevel@tonic-gate ! %o0 and %o1 are now available as scratch registers. 5607c478bd9Sstevel@tonic-gate ! 5617c478bd9Sstevel@tonic-gate0: 5627c478bd9Sstevel@tonic-gate SERVE_INTR(%o1, %o2, %l1, %l3, %o4, %o5, %o3, %o0) 5637c478bd9Sstevel@tonic-gate ! 564*b0fc0e77Sgovinda ! If %o3 is set, we must call serve_intr_next, and both %l1 and %o3 5657c478bd9Sstevel@tonic-gate ! must be preserved. %l1 holds our pil, %l3 holds our inum. 5667c478bd9Sstevel@tonic-gate ! 5677c478bd9Sstevel@tonic-gate ! Note: %l1 is the pil level we're processing, but we may have a 5687c478bd9Sstevel@tonic-gate ! higher effective pil because a higher-level interrupt may have 5697c478bd9Sstevel@tonic-gate ! blocked. 5707c478bd9Sstevel@tonic-gate ! 5717c478bd9Sstevel@tonic-gate wrpr %g0, DISP_LEVEL, %pil 5727c478bd9Sstevel@tonic-gate ! 5737c478bd9Sstevel@tonic-gate ! Take timestamp, compute interval, update cumulative counter. 5747c478bd9Sstevel@tonic-gate ! 5757c478bd9Sstevel@tonic-gate add THREAD_REG, T_INTR_START, %o5 5767c478bd9Sstevel@tonic-gate1: 5777c478bd9Sstevel@tonic-gate ldx [%o5], %o0 5787c478bd9Sstevel@tonic-gate#ifdef DEBUG 5797c478bd9Sstevel@tonic-gate brnz %o0, 9f 5807c478bd9Sstevel@tonic-gate nop 5817c478bd9Sstevel@tonic-gate ! Do not call panic if a panic is already in progress. 5827c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %o1 5837c478bd9Sstevel@tonic-gate ld [%o1 + %lo(panic_quiesce)], %o1 5847c478bd9Sstevel@tonic-gate brnz,pn %o1, 9f 5857c478bd9Sstevel@tonic-gate nop 5867c478bd9Sstevel@tonic-gate sethi %hi(intr_thread_t_intr_start_zero), %o0 5877c478bd9Sstevel@tonic-gate call panic 5887c478bd9Sstevel@tonic-gate or %o0, %lo(intr_thread_t_intr_start_zero), %o0 5897c478bd9Sstevel@tonic-gate9: 5907c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 5917c478bd9Sstevel@tonic-gate rdpr %tick, %o1 5927c478bd9Sstevel@tonic-gate sllx %o1, 1, %o1 5937c478bd9Sstevel@tonic-gate srlx %o1, 1, %o1 ! shift off NPT bit 5947c478bd9Sstevel@tonic-gate sub %o1, %o0, %l2 ! l2 has interval 5957c478bd9Sstevel@tonic-gate ! 5967c478bd9Sstevel@tonic-gate ! The general outline of what the code here does is: 5977c478bd9Sstevel@tonic-gate ! 1. load t_intr_start, %tick, and calculate the delta 5987c478bd9Sstevel@tonic-gate ! 2. replace t_intr_start with %tick (if %o3 is set) or 0. 5997c478bd9Sstevel@tonic-gate ! 6007c478bd9Sstevel@tonic-gate ! The problem is that a high-level interrupt could arrive at any time. 6017c478bd9Sstevel@tonic-gate ! It will account for (%tick - t_intr_start) for us when it starts, 6027c478bd9Sstevel@tonic-gate ! unless we have set t_intr_start to zero, and then set t_intr_start 6037c478bd9Sstevel@tonic-gate ! to a new %tick when it finishes. To account for this, our first step 6047c478bd9Sstevel@tonic-gate ! is to load t_intr_start and the last is to use casx to store the new 6057c478bd9Sstevel@tonic-gate ! t_intr_start. This guarantees atomicity in reading t_intr_start, 6067c478bd9Sstevel@tonic-gate ! reading %tick, and updating t_intr_start. 6077c478bd9Sstevel@tonic-gate ! 6087c478bd9Sstevel@tonic-gate movrz %o3, %g0, %o1 6097c478bd9Sstevel@tonic-gate casx [%o5], %o0, %o1 6107c478bd9Sstevel@tonic-gate cmp %o0, %o1 6117c478bd9Sstevel@tonic-gate bne,pn %xcc, 1b 6127c478bd9Sstevel@tonic-gate ! 6137c478bd9Sstevel@tonic-gate ! Check for Energy Star mode 6147c478bd9Sstevel@tonic-gate ! 6157c478bd9Sstevel@tonic-gate lduh [%o2 + CPU_DIVISOR], %o0 ! delay -- %o0 = clock divisor 6167c478bd9Sstevel@tonic-gate cmp %o0, 1 6177c478bd9Sstevel@tonic-gate bg,a,pn %xcc, 2f 6187c478bd9Sstevel@tonic-gate mulx %l2, %o0, %l2 ! multiply interval by clock divisor iff > 1 6197c478bd9Sstevel@tonic-gate2: 6207c478bd9Sstevel@tonic-gate ! 6217c478bd9Sstevel@tonic-gate ! Update cpu_intrstat. If o3 is set then we will be processing another 6227c478bd9Sstevel@tonic-gate ! interrupt. Above we have set t_intr_start to %tick, not 0. This 6237c478bd9Sstevel@tonic-gate ! means a high-level interrupt can arrive and update the same stats 6247c478bd9Sstevel@tonic-gate ! we're updating. Need to use casx. 6257c478bd9Sstevel@tonic-gate ! 6267c478bd9Sstevel@tonic-gate sllx %l1, 4, %o1 ! delay - PIL as byte offset 6277c478bd9Sstevel@tonic-gate add %o1, CPU_MCPU, %o1 ! CPU_INTRSTAT const too big 6287c478bd9Sstevel@tonic-gate add %o1, MCPU_INTRSTAT, %o1 ! add parts separately 6297c478bd9Sstevel@tonic-gate add %o1, %o2, %o1 6307c478bd9Sstevel@tonic-gate1: 6317c478bd9Sstevel@tonic-gate ldx [%o1], %o5 ! old counter in o5 6327c478bd9Sstevel@tonic-gate add %o5, %l2, %o0 ! new counter in o0 6337c478bd9Sstevel@tonic-gate stx %o0, [%o1 + 8] ! store into intrstat[pil][1] 6347c478bd9Sstevel@tonic-gate casx [%o1], %o5, %o0 ! and into intrstat[pil][0] 6357c478bd9Sstevel@tonic-gate cmp %o5, %o0 6367c478bd9Sstevel@tonic-gate bne,pn %xcc, 1b 6377c478bd9Sstevel@tonic-gate nop 638eda89462Sesolom 639eda89462Sesolom ! Also update intracct[] 640eda89462Sesolom lduh [%o2 + CPU_MSTATE], %o1 641eda89462Sesolom sllx %o1, 3, %o1 642eda89462Sesolom add %o1, CPU_INTRACCT, %o1 643eda89462Sesolom add %o1, %o2, %o1 644eda89462Sesolom1: 645eda89462Sesolom ldx [%o1], %o5 646eda89462Sesolom add %o5, %l2, %o0 647eda89462Sesolom casx [%o1], %o5, %o0 648eda89462Sesolom cmp %o5, %o0 649eda89462Sesolom bne,pn %xcc, 1b 650eda89462Sesolom nop 651eda89462Sesolom 6527c478bd9Sstevel@tonic-gate ! 6537c478bd9Sstevel@tonic-gate ! Don't keep a pinned process pinned indefinitely. Bump cpu_intrcnt 6547c478bd9Sstevel@tonic-gate ! for each interrupt handler we invoke. If we hit INTRCNT_LIMIT, then 6557c478bd9Sstevel@tonic-gate ! we've crossed the threshold and we should unpin the pinned threads 6567c478bd9Sstevel@tonic-gate ! by preempt()ing ourselves, which will bubble up the t_intr chain 6577c478bd9Sstevel@tonic-gate ! until hitting the non-interrupt thread, which will then in turn 6587c478bd9Sstevel@tonic-gate ! preempt itself allowing the interrupt processing to resume. Finally, 6597c478bd9Sstevel@tonic-gate ! the scheduler takes over and picks the next thread to run. 6607c478bd9Sstevel@tonic-gate ! 6617c478bd9Sstevel@tonic-gate ! If our CPU is quiesced, we cannot preempt because the idle thread 6627c478bd9Sstevel@tonic-gate ! won't ever re-enter the scheduler, and the interrupt will be forever 6637c478bd9Sstevel@tonic-gate ! blocked. 6647c478bd9Sstevel@tonic-gate ! 6657c478bd9Sstevel@tonic-gate ! If t_intr is NULL, we're not pinning anyone, so we use a simpler 6667c478bd9Sstevel@tonic-gate ! algorithm. Just check for cpu_kprunrun, and if set then preempt. 6677c478bd9Sstevel@tonic-gate ! This insures we enter the scheduler if a higher-priority thread 6687c478bd9Sstevel@tonic-gate ! has become runnable. 6697c478bd9Sstevel@tonic-gate ! 6707c478bd9Sstevel@tonic-gate lduh [%o2 + CPU_FLAGS], %o5 ! don't preempt if quiesced 6717c478bd9Sstevel@tonic-gate andcc %o5, CPU_QUIESCED, %g0 6727c478bd9Sstevel@tonic-gate bnz,pn %xcc, 1f 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_INTR], %o5 ! pinning anything? 6757c478bd9Sstevel@tonic-gate brz,pn %o5, 3f ! if not, don't inc intrcnt 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate ldub [%o2 + CPU_INTRCNT], %o5 ! delay - %o5 = cpu_intrcnt 6787c478bd9Sstevel@tonic-gate inc %o5 6797c478bd9Sstevel@tonic-gate cmp %o5, INTRCNT_LIMIT ! have we hit the limit? 6807c478bd9Sstevel@tonic-gate bl,a,pt %xcc, 1f ! no preempt if < INTRCNT_LIMIT 6817c478bd9Sstevel@tonic-gate stub %o5, [%o2 + CPU_INTRCNT] ! delay annul - inc CPU_INTRCNT 6827c478bd9Sstevel@tonic-gate bg,pn %xcc, 2f ! don't inc stats again 6837c478bd9Sstevel@tonic-gate ! 6847c478bd9Sstevel@tonic-gate ! We've reached the limit. Set cpu_intrcnt and cpu_kprunrun, and do 6857c478bd9Sstevel@tonic-gate ! CPU_STATS_ADDQ(cp, sys, intrunpin, 1). Then call preempt. 6867c478bd9Sstevel@tonic-gate ! 6877c478bd9Sstevel@tonic-gate mov 1, %o4 ! delay 6887c478bd9Sstevel@tonic-gate stub %o4, [%o2 + CPU_KPRUNRUN] 6897c478bd9Sstevel@tonic-gate ldx [%o2 + CPU_STATS_SYS_INTRUNPIN], %o4 6907c478bd9Sstevel@tonic-gate inc %o4 6917c478bd9Sstevel@tonic-gate stx %o4, [%o2 + CPU_STATS_SYS_INTRUNPIN] 6927c478bd9Sstevel@tonic-gate ba 2f 6937c478bd9Sstevel@tonic-gate stub %o5, [%o2 + CPU_INTRCNT] ! delay 6947c478bd9Sstevel@tonic-gate3: 6957c478bd9Sstevel@tonic-gate ! Code for t_intr == NULL 6967c478bd9Sstevel@tonic-gate ldub [%o2 + CPU_KPRUNRUN], %o5 6977c478bd9Sstevel@tonic-gate brz,pt %o5, 1f ! don't preempt unless kprunrun 6987c478bd9Sstevel@tonic-gate2: 6997c478bd9Sstevel@tonic-gate ! Time to call preempt 7007c478bd9Sstevel@tonic-gate mov %o2, %l3 ! delay - save %o2 7017c478bd9Sstevel@tonic-gate call preempt 7027c478bd9Sstevel@tonic-gate mov %o3, %l2 ! delay - save %o3. 7037c478bd9Sstevel@tonic-gate mov %l3, %o2 ! restore %o2 7047c478bd9Sstevel@tonic-gate mov %l2, %o3 ! restore %o3 7057c478bd9Sstevel@tonic-gate wrpr %g0, DISP_LEVEL, %pil ! up from cpu_base_spl 7067c478bd9Sstevel@tonic-gate1: 7077c478bd9Sstevel@tonic-gate ! 708*b0fc0e77Sgovinda ! Do we need to call serve_intr_next and do this again? 7097c478bd9Sstevel@tonic-gate ! 7107c478bd9Sstevel@tonic-gate brz,a,pt %o3, 0f 7117c478bd9Sstevel@tonic-gate ld [%o2 + CPU_INTR_ACTV], %o5 ! delay annulled 7127c478bd9Sstevel@tonic-gate ! 7137c478bd9Sstevel@tonic-gate ! Restore %pil before calling serve_intr() again. We must check 7147c478bd9Sstevel@tonic-gate ! CPU_BASE_SPL and set %pil to max(our-pil, CPU_BASE_SPL) 7157c478bd9Sstevel@tonic-gate ! 7167c478bd9Sstevel@tonic-gate ld [%o2 + CPU_BASE_SPL], %o4 7177c478bd9Sstevel@tonic-gate cmp %o4, %l1 7187c478bd9Sstevel@tonic-gate movl %xcc, %l1, %o4 7197c478bd9Sstevel@tonic-gate wrpr %g0, %o4, %pil 7207c478bd9Sstevel@tonic-gate SERVE_INTR_NEXT(%o1, %o2, %l1, %l3, %o4, %o5, %o3, %o0) 7217c478bd9Sstevel@tonic-gate ba 0b ! compute new stats 7227c478bd9Sstevel@tonic-gate nop 7237c478bd9Sstevel@tonic-gate0: 7247c478bd9Sstevel@tonic-gate ! 7257c478bd9Sstevel@tonic-gate ! Clear bit for this level in CPU's interrupt active bitmask. 7267c478bd9Sstevel@tonic-gate ! 7277c478bd9Sstevel@tonic-gate mov 1, %o4 7287c478bd9Sstevel@tonic-gate sll %o4, %l1, %o4 7297c478bd9Sstevel@tonic-gate#ifdef DEBUG 7307c478bd9Sstevel@tonic-gate ! 7317c478bd9Sstevel@tonic-gate ! ASSERT(CPU->cpu_intr_actv & (1 << PIL)) 7327c478bd9Sstevel@tonic-gate ! 7337c478bd9Sstevel@tonic-gate andcc %o4, %o5, %g0 7347c478bd9Sstevel@tonic-gate bnz,pt %xcc, 0f 7357c478bd9Sstevel@tonic-gate nop 7367c478bd9Sstevel@tonic-gate ! Do not call panic if a panic is already in progress. 7377c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l2 7387c478bd9Sstevel@tonic-gate ld [%l2 + %lo(panic_quiesce)], %l2 7397c478bd9Sstevel@tonic-gate brnz,pn %l2, 0f 7407c478bd9Sstevel@tonic-gate nop 7417c478bd9Sstevel@tonic-gate sethi %hi(intr_thread_actv_bit_not_set), %o0 7427c478bd9Sstevel@tonic-gate call panic 7437c478bd9Sstevel@tonic-gate or %o0, %lo(intr_thread_actv_bit_not_set), %o0 7447c478bd9Sstevel@tonic-gate0: 7457c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 7467c478bd9Sstevel@tonic-gate andn %o5, %o4, %o5 7477c478bd9Sstevel@tonic-gate st %o5, [%o2 + CPU_INTR_ACTV] 7487c478bd9Sstevel@tonic-gate ! 7497c478bd9Sstevel@tonic-gate ! If there is still an interrupted thread underneath this one, 7507c478bd9Sstevel@tonic-gate ! then the interrupt was never blocked and the return is fairly 7517c478bd9Sstevel@tonic-gate ! simple. Otherwise jump to intr_thread_exit. 7527c478bd9Sstevel@tonic-gate ! 7537c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_INTR], %o4 ! pinned thread 7547c478bd9Sstevel@tonic-gate brz,pn %o4, intr_thread_exit ! branch if none 7557c478bd9Sstevel@tonic-gate nop 7567c478bd9Sstevel@tonic-gate ! 7577c478bd9Sstevel@tonic-gate ! link the thread back onto the interrupt thread pool 7587c478bd9Sstevel@tonic-gate ! 7597c478bd9Sstevel@tonic-gate ldn [%o2 + CPU_INTR_THREAD], %o3 7607c478bd9Sstevel@tonic-gate stn %o3, [THREAD_REG + T_LINK] 7617c478bd9Sstevel@tonic-gate stn THREAD_REG, [%o2 + CPU_INTR_THREAD] 7627c478bd9Sstevel@tonic-gate ! 7637c478bd9Sstevel@tonic-gate ! set the thread state to free so kernel debuggers don't see it 7647c478bd9Sstevel@tonic-gate ! 7657c478bd9Sstevel@tonic-gate mov TS_FREE, %o5 7667c478bd9Sstevel@tonic-gate st %o5, [THREAD_REG + T_STATE] 7677c478bd9Sstevel@tonic-gate ! 7687c478bd9Sstevel@tonic-gate ! Switch back to the interrupted thread and return 7697c478bd9Sstevel@tonic-gate ! 7707c478bd9Sstevel@tonic-gate stn %o4, [%o2 + CPU_THREAD] 77125cf1a30Sjl139090 membar #StoreLoad ! sync with mutex_exit() 7727c478bd9Sstevel@tonic-gate mov %o4, THREAD_REG 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate ! If we pinned an interrupt thread, store its starting timestamp. 7757c478bd9Sstevel@tonic-gate lduh [THREAD_REG + T_FLAGS], %o5 7767c478bd9Sstevel@tonic-gate andcc %o5, T_INTR_THREAD, %g0 7777c478bd9Sstevel@tonic-gate bz,pt %xcc, 1f 7787c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_SP], %sp ! delay - restore %sp 7797c478bd9Sstevel@tonic-gate 7807c478bd9Sstevel@tonic-gate add THREAD_REG, T_INTR_START, %o3 ! o3 has &curthread->t_intr_star 7817c478bd9Sstevel@tonic-gate0: 7827c478bd9Sstevel@tonic-gate ldx [%o3], %o4 ! o4 = t_intr_start before 7837c478bd9Sstevel@tonic-gate rdpr %tick, %o5 7847c478bd9Sstevel@tonic-gate sllx %o5, 1, %o5 7857c478bd9Sstevel@tonic-gate srlx %o5, 1, %o5 ! shift off NPT bit 7867c478bd9Sstevel@tonic-gate casx [%o3], %o4, %o5 ! put o5 in ts if o4 == ts after 7877c478bd9Sstevel@tonic-gate cmp %o4, %o5 7887c478bd9Sstevel@tonic-gate ! If a high-level interrupt occurred while we were attempting to store 7897c478bd9Sstevel@tonic-gate ! the timestamp, try again. 7907c478bd9Sstevel@tonic-gate bne,pn %xcc, 0b 7917c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_SP], %sp ! delay - restore %sp 7927c478bd9Sstevel@tonic-gate1: 7937c478bd9Sstevel@tonic-gate ! If the thread being restarted isn't pinning anyone, and no interrupts 7947c478bd9Sstevel@tonic-gate ! are pending, zero out cpu_intrcnt 7957c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_INTR], %o4 7967c478bd9Sstevel@tonic-gate brnz,pn %o4, 2f 7977c478bd9Sstevel@tonic-gate rd SOFTINT, %o4 ! delay 7987c478bd9Sstevel@tonic-gate set SOFTINT_MASK, %o5 7997c478bd9Sstevel@tonic-gate andcc %o4, %o5, %g0 8007c478bd9Sstevel@tonic-gate bz,a,pt %xcc, 2f 8017c478bd9Sstevel@tonic-gate stub %g0, [%o2 + CPU_INTRCNT] ! delay annul 8027c478bd9Sstevel@tonic-gate2: 8037c478bd9Sstevel@tonic-gate jmp %l0 + 8 8047c478bd9Sstevel@tonic-gate nop 8057c478bd9Sstevel@tonic-gate SET_SIZE(intr_thread) 8067c478bd9Sstevel@tonic-gate /* Not Reached */ 8077c478bd9Sstevel@tonic-gate 8087c478bd9Sstevel@tonic-gate ! 8097c478bd9Sstevel@tonic-gate ! An interrupt returned on what was once (and still might be) 8107c478bd9Sstevel@tonic-gate ! an interrupt thread stack, but the interrupted process is no longer 8117c478bd9Sstevel@tonic-gate ! there. This means the interrupt must have blocked. 8127c478bd9Sstevel@tonic-gate ! 8137c478bd9Sstevel@tonic-gate ! There is no longer a thread under this one, so put this thread back 8147c478bd9Sstevel@tonic-gate ! on the CPU's free list and resume the idle thread which will dispatch 8157c478bd9Sstevel@tonic-gate ! the next thread to run. 8167c478bd9Sstevel@tonic-gate ! 8177c478bd9Sstevel@tonic-gate ! All traps below DISP_LEVEL are disabled here, but the mondo interrupt 8187c478bd9Sstevel@tonic-gate ! is enabled. 8197c478bd9Sstevel@tonic-gate ! 8207c478bd9Sstevel@tonic-gate ENTRY_NP(intr_thread_exit) 8217c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE 8227c478bd9Sstevel@tonic-gate rdpr %pstate, %l2 8237c478bd9Sstevel@tonic-gate andn %l2, PSTATE_IE | PSTATE_AM, %o4 8247c478bd9Sstevel@tonic-gate wrpr %g0, %o4, %pstate ! cpu to known state 8257c478bd9Sstevel@tonic-gate TRACE_PTR(%o4, %o5) 8267c478bd9Sstevel@tonic-gate GET_TRACE_TICK(%o5) 8277c478bd9Sstevel@tonic-gate stxa %o5, [%o4 + TRAP_ENT_TICK]%asi 8287c478bd9Sstevel@tonic-gate TRACE_SAVE_TL_GL_REGS(%o4, %o5) 8297c478bd9Sstevel@tonic-gate set TT_INTR_EXIT, %o5 8307c478bd9Sstevel@tonic-gate stha %o5, [%o4 + TRAP_ENT_TT]%asi 8317c478bd9Sstevel@tonic-gate stna %g0, [%o4 + TRAP_ENT_TPC]%asi 8327c478bd9Sstevel@tonic-gate stxa %g0, [%o4 + TRAP_ENT_TSTATE]%asi 8337c478bd9Sstevel@tonic-gate stna %sp, [%o4 + TRAP_ENT_SP]%asi 8347c478bd9Sstevel@tonic-gate stna THREAD_REG, [%o4 + TRAP_ENT_TR]%asi 8357c478bd9Sstevel@tonic-gate ld [%o2 + CPU_BASE_SPL], %o5 8367c478bd9Sstevel@tonic-gate stna %o5, [%o4 + TRAP_ENT_F1]%asi 8377c478bd9Sstevel@tonic-gate stna %g0, [%o4 + TRAP_ENT_F2]%asi 8387c478bd9Sstevel@tonic-gate stna %g0, [%o4 + TRAP_ENT_F3]%asi 8397c478bd9Sstevel@tonic-gate stna %g0, [%o4 + TRAP_ENT_F4]%asi 8407c478bd9Sstevel@tonic-gate TRACE_NEXT(%o4, %o5, %o0) 8417c478bd9Sstevel@tonic-gate wrpr %g0, %l2, %pstate 8427c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */ 8437c478bd9Sstevel@tonic-gate ! cpu_stats.sys.intrblk++ 8447c478bd9Sstevel@tonic-gate ldx [%o2 + CPU_STATS_SYS_INTRBLK], %o4 8457c478bd9Sstevel@tonic-gate inc %o4 8467c478bd9Sstevel@tonic-gate stx %o4, [%o2 + CPU_STATS_SYS_INTRBLK] 8477c478bd9Sstevel@tonic-gate ! 8487c478bd9Sstevel@tonic-gate ! Put thread back on the interrupt thread list. 8497c478bd9Sstevel@tonic-gate ! 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate ! 8527c478bd9Sstevel@tonic-gate ! Set the CPU's base SPL level. 8537c478bd9Sstevel@tonic-gate ! 8547c478bd9Sstevel@tonic-gate#ifdef DEBUG 8557c478bd9Sstevel@tonic-gate ! 8567c478bd9Sstevel@tonic-gate ! ASSERT(!(CPU->cpu_intr_actv & (1 << PIL))) 8577c478bd9Sstevel@tonic-gate ! 8587c478bd9Sstevel@tonic-gate ld [%o2 + CPU_INTR_ACTV], %o5 8597c478bd9Sstevel@tonic-gate mov 1, %o4 8607c478bd9Sstevel@tonic-gate sll %o4, %l1, %o4 8617c478bd9Sstevel@tonic-gate and %o5, %o4, %o4 8627c478bd9Sstevel@tonic-gate brz,pt %o4, 0f 8637c478bd9Sstevel@tonic-gate nop 8647c478bd9Sstevel@tonic-gate ! Do not call panic if a panic is already in progress. 8657c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l2 8667c478bd9Sstevel@tonic-gate ld [%l2 + %lo(panic_quiesce)], %l2 8677c478bd9Sstevel@tonic-gate brnz,pn %l2, 0f 8687c478bd9Sstevel@tonic-gate nop 8697c478bd9Sstevel@tonic-gate sethi %hi(intr_thread_exit_actv_bit_set), %o0 8707c478bd9Sstevel@tonic-gate call panic 8717c478bd9Sstevel@tonic-gate or %o0, %lo(intr_thread_exit_actv_bit_set), %o0 8727c478bd9Sstevel@tonic-gate0: 8737c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 8747c478bd9Sstevel@tonic-gate call _intr_set_spl ! set CPU's base SPL level 8757c478bd9Sstevel@tonic-gate ld [%o2 + CPU_INTR_ACTV], %o5 ! delay - load active mask 8767c478bd9Sstevel@tonic-gate ! 8777c478bd9Sstevel@tonic-gate ! set the thread state to free so kernel debuggers don't see it 8787c478bd9Sstevel@tonic-gate ! 8797c478bd9Sstevel@tonic-gate mov TS_FREE, %o4 8807c478bd9Sstevel@tonic-gate st %o4, [THREAD_REG + T_STATE] 8817c478bd9Sstevel@tonic-gate ! 8827c478bd9Sstevel@tonic-gate ! Put thread on either the interrupt pool or the free pool and 8837c478bd9Sstevel@tonic-gate ! call swtch() to resume another thread. 8847c478bd9Sstevel@tonic-gate ! 8857c478bd9Sstevel@tonic-gate ldn [%o2 + CPU_INTR_THREAD], %o5 ! get list pointer 8867c478bd9Sstevel@tonic-gate stn %o5, [THREAD_REG + T_LINK] 8877c478bd9Sstevel@tonic-gate call swtch ! switch to best thread 8887c478bd9Sstevel@tonic-gate stn THREAD_REG, [%o2 + CPU_INTR_THREAD] ! delay - put thread on list 8897c478bd9Sstevel@tonic-gate ba,a,pt %xcc, . ! swtch() shouldn't return 8907c478bd9Sstevel@tonic-gate SET_SIZE(intr_thread_exit) 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate .global ftrace_intr_thread_format_str 8937c478bd9Sstevel@tonic-gateftrace_intr_thread_format_str: 8947c478bd9Sstevel@tonic-gate .asciz "intr_thread(): regs=0x%lx, int=0x%lx, pil=0x%lx" 8957c478bd9Sstevel@tonic-gate#ifdef DEBUG 8967c478bd9Sstevel@tonic-gateintr_thread_actv_bit_set: 8977c478bd9Sstevel@tonic-gate .asciz "intr_thread(): cpu_intr_actv bit already set for PIL" 8987c478bd9Sstevel@tonic-gateintr_thread_actv_bit_not_set: 8997c478bd9Sstevel@tonic-gate .asciz "intr_thread(): cpu_intr_actv bit not set for PIL" 9007c478bd9Sstevel@tonic-gateintr_thread_exit_actv_bit_set: 9017c478bd9Sstevel@tonic-gate .asciz "intr_thread_exit(): cpu_intr_actv bit erroneously set for PIL" 9027c478bd9Sstevel@tonic-gateintr_thread_t_intr_start_zero: 9037c478bd9Sstevel@tonic-gate .asciz "intr_thread(): t_intr_start zero upon handler return" 9047c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 9057c478bd9Sstevel@tonic-gate#endif /* lint */ 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate#if defined(lint) 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate/* 9107c478bd9Sstevel@tonic-gate * Handle an interrupt in the current thread 9117c478bd9Sstevel@tonic-gate * Entry: 9127c478bd9Sstevel@tonic-gate * %o0 = pointer to regs structure 913*b0fc0e77Sgovinda * %o1 = pointer to current intr_vec_t (iv) to be processed 9147c478bd9Sstevel@tonic-gate * %o2 = pil 9157c478bd9Sstevel@tonic-gate * %sp = on current thread's kernel stack 9167c478bd9Sstevel@tonic-gate * %o7 = return linkage to trap code 9177c478bd9Sstevel@tonic-gate * %g7 = current thread 9187c478bd9Sstevel@tonic-gate * %pstate = normal globals, interrupts enabled, 9197c478bd9Sstevel@tonic-gate * privileged, fp disabled 9207c478bd9Sstevel@tonic-gate * %pil = PIL_MAX 9217c478bd9Sstevel@tonic-gate * 9227c478bd9Sstevel@tonic-gate * Register Usage 9237c478bd9Sstevel@tonic-gate * %l0 = return linkage 9247c478bd9Sstevel@tonic-gate * %l1 = old stack 9257c478bd9Sstevel@tonic-gate * %l2 - %l3 = scratch 9267c478bd9Sstevel@tonic-gate * %l4 - %l7 = reserved for sys_trap 9277c478bd9Sstevel@tonic-gate * %o3 = cpu 9287c478bd9Sstevel@tonic-gate * %o0 = scratch 9297c478bd9Sstevel@tonic-gate * %o4 - %o5 = scratch 9307c478bd9Sstevel@tonic-gate */ 9317c478bd9Sstevel@tonic-gate/* ARGSUSED */ 9327c478bd9Sstevel@tonic-gatevoid 933*b0fc0e77Sgovindacurrent_thread(struct regs *regs, uint64_t iv_p, uint_t pil) 9347c478bd9Sstevel@tonic-gate{} 9357c478bd9Sstevel@tonic-gate 9367c478bd9Sstevel@tonic-gate#else /* lint */ 9377c478bd9Sstevel@tonic-gate 9387c478bd9Sstevel@tonic-gate ENTRY_NP(current_thread) 9397c478bd9Sstevel@tonic-gate 9407c478bd9Sstevel@tonic-gate mov %o7, %l0 9417c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CPU], %o3 9427c478bd9Sstevel@tonic-gate ! 9437c478bd9Sstevel@tonic-gate ! Set bit for this level in CPU's active interrupt bitmask. 9447c478bd9Sstevel@tonic-gate ! 9457c478bd9Sstevel@tonic-gate ld [%o3 + CPU_INTR_ACTV], %o5 ! o5 has cpu_intr_actv b4 chng 9467c478bd9Sstevel@tonic-gate mov 1, %o4 9477c478bd9Sstevel@tonic-gate sll %o4, %o2, %o4 ! construct mask for level 9487c478bd9Sstevel@tonic-gate#ifdef DEBUG 9497c478bd9Sstevel@tonic-gate ! 9507c478bd9Sstevel@tonic-gate ! ASSERT(!(CPU->cpu_intr_actv & (1 << PIL))) 9517c478bd9Sstevel@tonic-gate ! 9527c478bd9Sstevel@tonic-gate andcc %o5, %o4, %g0 9537c478bd9Sstevel@tonic-gate bz,pt %xcc, 0f 9547c478bd9Sstevel@tonic-gate nop 9557c478bd9Sstevel@tonic-gate ! Do not call panic if a panic is already in progress. 9567c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l2 9577c478bd9Sstevel@tonic-gate ld [%l2 + %lo(panic_quiesce)], %l2 9587c478bd9Sstevel@tonic-gate brnz,pn %l2, 0f 9597c478bd9Sstevel@tonic-gate nop 9607c478bd9Sstevel@tonic-gate sethi %hi(current_thread_actv_bit_set), %o0 9617c478bd9Sstevel@tonic-gate call panic 9627c478bd9Sstevel@tonic-gate or %o0, %lo(current_thread_actv_bit_set), %o0 9637c478bd9Sstevel@tonic-gate0: 9647c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 9657c478bd9Sstevel@tonic-gate or %o5, %o4, %o4 9667c478bd9Sstevel@tonic-gate ! 9677c478bd9Sstevel@tonic-gate ! See if we are interrupting another high-level interrupt. 9687c478bd9Sstevel@tonic-gate ! 9697c478bd9Sstevel@tonic-gate srl %o5, LOCK_LEVEL + 1, %o5 ! only look at high-level bits 9707c478bd9Sstevel@tonic-gate brz,pt %o5, 1f 9717c478bd9Sstevel@tonic-gate st %o4, [%o3 + CPU_INTR_ACTV] ! delay - store active mask 9727c478bd9Sstevel@tonic-gate ! 9737c478bd9Sstevel@tonic-gate ! We have interrupted another high-level interrupt. Find its PIL, 9747c478bd9Sstevel@tonic-gate ! compute the interval it ran for, and update its cumulative counter. 9757c478bd9Sstevel@tonic-gate ! 9767c478bd9Sstevel@tonic-gate ! Register usage: 9777c478bd9Sstevel@tonic-gate 9787c478bd9Sstevel@tonic-gate ! o2 = PIL of this interrupt 9797c478bd9Sstevel@tonic-gate ! o5 = high PIL bits of INTR_ACTV (not including this PIL) 9807c478bd9Sstevel@tonic-gate ! l1 = bitmask used to find other active high-level PIL 9817c478bd9Sstevel@tonic-gate ! o4 = index of bit set in l1 9827c478bd9Sstevel@tonic-gate ! Use cpu_intr_actv to find the cpu_pil_high_start[] offset for the 9837c478bd9Sstevel@tonic-gate ! interrupted high-level interrupt. 9847c478bd9Sstevel@tonic-gate ! Create mask for cpu_intr_actv. Begin by looking for bits set 9857c478bd9Sstevel@tonic-gate ! at one level below the current PIL. Since %o5 contains the active 9867c478bd9Sstevel@tonic-gate ! mask already shifted right by (LOCK_LEVEL + 1), we start by looking 9877c478bd9Sstevel@tonic-gate ! at bit (current_pil - (LOCK_LEVEL + 2)). 9887c478bd9Sstevel@tonic-gate sub %o2, LOCK_LEVEL + 2, %o4 9897c478bd9Sstevel@tonic-gate mov 1, %l1 9907c478bd9Sstevel@tonic-gate sll %l1, %o4, %l1 9917c478bd9Sstevel@tonic-gate2: 9927c478bd9Sstevel@tonic-gate#ifdef DEBUG 9937c478bd9Sstevel@tonic-gate ! ASSERT(%l1 != 0) (we didn't shift the bit off the right edge) 9947c478bd9Sstevel@tonic-gate brnz,pt %l1, 9f 9957c478bd9Sstevel@tonic-gate nop 9967c478bd9Sstevel@tonic-gate 9977c478bd9Sstevel@tonic-gate ! Don't panic if a panic is already in progress. 9987c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l3 9997c478bd9Sstevel@tonic-gate ld [%l3 + %lo(panic_quiesce)], %l3 10007c478bd9Sstevel@tonic-gate brnz,pn %l3, 9f 10017c478bd9Sstevel@tonic-gate nop 10027c478bd9Sstevel@tonic-gate sethi %hi(current_thread_nested_PIL_not_found), %o0 10037c478bd9Sstevel@tonic-gate call panic 10047c478bd9Sstevel@tonic-gate or %o0, %lo(current_thread_nested_PIL_not_found), %o0 10057c478bd9Sstevel@tonic-gate9: 10067c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 10077c478bd9Sstevel@tonic-gate andcc %l1, %o5, %g0 ! test mask against high-level bits of 10087c478bd9Sstevel@tonic-gate bnz %xcc, 3f ! cpu_intr_actv 10097c478bd9Sstevel@tonic-gate nop 10107c478bd9Sstevel@tonic-gate srl %l1, 1, %l1 ! No match. Try next lower PIL. 10117c478bd9Sstevel@tonic-gate ba,pt %xcc, 2b 10127c478bd9Sstevel@tonic-gate sub %o4, 1, %o4 ! delay - decrement PIL 10137c478bd9Sstevel@tonic-gate3: 10147c478bd9Sstevel@tonic-gate sll %o4, 3, %o4 ! index to byte offset 10157c478bd9Sstevel@tonic-gate add %o4, CPU_MCPU, %l1 ! CPU_PIL_HIGH_START is too large 10167c478bd9Sstevel@tonic-gate add %l1, MCPU_PIL_HIGH_START, %l1 10177c478bd9Sstevel@tonic-gate ldx [%o3 + %l1], %l3 ! load starting timestamp 10187c478bd9Sstevel@tonic-gate#ifdef DEBUG 10197c478bd9Sstevel@tonic-gate brnz,pt %l3, 9f 10207c478bd9Sstevel@tonic-gate nop 10217c478bd9Sstevel@tonic-gate ! Don't panic if a panic is already in progress. 10227c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l1 10237c478bd9Sstevel@tonic-gate ld [%l1 + %lo(panic_quiesce)], %l1 10247c478bd9Sstevel@tonic-gate brnz,pn %l1, 9f 10257c478bd9Sstevel@tonic-gate nop 10267c478bd9Sstevel@tonic-gate srl %o4, 3, %o1 ! Find interrupted PIL for panic 10277c478bd9Sstevel@tonic-gate add %o1, LOCK_LEVEL + 1, %o1 10287c478bd9Sstevel@tonic-gate sethi %hi(current_thread_nested_pil_zero), %o0 10297c478bd9Sstevel@tonic-gate call panic 10307c478bd9Sstevel@tonic-gate or %o0, %lo(current_thread_nested_pil_zero), %o0 10317c478bd9Sstevel@tonic-gate9: 10327c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 10337c478bd9Sstevel@tonic-gate rdpr %tick, %l1 10347c478bd9Sstevel@tonic-gate sllx %l1, 1, %l1 10357c478bd9Sstevel@tonic-gate srlx %l1, 1, %l1 ! shake off NPT bit 10367c478bd9Sstevel@tonic-gate sub %l1, %l3, %l3 ! interval in %l3 10377c478bd9Sstevel@tonic-gate ! 10387c478bd9Sstevel@tonic-gate ! Check for Energy Star mode 10397c478bd9Sstevel@tonic-gate ! 10407c478bd9Sstevel@tonic-gate lduh [%o3 + CPU_DIVISOR], %l1 ! %l1 = clock divisor 10417c478bd9Sstevel@tonic-gate cmp %l1, 1 10427c478bd9Sstevel@tonic-gate bg,a,pn %xcc, 2f 10437c478bd9Sstevel@tonic-gate mulx %l3, %l1, %l3 ! multiply interval by clock divisor iff > 1 10447c478bd9Sstevel@tonic-gate2: 10457c478bd9Sstevel@tonic-gate ! 10467c478bd9Sstevel@tonic-gate ! We need to find the CPU offset of the cumulative counter. We start 10477c478bd9Sstevel@tonic-gate ! with %o4, which has (PIL - (LOCK_LEVEL + 1)) * 8. We need PIL * 16, 10487c478bd9Sstevel@tonic-gate ! so we shift left 1, then add (LOCK_LEVEL + 1) * 16, which is 10497c478bd9Sstevel@tonic-gate ! CPU_INTRSTAT_LOW_PIL_OFFSET. 10507c478bd9Sstevel@tonic-gate ! 10517c478bd9Sstevel@tonic-gate sll %o4, 1, %o4 10527c478bd9Sstevel@tonic-gate add %o4, CPU_MCPU, %o4 ! CPU_INTRSTAT const too large 10537c478bd9Sstevel@tonic-gate add %o4, MCPU_INTRSTAT, %o4 ! add parts separately 10547c478bd9Sstevel@tonic-gate add %o4, CPU_INTRSTAT_LOW_PIL_OFFSET, %o4 10557c478bd9Sstevel@tonic-gate ldx [%o3 + %o4], %l1 ! old counter in l1 10567c478bd9Sstevel@tonic-gate add %l1, %l3, %l1 ! new counter in l1 1057eda89462Sesolom stx %l1, [%o3 + %o4] ! store new counter 1058eda89462Sesolom 1059eda89462Sesolom ! Also update intracct[] 1060eda89462Sesolom lduh [%o3 + CPU_MSTATE], %o4 1061eda89462Sesolom sllx %o4, 3, %o4 1062eda89462Sesolom add %o4, CPU_INTRACCT, %o4 1063eda89462Sesolom ldx [%o3 + %o4], %l1 1064eda89462Sesolom add %l1, %l3, %l1 10657c478bd9Sstevel@tonic-gate ! Another high-level interrupt is active below this one, so 10667c478bd9Sstevel@tonic-gate ! there is no need to check for an interrupt thread. That will be 10677c478bd9Sstevel@tonic-gate ! done by the lowest priority high-level interrupt active. 10687c478bd9Sstevel@tonic-gate ba,pt %xcc, 5f 10697c478bd9Sstevel@tonic-gate stx %l1, [%o3 + %o4] ! delay - store new counter 10707c478bd9Sstevel@tonic-gate1: 10717c478bd9Sstevel@tonic-gate ! If we haven't interrupted another high-level interrupt, we may be 10727c478bd9Sstevel@tonic-gate ! interrupting a low level interrupt thread. If so, compute its interval 10737c478bd9Sstevel@tonic-gate ! and update its cumulative counter. 10747c478bd9Sstevel@tonic-gate lduh [THREAD_REG + T_FLAGS], %o4 10757c478bd9Sstevel@tonic-gate andcc %o4, T_INTR_THREAD, %g0 10767c478bd9Sstevel@tonic-gate bz,pt %xcc, 4f 10777c478bd9Sstevel@tonic-gate nop 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate ! We have interrupted an interrupt thread. Take timestamp, compute 10807c478bd9Sstevel@tonic-gate ! interval, update cumulative counter. 10817c478bd9Sstevel@tonic-gate 10827c478bd9Sstevel@tonic-gate ! Check t_intr_start. If it is zero, either intr_thread() or 10837c478bd9Sstevel@tonic-gate ! current_thread() (at a lower PIL, of course) already did 10847c478bd9Sstevel@tonic-gate ! the accounting for the underlying interrupt thread. 10857c478bd9Sstevel@tonic-gate ldx [THREAD_REG + T_INTR_START], %o5 10867c478bd9Sstevel@tonic-gate brz,pn %o5, 4f 10877c478bd9Sstevel@tonic-gate nop 10887c478bd9Sstevel@tonic-gate 10897c478bd9Sstevel@tonic-gate stx %g0, [THREAD_REG + T_INTR_START] 10907c478bd9Sstevel@tonic-gate rdpr %tick, %o4 10917c478bd9Sstevel@tonic-gate sllx %o4, 1, %o4 10927c478bd9Sstevel@tonic-gate srlx %o4, 1, %o4 ! shake off NPT bit 10937c478bd9Sstevel@tonic-gate sub %o4, %o5, %o5 ! o5 has the interval 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate ! Check for Energy Star mode 10967c478bd9Sstevel@tonic-gate lduh [%o3 + CPU_DIVISOR], %o4 ! %o4 = clock divisor 10977c478bd9Sstevel@tonic-gate cmp %o4, 1 10987c478bd9Sstevel@tonic-gate bg,a,pn %xcc, 2f 10997c478bd9Sstevel@tonic-gate mulx %o5, %o4, %o5 ! multiply interval by clock divisor iff > 1 11007c478bd9Sstevel@tonic-gate2: 11017c478bd9Sstevel@tonic-gate ldub [THREAD_REG + T_PIL], %o4 11027c478bd9Sstevel@tonic-gate sllx %o4, 4, %o4 ! PIL index to byte offset 11037c478bd9Sstevel@tonic-gate add %o4, CPU_MCPU, %o4 ! CPU_INTRSTAT const too large 11047c478bd9Sstevel@tonic-gate add %o4, MCPU_INTRSTAT, %o4 ! add parts separately 11057c478bd9Sstevel@tonic-gate ldx [%o3 + %o4], %l2 ! old counter in l2 11067c478bd9Sstevel@tonic-gate add %l2, %o5, %l2 ! new counter in l2 11077c478bd9Sstevel@tonic-gate stx %l2, [%o3 + %o4] ! store new counter 11087c478bd9Sstevel@tonic-gate 1109eda89462Sesolom ! Also update intracct[] 1110eda89462Sesolom lduh [%o3 + CPU_MSTATE], %o4 1111eda89462Sesolom sllx %o4, 3, %o4 1112eda89462Sesolom add %o4, CPU_INTRACCT, %o4 1113eda89462Sesolom ldx [%o3 + %o4], %l2 1114eda89462Sesolom add %l2, %o5, %l2 1115eda89462Sesolom stx %l2, [%o3 + %o4] 11167c478bd9Sstevel@tonic-gate4: 11177c478bd9Sstevel@tonic-gate ! 11187c478bd9Sstevel@tonic-gate ! Handle high-level interrupts on separate interrupt stack. 11197c478bd9Sstevel@tonic-gate ! No other high-level interrupts are active, so switch to int stack. 11207c478bd9Sstevel@tonic-gate ! 11217c478bd9Sstevel@tonic-gate mov %sp, %l1 11227c478bd9Sstevel@tonic-gate ldn [%o3 + CPU_INTR_STACK], %l3 11237c478bd9Sstevel@tonic-gate sub %l3, STACK_BIAS, %sp 11247c478bd9Sstevel@tonic-gate 11257c478bd9Sstevel@tonic-gate5: 11267c478bd9Sstevel@tonic-gate#ifdef DEBUG 11277c478bd9Sstevel@tonic-gate ! 11287c478bd9Sstevel@tonic-gate ! ASSERT(%o2 > LOCK_LEVEL) 11297c478bd9Sstevel@tonic-gate ! 11307c478bd9Sstevel@tonic-gate cmp %o2, LOCK_LEVEL 11317c478bd9Sstevel@tonic-gate bg,pt %xcc, 3f 11327c478bd9Sstevel@tonic-gate nop 11337c478bd9Sstevel@tonic-gate mov CE_PANIC, %o0 11347c478bd9Sstevel@tonic-gate sethi %hi(current_thread_wrong_pil), %o1 11357c478bd9Sstevel@tonic-gate call cmn_err ! %o2 has the %pil already 11367c478bd9Sstevel@tonic-gate or %o1, %lo(current_thread_wrong_pil), %o1 11377c478bd9Sstevel@tonic-gate#endif 11387c478bd9Sstevel@tonic-gate3: 11397c478bd9Sstevel@tonic-gate ! Store starting timestamp for this PIL in CPU structure at 11407c478bd9Sstevel@tonic-gate ! cpu.cpu_m.pil_high_start[PIL - (LOCK_LEVEL + 1)] 11417c478bd9Sstevel@tonic-gate sub %o2, LOCK_LEVEL + 1, %o4 ! convert PIL to array index 11427c478bd9Sstevel@tonic-gate sllx %o4, 3, %o4 ! index to byte offset 11437c478bd9Sstevel@tonic-gate add %o4, CPU_MCPU, %o4 ! CPU_PIL_HIGH_START is too large 11447c478bd9Sstevel@tonic-gate add %o4, MCPU_PIL_HIGH_START, %o4 11457c478bd9Sstevel@tonic-gate rdpr %tick, %o5 11467c478bd9Sstevel@tonic-gate sllx %o5, 1, %o5 11477c478bd9Sstevel@tonic-gate srlx %o5, 1, %o5 11487c478bd9Sstevel@tonic-gate stx %o5, [%o3 + %o4] 11497c478bd9Sstevel@tonic-gate 11507c478bd9Sstevel@tonic-gate wrpr %g0, %o2, %pil ! enable interrupts 11517c478bd9Sstevel@tonic-gate 11527c478bd9Sstevel@tonic-gate ! 11537c478bd9Sstevel@tonic-gate ! call the handler 11547c478bd9Sstevel@tonic-gate ! 11557c478bd9Sstevel@tonic-gate SERVE_INTR_PRE(%o1, %o3, %l2, %l3, %o4, %o5, %o2, %o0) 11567c478bd9Sstevel@tonic-gate1: 11577c478bd9Sstevel@tonic-gate SERVE_INTR(%o1, %o3, %l2, %l3, %o4, %o5, %o2, %o0) 11587c478bd9Sstevel@tonic-gate 11597c478bd9Sstevel@tonic-gate brz,a,pt %o2, 0f ! if %o2, more intrs await 11607c478bd9Sstevel@tonic-gate rdpr %pil, %o2 ! delay annulled 11617c478bd9Sstevel@tonic-gate SERVE_INTR_NEXT(%o1, %o3, %l2, %l3, %o4, %o5, %o2, %o0) 11627c478bd9Sstevel@tonic-gate ba 1b 11637c478bd9Sstevel@tonic-gate nop 11647c478bd9Sstevel@tonic-gate0: 11657c478bd9Sstevel@tonic-gate wrpr %g0, PIL_MAX, %pil ! disable interrupts (1-15) 11667c478bd9Sstevel@tonic-gate 11677c478bd9Sstevel@tonic-gate cmp %o2, PIL_15 11687c478bd9Sstevel@tonic-gate bne,pt %xcc, 3f 11697c478bd9Sstevel@tonic-gate nop 11707c478bd9Sstevel@tonic-gate 11717c478bd9Sstevel@tonic-gate sethi %hi(cpc_level15_inum), %o1 1172*b0fc0e77Sgovinda ldx [%o1 + %lo(cpc_level15_inum)], %o1 ! arg for intr_enqueue_req 11737c478bd9Sstevel@tonic-gate brz %o1, 3f 11747c478bd9Sstevel@tonic-gate nop 11757c478bd9Sstevel@tonic-gate 11767c478bd9Sstevel@tonic-gate rdpr %pstate, %g5 11777c478bd9Sstevel@tonic-gate andn %g5, PSTATE_IE, %g1 11787c478bd9Sstevel@tonic-gate wrpr %g0, %g1, %pstate ! Disable vec interrupts 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate call intr_enqueue_req ! preserves %g5 11817c478bd9Sstevel@tonic-gate mov PIL_15, %o0 11827c478bd9Sstevel@tonic-gate 11837c478bd9Sstevel@tonic-gate ! clear perfcntr overflow 11847c478bd9Sstevel@tonic-gate mov 1, %o0 11857c478bd9Sstevel@tonic-gate sllx %o0, PIL_15, %o0 11867c478bd9Sstevel@tonic-gate wr %o0, CLEAR_SOFTINT 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate wrpr %g0, %g5, %pstate ! Enable vec interrupts 11897c478bd9Sstevel@tonic-gate 11907c478bd9Sstevel@tonic-gate3: 11917c478bd9Sstevel@tonic-gate cmp %o2, PIL_14 11927c478bd9Sstevel@tonic-gate be tick_rtt ! cpu-specific tick processing 11937c478bd9Sstevel@tonic-gate nop 11947c478bd9Sstevel@tonic-gate .global current_thread_complete 11957c478bd9Sstevel@tonic-gatecurrent_thread_complete: 11967c478bd9Sstevel@tonic-gate ! 11977c478bd9Sstevel@tonic-gate ! Register usage: 11987c478bd9Sstevel@tonic-gate ! 11997c478bd9Sstevel@tonic-gate ! %l1 = stack pointer 12007c478bd9Sstevel@tonic-gate ! %l2 = CPU_INTR_ACTV >> (LOCK_LEVEL + 1) 12017c478bd9Sstevel@tonic-gate ! %o2 = PIL 12027c478bd9Sstevel@tonic-gate ! %o3 = CPU pointer 12037c478bd9Sstevel@tonic-gate ! %o4, %o5, %l3, %l4, %l5 = scratch 12047c478bd9Sstevel@tonic-gate ! 12057c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CPU], %o3 12067c478bd9Sstevel@tonic-gate ! 12077c478bd9Sstevel@tonic-gate ! Clear bit for this level in CPU's interrupt active bitmask. 12087c478bd9Sstevel@tonic-gate ! 12097c478bd9Sstevel@tonic-gate ld [%o3 + CPU_INTR_ACTV], %l2 12107c478bd9Sstevel@tonic-gate mov 1, %o5 12117c478bd9Sstevel@tonic-gate sll %o5, %o2, %o5 12127c478bd9Sstevel@tonic-gate#ifdef DEBUG 12137c478bd9Sstevel@tonic-gate ! 12147c478bd9Sstevel@tonic-gate ! ASSERT(CPU->cpu_intr_actv & (1 << PIL)) 12157c478bd9Sstevel@tonic-gate ! 12167c478bd9Sstevel@tonic-gate andcc %l2, %o5, %g0 12177c478bd9Sstevel@tonic-gate bnz,pt %xcc, 0f 12187c478bd9Sstevel@tonic-gate nop 12197c478bd9Sstevel@tonic-gate ! Do not call panic if a panic is already in progress. 12207c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l2 12217c478bd9Sstevel@tonic-gate ld [%l2 + %lo(panic_quiesce)], %l2 12227c478bd9Sstevel@tonic-gate brnz,pn %l2, 0f 12237c478bd9Sstevel@tonic-gate nop 12247c478bd9Sstevel@tonic-gate sethi %hi(current_thread_actv_bit_not_set), %o0 12257c478bd9Sstevel@tonic-gate call panic 12267c478bd9Sstevel@tonic-gate or %o0, %lo(current_thread_actv_bit_not_set), %o0 12277c478bd9Sstevel@tonic-gate0: 12287c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 12297c478bd9Sstevel@tonic-gate andn %l2, %o5, %l2 12307c478bd9Sstevel@tonic-gate st %l2, [%o3 + CPU_INTR_ACTV] 12317c478bd9Sstevel@tonic-gate 12327c478bd9Sstevel@tonic-gate ! Take timestamp, compute interval, update cumulative counter. 12337c478bd9Sstevel@tonic-gate sub %o2, LOCK_LEVEL + 1, %o4 ! PIL to array index 12347c478bd9Sstevel@tonic-gate sllx %o4, 3, %o4 ! index to byte offset 12357c478bd9Sstevel@tonic-gate add %o4, CPU_MCPU, %o4 ! CPU_PIL_HIGH_START is too large 12367c478bd9Sstevel@tonic-gate add %o4, MCPU_PIL_HIGH_START, %o4 12377c478bd9Sstevel@tonic-gate rdpr %tick, %o5 12387c478bd9Sstevel@tonic-gate sllx %o5, 1, %o5 12397c478bd9Sstevel@tonic-gate srlx %o5, 1, %o5 12407c478bd9Sstevel@tonic-gate ldx [%o3 + %o4], %o0 12417c478bd9Sstevel@tonic-gate#ifdef DEBUG 12427c478bd9Sstevel@tonic-gate ! ASSERT(cpu.cpu_m.pil_high_start[pil - (LOCK_LEVEL + 1)] != 0) 12437c478bd9Sstevel@tonic-gate brnz,pt %o0, 9f 12447c478bd9Sstevel@tonic-gate nop 12457c478bd9Sstevel@tonic-gate ! Don't panic if a panic is already in progress. 12467c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l2 12477c478bd9Sstevel@tonic-gate ld [%l2 + %lo(panic_quiesce)], %l2 12487c478bd9Sstevel@tonic-gate brnz,pn %l2, 9f 12497c478bd9Sstevel@tonic-gate nop 12507c478bd9Sstevel@tonic-gate sethi %hi(current_thread_timestamp_zero), %o0 12517c478bd9Sstevel@tonic-gate call panic 12527c478bd9Sstevel@tonic-gate or %o0, %lo(current_thread_timestamp_zero), %o0 12537c478bd9Sstevel@tonic-gate9: 12547c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 12557c478bd9Sstevel@tonic-gate stx %g0, [%o3 + %o4] 12567c478bd9Sstevel@tonic-gate sub %o5, %o0, %o5 ! interval in o5 12577c478bd9Sstevel@tonic-gate 12587c478bd9Sstevel@tonic-gate ! Check for Energy Star mode 12597c478bd9Sstevel@tonic-gate lduh [%o3 + CPU_DIVISOR], %o4 ! %o4 = clock divisor 12607c478bd9Sstevel@tonic-gate cmp %o4, 1 12617c478bd9Sstevel@tonic-gate bg,a,pn %xcc, 2f 12627c478bd9Sstevel@tonic-gate mulx %o5, %o4, %o5 ! multiply interval by clock divisor iff > 1 12637c478bd9Sstevel@tonic-gate2: 12647c478bd9Sstevel@tonic-gate sllx %o2, 4, %o4 ! PIL index to byte offset 12657c478bd9Sstevel@tonic-gate add %o4, CPU_MCPU, %o4 ! CPU_INTRSTAT too large 12667c478bd9Sstevel@tonic-gate add %o4, MCPU_INTRSTAT, %o4 ! add parts separately 12677c478bd9Sstevel@tonic-gate ldx [%o3 + %o4], %o0 ! old counter in o0 12687c478bd9Sstevel@tonic-gate add %o0, %o5, %o0 ! new counter in o0 12697c478bd9Sstevel@tonic-gate stx %o0, [%o3 + %o4] ! store new counter 12707c478bd9Sstevel@tonic-gate 1271eda89462Sesolom ! Also update intracct[] 1272eda89462Sesolom lduh [%o3 + CPU_MSTATE], %o4 1273eda89462Sesolom sllx %o4, 3, %o4 1274eda89462Sesolom add %o4, CPU_INTRACCT, %o4 1275eda89462Sesolom ldx [%o3 + %o4], %o0 1276eda89462Sesolom add %o0, %o5, %o0 1277eda89462Sesolom stx %o0, [%o3 + %o4] 1278eda89462Sesolom 12797c478bd9Sstevel@tonic-gate ! 12807c478bd9Sstevel@tonic-gate ! get back on current thread's stack 12817c478bd9Sstevel@tonic-gate ! 12827c478bd9Sstevel@tonic-gate srl %l2, LOCK_LEVEL + 1, %l2 12837c478bd9Sstevel@tonic-gate tst %l2 ! any more high-level ints? 12847c478bd9Sstevel@tonic-gate movz %xcc, %l1, %sp 12857c478bd9Sstevel@tonic-gate ! 12867c478bd9Sstevel@tonic-gate ! Current register usage: 12877c478bd9Sstevel@tonic-gate ! o2 = PIL 12887c478bd9Sstevel@tonic-gate ! o3 = CPU pointer 12897c478bd9Sstevel@tonic-gate ! l0 = return address 12907c478bd9Sstevel@tonic-gate ! l2 = intr_actv shifted right 12917c478bd9Sstevel@tonic-gate ! 12927c478bd9Sstevel@tonic-gate bz,pt %xcc, 3f ! if l2 was zero, no more ints 12937c478bd9Sstevel@tonic-gate nop 12947c478bd9Sstevel@tonic-gate ! 12957c478bd9Sstevel@tonic-gate ! We found another high-level interrupt active below the one that just 12967c478bd9Sstevel@tonic-gate ! returned. Store a starting timestamp for it in the CPU structure. 12977c478bd9Sstevel@tonic-gate ! 12987c478bd9Sstevel@tonic-gate ! Use cpu_intr_actv to find the cpu_pil_high_start[] offset for the 12997c478bd9Sstevel@tonic-gate ! interrupted high-level interrupt. 13007c478bd9Sstevel@tonic-gate ! Create mask for cpu_intr_actv. Begin by looking for bits set 13017c478bd9Sstevel@tonic-gate ! at one level below the current PIL. Since %l2 contains the active 13027c478bd9Sstevel@tonic-gate ! mask already shifted right by (LOCK_LEVEL + 1), we start by looking 13037c478bd9Sstevel@tonic-gate ! at bit (current_pil - (LOCK_LEVEL + 2)). 13047c478bd9Sstevel@tonic-gate ! %l1 = mask, %o5 = index of bit set in mask 13057c478bd9Sstevel@tonic-gate ! 13067c478bd9Sstevel@tonic-gate mov 1, %l1 13077c478bd9Sstevel@tonic-gate sub %o2, LOCK_LEVEL + 2, %o5 13087c478bd9Sstevel@tonic-gate sll %l1, %o5, %l1 ! l1 = mask for level 13097c478bd9Sstevel@tonic-gate1: 13107c478bd9Sstevel@tonic-gate#ifdef DEBUG 13117c478bd9Sstevel@tonic-gate ! ASSERT(%l1 != 0) (we didn't shift the bit off the right edge) 13127c478bd9Sstevel@tonic-gate brnz,pt %l1, 9f 13137c478bd9Sstevel@tonic-gate nop 13147c478bd9Sstevel@tonic-gate sethi %hi(current_thread_nested_PIL_not_found), %o0 13157c478bd9Sstevel@tonic-gate call panic 13167c478bd9Sstevel@tonic-gate or %o0, %lo(current_thread_nested_PIL_not_found), %o0 13177c478bd9Sstevel@tonic-gate9: 13187c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 13197c478bd9Sstevel@tonic-gate andcc %l1, %l2, %g0 ! test mask against high-level bits of 13207c478bd9Sstevel@tonic-gate bnz %xcc, 2f ! cpu_intr_actv 13217c478bd9Sstevel@tonic-gate nop 13227c478bd9Sstevel@tonic-gate srl %l1, 1, %l1 ! No match. Try next lower PIL. 13237c478bd9Sstevel@tonic-gate ba,pt %xcc, 1b 13247c478bd9Sstevel@tonic-gate sub %o5, 1, %o5 ! delay - decrement PIL 13257c478bd9Sstevel@tonic-gate2: 13267c478bd9Sstevel@tonic-gate sll %o5, 3, %o5 ! convert array index to byte offset 13277c478bd9Sstevel@tonic-gate add %o5, CPU_MCPU, %o5 ! CPU_PIL_HIGH_START is too large 13287c478bd9Sstevel@tonic-gate add %o5, MCPU_PIL_HIGH_START, %o5 13297c478bd9Sstevel@tonic-gate rdpr %tick, %o4 13307c478bd9Sstevel@tonic-gate sllx %o4, 1, %o4 13317c478bd9Sstevel@tonic-gate srlx %o4, 1, %o4 13327c478bd9Sstevel@tonic-gate ! Another high-level interrupt is active below this one, so 13337c478bd9Sstevel@tonic-gate ! there is no need to check for an interrupt thread. That will be 13347c478bd9Sstevel@tonic-gate ! done by the lowest priority high-level interrupt active. 13357c478bd9Sstevel@tonic-gate ba,pt %xcc, 1f 13367c478bd9Sstevel@tonic-gate stx %o4, [%o3 + %o5] ! delay - store timestamp 13377c478bd9Sstevel@tonic-gate3: 13387c478bd9Sstevel@tonic-gate ! If we haven't interrupted another high-level interrupt, we may have 13397c478bd9Sstevel@tonic-gate ! interrupted a low level interrupt thread. If so, store a starting 13407c478bd9Sstevel@tonic-gate ! timestamp in its thread structure. 13417c478bd9Sstevel@tonic-gate lduh [THREAD_REG + T_FLAGS], %o4 13427c478bd9Sstevel@tonic-gate andcc %o4, T_INTR_THREAD, %g0 13437c478bd9Sstevel@tonic-gate bz,pt %xcc, 1f 13447c478bd9Sstevel@tonic-gate nop 13457c478bd9Sstevel@tonic-gate 13467c478bd9Sstevel@tonic-gate rdpr %tick, %o4 13477c478bd9Sstevel@tonic-gate sllx %o4, 1, %o4 13487c478bd9Sstevel@tonic-gate srlx %o4, 1, %o4 ! Shake off NPT bit 13497c478bd9Sstevel@tonic-gate stx %o4, [THREAD_REG + T_INTR_START] 13507c478bd9Sstevel@tonic-gate1: 13517c478bd9Sstevel@tonic-gate ! Enable interrupts and return 13527c478bd9Sstevel@tonic-gate jmp %l0 + 8 13537c478bd9Sstevel@tonic-gate wrpr %g0, %o2, %pil ! enable interrupts 13547c478bd9Sstevel@tonic-gate SET_SIZE(current_thread) 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate 13577c478bd9Sstevel@tonic-gate#ifdef DEBUG 13587c478bd9Sstevel@tonic-gatecurrent_thread_wrong_pil: 13597c478bd9Sstevel@tonic-gate .asciz "current_thread: unexpected pil level: %d" 13607c478bd9Sstevel@tonic-gatecurrent_thread_actv_bit_set: 13617c478bd9Sstevel@tonic-gate .asciz "current_thread(): cpu_intr_actv bit already set for PIL" 13627c478bd9Sstevel@tonic-gatecurrent_thread_actv_bit_not_set: 13637c478bd9Sstevel@tonic-gate .asciz "current_thread(): cpu_intr_actv bit not set for PIL" 13647c478bd9Sstevel@tonic-gatecurrent_thread_nested_pil_zero: 13657c478bd9Sstevel@tonic-gate .asciz "current_thread(): timestamp zero for nested PIL %d" 13667c478bd9Sstevel@tonic-gatecurrent_thread_timestamp_zero: 13677c478bd9Sstevel@tonic-gate .asciz "current_thread(): timestamp zero upon handler return" 13687c478bd9Sstevel@tonic-gatecurrent_thread_nested_PIL_not_found: 13697c478bd9Sstevel@tonic-gate .asciz "current_thread: couldn't find nested high-level PIL" 13707c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 13717c478bd9Sstevel@tonic-gate#endif /* lint */ 13727c478bd9Sstevel@tonic-gate 13737c478bd9Sstevel@tonic-gate/* 13747c478bd9Sstevel@tonic-gate * Return a thread's interrupt level. 13757c478bd9Sstevel@tonic-gate * Since this isn't saved anywhere but in %l4 on interrupt entry, we 13767c478bd9Sstevel@tonic-gate * must dig it out of the save area. 13777c478bd9Sstevel@tonic-gate * 13787c478bd9Sstevel@tonic-gate * Caller 'swears' that this really is an interrupt thread. 13797c478bd9Sstevel@tonic-gate * 13807c478bd9Sstevel@tonic-gate * int 13817c478bd9Sstevel@tonic-gate * intr_level(t) 13827c478bd9Sstevel@tonic-gate * kthread_id_t t; 13837c478bd9Sstevel@tonic-gate */ 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate#if defined(lint) 13867c478bd9Sstevel@tonic-gate 13877c478bd9Sstevel@tonic-gate/* ARGSUSED */ 13887c478bd9Sstevel@tonic-gateint 13897c478bd9Sstevel@tonic-gateintr_level(kthread_id_t t) 13907c478bd9Sstevel@tonic-gate{ return (0); } 13917c478bd9Sstevel@tonic-gate 13927c478bd9Sstevel@tonic-gate#else /* lint */ 13937c478bd9Sstevel@tonic-gate 13947c478bd9Sstevel@tonic-gate ENTRY_NP(intr_level) 13957c478bd9Sstevel@tonic-gate retl 13967c478bd9Sstevel@tonic-gate ldub [%o0 + T_PIL], %o0 ! return saved pil 13977c478bd9Sstevel@tonic-gate SET_SIZE(intr_level) 13987c478bd9Sstevel@tonic-gate 13997c478bd9Sstevel@tonic-gate#endif /* lint */ 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate#if defined(lint) 14027c478bd9Sstevel@tonic-gate 14037c478bd9Sstevel@tonic-gate/* ARGSUSED */ 14047c478bd9Sstevel@tonic-gateint 14057c478bd9Sstevel@tonic-gatedisable_pil_intr() 14067c478bd9Sstevel@tonic-gate{ return (0); } 14077c478bd9Sstevel@tonic-gate 14087c478bd9Sstevel@tonic-gate#else /* lint */ 14097c478bd9Sstevel@tonic-gate 14107c478bd9Sstevel@tonic-gate ENTRY_NP(disable_pil_intr) 14117c478bd9Sstevel@tonic-gate rdpr %pil, %o0 14127c478bd9Sstevel@tonic-gate retl 14137c478bd9Sstevel@tonic-gate wrpr %g0, PIL_MAX, %pil ! disable interrupts (1-15) 14147c478bd9Sstevel@tonic-gate SET_SIZE(disable_pil_intr) 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate#endif /* lint */ 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate#if defined(lint) 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate/* ARGSUSED */ 14217c478bd9Sstevel@tonic-gatevoid 14227c478bd9Sstevel@tonic-gateenable_pil_intr(int pil_save) 14237c478bd9Sstevel@tonic-gate{} 14247c478bd9Sstevel@tonic-gate 14257c478bd9Sstevel@tonic-gate#else /* lint */ 14267c478bd9Sstevel@tonic-gate 14277c478bd9Sstevel@tonic-gate ENTRY_NP(enable_pil_intr) 14287c478bd9Sstevel@tonic-gate retl 14297c478bd9Sstevel@tonic-gate wrpr %o0, %pil 14307c478bd9Sstevel@tonic-gate SET_SIZE(enable_pil_intr) 14317c478bd9Sstevel@tonic-gate 14327c478bd9Sstevel@tonic-gate#endif /* lint */ 14337c478bd9Sstevel@tonic-gate 14347c478bd9Sstevel@tonic-gate#if defined(lint) 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate/* ARGSUSED */ 14377c478bd9Sstevel@tonic-gateuint_t 14387c478bd9Sstevel@tonic-gatedisable_vec_intr(void) 14397c478bd9Sstevel@tonic-gate{ return (0); } 14407c478bd9Sstevel@tonic-gate 14417c478bd9Sstevel@tonic-gate#else /* lint */ 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate ENTRY_NP(disable_vec_intr) 14447c478bd9Sstevel@tonic-gate rdpr %pstate, %o0 14457c478bd9Sstevel@tonic-gate andn %o0, PSTATE_IE, %g1 14467c478bd9Sstevel@tonic-gate retl 14477c478bd9Sstevel@tonic-gate wrpr %g0, %g1, %pstate ! disable interrupt 14487c478bd9Sstevel@tonic-gate SET_SIZE(disable_vec_intr) 14497c478bd9Sstevel@tonic-gate 14507c478bd9Sstevel@tonic-gate#endif /* lint */ 14517c478bd9Sstevel@tonic-gate 14527c478bd9Sstevel@tonic-gate#if defined(lint) 14537c478bd9Sstevel@tonic-gate 14547c478bd9Sstevel@tonic-gate/* ARGSUSED */ 14557c478bd9Sstevel@tonic-gatevoid 14567c478bd9Sstevel@tonic-gateenable_vec_intr(uint_t pstate_save) 14577c478bd9Sstevel@tonic-gate{} 14587c478bd9Sstevel@tonic-gate 14597c478bd9Sstevel@tonic-gate#else /* lint */ 14607c478bd9Sstevel@tonic-gate 14617c478bd9Sstevel@tonic-gate ENTRY_NP(enable_vec_intr) 14627c478bd9Sstevel@tonic-gate retl 14637c478bd9Sstevel@tonic-gate wrpr %g0, %o0, %pstate 14647c478bd9Sstevel@tonic-gate SET_SIZE(enable_vec_intr) 14657c478bd9Sstevel@tonic-gate 14667c478bd9Sstevel@tonic-gate#endif /* lint */ 14677c478bd9Sstevel@tonic-gate 14687c478bd9Sstevel@tonic-gate#if defined(lint) 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gatevoid 14717c478bd9Sstevel@tonic-gatecbe_level14(void) 14727c478bd9Sstevel@tonic-gate{} 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate#else /* lint */ 14757c478bd9Sstevel@tonic-gate 14767c478bd9Sstevel@tonic-gate ENTRY_NP(cbe_level14) 14777c478bd9Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp ! get a new window 14787c478bd9Sstevel@tonic-gate ! 14797c478bd9Sstevel@tonic-gate ! Make sure that this is from TICK_COMPARE; if not just return 14807c478bd9Sstevel@tonic-gate ! 14817c478bd9Sstevel@tonic-gate rd SOFTINT, %l1 14827c478bd9Sstevel@tonic-gate set (TICK_INT_MASK | STICK_INT_MASK), %o2 14837c478bd9Sstevel@tonic-gate andcc %l1, %o2, %g0 14847c478bd9Sstevel@tonic-gate bz,pn %icc, 2f 14857c478bd9Sstevel@tonic-gate nop 14867c478bd9Sstevel@tonic-gate 14877c478bd9Sstevel@tonic-gate CPU_ADDR(%o1, %o2) 14887c478bd9Sstevel@tonic-gate call cyclic_fire 14897c478bd9Sstevel@tonic-gate mov %o1, %o0 14907c478bd9Sstevel@tonic-gate2: 14917c478bd9Sstevel@tonic-gate ret 14927c478bd9Sstevel@tonic-gate restore %g0, 1, %o0 14937c478bd9Sstevel@tonic-gate SET_SIZE(cbe_level14) 14947c478bd9Sstevel@tonic-gate 14957c478bd9Sstevel@tonic-gate#endif /* lint */ 14967c478bd9Sstevel@tonic-gate 14977c478bd9Sstevel@tonic-gate 14987c478bd9Sstevel@tonic-gate#if defined(lint) 14997c478bd9Sstevel@tonic-gate 15007c478bd9Sstevel@tonic-gate/* ARGSUSED */ 15017c478bd9Sstevel@tonic-gatevoid 1502*b0fc0e77Sgovindasetsoftint(uint64_t iv_p) 15037c478bd9Sstevel@tonic-gate{} 15047c478bd9Sstevel@tonic-gate 15057c478bd9Sstevel@tonic-gate#else /* lint */ 15067c478bd9Sstevel@tonic-gate 15077c478bd9Sstevel@tonic-gate ENTRY_NP(setsoftint) 15087c478bd9Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp ! get a new window 15097c478bd9Sstevel@tonic-gate rdpr %pstate, %l5 15107c478bd9Sstevel@tonic-gate andn %l5, PSTATE_IE, %l1 15117c478bd9Sstevel@tonic-gate wrpr %l1, %pstate ! disable interrupt 15127c478bd9Sstevel@tonic-gate ! 1513*b0fc0e77Sgovinda ! We have a pointer to an interrupt vector data structure. 1514*b0fc0e77Sgovinda ! Put the request on the cpu's softint priority list and 1515*b0fc0e77Sgovinda ! set %set_softint. 15167c478bd9Sstevel@tonic-gate ! 15177c478bd9Sstevel@tonic-gate ! Register usage 1518*b0fc0e77Sgovinda ! %i0 - pointer to intr_vec_t (iv) 15197c478bd9Sstevel@tonic-gate ! %l2 - requested pil 1520*b0fc0e77Sgovinda ! %l4 - cpu 1521*b0fc0e77Sgovinda ! %l5 - pstate 1522*b0fc0e77Sgovinda ! %l1, %l3, %l6 - temps 15237c478bd9Sstevel@tonic-gate ! 1524*b0fc0e77Sgovinda ! check if a softint is pending for this softint, 1525*b0fc0e77Sgovinda ! if one is pending, don't bother queuing another. 15267c478bd9Sstevel@tonic-gate ! 1527*b0fc0e77Sgovinda lduh [%i0 + IV_FLAGS], %l1 ! %l1 = iv->iv_flags 1528*b0fc0e77Sgovinda and %l1, IV_SOFTINT_PEND, %l6 ! %l6 = iv->iv_flags & IV_SOFTINT_PEND 1529*b0fc0e77Sgovinda brnz,pn %l6, 4f ! branch if softint is already pending 1530*b0fc0e77Sgovinda or %l1, IV_SOFTINT_PEND, %l2 1531*b0fc0e77Sgovinda sth %l2, [%i0 + IV_FLAGS] ! Set IV_SOFTINT_PEND flag 1532*b0fc0e77Sgovinda 1533*b0fc0e77Sgovinda CPU_ADDR(%l4, %l2) ! %l4 = cpu 1534*b0fc0e77Sgovinda lduh [%i0 + IV_PIL], %l2 ! %l2 = iv->iv_pil 1535*b0fc0e77Sgovinda 15367c478bd9Sstevel@tonic-gate ! 1537*b0fc0e77Sgovinda ! Insert intr_vec_t (iv) to appropriate cpu's softint priority list 15387c478bd9Sstevel@tonic-gate ! 1539*b0fc0e77Sgovinda sll %l2, CPTRSHIFT, %l0 ! %l0 = offset to pil entry 1540*b0fc0e77Sgovinda add %l4, INTR_TAIL, %l6 ! %l6 = &cpu->m_cpu.intr_tail 1541*b0fc0e77Sgovinda ldn [%l6 + %l0], %l1 ! %l1 = cpu->m_cpu.intr_tail[pil] 1542*b0fc0e77Sgovinda ! current tail (ct) 1543*b0fc0e77Sgovinda brz,pt %l1, 2f ! branch if current tail is NULL 1544*b0fc0e77Sgovinda stn %i0, [%l6 + %l0] ! make intr_vec_t (iv) as new tail 15457c478bd9Sstevel@tonic-gate ! 1546*b0fc0e77Sgovinda ! there's pending intr_vec_t already 15477c478bd9Sstevel@tonic-gate ! 1548*b0fc0e77Sgovinda lduh [%l1 + IV_FLAGS], %l6 ! %l6 = ct->iv_flags 1549*b0fc0e77Sgovinda and %l6, IV_SOFTINT_MT, %l6 ! %l6 = ct->iv_flags & IV_SOFTINT_MT 1550*b0fc0e77Sgovinda brz,pt %l6, 1f ! check for Multi target softint flag 1551*b0fc0e77Sgovinda add %l1, IV_PIL_NEXT, %l3 ! %l3 = &ct->iv_pil_next 1552*b0fc0e77Sgovinda ld [%l4 + CPU_ID], %l6 ! for multi target softint, use cpuid 1553*b0fc0e77Sgovinda sll %l6, CPTRSHIFT, %l6 ! calculate offset address from cpuid 1554*b0fc0e77Sgovinda add %l3, %l6, %l3 ! %l3 = &ct->iv_xpil_next[cpuid] 1555*b0fc0e77Sgovinda1: 15567c478bd9Sstevel@tonic-gate ! 1557*b0fc0e77Sgovinda ! update old tail 15587c478bd9Sstevel@tonic-gate ! 15597c478bd9Sstevel@tonic-gate ba,pt %xcc, 3f 1560*b0fc0e77Sgovinda stn %i0, [%l3] ! [%l3] = iv, set pil_next field 15617c478bd9Sstevel@tonic-gate2: 15627c478bd9Sstevel@tonic-gate ! 1563*b0fc0e77Sgovinda ! no pending intr_vec_t; make intr_vec_t as new head 15647c478bd9Sstevel@tonic-gate ! 1565*b0fc0e77Sgovinda add %l4, INTR_HEAD, %l6 ! %l6 = &cpu->m_cpu.intr_head[pil] 1566*b0fc0e77Sgovinda stn %i0, [%l6 + %l0] ! cpu->m_cpu.intr_head[pil] = iv 15677c478bd9Sstevel@tonic-gate3: 15687c478bd9Sstevel@tonic-gate ! 15697c478bd9Sstevel@tonic-gate ! Write %set_softint with (1<<pil) to cause a "pil" level trap 15707c478bd9Sstevel@tonic-gate ! 1571*b0fc0e77Sgovinda mov 1, %l1 ! %l1 = 1 1572*b0fc0e77Sgovinda sll %l1, %l2, %l1 ! %l1 = 1 << pil 1573*b0fc0e77Sgovinda wr %l1, SET_SOFTINT ! trigger required pil softint 15747c478bd9Sstevel@tonic-gate4: 1575*b0fc0e77Sgovinda wrpr %g0, %l5, %pstate ! %pstate = saved %pstate (in %l5) 15767c478bd9Sstevel@tonic-gate ret 15777c478bd9Sstevel@tonic-gate restore 15787c478bd9Sstevel@tonic-gate SET_SIZE(setsoftint) 15797c478bd9Sstevel@tonic-gate 15807c478bd9Sstevel@tonic-gate#endif /* lint */ 15817c478bd9Sstevel@tonic-gate 15827c478bd9Sstevel@tonic-gate#if defined(lint) 15837c478bd9Sstevel@tonic-gate 15847c478bd9Sstevel@tonic-gate/*ARGSUSED*/ 15857c478bd9Sstevel@tonic-gatevoid 1586*b0fc0e77Sgovindasetsoftint_tl1(uint64_t iv_p, uint64_t dummy) 15877c478bd9Sstevel@tonic-gate{} 15887c478bd9Sstevel@tonic-gate 15897c478bd9Sstevel@tonic-gate#else /* lint */ 15907c478bd9Sstevel@tonic-gate 15917c478bd9Sstevel@tonic-gate ! 15927c478bd9Sstevel@tonic-gate ! Register usage 1593*b0fc0e77Sgovinda ! Arguments: 1594*b0fc0e77Sgovinda ! %g1 - Pointer to intr_vec_t (iv) 15957c478bd9Sstevel@tonic-gate ! 1596*b0fc0e77Sgovinda ! Internal: 1597*b0fc0e77Sgovinda ! %g2 - pil 1598*b0fc0e77Sgovinda ! %g4 - cpu 1599*b0fc0e77Sgovinda ! %g3,%g5-g7 - temps 1600*b0fc0e77Sgovinda ! 1601*b0fc0e77Sgovinda ENTRY_NP(setsoftint_tl1) 1602*b0fc0e77Sgovinda ! 1603*b0fc0e77Sgovinda ! We have a pointer to an interrupt vector data structure. 1604*b0fc0e77Sgovinda ! Put the request on the cpu's softint priority list and 1605*b0fc0e77Sgovinda ! set %set_softint. 1606*b0fc0e77Sgovinda ! 1607*b0fc0e77Sgovinda CPU_ADDR(%g4, %g2) ! %g4 = cpu 1608*b0fc0e77Sgovinda lduh [%g1 + IV_PIL], %g2 ! %g2 = iv->iv_pil 1609*b0fc0e77Sgovinda 1610*b0fc0e77Sgovinda ! 1611*b0fc0e77Sgovinda ! Insert intr_vec_t (iv) to appropriate cpu's softint priority list 1612*b0fc0e77Sgovinda ! 1613*b0fc0e77Sgovinda sll %g2, CPTRSHIFT, %g7 ! %g7 = offset to pil entry 1614*b0fc0e77Sgovinda add %g4, INTR_TAIL, %g6 ! %g6 = &cpu->m_cpu.intr_tail 1615*b0fc0e77Sgovinda ldn [%g6 + %g7], %g5 ! %g5 = cpu->m_cpu.intr_tail[pil] 1616*b0fc0e77Sgovinda ! current tail (ct) 1617*b0fc0e77Sgovinda brz,pt %g5, 1f ! branch if current tail is NULL 1618*b0fc0e77Sgovinda stn %g1, [%g6 + %g7] ! make intr_rec_t (iv) as new tail 1619*b0fc0e77Sgovinda ! 1620*b0fc0e77Sgovinda ! there's pending intr_vec_t already 1621*b0fc0e77Sgovinda ! 1622*b0fc0e77Sgovinda lduh [%g5 + IV_FLAGS], %g6 ! %g6 = ct->iv_flags 1623*b0fc0e77Sgovinda and %g6, IV_SOFTINT_MT, %g6 ! %g6 = ct->iv_flags & IV_SOFTINT_MT 1624*b0fc0e77Sgovinda brz,pt %g6, 0f ! check for Multi target softint flag 1625*b0fc0e77Sgovinda add %g5, IV_PIL_NEXT, %g3 ! %g3 = &ct->iv_pil_next 1626*b0fc0e77Sgovinda ld [%g4 + CPU_ID], %g6 ! for multi target softint, use cpuid 1627*b0fc0e77Sgovinda sll %g6, CPTRSHIFT, %g6 ! calculate offset address from cpuid 1628*b0fc0e77Sgovinda add %g3, %g6, %g3 ! %g3 = &ct->iv_xpil_next[cpuid] 1629*b0fc0e77Sgovinda0: 1630*b0fc0e77Sgovinda ! 1631*b0fc0e77Sgovinda ! update old tail 1632*b0fc0e77Sgovinda ! 1633*b0fc0e77Sgovinda ba,pt %xcc, 2f 1634*b0fc0e77Sgovinda stn %g1, [%g3] ! [%g3] = iv, set pil_next field 1635*b0fc0e77Sgovinda1: 1636*b0fc0e77Sgovinda ! 1637*b0fc0e77Sgovinda ! no pending intr_vec_t; make intr_vec_t as new head 1638*b0fc0e77Sgovinda ! 1639*b0fc0e77Sgovinda add %g4, INTR_HEAD, %g6 ! %g6 = &cpu->m_cpu.intr_head[pil] 1640*b0fc0e77Sgovinda stn %g1, [%g6 + %g7] ! cpu->m_cpu.intr_head[pil] = iv 1641*b0fc0e77Sgovinda2: 1642*b0fc0e77Sgovinda#ifdef TRAPTRACE 1643*b0fc0e77Sgovinda TRACE_PTR(%g5, %g6) 1644*b0fc0e77Sgovinda GET_TRACE_TICK(%g6) 1645*b0fc0e77Sgovinda stxa %g6, [%g5 + TRAP_ENT_TICK]%asi ! trap_tick = %tick 1646*b0fc0e77Sgovinda TRACE_SAVE_TL_GL_REGS(%g5, %g6) 1647*b0fc0e77Sgovinda rdpr %tt, %g6 1648*b0fc0e77Sgovinda stha %g6, [%g5 + TRAP_ENT_TT]%asi ! trap_type = %tt 1649*b0fc0e77Sgovinda rdpr %tpc, %g6 1650*b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_TPC]%asi ! trap_pc = %tpc 1651*b0fc0e77Sgovinda rdpr %tstate, %g6 1652*b0fc0e77Sgovinda stxa %g6, [%g5 + TRAP_ENT_TSTATE]%asi ! trap_tstate = %tstate 1653*b0fc0e77Sgovinda stna %sp, [%g5 + TRAP_ENT_SP]%asi ! trap_sp = %sp 1654*b0fc0e77Sgovinda stna %g1, [%g5 + TRAP_ENT_TR]%asi ! trap_tr = iv 1655*b0fc0e77Sgovinda ldn [%g1 + IV_PIL_NEXT], %g6 ! 1656*b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_F1]%asi ! trap_f1 = iv->iv_pil_next 1657*b0fc0e77Sgovinda add %g4, INTR_HEAD, %g6 1658*b0fc0e77Sgovinda ldn [%g6 + %g7], %g6 ! %g6=cpu->m_cpu.intr_head[pil] 1659*b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_F2]%asi ! trap_f2 = intr_head[pil] 1660*b0fc0e77Sgovinda add %g4, INTR_TAIL, %g6 1661*b0fc0e77Sgovinda ldn [%g6 + %g7], %g6 ! %g6=cpu->m_cpu.intr_tail[pil] 1662*b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_F3]%asi ! trap_f3 = intr_tail[pil] 1663*b0fc0e77Sgovinda stna %g2, [%g5 + TRAP_ENT_F4]%asi ! trap_f4 = pil 1664*b0fc0e77Sgovinda TRACE_NEXT(%g5, %g6, %g3) 1665*b0fc0e77Sgovinda#endif /* TRAPTRACE */ 1666*b0fc0e77Sgovinda ! 1667*b0fc0e77Sgovinda ! Write %set_softint with (1<<pil) to cause a "pil" level trap 1668*b0fc0e77Sgovinda ! 1669*b0fc0e77Sgovinda mov 1, %g5 ! %g5 = 1 1670*b0fc0e77Sgovinda sll %g5, %g2, %g5 ! %g5 = 1 << pil 1671*b0fc0e77Sgovinda wr %g5, SET_SOFTINT ! trigger required pil softint 1672*b0fc0e77Sgovinda retry 1673*b0fc0e77Sgovinda SET_SIZE(setsoftint_tl1) 1674*b0fc0e77Sgovinda 1675*b0fc0e77Sgovinda#endif /* lint */ 1676*b0fc0e77Sgovinda 1677*b0fc0e77Sgovinda#if defined(lint) 1678*b0fc0e77Sgovinda 1679*b0fc0e77Sgovinda/*ARGSUSED*/ 1680*b0fc0e77Sgovindavoid 1681*b0fc0e77Sgovindasetvecint_tl1(uint64_t inum, uint64_t dummy) 1682*b0fc0e77Sgovinda{} 1683*b0fc0e77Sgovinda 1684*b0fc0e77Sgovinda#else /* lint */ 1685*b0fc0e77Sgovinda 1686*b0fc0e77Sgovinda ! 1687*b0fc0e77Sgovinda ! Register usage 16887c478bd9Sstevel@tonic-gate ! Arguments: 16897c478bd9Sstevel@tonic-gate ! %g1 - inumber 16907c478bd9Sstevel@tonic-gate ! 16917c478bd9Sstevel@tonic-gate ! Internal: 1692*b0fc0e77Sgovinda ! %g1 - softint pil mask 1693*b0fc0e77Sgovinda ! %g2 - pil of intr_vec_t 1694*b0fc0e77Sgovinda ! %g3 - pointer to current intr_vec_t (iv) 1695*b0fc0e77Sgovinda ! %g4 - cpu 16967c478bd9Sstevel@tonic-gate ! %g5, %g6,%g7 - temps 16977c478bd9Sstevel@tonic-gate ! 1698*b0fc0e77Sgovinda ENTRY_NP(setvecint_tl1) 16997c478bd9Sstevel@tonic-gate ! 17007c478bd9Sstevel@tonic-gate ! Verify the inumber received (should be inum < MAXIVNUM). 17017c478bd9Sstevel@tonic-gate ! 17027c478bd9Sstevel@tonic-gate set MAXIVNUM, %g2 17037c478bd9Sstevel@tonic-gate cmp %g1, %g2 17047c478bd9Sstevel@tonic-gate bgeu,pn %xcc, .no_ivintr 17057c478bd9Sstevel@tonic-gate clr %g2 ! expected in .no_ivintr 17067c478bd9Sstevel@tonic-gate 17077c478bd9Sstevel@tonic-gate ! 1708*b0fc0e77Sgovinda ! Fetch data from intr_vec_table according to the inum. 17097c478bd9Sstevel@tonic-gate ! 1710*b0fc0e77Sgovinda ! We have an interrupt number. Fetch the interrupt vector requests 1711*b0fc0e77Sgovinda ! from the interrupt vector table for a given interrupt number and 1712*b0fc0e77Sgovinda ! insert them into cpu's softint priority lists and set %set_softint. 1713*b0fc0e77Sgovinda ! 1714*b0fc0e77Sgovinda set intr_vec_table, %g5 ! %g5 = intr_vec_table 1715*b0fc0e77Sgovinda sll %g1, CPTRSHIFT, %g6 ! %g6 = offset to inum entry in table 1716*b0fc0e77Sgovinda add %g5, %g6, %g5 ! %g5 = &intr_vec_table[inum] 1717*b0fc0e77Sgovinda ldn [%g5], %g3 ! %g3 = pointer to first entry of 1718*b0fc0e77Sgovinda ! intr_vec_t list 17197c478bd9Sstevel@tonic-gate 1720*b0fc0e77Sgovinda ! Verify the first intr_vec_t pointer for a given inum and it should 1721*b0fc0e77Sgovinda ! not be NULL. This used to be guarded by DEBUG but broken drivers can 1722*b0fc0e77Sgovinda ! cause spurious tick interrupts when the softint register is programmed 1723*b0fc0e77Sgovinda ! with 1 << 0 at the end of this routine. Now we always check for a 1724*b0fc0e77Sgovinda ! valid intr_vec_t pointer. 1725*b0fc0e77Sgovinda brz,pn %g3, .no_ivintr 17267c478bd9Sstevel@tonic-gate nop 17277c478bd9Sstevel@tonic-gate 17287c478bd9Sstevel@tonic-gate ! 1729*b0fc0e77Sgovinda ! Traverse the intr_vec_t link list, put each item on to corresponding 1730*b0fc0e77Sgovinda ! CPU softint priority queue, and compose the final softint pil mask. 17317c478bd9Sstevel@tonic-gate ! 1732*b0fc0e77Sgovinda ! At this point: 1733*b0fc0e77Sgovinda ! %g3 = intr_vec_table[inum] 17347c478bd9Sstevel@tonic-gate ! 1735*b0fc0e77Sgovinda CPU_ADDR(%g4, %g2) ! %g4 = cpu 1736*b0fc0e77Sgovinda mov %g0, %g1 ! %g1 = 0, initialize pil mask to 0 1737*b0fc0e77Sgovinda0: 17387c478bd9Sstevel@tonic-gate ! 1739*b0fc0e77Sgovinda ! Insert next intr_vec_t (iv) to appropriate cpu's softint priority list 17407c478bd9Sstevel@tonic-gate ! 1741*b0fc0e77Sgovinda ! At this point: 1742*b0fc0e77Sgovinda ! %g1 = softint pil mask 1743*b0fc0e77Sgovinda ! %g3 = pointer to next intr_vec_t (iv) 1744*b0fc0e77Sgovinda ! %g4 = cpu 17457c478bd9Sstevel@tonic-gate ! 1746*b0fc0e77Sgovinda lduh [%g3 + IV_PIL], %g2 ! %g2 = iv->iv_pil 1747*b0fc0e77Sgovinda sll %g2, CPTRSHIFT, %g7 ! %g7 = offset to pil entry 1748*b0fc0e77Sgovinda add %g4, INTR_TAIL, %g6 ! %g6 = &cpu->m_cpu.intr_tail 1749*b0fc0e77Sgovinda ldn [%g6 + %g7], %g5 ! %g5 = cpu->m_cpu.intr_tail[pil] 1750*b0fc0e77Sgovinda ! current tail (ct) 1751*b0fc0e77Sgovinda brz,pt %g5, 2f ! branch if current tail is NULL 1752*b0fc0e77Sgovinda stn %g3, [%g6 + %g7] ! make intr_vec_t (iv) as new tail 1753*b0fc0e77Sgovinda ! cpu->m_cpu.intr_tail[pil] = iv 17547c478bd9Sstevel@tonic-gate ! 1755*b0fc0e77Sgovinda ! there's pending intr_vec_t already 1756*b0fc0e77Sgovinda ! 1757*b0fc0e77Sgovinda lduh [%g5 + IV_FLAGS], %g6 ! %g6 = ct->iv_flags 1758*b0fc0e77Sgovinda and %g6, IV_SOFTINT_MT, %g6 ! %g6 = ct->iv_flags & IV_SOFTINT_MT 1759*b0fc0e77Sgovinda brz,pt %g6, 1f ! check for Multi target softint flag 1760*b0fc0e77Sgovinda add %g5, IV_PIL_NEXT, %g5 ! %g5 = &ct->iv_pil_next 1761*b0fc0e77Sgovinda ld [%g4 + CPU_ID], %g6 ! for multi target softint, use cpuid 1762*b0fc0e77Sgovinda sll %g6, CPTRSHIFT, %g6 ! calculate offset address from cpuid 1763*b0fc0e77Sgovinda add %g5, %g6, %g5 ! %g5 = &ct->iv_xpil_next[cpuid] 1764*b0fc0e77Sgovinda1: 1765*b0fc0e77Sgovinda ! 1766*b0fc0e77Sgovinda ! update old tail 17677c478bd9Sstevel@tonic-gate ! 17687c478bd9Sstevel@tonic-gate ba,pt %xcc, 3f 1769*b0fc0e77Sgovinda stn %g3, [%g5] ! [%g5] = iv, set pil_next field 17707c478bd9Sstevel@tonic-gate2: 17717c478bd9Sstevel@tonic-gate ! 1772*b0fc0e77Sgovinda ! no pending intr_vec_t; make intr_vec_t as new head 17737c478bd9Sstevel@tonic-gate ! 1774*b0fc0e77Sgovinda add %g4, INTR_HEAD, %g6 ! %g6 = &cpu->m_cpu.intr_head[pil] 1775*b0fc0e77Sgovinda stn %g3, [%g6 + %g7] ! cpu->m_cpu.intr_head[pil] = iv 17767c478bd9Sstevel@tonic-gate3: 17777c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE 1778*b0fc0e77Sgovinda TRACE_PTR(%g5, %g6) 17797c478bd9Sstevel@tonic-gate GET_TRACE_TICK(%g6) 1780*b0fc0e77Sgovinda stxa %g6, [%g5 + TRAP_ENT_TICK]%asi ! trap_tick = %tick 1781*b0fc0e77Sgovinda TRACE_SAVE_TL_GL_REGS(%g5, %g6) 17827c478bd9Sstevel@tonic-gate rdpr %tt, %g6 1783*b0fc0e77Sgovinda stha %g6, [%g5 + TRAP_ENT_TT]%asi ! trap_type = %tt` 17847c478bd9Sstevel@tonic-gate rdpr %tpc, %g6 1785*b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_TPC]%asi ! trap_pc = %tpc 17867c478bd9Sstevel@tonic-gate rdpr %tstate, %g6 1787*b0fc0e77Sgovinda stxa %g6, [%g5 + TRAP_ENT_TSTATE]%asi ! trap_tstate = %tstate 1788*b0fc0e77Sgovinda stna %sp, [%g5 + TRAP_ENT_SP]%asi ! trap_sp = %sp 1789*b0fc0e77Sgovinda stna %g3, [%g5 + TRAP_ENT_TR]%asi ! trap_tr = iv 1790*b0fc0e77Sgovinda stna %g1, [%g5 + TRAP_ENT_F1]%asi ! trap_f1 = pil mask 17917c478bd9Sstevel@tonic-gate add %g4, INTR_HEAD, %g6 1792*b0fc0e77Sgovinda ldn [%g6 + %g7], %g6 ! %g6=cpu->m_cpu.intr_head[pil] 1793*b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_F2]%asi ! trap_f2 = intr_head[pil] 17947c478bd9Sstevel@tonic-gate add %g4, INTR_TAIL, %g6 1795*b0fc0e77Sgovinda ldn [%g6 + %g7], %g6 ! %g6=cpu->m_cpu.intr_tail[pil] 1796*b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_F3]%asi ! trap_f3 = intr_tail[pil] 1797*b0fc0e77Sgovinda stna %g2, [%g5 + TRAP_ENT_F4]%asi ! trap_f4 = pil 1798*b0fc0e77Sgovinda TRACE_NEXT(%g5, %g6, %g7) 17997c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */ 1800*b0fc0e77Sgovinda mov 1, %g6 ! %g6 = 1 1801*b0fc0e77Sgovinda sll %g6, %g2, %g6 ! %g6 = 1 << pil 1802*b0fc0e77Sgovinda or %g1, %g6, %g1 ! %g1 |= (1 << pil), pil mask 1803*b0fc0e77Sgovinda ldn [%g3 + IV_VEC_NEXT], %g3 ! %g3 = pointer to next intr_vec_t (iv) 1804*b0fc0e77Sgovinda brnz,pn %g3, 0b ! iv->iv_vec_next is non NULL, goto 0b 1805*b0fc0e77Sgovinda nop 1806*b0fc0e77Sgovinda wr %g1, SET_SOFTINT ! triggered one or more pil softints 18077c478bd9Sstevel@tonic-gate retry 18087c478bd9Sstevel@tonic-gate 18097c478bd9Sstevel@tonic-gate.no_ivintr: 18107c478bd9Sstevel@tonic-gate ! no_ivintr: arguments: rp, inum (%g1), pil (%g2 == 0) 18117c478bd9Sstevel@tonic-gate mov %g2, %g3 18127c478bd9Sstevel@tonic-gate mov %g1, %g2 18137c478bd9Sstevel@tonic-gate set no_ivintr, %g1 18147c478bd9Sstevel@tonic-gate ba,pt %xcc, sys_trap 18157c478bd9Sstevel@tonic-gate mov PIL_15, %g4 1816*b0fc0e77Sgovinda SET_SIZE(setvecint_tl1) 18177c478bd9Sstevel@tonic-gate 18187c478bd9Sstevel@tonic-gate#endif /* lint */ 18197c478bd9Sstevel@tonic-gate 18207c478bd9Sstevel@tonic-gate#if defined(lint) 18217c478bd9Sstevel@tonic-gate 18227c478bd9Sstevel@tonic-gate/*ARGSUSED*/ 18237c478bd9Sstevel@tonic-gatevoid 18247c478bd9Sstevel@tonic-gatewr_clr_softint(uint_t value) 18257c478bd9Sstevel@tonic-gate{} 18267c478bd9Sstevel@tonic-gate 18277c478bd9Sstevel@tonic-gate#else 18287c478bd9Sstevel@tonic-gate 18297c478bd9Sstevel@tonic-gate ENTRY_NP(wr_clr_softint) 18307c478bd9Sstevel@tonic-gate retl 18317c478bd9Sstevel@tonic-gate wr %o0, CLEAR_SOFTINT 18327c478bd9Sstevel@tonic-gate SET_SIZE(wr_clr_softint) 18337c478bd9Sstevel@tonic-gate 18347c478bd9Sstevel@tonic-gate#endif /* lint */ 18357c478bd9Sstevel@tonic-gate 18367c478bd9Sstevel@tonic-gate#if defined(lint) 18377c478bd9Sstevel@tonic-gate 18387c478bd9Sstevel@tonic-gate/*ARGSUSED*/ 18397c478bd9Sstevel@tonic-gatevoid 1840*b0fc0e77Sgovindaintr_enqueue_req(uint_t pil, uint64_t inum) 18417c478bd9Sstevel@tonic-gate{} 18427c478bd9Sstevel@tonic-gate 18437c478bd9Sstevel@tonic-gate#else /* lint */ 18447c478bd9Sstevel@tonic-gate 18457c478bd9Sstevel@tonic-gate/* 18467c478bd9Sstevel@tonic-gate * intr_enqueue_req 18477c478bd9Sstevel@tonic-gate * 18487c478bd9Sstevel@tonic-gate * %o0 - pil 1849*b0fc0e77Sgovinda * %o1 - pointer to intr_vec_t (iv) 18507c478bd9Sstevel@tonic-gate * %o5 - preserved 18517c478bd9Sstevel@tonic-gate * %g5 - preserved 18527c478bd9Sstevel@tonic-gate */ 18537c478bd9Sstevel@tonic-gate ENTRY_NP(intr_enqueue_req) 1854*b0fc0e77Sgovinda ! 1855*b0fc0e77Sgovinda CPU_ADDR(%g4, %g1) ! %g4 = cpu 18567c478bd9Sstevel@tonic-gate 1857*b0fc0e77Sgovinda ! 1858*b0fc0e77Sgovinda ! Insert intr_vec_t (iv) to appropriate cpu's softint priority list 1859*b0fc0e77Sgovinda ! 1860*b0fc0e77Sgovinda sll %o0, CPTRSHIFT, %o0 ! %o0 = offset to pil entry 1861*b0fc0e77Sgovinda add %g4, INTR_TAIL, %g6 ! %g6 = &cpu->m_cpu.intr_tail 1862*b0fc0e77Sgovinda ldn [%o0 + %g6], %g1 ! %g1 = cpu->m_cpu.intr_tail[pil] 1863*b0fc0e77Sgovinda ! current tail (ct) 1864*b0fc0e77Sgovinda brz,pt %g1, 2f ! branch if current tail is NULL 1865*b0fc0e77Sgovinda stn %o1, [%g6 + %o0] ! make intr_vec_t (iv) as new tail 18667c478bd9Sstevel@tonic-gate 1867*b0fc0e77Sgovinda ! 1868*b0fc0e77Sgovinda ! there's pending intr_vec_t already 1869*b0fc0e77Sgovinda ! 1870*b0fc0e77Sgovinda lduh [%g1 + IV_FLAGS], %g6 ! %g6 = ct->iv_flags 1871*b0fc0e77Sgovinda and %g6, IV_SOFTINT_MT, %g6 ! %g6 = ct->iv_flags & IV_SOFTINT_MT 1872*b0fc0e77Sgovinda brz,pt %g6, 1f ! check for Multi target softint flag 1873*b0fc0e77Sgovinda add %g1, IV_PIL_NEXT, %g3 ! %g3 = &ct->iv_pil_next 1874*b0fc0e77Sgovinda ld [%g4 + CPU_ID], %g6 ! for multi target softint, use cpuid 1875*b0fc0e77Sgovinda sll %g6, CPTRSHIFT, %g6 ! calculate offset address from cpuid 1876*b0fc0e77Sgovinda add %g3, %g6, %g3 ! %g3 = &ct->iv_xpil_next[cpuid] 1877*b0fc0e77Sgovinda1: 1878*b0fc0e77Sgovinda ! 1879*b0fc0e77Sgovinda ! update old tail 1880*b0fc0e77Sgovinda ! 18817c478bd9Sstevel@tonic-gate ba,pt %xcc, 3f 1882*b0fc0e77Sgovinda stn %o1, [%g3] ! {%g5] = iv, set pil_next field 18837c478bd9Sstevel@tonic-gate2: 1884*b0fc0e77Sgovinda ! 1885*b0fc0e77Sgovinda ! no intr_vec_t's queued so make intr_vec_t as new head 1886*b0fc0e77Sgovinda ! 1887*b0fc0e77Sgovinda add %g4, INTR_HEAD, %g6 ! %g6 = &cpu->m_cpu.intr_head[pil] 1888*b0fc0e77Sgovinda stn %o1, [%g6 + %o0] ! cpu->m_cpu.intr_head[pil] = iv 18897c478bd9Sstevel@tonic-gate3: 18907c478bd9Sstevel@tonic-gate retl 18917c478bd9Sstevel@tonic-gate nop 18927c478bd9Sstevel@tonic-gate SET_SIZE(intr_enqueue_req) 18937c478bd9Sstevel@tonic-gate 18947c478bd9Sstevel@tonic-gate#endif /* lint */ 18957c478bd9Sstevel@tonic-gate 18967c478bd9Sstevel@tonic-gate/* 18977c478bd9Sstevel@tonic-gate * Set CPU's base SPL level, based on which interrupt levels are active. 18987c478bd9Sstevel@tonic-gate * Called at spl7 or above. 18997c478bd9Sstevel@tonic-gate */ 19007c478bd9Sstevel@tonic-gate 19017c478bd9Sstevel@tonic-gate#if defined(lint) 19027c478bd9Sstevel@tonic-gate 19037c478bd9Sstevel@tonic-gatevoid 19047c478bd9Sstevel@tonic-gateset_base_spl(void) 19057c478bd9Sstevel@tonic-gate{} 19067c478bd9Sstevel@tonic-gate 19077c478bd9Sstevel@tonic-gate#else /* lint */ 19087c478bd9Sstevel@tonic-gate 19097c478bd9Sstevel@tonic-gate ENTRY_NP(set_base_spl) 19107c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CPU], %o2 ! load CPU pointer 19117c478bd9Sstevel@tonic-gate ld [%o2 + CPU_INTR_ACTV], %o5 ! load active interrupts mask 19127c478bd9Sstevel@tonic-gate 19137c478bd9Sstevel@tonic-gate/* 19147c478bd9Sstevel@tonic-gate * WARNING: non-standard callinq sequence; do not call from C 19157c478bd9Sstevel@tonic-gate * %o2 = pointer to CPU 19167c478bd9Sstevel@tonic-gate * %o5 = updated CPU_INTR_ACTV 19177c478bd9Sstevel@tonic-gate */ 19187c478bd9Sstevel@tonic-gate_intr_set_spl: ! intr_thread_exit enters here 19197c478bd9Sstevel@tonic-gate ! 19207c478bd9Sstevel@tonic-gate ! Determine highest interrupt level active. Several could be blocked 19217c478bd9Sstevel@tonic-gate ! at higher levels than this one, so must convert flags to a PIL 19227c478bd9Sstevel@tonic-gate ! Normally nothing will be blocked, so test this first. 19237c478bd9Sstevel@tonic-gate ! 19247c478bd9Sstevel@tonic-gate brz,pt %o5, 1f ! nothing active 19257c478bd9Sstevel@tonic-gate sra %o5, 11, %o3 ! delay - set %o3 to bits 15-11 19267c478bd9Sstevel@tonic-gate set _intr_flag_table, %o1 19277c478bd9Sstevel@tonic-gate tst %o3 ! see if any of the bits set 19287c478bd9Sstevel@tonic-gate ldub [%o1 + %o3], %o3 ! load bit number 19297c478bd9Sstevel@tonic-gate bnz,a,pn %xcc, 1f ! yes, add 10 and we're done 19307c478bd9Sstevel@tonic-gate add %o3, 11-1, %o3 ! delay - add bit number - 1 19317c478bd9Sstevel@tonic-gate 19327c478bd9Sstevel@tonic-gate sra %o5, 6, %o3 ! test bits 10-6 19337c478bd9Sstevel@tonic-gate tst %o3 19347c478bd9Sstevel@tonic-gate ldub [%o1 + %o3], %o3 19357c478bd9Sstevel@tonic-gate bnz,a,pn %xcc, 1f 19367c478bd9Sstevel@tonic-gate add %o3, 6-1, %o3 19377c478bd9Sstevel@tonic-gate 19387c478bd9Sstevel@tonic-gate sra %o5, 1, %o3 ! test bits 5-1 19397c478bd9Sstevel@tonic-gate ldub [%o1 + %o3], %o3 19407c478bd9Sstevel@tonic-gate 19417c478bd9Sstevel@tonic-gate ! 19427c478bd9Sstevel@tonic-gate ! highest interrupt level number active is in %l6 19437c478bd9Sstevel@tonic-gate ! 19447c478bd9Sstevel@tonic-gate1: 19457c478bd9Sstevel@tonic-gate retl 19467c478bd9Sstevel@tonic-gate st %o3, [%o2 + CPU_BASE_SPL] ! delay - store base priority 19477c478bd9Sstevel@tonic-gate SET_SIZE(set_base_spl) 19487c478bd9Sstevel@tonic-gate 19497c478bd9Sstevel@tonic-gate/* 19507c478bd9Sstevel@tonic-gate * Table that finds the most significant bit set in a five bit field. 19517c478bd9Sstevel@tonic-gate * Each entry is the high-order bit number + 1 of it's index in the table. 19527c478bd9Sstevel@tonic-gate * This read-only data is in the text segment. 19537c478bd9Sstevel@tonic-gate */ 19547c478bd9Sstevel@tonic-gate_intr_flag_table: 19557c478bd9Sstevel@tonic-gate .byte 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4 19567c478bd9Sstevel@tonic-gate .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 19577c478bd9Sstevel@tonic-gate .align 4 19587c478bd9Sstevel@tonic-gate 19597c478bd9Sstevel@tonic-gate#endif /* lint */ 19607c478bd9Sstevel@tonic-gate 19617c478bd9Sstevel@tonic-gate/* 19627c478bd9Sstevel@tonic-gate * int 19637c478bd9Sstevel@tonic-gate * intr_passivate(from, to) 19647c478bd9Sstevel@tonic-gate * kthread_id_t from; interrupt thread 19657c478bd9Sstevel@tonic-gate * kthread_id_t to; interrupted thread 19667c478bd9Sstevel@tonic-gate */ 19677c478bd9Sstevel@tonic-gate 19687c478bd9Sstevel@tonic-gate#if defined(lint) 19697c478bd9Sstevel@tonic-gate 19707c478bd9Sstevel@tonic-gate/* ARGSUSED */ 19717c478bd9Sstevel@tonic-gateint 19727c478bd9Sstevel@tonic-gateintr_passivate(kthread_id_t from, kthread_id_t to) 19737c478bd9Sstevel@tonic-gate{ return (0); } 19747c478bd9Sstevel@tonic-gate 19757c478bd9Sstevel@tonic-gate#else /* lint */ 19767c478bd9Sstevel@tonic-gate 19777c478bd9Sstevel@tonic-gate ENTRY_NP(intr_passivate) 19787c478bd9Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp ! get a new window 19797c478bd9Sstevel@tonic-gate 19807c478bd9Sstevel@tonic-gate flushw ! force register windows to stack 19817c478bd9Sstevel@tonic-gate ! 19827c478bd9Sstevel@tonic-gate ! restore registers from the base of the stack of the interrupt thread. 19837c478bd9Sstevel@tonic-gate ! 19847c478bd9Sstevel@tonic-gate ldn [%i0 + T_STACK], %i2 ! get stack save area pointer 19857c478bd9Sstevel@tonic-gate ldn [%i2 + (0*GREGSIZE)], %l0 ! load locals 19867c478bd9Sstevel@tonic-gate ldn [%i2 + (1*GREGSIZE)], %l1 19877c478bd9Sstevel@tonic-gate ldn [%i2 + (2*GREGSIZE)], %l2 19887c478bd9Sstevel@tonic-gate ldn [%i2 + (3*GREGSIZE)], %l3 19897c478bd9Sstevel@tonic-gate ldn [%i2 + (4*GREGSIZE)], %l4 19907c478bd9Sstevel@tonic-gate ldn [%i2 + (5*GREGSIZE)], %l5 19917c478bd9Sstevel@tonic-gate ldn [%i2 + (6*GREGSIZE)], %l6 19927c478bd9Sstevel@tonic-gate ldn [%i2 + (7*GREGSIZE)], %l7 19937c478bd9Sstevel@tonic-gate ldn [%i2 + (8*GREGSIZE)], %o0 ! put ins from stack in outs 19947c478bd9Sstevel@tonic-gate ldn [%i2 + (9*GREGSIZE)], %o1 19957c478bd9Sstevel@tonic-gate ldn [%i2 + (10*GREGSIZE)], %o2 19967c478bd9Sstevel@tonic-gate ldn [%i2 + (11*GREGSIZE)], %o3 19977c478bd9Sstevel@tonic-gate ldn [%i2 + (12*GREGSIZE)], %o4 19987c478bd9Sstevel@tonic-gate ldn [%i2 + (13*GREGSIZE)], %o5 19997c478bd9Sstevel@tonic-gate ldn [%i2 + (14*GREGSIZE)], %i4 20007c478bd9Sstevel@tonic-gate ! copy stack/pointer without using %sp 20017c478bd9Sstevel@tonic-gate ldn [%i2 + (15*GREGSIZE)], %i5 20027c478bd9Sstevel@tonic-gate ! 20037c478bd9Sstevel@tonic-gate ! put registers into the save area at the top of the interrupted 20047c478bd9Sstevel@tonic-gate ! thread's stack, pointed to by %l7 in the save area just loaded. 20057c478bd9Sstevel@tonic-gate ! 20067c478bd9Sstevel@tonic-gate ldn [%i1 + T_SP], %i3 ! get stack save area pointer 20077c478bd9Sstevel@tonic-gate stn %l0, [%i3 + STACK_BIAS + (0*GREGSIZE)] ! save locals 20087c478bd9Sstevel@tonic-gate stn %l1, [%i3 + STACK_BIAS + (1*GREGSIZE)] 20097c478bd9Sstevel@tonic-gate stn %l2, [%i3 + STACK_BIAS + (2*GREGSIZE)] 20107c478bd9Sstevel@tonic-gate stn %l3, [%i3 + STACK_BIAS + (3*GREGSIZE)] 20117c478bd9Sstevel@tonic-gate stn %l4, [%i3 + STACK_BIAS + (4*GREGSIZE)] 20127c478bd9Sstevel@tonic-gate stn %l5, [%i3 + STACK_BIAS + (5*GREGSIZE)] 20137c478bd9Sstevel@tonic-gate stn %l6, [%i3 + STACK_BIAS + (6*GREGSIZE)] 20147c478bd9Sstevel@tonic-gate stn %l7, [%i3 + STACK_BIAS + (7*GREGSIZE)] 20157c478bd9Sstevel@tonic-gate stn %o0, [%i3 + STACK_BIAS + (8*GREGSIZE)] ! save ins using outs 20167c478bd9Sstevel@tonic-gate stn %o1, [%i3 + STACK_BIAS + (9*GREGSIZE)] 20177c478bd9Sstevel@tonic-gate stn %o2, [%i3 + STACK_BIAS + (10*GREGSIZE)] 20187c478bd9Sstevel@tonic-gate stn %o3, [%i3 + STACK_BIAS + (11*GREGSIZE)] 20197c478bd9Sstevel@tonic-gate stn %o4, [%i3 + STACK_BIAS + (12*GREGSIZE)] 20207c478bd9Sstevel@tonic-gate stn %o5, [%i3 + STACK_BIAS + (13*GREGSIZE)] 20217c478bd9Sstevel@tonic-gate stn %i4, [%i3 + STACK_BIAS + (14*GREGSIZE)] 20227c478bd9Sstevel@tonic-gate ! fp, %i7 copied using %i4 20237c478bd9Sstevel@tonic-gate stn %i5, [%i3 + STACK_BIAS + (15*GREGSIZE)] 20247c478bd9Sstevel@tonic-gate stn %g0, [%i2 + ((8+6)*GREGSIZE)] 20257c478bd9Sstevel@tonic-gate ! clear fp in save area 20267c478bd9Sstevel@tonic-gate 20277c478bd9Sstevel@tonic-gate ! load saved pil for return 20287c478bd9Sstevel@tonic-gate ldub [%i0 + T_PIL], %i0 20297c478bd9Sstevel@tonic-gate ret 20307c478bd9Sstevel@tonic-gate restore 20317c478bd9Sstevel@tonic-gate SET_SIZE(intr_passivate) 20327c478bd9Sstevel@tonic-gate 20337c478bd9Sstevel@tonic-gate#endif /* lint */ 20347c478bd9Sstevel@tonic-gate 20357c478bd9Sstevel@tonic-gate#if defined(lint) 20367c478bd9Sstevel@tonic-gate 20377c478bd9Sstevel@tonic-gate/* 20387c478bd9Sstevel@tonic-gate * intr_get_time() is a resource for interrupt handlers to determine how 20397c478bd9Sstevel@tonic-gate * much time has been spent handling the current interrupt. Such a function 20407c478bd9Sstevel@tonic-gate * is needed because higher level interrupts can arrive during the 20417c478bd9Sstevel@tonic-gate * processing of an interrupt, thus making direct comparisons of %tick by 20427c478bd9Sstevel@tonic-gate * the handler inaccurate. intr_get_time() only returns time spent in the 20437c478bd9Sstevel@tonic-gate * current interrupt handler. 20447c478bd9Sstevel@tonic-gate * 20457c478bd9Sstevel@tonic-gate * The caller must be calling from an interrupt handler running at a pil 20467c478bd9Sstevel@tonic-gate * below or at lock level. Timings are not provided for high-level 20477c478bd9Sstevel@tonic-gate * interrupts. 20487c478bd9Sstevel@tonic-gate * 20497c478bd9Sstevel@tonic-gate * The first time intr_get_time() is called while handling an interrupt, 20507c478bd9Sstevel@tonic-gate * it returns the time since the interrupt handler was invoked. Subsequent 20517c478bd9Sstevel@tonic-gate * calls will return the time since the prior call to intr_get_time(). Time 20527c478bd9Sstevel@tonic-gate * is returned as ticks, adjusted for any clock divisor due to power 20537c478bd9Sstevel@tonic-gate * management. Use tick2ns() to convert ticks to nsec. Warning: ticks may 20547c478bd9Sstevel@tonic-gate * not be the same across CPUs. 20557c478bd9Sstevel@tonic-gate * 20567c478bd9Sstevel@tonic-gate * Theory Of Intrstat[][]: 20577c478bd9Sstevel@tonic-gate * 20587c478bd9Sstevel@tonic-gate * uint64_t intrstat[pil][0..1] is an array indexed by pil level, with two 20597c478bd9Sstevel@tonic-gate * uint64_ts per pil. 20607c478bd9Sstevel@tonic-gate * 20617c478bd9Sstevel@tonic-gate * intrstat[pil][0] is a cumulative count of the number of ticks spent 20627c478bd9Sstevel@tonic-gate * handling all interrupts at the specified pil on this CPU. It is 20637c478bd9Sstevel@tonic-gate * exported via kstats to the user. 20647c478bd9Sstevel@tonic-gate * 20657c478bd9Sstevel@tonic-gate * intrstat[pil][1] is always a count of ticks less than or equal to the 20667c478bd9Sstevel@tonic-gate * value in [0]. The difference between [1] and [0] is the value returned 20677c478bd9Sstevel@tonic-gate * by a call to intr_get_time(). At the start of interrupt processing, 20687c478bd9Sstevel@tonic-gate * [0] and [1] will be equal (or nearly so). As the interrupt consumes 20697c478bd9Sstevel@tonic-gate * time, [0] will increase, but [1] will remain the same. A call to 20707c478bd9Sstevel@tonic-gate * intr_get_time() will return the difference, then update [1] to be the 20717c478bd9Sstevel@tonic-gate * same as [0]. Future calls will return the time since the last call. 20727c478bd9Sstevel@tonic-gate * Finally, when the interrupt completes, [1] is updated to the same as [0]. 20737c478bd9Sstevel@tonic-gate * 20747c478bd9Sstevel@tonic-gate * Implementation: 20757c478bd9Sstevel@tonic-gate * 20767c478bd9Sstevel@tonic-gate * intr_get_time() works much like a higher level interrupt arriving. It 20777c478bd9Sstevel@tonic-gate * "checkpoints" the timing information by incrementing intrstat[pil][0] 20787c478bd9Sstevel@tonic-gate * to include elapsed running time, and by setting t_intr_start to %tick. 20797c478bd9Sstevel@tonic-gate * It then sets the return value to intrstat[pil][0] - intrstat[pil][1], 20807c478bd9Sstevel@tonic-gate * and updates intrstat[pil][1] to be the same as the new value of 20817c478bd9Sstevel@tonic-gate * intrstat[pil][0]. 20827c478bd9Sstevel@tonic-gate * 20837c478bd9Sstevel@tonic-gate * In the normal handling of interrupts, after an interrupt handler returns 20847c478bd9Sstevel@tonic-gate * and the code in intr_thread() updates intrstat[pil][0], it then sets 20857c478bd9Sstevel@tonic-gate * intrstat[pil][1] to the new value of intrstat[pil][0]. When [0] == [1], 20867c478bd9Sstevel@tonic-gate * the timings are reset, i.e. intr_get_time() will return [0] - [1] which 20877c478bd9Sstevel@tonic-gate * is 0. 20887c478bd9Sstevel@tonic-gate * 20897c478bd9Sstevel@tonic-gate * Whenever interrupts arrive on a CPU which is handling a lower pil 20907c478bd9Sstevel@tonic-gate * interrupt, they update the lower pil's [0] to show time spent in the 20917c478bd9Sstevel@tonic-gate * handler that they've interrupted. This results in a growing discrepancy 20927c478bd9Sstevel@tonic-gate * between [0] and [1], which is returned the next time intr_get_time() is 20937c478bd9Sstevel@tonic-gate * called. Time spent in the higher-pil interrupt will not be returned in 20947c478bd9Sstevel@tonic-gate * the next intr_get_time() call from the original interrupt, because 20957c478bd9Sstevel@tonic-gate * the higher-pil interrupt's time is accumulated in intrstat[higherpil][]. 20967c478bd9Sstevel@tonic-gate */ 20977c478bd9Sstevel@tonic-gate 20987c478bd9Sstevel@tonic-gate/*ARGSUSED*/ 20997c478bd9Sstevel@tonic-gateuint64_t 21007c478bd9Sstevel@tonic-gateintr_get_time(void) 21017c478bd9Sstevel@tonic-gate{ return 0; } 21027c478bd9Sstevel@tonic-gate#else /* lint */ 21037c478bd9Sstevel@tonic-gate 21047c478bd9Sstevel@tonic-gate ENTRY_NP(intr_get_time) 21057c478bd9Sstevel@tonic-gate#ifdef DEBUG 21067c478bd9Sstevel@tonic-gate ! 21077c478bd9Sstevel@tonic-gate ! Lots of asserts, but just check panic_quiesce first. 21087c478bd9Sstevel@tonic-gate ! Don't bother with lots of tests if we're just ignoring them. 21097c478bd9Sstevel@tonic-gate ! 21107c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %o0 21117c478bd9Sstevel@tonic-gate ld [%o0 + %lo(panic_quiesce)], %o0 21127c478bd9Sstevel@tonic-gate brnz,pn %o0, 2f 21137c478bd9Sstevel@tonic-gate nop 21147c478bd9Sstevel@tonic-gate ! 21157c478bd9Sstevel@tonic-gate ! ASSERT(%pil <= LOCK_LEVEL) 21167c478bd9Sstevel@tonic-gate ! 21177c478bd9Sstevel@tonic-gate rdpr %pil, %o1 21187c478bd9Sstevel@tonic-gate cmp %o1, LOCK_LEVEL 21197c478bd9Sstevel@tonic-gate ble,pt %xcc, 0f 21207c478bd9Sstevel@tonic-gate sethi %hi(intr_get_time_high_pil), %o0 ! delay 21217c478bd9Sstevel@tonic-gate call panic 21227c478bd9Sstevel@tonic-gate or %o0, %lo(intr_get_time_high_pil), %o0 21237c478bd9Sstevel@tonic-gate0: 21247c478bd9Sstevel@tonic-gate ! 21257c478bd9Sstevel@tonic-gate ! ASSERT((t_flags & T_INTR_THREAD) != 0 && t_pil > 0) 21267c478bd9Sstevel@tonic-gate ! 21277c478bd9Sstevel@tonic-gate lduh [THREAD_REG + T_FLAGS], %o2 21287c478bd9Sstevel@tonic-gate andcc %o2, T_INTR_THREAD, %g0 21297c478bd9Sstevel@tonic-gate bz,pn %xcc, 1f 21307c478bd9Sstevel@tonic-gate ldub [THREAD_REG + T_PIL], %o1 ! delay 21317c478bd9Sstevel@tonic-gate brnz,pt %o1, 0f 21327c478bd9Sstevel@tonic-gate1: 21337c478bd9Sstevel@tonic-gate sethi %hi(intr_get_time_not_intr), %o0 21347c478bd9Sstevel@tonic-gate call panic 21357c478bd9Sstevel@tonic-gate or %o0, %lo(intr_get_time_not_intr), %o0 21367c478bd9Sstevel@tonic-gate0: 21377c478bd9Sstevel@tonic-gate ! 21387c478bd9Sstevel@tonic-gate ! ASSERT(t_intr_start != 0) 21397c478bd9Sstevel@tonic-gate ! 21407c478bd9Sstevel@tonic-gate ldx [THREAD_REG + T_INTR_START], %o1 21417c478bd9Sstevel@tonic-gate brnz,pt %o1, 2f 21427c478bd9Sstevel@tonic-gate sethi %hi(intr_get_time_no_start_time), %o0 ! delay 21437c478bd9Sstevel@tonic-gate call panic 21447c478bd9Sstevel@tonic-gate or %o0, %lo(intr_get_time_no_start_time), %o0 21457c478bd9Sstevel@tonic-gate2: 21467c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 21477c478bd9Sstevel@tonic-gate ! 21487c478bd9Sstevel@tonic-gate ! %o0 = elapsed time and return value 21497c478bd9Sstevel@tonic-gate ! %o1 = pil 21507c478bd9Sstevel@tonic-gate ! %o2 = scratch 21517c478bd9Sstevel@tonic-gate ! %o3 = scratch 21527c478bd9Sstevel@tonic-gate ! %o4 = scratch 21537c478bd9Sstevel@tonic-gate ! %o5 = cpu 21547c478bd9Sstevel@tonic-gate ! 21557c478bd9Sstevel@tonic-gate wrpr %g0, PIL_MAX, %pil ! make this easy -- block normal intrs 21567c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CPU], %o5 21577c478bd9Sstevel@tonic-gate ldub [THREAD_REG + T_PIL], %o1 21587c478bd9Sstevel@tonic-gate ldx [THREAD_REG + T_INTR_START], %o3 ! %o3 = t_intr_start 21597c478bd9Sstevel@tonic-gate ! 21607c478bd9Sstevel@tonic-gate ! Calculate elapsed time since t_intr_start. Update t_intr_start, 21617c478bd9Sstevel@tonic-gate ! get delta, and multiply by cpu_divisor if necessary. 21627c478bd9Sstevel@tonic-gate ! 21637c478bd9Sstevel@tonic-gate rdpr %tick, %o2 21647c478bd9Sstevel@tonic-gate sllx %o2, 1, %o2 21657c478bd9Sstevel@tonic-gate srlx %o2, 1, %o2 21667c478bd9Sstevel@tonic-gate stx %o2, [THREAD_REG + T_INTR_START] 21677c478bd9Sstevel@tonic-gate sub %o2, %o3, %o0 21687c478bd9Sstevel@tonic-gate 21697c478bd9Sstevel@tonic-gate lduh [%o5 + CPU_DIVISOR], %o4 21707c478bd9Sstevel@tonic-gate cmp %o4, 1 21717c478bd9Sstevel@tonic-gate bg,a,pn %xcc, 1f 21727c478bd9Sstevel@tonic-gate mulx %o0, %o4, %o0 ! multiply interval by clock divisor iff > 1 21737c478bd9Sstevel@tonic-gate1: 2174eda89462Sesolom ! Update intracct[] 2175eda89462Sesolom lduh [%o5 + CPU_MSTATE], %o4 2176eda89462Sesolom sllx %o4, 3, %o4 2177eda89462Sesolom add %o4, CPU_INTRACCT, %o4 2178eda89462Sesolom ldx [%o5 + %o4], %o2 2179eda89462Sesolom add %o2, %o0, %o2 2180eda89462Sesolom stx %o2, [%o5 + %o4] 2181eda89462Sesolom 21827c478bd9Sstevel@tonic-gate ! 21837c478bd9Sstevel@tonic-gate ! Increment cpu_m.intrstat[pil][0]. Calculate elapsed time since 21847c478bd9Sstevel@tonic-gate ! cpu_m.intrstat[pil][1], which is either when the interrupt was 21857c478bd9Sstevel@tonic-gate ! first entered, or the last time intr_get_time() was invoked. Then 21867c478bd9Sstevel@tonic-gate ! update cpu_m.intrstat[pil][1] to match [0]. 21877c478bd9Sstevel@tonic-gate ! 21887c478bd9Sstevel@tonic-gate sllx %o1, 4, %o3 21897c478bd9Sstevel@tonic-gate add %o3, CPU_MCPU, %o3 21907c478bd9Sstevel@tonic-gate add %o3, MCPU_INTRSTAT, %o3 21917c478bd9Sstevel@tonic-gate add %o3, %o5, %o3 ! %o3 = cpu_m.intrstat[pil][0] 21927c478bd9Sstevel@tonic-gate ldx [%o3], %o2 21937c478bd9Sstevel@tonic-gate add %o2, %o0, %o2 ! %o2 = new value for intrstat 21947c478bd9Sstevel@tonic-gate stx %o2, [%o3] 21957c478bd9Sstevel@tonic-gate ldx [%o3 + 8], %o4 ! %o4 = cpu_m.intrstat[pil][1] 21967c478bd9Sstevel@tonic-gate sub %o2, %o4, %o0 ! %o0 is elapsed time since %o4 21977c478bd9Sstevel@tonic-gate stx %o2, [%o3 + 8] ! make [1] match [0], resetting time 21987c478bd9Sstevel@tonic-gate 21997c478bd9Sstevel@tonic-gate ld [%o5 + CPU_BASE_SPL], %o2 ! restore %pil to the greater 22007c478bd9Sstevel@tonic-gate cmp %o2, %o1 ! of either our pil %o1 or 22017c478bd9Sstevel@tonic-gate movl %xcc, %o1, %o2 ! cpu_base_spl. 22027c478bd9Sstevel@tonic-gate retl 22037c478bd9Sstevel@tonic-gate wrpr %g0, %o2, %pil 22047c478bd9Sstevel@tonic-gate SET_SIZE(intr_get_time) 22057c478bd9Sstevel@tonic-gate 22067c478bd9Sstevel@tonic-gate#ifdef DEBUG 22077c478bd9Sstevel@tonic-gateintr_get_time_high_pil: 22087c478bd9Sstevel@tonic-gate .asciz "intr_get_time(): %pil > LOCK_LEVEL" 22097c478bd9Sstevel@tonic-gateintr_get_time_not_intr: 22107c478bd9Sstevel@tonic-gate .asciz "intr_get_time(): not called from an interrupt thread" 22117c478bd9Sstevel@tonic-gateintr_get_time_no_start_time: 22127c478bd9Sstevel@tonic-gate .asciz "intr_get_time(): t_intr_start == 0" 22137c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 22147c478bd9Sstevel@tonic-gate#endif /* lint */ 2215