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/* 224df4bd60Sbs21162 * Copyright 2007 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> 41b0fc0e77Sgovinda#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 66b0fc0e77Sgovinda ! %g2 - pointer to intr_vec_t (iv) 677c478bd9Sstevel@tonic-gate ! %g4 - pil 68b0fc0e77Sgovinda ! %g3, %g5, %g6, %g7 - temps 697c478bd9Sstevel@tonic-gate ! 70b0fc0e77Sgovinda ! Grab the first or list head intr_vec_t off the intr_head[pil] 71b0fc0e77Sgovinda ! and panic immediately if list head is NULL. Otherwise, update 72b0fc0e77Sgovinda ! intr_head[pil] to next intr_vec_t on the list and clear softint 73b0fc0e77Sgovinda ! %clear_softint, if next intr_vec_t is NULL. 747c478bd9Sstevel@tonic-gate ! 75b0fc0e77Sgovinda CPU_ADDR(%g1, %g5) ! %g1 = cpu 767c478bd9Sstevel@tonic-gate ! 777c478bd9Sstevel@tonic-gate ALTENTRY(pil_interrupt_common) 78b0fc0e77Sgovinda sll %g4, CPTRSHIFT, %g5 ! %g5 = offset to the pil entry 79b0fc0e77Sgovinda add %g1, INTR_HEAD, %g6 ! %g6 = &cpu->m_cpu.intr_head 80b0fc0e77Sgovinda add %g6, %g5, %g6 ! %g6 = &cpu->m_cpu.intr_head[pil] 81b0fc0e77Sgovinda ldn [%g6], %g2 ! %g2 = cpu->m_cpu.intr_head[pil] 82b0fc0e77Sgovinda brnz,pt %g2, 0f ! check list head (iv) is NULL 837c478bd9Sstevel@tonic-gate nop 84b0fc0e77Sgovinda ba ptl1_panic ! panic, list head (iv) is NULL 85b0fc0e77Sgovinda mov PTL1_BAD_INTR_VEC, %g1 86b0fc0e77Sgovinda0: 87b0fc0e77Sgovinda lduh [%g2 + IV_FLAGS], %g7 ! %g7 = iv->iv_flags 88b0fc0e77Sgovinda and %g7, IV_SOFTINT_MT, %g3 ! %g3 = iv->iv_flags & IV_SOFTINT_MT 89b0fc0e77Sgovinda brz,pt %g3, 1f ! check for multi target softint 90b0fc0e77Sgovinda add %g2, IV_PIL_NEXT, %g7 ! g7% = &iv->iv_pil_next 91b0fc0e77Sgovinda ld [%g1 + CPU_ID], %g3 ! for multi target softint, use cpuid 92b0fc0e77Sgovinda sll %g3, CPTRSHIFT, %g3 ! convert cpuid to offset address 93b0fc0e77Sgovinda add %g7, %g3, %g7 ! %g5 = &iv->iv_xpil_next[cpuid] 947c478bd9Sstevel@tonic-gate1: 95b0fc0e77Sgovinda ldn [%g7], %g3 ! %g3 = next intr_vec_t 96b0fc0e77Sgovinda brnz,pn %g3, 2f ! branch if next intr_vec_t non NULL 97b0fc0e77Sgovinda stn %g3, [%g6] ! update cpu->m_cpu.intr_head[pil] 98b0fc0e77Sgovinda add %g1, INTR_TAIL, %g6 ! %g6 = &cpu->m_cpu.intr_tail 99b0fc0e77Sgovinda stn %g0, [%g5 + %g6] ! clear cpu->m_cpu.intr_tail[pil] 100b0fc0e77Sgovinda mov 1, %g5 ! %g5 = 1 101b0fc0e77Sgovinda sll %g5, %g4, %g5 ! %g5 = 1 << pil 102b0fc0e77Sgovinda wr %g5, CLEAR_SOFTINT ! clear interrupt on this pil 103b0fc0e77Sgovinda2: 1047c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE 1057c478bd9Sstevel@tonic-gate TRACE_PTR(%g5, %g6) 1067c478bd9Sstevel@tonic-gate GET_TRACE_TICK(%g6) 107b0fc0e77Sgovinda 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 110b0fc0e77Sgovinda stha %g6, [%g5 + TRAP_ENT_TT]%asi ! trap_type = %tt 1117c478bd9Sstevel@tonic-gate rdpr %tpc, %g6 112b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_TPC]%asi ! trap_pc = %tpc 1137c478bd9Sstevel@tonic-gate rdpr %tstate, %g6 114b0fc0e77Sgovinda stxa %g6, [%g5 + TRAP_ENT_TSTATE]%asi ! trap_tstate = %tstate 115b0fc0e77Sgovinda stna %sp, [%g5 + TRAP_ENT_SP]%asi ! trap_sp = %sp 116b0fc0e77Sgovinda stna %g2, [%g5 + TRAP_ENT_TR]%asi ! trap_tr = first intr_vec 117b0fc0e77Sgovinda 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 120b0fc0e77Sgovinda ldn [%g6 + %g3], %g6 ! %g6=cpu->m_cpu.intr_head[pil] 121b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_F2]%asi ! trap_f2 = intr_head[pil] 1227c478bd9Sstevel@tonic-gate add %g1, INTR_TAIL, %g6 123b0fc0e77Sgovinda ldn [%g6 + %g3], %g6 ! %g6=cpu->m_cpu.intr_tail[pil] 124b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_F3]%asi ! trap_f3 = intr_tail[pil] 125b0fc0e77Sgovinda 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 ! 129b0fc0e77Sgovinda ! clear the iv_pending flag for this interrupt request 1307c478bd9Sstevel@tonic-gate ! 131b0fc0e77Sgovinda lduh [%g2 + IV_FLAGS], %g3 ! %g3 = iv->iv_flags 132b0fc0e77Sgovinda andn %g3, IV_SOFTINT_PEND, %g3 ! %g3 = !(iv->iv_flags & PEND) 133b0fc0e77Sgovinda sth %g3, [%g2 + IV_FLAGS] ! clear IV_SOFTINT_PEND flag 134b0fc0e77Sgovinda stn %g0, [%g7] ! clear iv->iv_pil_next or 135b0fc0e77Sgovinda ! 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 142b0fc0e77Sgovinda ! %g2 - pointer to current intr_vec_t (iv), 143b0fc0e77Sgovinda ! 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 ! 151b0fc0e77Sgovinda mov %g4, %g3 ! %g3 = %g4, pil 1527c478bd9Sstevel@tonic-gate cmp %g4, LOCK_LEVEL 153b0fc0e77Sgovinda bg,a,pt %xcc, 3f ! branch if pil > LOCK_LEVEL 154b0fc0e77Sgovinda mov PIL_MAX, %g4 ! %g4 = PIL_MAX (15) 155b0fc0e77Sgovinda sethi %hi(intr_thread), %g1 ! %g1 = intr_thread 156b0fc0e77Sgovinda 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 159b0fc0e77Sgovinda3: 160b0fc0e77Sgovinda 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 * 179b0fc0e77Sgovinda * 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 184b0fc0e77Sgovinda#define SERVE_INTR_PRE(iv_p, cpu, ls1, ls2, os1, os2, os3, regs) \ 185b0fc0e77Sgovinda mov iv_p, ls1; \ 186b0fc0e77Sgovinda mov iv_p, ls2; \ 187b0fc0e77Sgovinda 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 206b0fc0e77Sgovinda * 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; \ 213b0fc0e77Sgovinda ldn [ls1 + IV_ARG1], %o0; \ 214b0fc0e77Sgovinda 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; \ 247b0fc0e77Sgovinda lduh [os3 + IV_FLAGS], os2; \ 248b0fc0e77Sgovinda and os2, IV_SOFTINT_MT, os2; \ 249b0fc0e77Sgovinda brz,pt os2, 4f; \ 250b0fc0e77Sgovinda add os3, IV_PIL_NEXT, os2; \ 251b0fc0e77Sgovinda ld [cpu + CPU_ID], os5; \ 252b0fc0e77Sgovinda sll os5, CPTRSHIFT, os5; \ 253b0fc0e77Sgovinda add os2, os5, os2; \ 254b0fc0e77Sgovinda4: ldn [os2], os5; \ 255b0fc0e77Sgovinda brnz,pn os5, 5f; \ 256b0fc0e77Sgovinda 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; \ 262b0fc0e77Sgovinda5: lduh [os3 + IV_FLAGS], ls1; \ 263b0fc0e77Sgovinda andn ls1, IV_SOFTINT_PEND, ls1; \ 264b0fc0e77Sgovinda sth ls1, [os3 + IV_FLAGS]; \ 265b0fc0e77Sgovinda stn %g0, [os2]; \ 2667c478bd9Sstevel@tonic-gate wrpr %g0, ls2, %pstate; \ 267b0fc0e77Sgovinda mov os3, ls1; \ 268b0fc0e77Sgovinda mov os3, ls2; \ 269b0fc0e77Sgovinda 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 341b0fc0e77Sgovindaintr_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 352b0fc0e77Sgovinda * %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 mov %i5, %o3 5514df4bd60Sbs21162 call ftrace_3 5524df4bd60Sbs21162 ldn [%i0 + PC_OFF], %o4 5537c478bd9Sstevel@tonic-gate restore 5547c478bd9Sstevel@tonic-gate1: 5557c478bd9Sstevel@tonic-gate ! 5567c478bd9Sstevel@tonic-gate ! call the handler 5577c478bd9Sstevel@tonic-gate ! 5587c478bd9Sstevel@tonic-gate SERVE_INTR_PRE(%o1, %o2, %l1, %l3, %o4, %o5, %o3, %o0) 5597c478bd9Sstevel@tonic-gate ! 5607c478bd9Sstevel@tonic-gate ! %o0 and %o1 are now available as scratch registers. 5617c478bd9Sstevel@tonic-gate ! 5627c478bd9Sstevel@tonic-gate0: 5637c478bd9Sstevel@tonic-gate SERVE_INTR(%o1, %o2, %l1, %l3, %o4, %o5, %o3, %o0) 5647c478bd9Sstevel@tonic-gate ! 565b0fc0e77Sgovinda ! If %o3 is set, we must call serve_intr_next, and both %l1 and %o3 5667c478bd9Sstevel@tonic-gate ! must be preserved. %l1 holds our pil, %l3 holds our inum. 5677c478bd9Sstevel@tonic-gate ! 5687c478bd9Sstevel@tonic-gate ! Note: %l1 is the pil level we're processing, but we may have a 5697c478bd9Sstevel@tonic-gate ! higher effective pil because a higher-level interrupt may have 5707c478bd9Sstevel@tonic-gate ! blocked. 5717c478bd9Sstevel@tonic-gate ! 5727c478bd9Sstevel@tonic-gate wrpr %g0, DISP_LEVEL, %pil 5737c478bd9Sstevel@tonic-gate ! 5747c478bd9Sstevel@tonic-gate ! Take timestamp, compute interval, update cumulative counter. 5757c478bd9Sstevel@tonic-gate ! 5767c478bd9Sstevel@tonic-gate add THREAD_REG, T_INTR_START, %o5 5777c478bd9Sstevel@tonic-gate1: 5787c478bd9Sstevel@tonic-gate ldx [%o5], %o0 5797c478bd9Sstevel@tonic-gate#ifdef DEBUG 5807c478bd9Sstevel@tonic-gate brnz %o0, 9f 5817c478bd9Sstevel@tonic-gate nop 5827c478bd9Sstevel@tonic-gate ! Do not call panic if a panic is already in progress. 5837c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %o1 5847c478bd9Sstevel@tonic-gate ld [%o1 + %lo(panic_quiesce)], %o1 5857c478bd9Sstevel@tonic-gate brnz,pn %o1, 9f 5867c478bd9Sstevel@tonic-gate nop 5877c478bd9Sstevel@tonic-gate sethi %hi(intr_thread_t_intr_start_zero), %o0 5887c478bd9Sstevel@tonic-gate call panic 5897c478bd9Sstevel@tonic-gate or %o0, %lo(intr_thread_t_intr_start_zero), %o0 5907c478bd9Sstevel@tonic-gate9: 5917c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 5927c478bd9Sstevel@tonic-gate rdpr %tick, %o1 5937c478bd9Sstevel@tonic-gate sllx %o1, 1, %o1 5947c478bd9Sstevel@tonic-gate srlx %o1, 1, %o1 ! shift off NPT bit 5957c478bd9Sstevel@tonic-gate sub %o1, %o0, %l2 ! l2 has interval 5967c478bd9Sstevel@tonic-gate ! 5977c478bd9Sstevel@tonic-gate ! The general outline of what the code here does is: 5987c478bd9Sstevel@tonic-gate ! 1. load t_intr_start, %tick, and calculate the delta 5997c478bd9Sstevel@tonic-gate ! 2. replace t_intr_start with %tick (if %o3 is set) or 0. 6007c478bd9Sstevel@tonic-gate ! 6017c478bd9Sstevel@tonic-gate ! The problem is that a high-level interrupt could arrive at any time. 6027c478bd9Sstevel@tonic-gate ! It will account for (%tick - t_intr_start) for us when it starts, 6037c478bd9Sstevel@tonic-gate ! unless we have set t_intr_start to zero, and then set t_intr_start 6047c478bd9Sstevel@tonic-gate ! to a new %tick when it finishes. To account for this, our first step 6057c478bd9Sstevel@tonic-gate ! is to load t_intr_start and the last is to use casx to store the new 6067c478bd9Sstevel@tonic-gate ! t_intr_start. This guarantees atomicity in reading t_intr_start, 6077c478bd9Sstevel@tonic-gate ! reading %tick, and updating t_intr_start. 6087c478bd9Sstevel@tonic-gate ! 6097c478bd9Sstevel@tonic-gate movrz %o3, %g0, %o1 6107c478bd9Sstevel@tonic-gate casx [%o5], %o0, %o1 6117c478bd9Sstevel@tonic-gate cmp %o0, %o1 6127c478bd9Sstevel@tonic-gate bne,pn %xcc, 1b 6137c478bd9Sstevel@tonic-gate ! 6147c478bd9Sstevel@tonic-gate ! Check for Energy Star mode 6157c478bd9Sstevel@tonic-gate ! 6167c478bd9Sstevel@tonic-gate lduh [%o2 + CPU_DIVISOR], %o0 ! delay -- %o0 = clock divisor 6177c478bd9Sstevel@tonic-gate cmp %o0, 1 6187c478bd9Sstevel@tonic-gate bg,a,pn %xcc, 2f 6197c478bd9Sstevel@tonic-gate mulx %l2, %o0, %l2 ! multiply interval by clock divisor iff > 1 6207c478bd9Sstevel@tonic-gate2: 6217c478bd9Sstevel@tonic-gate ! 6227c478bd9Sstevel@tonic-gate ! Update cpu_intrstat. If o3 is set then we will be processing another 6237c478bd9Sstevel@tonic-gate ! interrupt. Above we have set t_intr_start to %tick, not 0. This 6247c478bd9Sstevel@tonic-gate ! means a high-level interrupt can arrive and update the same stats 6257c478bd9Sstevel@tonic-gate ! we're updating. Need to use casx. 6267c478bd9Sstevel@tonic-gate ! 6277c478bd9Sstevel@tonic-gate sllx %l1, 4, %o1 ! delay - PIL as byte offset 6287c478bd9Sstevel@tonic-gate add %o1, CPU_MCPU, %o1 ! CPU_INTRSTAT const too big 6297c478bd9Sstevel@tonic-gate add %o1, MCPU_INTRSTAT, %o1 ! add parts separately 6307c478bd9Sstevel@tonic-gate add %o1, %o2, %o1 6317c478bd9Sstevel@tonic-gate1: 6327c478bd9Sstevel@tonic-gate ldx [%o1], %o5 ! old counter in o5 6337c478bd9Sstevel@tonic-gate add %o5, %l2, %o0 ! new counter in o0 6347c478bd9Sstevel@tonic-gate stx %o0, [%o1 + 8] ! store into intrstat[pil][1] 6357c478bd9Sstevel@tonic-gate casx [%o1], %o5, %o0 ! and into intrstat[pil][0] 6367c478bd9Sstevel@tonic-gate cmp %o5, %o0 6377c478bd9Sstevel@tonic-gate bne,pn %xcc, 1b 6387c478bd9Sstevel@tonic-gate nop 639eda89462Sesolom 640eda89462Sesolom ! Also update intracct[] 641eda89462Sesolom lduh [%o2 + CPU_MSTATE], %o1 642eda89462Sesolom sllx %o1, 3, %o1 643eda89462Sesolom add %o1, CPU_INTRACCT, %o1 644eda89462Sesolom add %o1, %o2, %o1 645eda89462Sesolom1: 646eda89462Sesolom ldx [%o1], %o5 647eda89462Sesolom add %o5, %l2, %o0 648eda89462Sesolom casx [%o1], %o5, %o0 649eda89462Sesolom cmp %o5, %o0 650eda89462Sesolom bne,pn %xcc, 1b 651eda89462Sesolom nop 652eda89462Sesolom 6537c478bd9Sstevel@tonic-gate ! 6547c478bd9Sstevel@tonic-gate ! Don't keep a pinned process pinned indefinitely. Bump cpu_intrcnt 6557c478bd9Sstevel@tonic-gate ! for each interrupt handler we invoke. If we hit INTRCNT_LIMIT, then 6567c478bd9Sstevel@tonic-gate ! we've crossed the threshold and we should unpin the pinned threads 6577c478bd9Sstevel@tonic-gate ! by preempt()ing ourselves, which will bubble up the t_intr chain 6587c478bd9Sstevel@tonic-gate ! until hitting the non-interrupt thread, which will then in turn 6597c478bd9Sstevel@tonic-gate ! preempt itself allowing the interrupt processing to resume. Finally, 6607c478bd9Sstevel@tonic-gate ! the scheduler takes over and picks the next thread to run. 6617c478bd9Sstevel@tonic-gate ! 6627c478bd9Sstevel@tonic-gate ! If our CPU is quiesced, we cannot preempt because the idle thread 6637c478bd9Sstevel@tonic-gate ! won't ever re-enter the scheduler, and the interrupt will be forever 6647c478bd9Sstevel@tonic-gate ! blocked. 6657c478bd9Sstevel@tonic-gate ! 6667c478bd9Sstevel@tonic-gate ! If t_intr is NULL, we're not pinning anyone, so we use a simpler 6677c478bd9Sstevel@tonic-gate ! algorithm. Just check for cpu_kprunrun, and if set then preempt. 6687c478bd9Sstevel@tonic-gate ! This insures we enter the scheduler if a higher-priority thread 6697c478bd9Sstevel@tonic-gate ! has become runnable. 6707c478bd9Sstevel@tonic-gate ! 6717c478bd9Sstevel@tonic-gate lduh [%o2 + CPU_FLAGS], %o5 ! don't preempt if quiesced 6727c478bd9Sstevel@tonic-gate andcc %o5, CPU_QUIESCED, %g0 6737c478bd9Sstevel@tonic-gate bnz,pn %xcc, 1f 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_INTR], %o5 ! pinning anything? 6767c478bd9Sstevel@tonic-gate brz,pn %o5, 3f ! if not, don't inc intrcnt 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate ldub [%o2 + CPU_INTRCNT], %o5 ! delay - %o5 = cpu_intrcnt 6797c478bd9Sstevel@tonic-gate inc %o5 6807c478bd9Sstevel@tonic-gate cmp %o5, INTRCNT_LIMIT ! have we hit the limit? 6817c478bd9Sstevel@tonic-gate bl,a,pt %xcc, 1f ! no preempt if < INTRCNT_LIMIT 6827c478bd9Sstevel@tonic-gate stub %o5, [%o2 + CPU_INTRCNT] ! delay annul - inc CPU_INTRCNT 6837c478bd9Sstevel@tonic-gate bg,pn %xcc, 2f ! don't inc stats again 6847c478bd9Sstevel@tonic-gate ! 6857c478bd9Sstevel@tonic-gate ! We've reached the limit. Set cpu_intrcnt and cpu_kprunrun, and do 6867c478bd9Sstevel@tonic-gate ! CPU_STATS_ADDQ(cp, sys, intrunpin, 1). Then call preempt. 6877c478bd9Sstevel@tonic-gate ! 6887c478bd9Sstevel@tonic-gate mov 1, %o4 ! delay 6897c478bd9Sstevel@tonic-gate stub %o4, [%o2 + CPU_KPRUNRUN] 6907c478bd9Sstevel@tonic-gate ldx [%o2 + CPU_STATS_SYS_INTRUNPIN], %o4 6917c478bd9Sstevel@tonic-gate inc %o4 6927c478bd9Sstevel@tonic-gate stx %o4, [%o2 + CPU_STATS_SYS_INTRUNPIN] 6937c478bd9Sstevel@tonic-gate ba 2f 6947c478bd9Sstevel@tonic-gate stub %o5, [%o2 + CPU_INTRCNT] ! delay 6957c478bd9Sstevel@tonic-gate3: 6967c478bd9Sstevel@tonic-gate ! Code for t_intr == NULL 6977c478bd9Sstevel@tonic-gate ldub [%o2 + CPU_KPRUNRUN], %o5 6987c478bd9Sstevel@tonic-gate brz,pt %o5, 1f ! don't preempt unless kprunrun 6997c478bd9Sstevel@tonic-gate2: 7007c478bd9Sstevel@tonic-gate ! Time to call preempt 7017c478bd9Sstevel@tonic-gate mov %o2, %l3 ! delay - save %o2 7027c478bd9Sstevel@tonic-gate call preempt 7037c478bd9Sstevel@tonic-gate mov %o3, %l2 ! delay - save %o3. 7047c478bd9Sstevel@tonic-gate mov %l3, %o2 ! restore %o2 7057c478bd9Sstevel@tonic-gate mov %l2, %o3 ! restore %o3 7067c478bd9Sstevel@tonic-gate wrpr %g0, DISP_LEVEL, %pil ! up from cpu_base_spl 7077c478bd9Sstevel@tonic-gate1: 7087c478bd9Sstevel@tonic-gate ! 709b0fc0e77Sgovinda ! Do we need to call serve_intr_next and do this again? 7107c478bd9Sstevel@tonic-gate ! 7117c478bd9Sstevel@tonic-gate brz,a,pt %o3, 0f 7127c478bd9Sstevel@tonic-gate ld [%o2 + CPU_INTR_ACTV], %o5 ! delay annulled 7137c478bd9Sstevel@tonic-gate ! 7147c478bd9Sstevel@tonic-gate ! Restore %pil before calling serve_intr() again. We must check 7157c478bd9Sstevel@tonic-gate ! CPU_BASE_SPL and set %pil to max(our-pil, CPU_BASE_SPL) 7167c478bd9Sstevel@tonic-gate ! 7177c478bd9Sstevel@tonic-gate ld [%o2 + CPU_BASE_SPL], %o4 7187c478bd9Sstevel@tonic-gate cmp %o4, %l1 7197c478bd9Sstevel@tonic-gate movl %xcc, %l1, %o4 7207c478bd9Sstevel@tonic-gate wrpr %g0, %o4, %pil 7217c478bd9Sstevel@tonic-gate SERVE_INTR_NEXT(%o1, %o2, %l1, %l3, %o4, %o5, %o3, %o0) 7227c478bd9Sstevel@tonic-gate ba 0b ! compute new stats 7237c478bd9Sstevel@tonic-gate nop 7247c478bd9Sstevel@tonic-gate0: 7257c478bd9Sstevel@tonic-gate ! 7267c478bd9Sstevel@tonic-gate ! Clear bit for this level in CPU's interrupt active bitmask. 7277c478bd9Sstevel@tonic-gate ! 7287c478bd9Sstevel@tonic-gate mov 1, %o4 7297c478bd9Sstevel@tonic-gate sll %o4, %l1, %o4 7307c478bd9Sstevel@tonic-gate#ifdef DEBUG 7317c478bd9Sstevel@tonic-gate ! 7327c478bd9Sstevel@tonic-gate ! ASSERT(CPU->cpu_intr_actv & (1 << PIL)) 7337c478bd9Sstevel@tonic-gate ! 7347c478bd9Sstevel@tonic-gate andcc %o4, %o5, %g0 7357c478bd9Sstevel@tonic-gate bnz,pt %xcc, 0f 7367c478bd9Sstevel@tonic-gate nop 7377c478bd9Sstevel@tonic-gate ! Do not call panic if a panic is already in progress. 7387c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l2 7397c478bd9Sstevel@tonic-gate ld [%l2 + %lo(panic_quiesce)], %l2 7407c478bd9Sstevel@tonic-gate brnz,pn %l2, 0f 7417c478bd9Sstevel@tonic-gate nop 7427c478bd9Sstevel@tonic-gate sethi %hi(intr_thread_actv_bit_not_set), %o0 7437c478bd9Sstevel@tonic-gate call panic 7447c478bd9Sstevel@tonic-gate or %o0, %lo(intr_thread_actv_bit_not_set), %o0 7457c478bd9Sstevel@tonic-gate0: 7467c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 7477c478bd9Sstevel@tonic-gate andn %o5, %o4, %o5 7487c478bd9Sstevel@tonic-gate st %o5, [%o2 + CPU_INTR_ACTV] 7497c478bd9Sstevel@tonic-gate ! 7507c478bd9Sstevel@tonic-gate ! If there is still an interrupted thread underneath this one, 7517c478bd9Sstevel@tonic-gate ! then the interrupt was never blocked and the return is fairly 7527c478bd9Sstevel@tonic-gate ! simple. Otherwise jump to intr_thread_exit. 7537c478bd9Sstevel@tonic-gate ! 7547c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_INTR], %o4 ! pinned thread 7557c478bd9Sstevel@tonic-gate brz,pn %o4, intr_thread_exit ! branch if none 7567c478bd9Sstevel@tonic-gate nop 7577c478bd9Sstevel@tonic-gate ! 7587c478bd9Sstevel@tonic-gate ! link the thread back onto the interrupt thread pool 7597c478bd9Sstevel@tonic-gate ! 7607c478bd9Sstevel@tonic-gate ldn [%o2 + CPU_INTR_THREAD], %o3 7617c478bd9Sstevel@tonic-gate stn %o3, [THREAD_REG + T_LINK] 7627c478bd9Sstevel@tonic-gate stn THREAD_REG, [%o2 + CPU_INTR_THREAD] 7637c478bd9Sstevel@tonic-gate ! 7647c478bd9Sstevel@tonic-gate ! set the thread state to free so kernel debuggers don't see it 7657c478bd9Sstevel@tonic-gate ! 7667c478bd9Sstevel@tonic-gate mov TS_FREE, %o5 7677c478bd9Sstevel@tonic-gate st %o5, [THREAD_REG + T_STATE] 7687c478bd9Sstevel@tonic-gate ! 7697c478bd9Sstevel@tonic-gate ! Switch back to the interrupted thread and return 7707c478bd9Sstevel@tonic-gate ! 7717c478bd9Sstevel@tonic-gate stn %o4, [%o2 + CPU_THREAD] 77225cf1a30Sjl139090 membar #StoreLoad ! sync with mutex_exit() 7737c478bd9Sstevel@tonic-gate mov %o4, THREAD_REG 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate ! If we pinned an interrupt thread, store its starting timestamp. 7767c478bd9Sstevel@tonic-gate lduh [THREAD_REG + T_FLAGS], %o5 7777c478bd9Sstevel@tonic-gate andcc %o5, T_INTR_THREAD, %g0 7787c478bd9Sstevel@tonic-gate bz,pt %xcc, 1f 7797c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_SP], %sp ! delay - restore %sp 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate add THREAD_REG, T_INTR_START, %o3 ! o3 has &curthread->t_intr_star 7827c478bd9Sstevel@tonic-gate0: 7837c478bd9Sstevel@tonic-gate ldx [%o3], %o4 ! o4 = t_intr_start before 7847c478bd9Sstevel@tonic-gate rdpr %tick, %o5 7857c478bd9Sstevel@tonic-gate sllx %o5, 1, %o5 7867c478bd9Sstevel@tonic-gate srlx %o5, 1, %o5 ! shift off NPT bit 7877c478bd9Sstevel@tonic-gate casx [%o3], %o4, %o5 ! put o5 in ts if o4 == ts after 7887c478bd9Sstevel@tonic-gate cmp %o4, %o5 7897c478bd9Sstevel@tonic-gate ! If a high-level interrupt occurred while we were attempting to store 7907c478bd9Sstevel@tonic-gate ! the timestamp, try again. 7917c478bd9Sstevel@tonic-gate bne,pn %xcc, 0b 7927c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_SP], %sp ! delay - restore %sp 7937c478bd9Sstevel@tonic-gate1: 7947c478bd9Sstevel@tonic-gate ! If the thread being restarted isn't pinning anyone, and no interrupts 7957c478bd9Sstevel@tonic-gate ! are pending, zero out cpu_intrcnt 7967c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_INTR], %o4 7977c478bd9Sstevel@tonic-gate brnz,pn %o4, 2f 7987c478bd9Sstevel@tonic-gate rd SOFTINT, %o4 ! delay 7997c478bd9Sstevel@tonic-gate set SOFTINT_MASK, %o5 8007c478bd9Sstevel@tonic-gate andcc %o4, %o5, %g0 8017c478bd9Sstevel@tonic-gate bz,a,pt %xcc, 2f 8027c478bd9Sstevel@tonic-gate stub %g0, [%o2 + CPU_INTRCNT] ! delay annul 8037c478bd9Sstevel@tonic-gate2: 8047c478bd9Sstevel@tonic-gate jmp %l0 + 8 8057c478bd9Sstevel@tonic-gate nop 8067c478bd9Sstevel@tonic-gate SET_SIZE(intr_thread) 8077c478bd9Sstevel@tonic-gate /* Not Reached */ 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate ! 8107c478bd9Sstevel@tonic-gate ! An interrupt returned on what was once (and still might be) 8117c478bd9Sstevel@tonic-gate ! an interrupt thread stack, but the interrupted process is no longer 8127c478bd9Sstevel@tonic-gate ! there. This means the interrupt must have blocked. 8137c478bd9Sstevel@tonic-gate ! 8147c478bd9Sstevel@tonic-gate ! There is no longer a thread under this one, so put this thread back 8157c478bd9Sstevel@tonic-gate ! on the CPU's free list and resume the idle thread which will dispatch 8167c478bd9Sstevel@tonic-gate ! the next thread to run. 8177c478bd9Sstevel@tonic-gate ! 8187c478bd9Sstevel@tonic-gate ! All traps below DISP_LEVEL are disabled here, but the mondo interrupt 8197c478bd9Sstevel@tonic-gate ! is enabled. 8207c478bd9Sstevel@tonic-gate ! 8217c478bd9Sstevel@tonic-gate ENTRY_NP(intr_thread_exit) 8227c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE 8237c478bd9Sstevel@tonic-gate rdpr %pstate, %l2 8247c478bd9Sstevel@tonic-gate andn %l2, PSTATE_IE | PSTATE_AM, %o4 8257c478bd9Sstevel@tonic-gate wrpr %g0, %o4, %pstate ! cpu to known state 8267c478bd9Sstevel@tonic-gate TRACE_PTR(%o4, %o5) 8277c478bd9Sstevel@tonic-gate GET_TRACE_TICK(%o5) 8287c478bd9Sstevel@tonic-gate stxa %o5, [%o4 + TRAP_ENT_TICK]%asi 8297c478bd9Sstevel@tonic-gate TRACE_SAVE_TL_GL_REGS(%o4, %o5) 8307c478bd9Sstevel@tonic-gate set TT_INTR_EXIT, %o5 8317c478bd9Sstevel@tonic-gate stha %o5, [%o4 + TRAP_ENT_TT]%asi 8327c478bd9Sstevel@tonic-gate stna %g0, [%o4 + TRAP_ENT_TPC]%asi 8337c478bd9Sstevel@tonic-gate stxa %g0, [%o4 + TRAP_ENT_TSTATE]%asi 8347c478bd9Sstevel@tonic-gate stna %sp, [%o4 + TRAP_ENT_SP]%asi 8357c478bd9Sstevel@tonic-gate stna THREAD_REG, [%o4 + TRAP_ENT_TR]%asi 8367c478bd9Sstevel@tonic-gate ld [%o2 + CPU_BASE_SPL], %o5 8377c478bd9Sstevel@tonic-gate stna %o5, [%o4 + TRAP_ENT_F1]%asi 8387c478bd9Sstevel@tonic-gate stna %g0, [%o4 + TRAP_ENT_F2]%asi 8397c478bd9Sstevel@tonic-gate stna %g0, [%o4 + TRAP_ENT_F3]%asi 8407c478bd9Sstevel@tonic-gate stna %g0, [%o4 + TRAP_ENT_F4]%asi 8417c478bd9Sstevel@tonic-gate TRACE_NEXT(%o4, %o5, %o0) 8427c478bd9Sstevel@tonic-gate wrpr %g0, %l2, %pstate 8437c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */ 8447c478bd9Sstevel@tonic-gate ! cpu_stats.sys.intrblk++ 8457c478bd9Sstevel@tonic-gate ldx [%o2 + CPU_STATS_SYS_INTRBLK], %o4 8467c478bd9Sstevel@tonic-gate inc %o4 8477c478bd9Sstevel@tonic-gate stx %o4, [%o2 + CPU_STATS_SYS_INTRBLK] 8487c478bd9Sstevel@tonic-gate ! 8497c478bd9Sstevel@tonic-gate ! Put thread back on the interrupt thread list. 8507c478bd9Sstevel@tonic-gate ! 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate ! 8537c478bd9Sstevel@tonic-gate ! Set the CPU's base SPL level. 8547c478bd9Sstevel@tonic-gate ! 8557c478bd9Sstevel@tonic-gate#ifdef DEBUG 8567c478bd9Sstevel@tonic-gate ! 8577c478bd9Sstevel@tonic-gate ! ASSERT(!(CPU->cpu_intr_actv & (1 << PIL))) 8587c478bd9Sstevel@tonic-gate ! 8597c478bd9Sstevel@tonic-gate ld [%o2 + CPU_INTR_ACTV], %o5 8607c478bd9Sstevel@tonic-gate mov 1, %o4 8617c478bd9Sstevel@tonic-gate sll %o4, %l1, %o4 8627c478bd9Sstevel@tonic-gate and %o5, %o4, %o4 8637c478bd9Sstevel@tonic-gate brz,pt %o4, 0f 8647c478bd9Sstevel@tonic-gate nop 8657c478bd9Sstevel@tonic-gate ! Do not call panic if a panic is already in progress. 8667c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l2 8677c478bd9Sstevel@tonic-gate ld [%l2 + %lo(panic_quiesce)], %l2 8687c478bd9Sstevel@tonic-gate brnz,pn %l2, 0f 8697c478bd9Sstevel@tonic-gate nop 8707c478bd9Sstevel@tonic-gate sethi %hi(intr_thread_exit_actv_bit_set), %o0 8717c478bd9Sstevel@tonic-gate call panic 8727c478bd9Sstevel@tonic-gate or %o0, %lo(intr_thread_exit_actv_bit_set), %o0 8737c478bd9Sstevel@tonic-gate0: 8747c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 8757c478bd9Sstevel@tonic-gate call _intr_set_spl ! set CPU's base SPL level 8767c478bd9Sstevel@tonic-gate ld [%o2 + CPU_INTR_ACTV], %o5 ! delay - load active mask 8777c478bd9Sstevel@tonic-gate ! 8787c478bd9Sstevel@tonic-gate ! set the thread state to free so kernel debuggers don't see it 8797c478bd9Sstevel@tonic-gate ! 8807c478bd9Sstevel@tonic-gate mov TS_FREE, %o4 8817c478bd9Sstevel@tonic-gate st %o4, [THREAD_REG + T_STATE] 8827c478bd9Sstevel@tonic-gate ! 8837c478bd9Sstevel@tonic-gate ! Put thread on either the interrupt pool or the free pool and 8847c478bd9Sstevel@tonic-gate ! call swtch() to resume another thread. 8857c478bd9Sstevel@tonic-gate ! 8867c478bd9Sstevel@tonic-gate ldn [%o2 + CPU_INTR_THREAD], %o5 ! get list pointer 8877c478bd9Sstevel@tonic-gate stn %o5, [THREAD_REG + T_LINK] 8887c478bd9Sstevel@tonic-gate call swtch ! switch to best thread 8897c478bd9Sstevel@tonic-gate stn THREAD_REG, [%o2 + CPU_INTR_THREAD] ! delay - put thread on list 8907c478bd9Sstevel@tonic-gate ba,a,pt %xcc, . ! swtch() shouldn't return 8917c478bd9Sstevel@tonic-gate SET_SIZE(intr_thread_exit) 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate .global ftrace_intr_thread_format_str 8947c478bd9Sstevel@tonic-gateftrace_intr_thread_format_str: 8957c478bd9Sstevel@tonic-gate .asciz "intr_thread(): regs=0x%lx, int=0x%lx, pil=0x%lx" 8967c478bd9Sstevel@tonic-gate#ifdef DEBUG 8977c478bd9Sstevel@tonic-gateintr_thread_actv_bit_set: 8987c478bd9Sstevel@tonic-gate .asciz "intr_thread(): cpu_intr_actv bit already set for PIL" 8997c478bd9Sstevel@tonic-gateintr_thread_actv_bit_not_set: 9007c478bd9Sstevel@tonic-gate .asciz "intr_thread(): cpu_intr_actv bit not set for PIL" 9017c478bd9Sstevel@tonic-gateintr_thread_exit_actv_bit_set: 9027c478bd9Sstevel@tonic-gate .asciz "intr_thread_exit(): cpu_intr_actv bit erroneously set for PIL" 9037c478bd9Sstevel@tonic-gateintr_thread_t_intr_start_zero: 9047c478bd9Sstevel@tonic-gate .asciz "intr_thread(): t_intr_start zero upon handler return" 9057c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 9067c478bd9Sstevel@tonic-gate#endif /* lint */ 9077c478bd9Sstevel@tonic-gate 9087c478bd9Sstevel@tonic-gate#if defined(lint) 9097c478bd9Sstevel@tonic-gate 9107c478bd9Sstevel@tonic-gate/* 9117c478bd9Sstevel@tonic-gate * Handle an interrupt in the current thread 9127c478bd9Sstevel@tonic-gate * Entry: 9137c478bd9Sstevel@tonic-gate * %o0 = pointer to regs structure 914b0fc0e77Sgovinda * %o1 = pointer to current intr_vec_t (iv) to be processed 9157c478bd9Sstevel@tonic-gate * %o2 = pil 9167c478bd9Sstevel@tonic-gate * %sp = on current thread's kernel stack 9177c478bd9Sstevel@tonic-gate * %o7 = return linkage to trap code 9187c478bd9Sstevel@tonic-gate * %g7 = current thread 9197c478bd9Sstevel@tonic-gate * %pstate = normal globals, interrupts enabled, 9207c478bd9Sstevel@tonic-gate * privileged, fp disabled 9217c478bd9Sstevel@tonic-gate * %pil = PIL_MAX 9227c478bd9Sstevel@tonic-gate * 9237c478bd9Sstevel@tonic-gate * Register Usage 9247c478bd9Sstevel@tonic-gate * %l0 = return linkage 9257c478bd9Sstevel@tonic-gate * %l1 = old stack 9267c478bd9Sstevel@tonic-gate * %l2 - %l3 = scratch 9277c478bd9Sstevel@tonic-gate * %l4 - %l7 = reserved for sys_trap 9287c478bd9Sstevel@tonic-gate * %o3 = cpu 9297c478bd9Sstevel@tonic-gate * %o0 = scratch 9307c478bd9Sstevel@tonic-gate * %o4 - %o5 = scratch 9317c478bd9Sstevel@tonic-gate */ 9327c478bd9Sstevel@tonic-gate/* ARGSUSED */ 9337c478bd9Sstevel@tonic-gatevoid 934b0fc0e77Sgovindacurrent_thread(struct regs *regs, uint64_t iv_p, uint_t pil) 9357c478bd9Sstevel@tonic-gate{} 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate#else /* lint */ 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate ENTRY_NP(current_thread) 9407c478bd9Sstevel@tonic-gate 9417c478bd9Sstevel@tonic-gate mov %o7, %l0 9427c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CPU], %o3 94326046578Svb70745 94426046578Svb70745 ldn [THREAD_REG + T_ONFAULT], %l2 94526046578Svb70745 brz,pt %l2, no_onfault ! branch if no onfault label set 94626046578Svb70745 nop 94726046578Svb70745 stn %g0, [THREAD_REG + T_ONFAULT]! clear onfault label 94826046578Svb70745 ldn [THREAD_REG + T_LOFAULT], %l3 94926046578Svb70745 stn %g0, [THREAD_REG + T_LOFAULT]! clear lofault data 95026046578Svb70745 95126046578Svb70745 sub %o2, LOCK_LEVEL + 1, %o5 95226046578Svb70745 sll %o5, CPTRSHIFT, %o5 95326046578Svb70745 add %o5, CPU_OFD, %o4 ! %o4 has on_fault data offset 95426046578Svb70745 stn %l2, [%o3 + %o4] ! save onfault label for pil %o2 95526046578Svb70745 add %o5, CPU_LFD, %o4 ! %o4 has lofault data offset 95626046578Svb70745 stn %l3, [%o3 + %o4] ! save lofault data for pil %o2 95726046578Svb70745 95826046578Svb70745no_onfault: 95926046578Svb70745 ldn [THREAD_REG + T_ONTRAP], %l2 96026046578Svb70745 brz,pt %l2, 6f ! branch if no on_trap protection 96126046578Svb70745 nop 96226046578Svb70745 stn %g0, [THREAD_REG + T_ONTRAP]! clear on_trap protection 96326046578Svb70745 sub %o2, LOCK_LEVEL + 1, %o5 96426046578Svb70745 sll %o5, CPTRSHIFT, %o5 96526046578Svb70745 add %o5, CPU_OTD, %o4 ! %o4 has on_trap data offset 96626046578Svb70745 stn %l2, [%o3 + %o4] ! save on_trap label for pil %o2 96726046578Svb70745 9687c478bd9Sstevel@tonic-gate ! 9697c478bd9Sstevel@tonic-gate ! Set bit for this level in CPU's active interrupt bitmask. 9707c478bd9Sstevel@tonic-gate ! 97126046578Svb707456: ld [%o3 + CPU_INTR_ACTV], %o5 ! o5 has cpu_intr_actv b4 chng 9727c478bd9Sstevel@tonic-gate mov 1, %o4 9737c478bd9Sstevel@tonic-gate sll %o4, %o2, %o4 ! construct mask for level 9747c478bd9Sstevel@tonic-gate#ifdef DEBUG 9757c478bd9Sstevel@tonic-gate ! 9767c478bd9Sstevel@tonic-gate ! ASSERT(!(CPU->cpu_intr_actv & (1 << PIL))) 9777c478bd9Sstevel@tonic-gate ! 9787c478bd9Sstevel@tonic-gate andcc %o5, %o4, %g0 9797c478bd9Sstevel@tonic-gate bz,pt %xcc, 0f 9807c478bd9Sstevel@tonic-gate nop 9817c478bd9Sstevel@tonic-gate ! Do not call panic if a panic is already in progress. 9827c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l2 9837c478bd9Sstevel@tonic-gate ld [%l2 + %lo(panic_quiesce)], %l2 9847c478bd9Sstevel@tonic-gate brnz,pn %l2, 0f 9857c478bd9Sstevel@tonic-gate nop 9867c478bd9Sstevel@tonic-gate sethi %hi(current_thread_actv_bit_set), %o0 9877c478bd9Sstevel@tonic-gate call panic 9887c478bd9Sstevel@tonic-gate or %o0, %lo(current_thread_actv_bit_set), %o0 9897c478bd9Sstevel@tonic-gate0: 9907c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 9917c478bd9Sstevel@tonic-gate or %o5, %o4, %o4 9927c478bd9Sstevel@tonic-gate ! 9937c478bd9Sstevel@tonic-gate ! See if we are interrupting another high-level interrupt. 9947c478bd9Sstevel@tonic-gate ! 9957c478bd9Sstevel@tonic-gate srl %o5, LOCK_LEVEL + 1, %o5 ! only look at high-level bits 9967c478bd9Sstevel@tonic-gate brz,pt %o5, 1f 9977c478bd9Sstevel@tonic-gate st %o4, [%o3 + CPU_INTR_ACTV] ! delay - store active mask 9987c478bd9Sstevel@tonic-gate ! 9997c478bd9Sstevel@tonic-gate ! We have interrupted another high-level interrupt. Find its PIL, 10007c478bd9Sstevel@tonic-gate ! compute the interval it ran for, and update its cumulative counter. 10017c478bd9Sstevel@tonic-gate ! 10027c478bd9Sstevel@tonic-gate ! Register usage: 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate ! o2 = PIL of this interrupt 10057c478bd9Sstevel@tonic-gate ! o5 = high PIL bits of INTR_ACTV (not including this PIL) 10067c478bd9Sstevel@tonic-gate ! l1 = bitmask used to find other active high-level PIL 10077c478bd9Sstevel@tonic-gate ! o4 = index of bit set in l1 10087c478bd9Sstevel@tonic-gate ! Use cpu_intr_actv to find the cpu_pil_high_start[] offset for the 10097c478bd9Sstevel@tonic-gate ! interrupted high-level interrupt. 10107c478bd9Sstevel@tonic-gate ! Create mask for cpu_intr_actv. Begin by looking for bits set 10117c478bd9Sstevel@tonic-gate ! at one level below the current PIL. Since %o5 contains the active 10127c478bd9Sstevel@tonic-gate ! mask already shifted right by (LOCK_LEVEL + 1), we start by looking 10137c478bd9Sstevel@tonic-gate ! at bit (current_pil - (LOCK_LEVEL + 2)). 10147c478bd9Sstevel@tonic-gate sub %o2, LOCK_LEVEL + 2, %o4 10157c478bd9Sstevel@tonic-gate mov 1, %l1 10167c478bd9Sstevel@tonic-gate sll %l1, %o4, %l1 10177c478bd9Sstevel@tonic-gate2: 10187c478bd9Sstevel@tonic-gate#ifdef DEBUG 10197c478bd9Sstevel@tonic-gate ! ASSERT(%l1 != 0) (we didn't shift the bit off the right edge) 10207c478bd9Sstevel@tonic-gate brnz,pt %l1, 9f 10217c478bd9Sstevel@tonic-gate nop 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate ! Don't panic if a panic is already in progress. 10247c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l3 10257c478bd9Sstevel@tonic-gate ld [%l3 + %lo(panic_quiesce)], %l3 10267c478bd9Sstevel@tonic-gate brnz,pn %l3, 9f 10277c478bd9Sstevel@tonic-gate nop 10287c478bd9Sstevel@tonic-gate sethi %hi(current_thread_nested_PIL_not_found), %o0 10297c478bd9Sstevel@tonic-gate call panic 10307c478bd9Sstevel@tonic-gate or %o0, %lo(current_thread_nested_PIL_not_found), %o0 10317c478bd9Sstevel@tonic-gate9: 10327c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 10337c478bd9Sstevel@tonic-gate andcc %l1, %o5, %g0 ! test mask against high-level bits of 10347c478bd9Sstevel@tonic-gate bnz %xcc, 3f ! cpu_intr_actv 10357c478bd9Sstevel@tonic-gate nop 10367c478bd9Sstevel@tonic-gate srl %l1, 1, %l1 ! No match. Try next lower PIL. 10377c478bd9Sstevel@tonic-gate ba,pt %xcc, 2b 10387c478bd9Sstevel@tonic-gate sub %o4, 1, %o4 ! delay - decrement PIL 10397c478bd9Sstevel@tonic-gate3: 10407c478bd9Sstevel@tonic-gate sll %o4, 3, %o4 ! index to byte offset 10417c478bd9Sstevel@tonic-gate add %o4, CPU_MCPU, %l1 ! CPU_PIL_HIGH_START is too large 10427c478bd9Sstevel@tonic-gate add %l1, MCPU_PIL_HIGH_START, %l1 10437c478bd9Sstevel@tonic-gate ldx [%o3 + %l1], %l3 ! load starting timestamp 10447c478bd9Sstevel@tonic-gate#ifdef DEBUG 10457c478bd9Sstevel@tonic-gate brnz,pt %l3, 9f 10467c478bd9Sstevel@tonic-gate nop 10477c478bd9Sstevel@tonic-gate ! Don't panic if a panic is already in progress. 10487c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l1 10497c478bd9Sstevel@tonic-gate ld [%l1 + %lo(panic_quiesce)], %l1 10507c478bd9Sstevel@tonic-gate brnz,pn %l1, 9f 10517c478bd9Sstevel@tonic-gate nop 10527c478bd9Sstevel@tonic-gate srl %o4, 3, %o1 ! Find interrupted PIL for panic 10537c478bd9Sstevel@tonic-gate add %o1, LOCK_LEVEL + 1, %o1 10547c478bd9Sstevel@tonic-gate sethi %hi(current_thread_nested_pil_zero), %o0 10557c478bd9Sstevel@tonic-gate call panic 10567c478bd9Sstevel@tonic-gate or %o0, %lo(current_thread_nested_pil_zero), %o0 10577c478bd9Sstevel@tonic-gate9: 10587c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 10597c478bd9Sstevel@tonic-gate rdpr %tick, %l1 10607c478bd9Sstevel@tonic-gate sllx %l1, 1, %l1 10617c478bd9Sstevel@tonic-gate srlx %l1, 1, %l1 ! shake off NPT bit 10627c478bd9Sstevel@tonic-gate sub %l1, %l3, %l3 ! interval in %l3 10637c478bd9Sstevel@tonic-gate ! 10647c478bd9Sstevel@tonic-gate ! Check for Energy Star mode 10657c478bd9Sstevel@tonic-gate ! 10667c478bd9Sstevel@tonic-gate lduh [%o3 + CPU_DIVISOR], %l1 ! %l1 = clock divisor 10677c478bd9Sstevel@tonic-gate cmp %l1, 1 10687c478bd9Sstevel@tonic-gate bg,a,pn %xcc, 2f 10697c478bd9Sstevel@tonic-gate mulx %l3, %l1, %l3 ! multiply interval by clock divisor iff > 1 10707c478bd9Sstevel@tonic-gate2: 10717c478bd9Sstevel@tonic-gate ! 10727c478bd9Sstevel@tonic-gate ! We need to find the CPU offset of the cumulative counter. We start 10737c478bd9Sstevel@tonic-gate ! with %o4, which has (PIL - (LOCK_LEVEL + 1)) * 8. We need PIL * 16, 10747c478bd9Sstevel@tonic-gate ! so we shift left 1, then add (LOCK_LEVEL + 1) * 16, which is 10757c478bd9Sstevel@tonic-gate ! CPU_INTRSTAT_LOW_PIL_OFFSET. 10767c478bd9Sstevel@tonic-gate ! 10777c478bd9Sstevel@tonic-gate sll %o4, 1, %o4 10787c478bd9Sstevel@tonic-gate add %o4, CPU_MCPU, %o4 ! CPU_INTRSTAT const too large 10797c478bd9Sstevel@tonic-gate add %o4, MCPU_INTRSTAT, %o4 ! add parts separately 10807c478bd9Sstevel@tonic-gate add %o4, CPU_INTRSTAT_LOW_PIL_OFFSET, %o4 10817c478bd9Sstevel@tonic-gate ldx [%o3 + %o4], %l1 ! old counter in l1 10827c478bd9Sstevel@tonic-gate add %l1, %l3, %l1 ! new counter in l1 1083eda89462Sesolom stx %l1, [%o3 + %o4] ! store new counter 1084eda89462Sesolom 1085eda89462Sesolom ! Also update intracct[] 1086eda89462Sesolom lduh [%o3 + CPU_MSTATE], %o4 1087eda89462Sesolom sllx %o4, 3, %o4 1088eda89462Sesolom add %o4, CPU_INTRACCT, %o4 1089eda89462Sesolom ldx [%o3 + %o4], %l1 1090eda89462Sesolom add %l1, %l3, %l1 10917c478bd9Sstevel@tonic-gate ! Another high-level interrupt is active below this one, so 10927c478bd9Sstevel@tonic-gate ! there is no need to check for an interrupt thread. That will be 10937c478bd9Sstevel@tonic-gate ! done by the lowest priority high-level interrupt active. 10947c478bd9Sstevel@tonic-gate ba,pt %xcc, 5f 10957c478bd9Sstevel@tonic-gate stx %l1, [%o3 + %o4] ! delay - store new counter 10967c478bd9Sstevel@tonic-gate1: 10977c478bd9Sstevel@tonic-gate ! If we haven't interrupted another high-level interrupt, we may be 10987c478bd9Sstevel@tonic-gate ! interrupting a low level interrupt thread. If so, compute its interval 10997c478bd9Sstevel@tonic-gate ! and update its cumulative counter. 11007c478bd9Sstevel@tonic-gate lduh [THREAD_REG + T_FLAGS], %o4 11017c478bd9Sstevel@tonic-gate andcc %o4, T_INTR_THREAD, %g0 11027c478bd9Sstevel@tonic-gate bz,pt %xcc, 4f 11037c478bd9Sstevel@tonic-gate nop 11047c478bd9Sstevel@tonic-gate 11057c478bd9Sstevel@tonic-gate ! We have interrupted an interrupt thread. Take timestamp, compute 11067c478bd9Sstevel@tonic-gate ! interval, update cumulative counter. 11077c478bd9Sstevel@tonic-gate 11087c478bd9Sstevel@tonic-gate ! Check t_intr_start. If it is zero, either intr_thread() or 11097c478bd9Sstevel@tonic-gate ! current_thread() (at a lower PIL, of course) already did 11107c478bd9Sstevel@tonic-gate ! the accounting for the underlying interrupt thread. 11117c478bd9Sstevel@tonic-gate ldx [THREAD_REG + T_INTR_START], %o5 11127c478bd9Sstevel@tonic-gate brz,pn %o5, 4f 11137c478bd9Sstevel@tonic-gate nop 11147c478bd9Sstevel@tonic-gate 11157c478bd9Sstevel@tonic-gate stx %g0, [THREAD_REG + T_INTR_START] 11167c478bd9Sstevel@tonic-gate rdpr %tick, %o4 11177c478bd9Sstevel@tonic-gate sllx %o4, 1, %o4 11187c478bd9Sstevel@tonic-gate srlx %o4, 1, %o4 ! shake off NPT bit 11197c478bd9Sstevel@tonic-gate sub %o4, %o5, %o5 ! o5 has the interval 11207c478bd9Sstevel@tonic-gate 11217c478bd9Sstevel@tonic-gate ! Check for Energy Star mode 11227c478bd9Sstevel@tonic-gate lduh [%o3 + CPU_DIVISOR], %o4 ! %o4 = clock divisor 11237c478bd9Sstevel@tonic-gate cmp %o4, 1 11247c478bd9Sstevel@tonic-gate bg,a,pn %xcc, 2f 11257c478bd9Sstevel@tonic-gate mulx %o5, %o4, %o5 ! multiply interval by clock divisor iff > 1 11267c478bd9Sstevel@tonic-gate2: 11277c478bd9Sstevel@tonic-gate ldub [THREAD_REG + T_PIL], %o4 11287c478bd9Sstevel@tonic-gate sllx %o4, 4, %o4 ! PIL index to byte offset 11297c478bd9Sstevel@tonic-gate add %o4, CPU_MCPU, %o4 ! CPU_INTRSTAT const too large 11307c478bd9Sstevel@tonic-gate add %o4, MCPU_INTRSTAT, %o4 ! add parts separately 11317c478bd9Sstevel@tonic-gate ldx [%o3 + %o4], %l2 ! old counter in l2 11327c478bd9Sstevel@tonic-gate add %l2, %o5, %l2 ! new counter in l2 11337c478bd9Sstevel@tonic-gate stx %l2, [%o3 + %o4] ! store new counter 11347c478bd9Sstevel@tonic-gate 1135eda89462Sesolom ! Also update intracct[] 1136eda89462Sesolom lduh [%o3 + CPU_MSTATE], %o4 1137eda89462Sesolom sllx %o4, 3, %o4 1138eda89462Sesolom add %o4, CPU_INTRACCT, %o4 1139eda89462Sesolom ldx [%o3 + %o4], %l2 1140eda89462Sesolom add %l2, %o5, %l2 1141eda89462Sesolom stx %l2, [%o3 + %o4] 11427c478bd9Sstevel@tonic-gate4: 11437c478bd9Sstevel@tonic-gate ! 11447c478bd9Sstevel@tonic-gate ! Handle high-level interrupts on separate interrupt stack. 11457c478bd9Sstevel@tonic-gate ! No other high-level interrupts are active, so switch to int stack. 11467c478bd9Sstevel@tonic-gate ! 11477c478bd9Sstevel@tonic-gate mov %sp, %l1 11487c478bd9Sstevel@tonic-gate ldn [%o3 + CPU_INTR_STACK], %l3 11497c478bd9Sstevel@tonic-gate sub %l3, STACK_BIAS, %sp 11507c478bd9Sstevel@tonic-gate 11517c478bd9Sstevel@tonic-gate5: 11527c478bd9Sstevel@tonic-gate#ifdef DEBUG 11537c478bd9Sstevel@tonic-gate ! 11547c478bd9Sstevel@tonic-gate ! ASSERT(%o2 > LOCK_LEVEL) 11557c478bd9Sstevel@tonic-gate ! 11567c478bd9Sstevel@tonic-gate cmp %o2, LOCK_LEVEL 11577c478bd9Sstevel@tonic-gate bg,pt %xcc, 3f 11587c478bd9Sstevel@tonic-gate nop 11597c478bd9Sstevel@tonic-gate mov CE_PANIC, %o0 11607c478bd9Sstevel@tonic-gate sethi %hi(current_thread_wrong_pil), %o1 11617c478bd9Sstevel@tonic-gate call cmn_err ! %o2 has the %pil already 11627c478bd9Sstevel@tonic-gate or %o1, %lo(current_thread_wrong_pil), %o1 11637c478bd9Sstevel@tonic-gate#endif 11647c478bd9Sstevel@tonic-gate3: 11657c478bd9Sstevel@tonic-gate ! Store starting timestamp for this PIL in CPU structure at 11667c478bd9Sstevel@tonic-gate ! cpu.cpu_m.pil_high_start[PIL - (LOCK_LEVEL + 1)] 11677c478bd9Sstevel@tonic-gate sub %o2, LOCK_LEVEL + 1, %o4 ! convert PIL to array index 11687c478bd9Sstevel@tonic-gate sllx %o4, 3, %o4 ! index to byte offset 11697c478bd9Sstevel@tonic-gate add %o4, CPU_MCPU, %o4 ! CPU_PIL_HIGH_START is too large 11707c478bd9Sstevel@tonic-gate add %o4, MCPU_PIL_HIGH_START, %o4 11717c478bd9Sstevel@tonic-gate rdpr %tick, %o5 11727c478bd9Sstevel@tonic-gate sllx %o5, 1, %o5 11737c478bd9Sstevel@tonic-gate srlx %o5, 1, %o5 11747c478bd9Sstevel@tonic-gate stx %o5, [%o3 + %o4] 11757c478bd9Sstevel@tonic-gate 11767c478bd9Sstevel@tonic-gate wrpr %g0, %o2, %pil ! enable interrupts 11777c478bd9Sstevel@tonic-gate 11787c478bd9Sstevel@tonic-gate ! 11797c478bd9Sstevel@tonic-gate ! call the handler 11807c478bd9Sstevel@tonic-gate ! 11817c478bd9Sstevel@tonic-gate SERVE_INTR_PRE(%o1, %o3, %l2, %l3, %o4, %o5, %o2, %o0) 11827c478bd9Sstevel@tonic-gate1: 11837c478bd9Sstevel@tonic-gate SERVE_INTR(%o1, %o3, %l2, %l3, %o4, %o5, %o2, %o0) 11847c478bd9Sstevel@tonic-gate 11857c478bd9Sstevel@tonic-gate brz,a,pt %o2, 0f ! if %o2, more intrs await 11867c478bd9Sstevel@tonic-gate rdpr %pil, %o2 ! delay annulled 11877c478bd9Sstevel@tonic-gate SERVE_INTR_NEXT(%o1, %o3, %l2, %l3, %o4, %o5, %o2, %o0) 11887c478bd9Sstevel@tonic-gate ba 1b 11897c478bd9Sstevel@tonic-gate nop 11907c478bd9Sstevel@tonic-gate0: 11917c478bd9Sstevel@tonic-gate wrpr %g0, PIL_MAX, %pil ! disable interrupts (1-15) 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate cmp %o2, PIL_15 11947c478bd9Sstevel@tonic-gate bne,pt %xcc, 3f 11957c478bd9Sstevel@tonic-gate nop 11967c478bd9Sstevel@tonic-gate 11977c478bd9Sstevel@tonic-gate sethi %hi(cpc_level15_inum), %o1 1198b0fc0e77Sgovinda ldx [%o1 + %lo(cpc_level15_inum)], %o1 ! arg for intr_enqueue_req 11997c478bd9Sstevel@tonic-gate brz %o1, 3f 12007c478bd9Sstevel@tonic-gate nop 12017c478bd9Sstevel@tonic-gate 12027c478bd9Sstevel@tonic-gate rdpr %pstate, %g5 12037c478bd9Sstevel@tonic-gate andn %g5, PSTATE_IE, %g1 12047c478bd9Sstevel@tonic-gate wrpr %g0, %g1, %pstate ! Disable vec interrupts 12057c478bd9Sstevel@tonic-gate 12067c478bd9Sstevel@tonic-gate call intr_enqueue_req ! preserves %g5 12077c478bd9Sstevel@tonic-gate mov PIL_15, %o0 12087c478bd9Sstevel@tonic-gate 12097c478bd9Sstevel@tonic-gate ! clear perfcntr overflow 12107c478bd9Sstevel@tonic-gate mov 1, %o0 12117c478bd9Sstevel@tonic-gate sllx %o0, PIL_15, %o0 12127c478bd9Sstevel@tonic-gate wr %o0, CLEAR_SOFTINT 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate wrpr %g0, %g5, %pstate ! Enable vec interrupts 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate3: 12177c478bd9Sstevel@tonic-gate cmp %o2, PIL_14 12187c478bd9Sstevel@tonic-gate be tick_rtt ! cpu-specific tick processing 12197c478bd9Sstevel@tonic-gate nop 12207c478bd9Sstevel@tonic-gate .global current_thread_complete 12217c478bd9Sstevel@tonic-gatecurrent_thread_complete: 12227c478bd9Sstevel@tonic-gate ! 12237c478bd9Sstevel@tonic-gate ! Register usage: 12247c478bd9Sstevel@tonic-gate ! 12257c478bd9Sstevel@tonic-gate ! %l1 = stack pointer 12267c478bd9Sstevel@tonic-gate ! %l2 = CPU_INTR_ACTV >> (LOCK_LEVEL + 1) 12277c478bd9Sstevel@tonic-gate ! %o2 = PIL 12287c478bd9Sstevel@tonic-gate ! %o3 = CPU pointer 12297c478bd9Sstevel@tonic-gate ! %o4, %o5, %l3, %l4, %l5 = scratch 12307c478bd9Sstevel@tonic-gate ! 12317c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CPU], %o3 12327c478bd9Sstevel@tonic-gate ! 12337c478bd9Sstevel@tonic-gate ! Clear bit for this level in CPU's interrupt active bitmask. 12347c478bd9Sstevel@tonic-gate ! 12357c478bd9Sstevel@tonic-gate ld [%o3 + CPU_INTR_ACTV], %l2 12367c478bd9Sstevel@tonic-gate mov 1, %o5 12377c478bd9Sstevel@tonic-gate sll %o5, %o2, %o5 12387c478bd9Sstevel@tonic-gate#ifdef DEBUG 12397c478bd9Sstevel@tonic-gate ! 12407c478bd9Sstevel@tonic-gate ! ASSERT(CPU->cpu_intr_actv & (1 << PIL)) 12417c478bd9Sstevel@tonic-gate ! 12427c478bd9Sstevel@tonic-gate andcc %l2, %o5, %g0 12437c478bd9Sstevel@tonic-gate bnz,pt %xcc, 0f 12447c478bd9Sstevel@tonic-gate nop 12457c478bd9Sstevel@tonic-gate ! Do not call 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, 0f 12497c478bd9Sstevel@tonic-gate nop 12507c478bd9Sstevel@tonic-gate sethi %hi(current_thread_actv_bit_not_set), %o0 12517c478bd9Sstevel@tonic-gate call panic 12527c478bd9Sstevel@tonic-gate or %o0, %lo(current_thread_actv_bit_not_set), %o0 12537c478bd9Sstevel@tonic-gate0: 12547c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 12557c478bd9Sstevel@tonic-gate andn %l2, %o5, %l2 12567c478bd9Sstevel@tonic-gate st %l2, [%o3 + CPU_INTR_ACTV] 12577c478bd9Sstevel@tonic-gate 12587c478bd9Sstevel@tonic-gate ! Take timestamp, compute interval, update cumulative counter. 12597c478bd9Sstevel@tonic-gate sub %o2, LOCK_LEVEL + 1, %o4 ! PIL to array index 12607c478bd9Sstevel@tonic-gate sllx %o4, 3, %o4 ! index to byte offset 12617c478bd9Sstevel@tonic-gate add %o4, CPU_MCPU, %o4 ! CPU_PIL_HIGH_START is too large 12627c478bd9Sstevel@tonic-gate add %o4, MCPU_PIL_HIGH_START, %o4 12637c478bd9Sstevel@tonic-gate rdpr %tick, %o5 12647c478bd9Sstevel@tonic-gate sllx %o5, 1, %o5 12657c478bd9Sstevel@tonic-gate srlx %o5, 1, %o5 12667c478bd9Sstevel@tonic-gate ldx [%o3 + %o4], %o0 12677c478bd9Sstevel@tonic-gate#ifdef DEBUG 12687c478bd9Sstevel@tonic-gate ! ASSERT(cpu.cpu_m.pil_high_start[pil - (LOCK_LEVEL + 1)] != 0) 12697c478bd9Sstevel@tonic-gate brnz,pt %o0, 9f 12707c478bd9Sstevel@tonic-gate nop 12717c478bd9Sstevel@tonic-gate ! Don't panic if a panic is already in progress. 12727c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l2 12737c478bd9Sstevel@tonic-gate ld [%l2 + %lo(panic_quiesce)], %l2 12747c478bd9Sstevel@tonic-gate brnz,pn %l2, 9f 12757c478bd9Sstevel@tonic-gate nop 12767c478bd9Sstevel@tonic-gate sethi %hi(current_thread_timestamp_zero), %o0 12777c478bd9Sstevel@tonic-gate call panic 12787c478bd9Sstevel@tonic-gate or %o0, %lo(current_thread_timestamp_zero), %o0 12797c478bd9Sstevel@tonic-gate9: 12807c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 12817c478bd9Sstevel@tonic-gate stx %g0, [%o3 + %o4] 12827c478bd9Sstevel@tonic-gate sub %o5, %o0, %o5 ! interval in o5 12837c478bd9Sstevel@tonic-gate 12847c478bd9Sstevel@tonic-gate ! Check for Energy Star mode 12857c478bd9Sstevel@tonic-gate lduh [%o3 + CPU_DIVISOR], %o4 ! %o4 = clock divisor 12867c478bd9Sstevel@tonic-gate cmp %o4, 1 12877c478bd9Sstevel@tonic-gate bg,a,pn %xcc, 2f 12887c478bd9Sstevel@tonic-gate mulx %o5, %o4, %o5 ! multiply interval by clock divisor iff > 1 12897c478bd9Sstevel@tonic-gate2: 12907c478bd9Sstevel@tonic-gate sllx %o2, 4, %o4 ! PIL index to byte offset 12917c478bd9Sstevel@tonic-gate add %o4, CPU_MCPU, %o4 ! CPU_INTRSTAT too large 12927c478bd9Sstevel@tonic-gate add %o4, MCPU_INTRSTAT, %o4 ! add parts separately 12937c478bd9Sstevel@tonic-gate ldx [%o3 + %o4], %o0 ! old counter in o0 12947c478bd9Sstevel@tonic-gate add %o0, %o5, %o0 ! new counter in o0 12957c478bd9Sstevel@tonic-gate stx %o0, [%o3 + %o4] ! store new counter 12967c478bd9Sstevel@tonic-gate 1297eda89462Sesolom ! Also update intracct[] 1298eda89462Sesolom lduh [%o3 + CPU_MSTATE], %o4 1299eda89462Sesolom sllx %o4, 3, %o4 1300eda89462Sesolom add %o4, CPU_INTRACCT, %o4 1301eda89462Sesolom ldx [%o3 + %o4], %o0 1302eda89462Sesolom add %o0, %o5, %o0 1303eda89462Sesolom stx %o0, [%o3 + %o4] 1304eda89462Sesolom 13057c478bd9Sstevel@tonic-gate ! 13067c478bd9Sstevel@tonic-gate ! get back on current thread's stack 13077c478bd9Sstevel@tonic-gate ! 13087c478bd9Sstevel@tonic-gate srl %l2, LOCK_LEVEL + 1, %l2 13097c478bd9Sstevel@tonic-gate tst %l2 ! any more high-level ints? 13107c478bd9Sstevel@tonic-gate movz %xcc, %l1, %sp 13117c478bd9Sstevel@tonic-gate ! 13127c478bd9Sstevel@tonic-gate ! Current register usage: 13137c478bd9Sstevel@tonic-gate ! o2 = PIL 13147c478bd9Sstevel@tonic-gate ! o3 = CPU pointer 13157c478bd9Sstevel@tonic-gate ! l0 = return address 13167c478bd9Sstevel@tonic-gate ! l2 = intr_actv shifted right 13177c478bd9Sstevel@tonic-gate ! 13187c478bd9Sstevel@tonic-gate bz,pt %xcc, 3f ! if l2 was zero, no more ints 13197c478bd9Sstevel@tonic-gate nop 13207c478bd9Sstevel@tonic-gate ! 13217c478bd9Sstevel@tonic-gate ! We found another high-level interrupt active below the one that just 13227c478bd9Sstevel@tonic-gate ! returned. Store a starting timestamp for it in the CPU structure. 13237c478bd9Sstevel@tonic-gate ! 13247c478bd9Sstevel@tonic-gate ! Use cpu_intr_actv to find the cpu_pil_high_start[] offset for the 13257c478bd9Sstevel@tonic-gate ! interrupted high-level interrupt. 13267c478bd9Sstevel@tonic-gate ! Create mask for cpu_intr_actv. Begin by looking for bits set 13277c478bd9Sstevel@tonic-gate ! at one level below the current PIL. Since %l2 contains the active 13287c478bd9Sstevel@tonic-gate ! mask already shifted right by (LOCK_LEVEL + 1), we start by looking 13297c478bd9Sstevel@tonic-gate ! at bit (current_pil - (LOCK_LEVEL + 2)). 13307c478bd9Sstevel@tonic-gate ! %l1 = mask, %o5 = index of bit set in mask 13317c478bd9Sstevel@tonic-gate ! 13327c478bd9Sstevel@tonic-gate mov 1, %l1 13337c478bd9Sstevel@tonic-gate sub %o2, LOCK_LEVEL + 2, %o5 13347c478bd9Sstevel@tonic-gate sll %l1, %o5, %l1 ! l1 = mask for level 13357c478bd9Sstevel@tonic-gate1: 13367c478bd9Sstevel@tonic-gate#ifdef DEBUG 13377c478bd9Sstevel@tonic-gate ! ASSERT(%l1 != 0) (we didn't shift the bit off the right edge) 13387c478bd9Sstevel@tonic-gate brnz,pt %l1, 9f 13397c478bd9Sstevel@tonic-gate nop 13407c478bd9Sstevel@tonic-gate sethi %hi(current_thread_nested_PIL_not_found), %o0 13417c478bd9Sstevel@tonic-gate call panic 13427c478bd9Sstevel@tonic-gate or %o0, %lo(current_thread_nested_PIL_not_found), %o0 13437c478bd9Sstevel@tonic-gate9: 13447c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 13457c478bd9Sstevel@tonic-gate andcc %l1, %l2, %g0 ! test mask against high-level bits of 13467c478bd9Sstevel@tonic-gate bnz %xcc, 2f ! cpu_intr_actv 13477c478bd9Sstevel@tonic-gate nop 13487c478bd9Sstevel@tonic-gate srl %l1, 1, %l1 ! No match. Try next lower PIL. 13497c478bd9Sstevel@tonic-gate ba,pt %xcc, 1b 13507c478bd9Sstevel@tonic-gate sub %o5, 1, %o5 ! delay - decrement PIL 13517c478bd9Sstevel@tonic-gate2: 13527c478bd9Sstevel@tonic-gate sll %o5, 3, %o5 ! convert array index to byte offset 13537c478bd9Sstevel@tonic-gate add %o5, CPU_MCPU, %o5 ! CPU_PIL_HIGH_START is too large 13547c478bd9Sstevel@tonic-gate add %o5, MCPU_PIL_HIGH_START, %o5 13557c478bd9Sstevel@tonic-gate rdpr %tick, %o4 13567c478bd9Sstevel@tonic-gate sllx %o4, 1, %o4 13577c478bd9Sstevel@tonic-gate srlx %o4, 1, %o4 13587c478bd9Sstevel@tonic-gate ! Another high-level interrupt is active below this one, so 13597c478bd9Sstevel@tonic-gate ! there is no need to check for an interrupt thread. That will be 13607c478bd9Sstevel@tonic-gate ! done by the lowest priority high-level interrupt active. 136126046578Svb70745 ba,pt %xcc, 7f 13627c478bd9Sstevel@tonic-gate stx %o4, [%o3 + %o5] ! delay - store timestamp 13637c478bd9Sstevel@tonic-gate3: 13647c478bd9Sstevel@tonic-gate ! If we haven't interrupted another high-level interrupt, we may have 13657c478bd9Sstevel@tonic-gate ! interrupted a low level interrupt thread. If so, store a starting 13667c478bd9Sstevel@tonic-gate ! timestamp in its thread structure. 13677c478bd9Sstevel@tonic-gate lduh [THREAD_REG + T_FLAGS], %o4 13687c478bd9Sstevel@tonic-gate andcc %o4, T_INTR_THREAD, %g0 136926046578Svb70745 bz,pt %xcc, 7f 13707c478bd9Sstevel@tonic-gate nop 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate rdpr %tick, %o4 13737c478bd9Sstevel@tonic-gate sllx %o4, 1, %o4 13747c478bd9Sstevel@tonic-gate srlx %o4, 1, %o4 ! Shake off NPT bit 13757c478bd9Sstevel@tonic-gate stx %o4, [THREAD_REG + T_INTR_START] 137626046578Svb70745 137726046578Svb707457: 137826046578Svb70745 sub %o2, LOCK_LEVEL + 1, %o4 137926046578Svb70745 sll %o4, CPTRSHIFT, %o5 138026046578Svb70745 138126046578Svb70745 ! Check on_trap saved area and restore as needed 138226046578Svb70745 add %o5, CPU_OTD, %o4 138326046578Svb70745 ldn [%o3 + %o4], %l2 138426046578Svb70745 brz,pt %l2, no_ontrp_restore 138526046578Svb70745 nop 138626046578Svb70745 stn %l2, [THREAD_REG + T_ONTRAP] ! restore 138726046578Svb70745 stn %g0, [%o3 + %o4] ! clear 138826046578Svb70745 138926046578Svb70745no_ontrp_restore: 139026046578Svb70745 ! Check on_fault saved area and restore as needed 139126046578Svb70745 add %o5, CPU_OFD, %o4 139226046578Svb70745 ldn [%o3 + %o4], %l2 139326046578Svb70745 brz,pt %l2, 8f 139426046578Svb70745 nop 139526046578Svb70745 stn %l2, [THREAD_REG + T_ONFAULT] ! restore 139626046578Svb70745 stn %g0, [%o3 + %o4] ! clear 139726046578Svb70745 add %o5, CPU_LFD, %o4 139826046578Svb70745 ldn [%o3 + %o4], %l2 139926046578Svb70745 stn %l2, [THREAD_REG + T_LOFAULT] ! restore 140026046578Svb70745 stn %g0, [%o3 + %o4] ! clear 140126046578Svb70745 140226046578Svb70745 140326046578Svb707458: 14047c478bd9Sstevel@tonic-gate ! Enable interrupts and return 14057c478bd9Sstevel@tonic-gate jmp %l0 + 8 14067c478bd9Sstevel@tonic-gate wrpr %g0, %o2, %pil ! enable interrupts 14077c478bd9Sstevel@tonic-gate SET_SIZE(current_thread) 14087c478bd9Sstevel@tonic-gate 14097c478bd9Sstevel@tonic-gate 14107c478bd9Sstevel@tonic-gate#ifdef DEBUG 14117c478bd9Sstevel@tonic-gatecurrent_thread_wrong_pil: 14127c478bd9Sstevel@tonic-gate .asciz "current_thread: unexpected pil level: %d" 14137c478bd9Sstevel@tonic-gatecurrent_thread_actv_bit_set: 14147c478bd9Sstevel@tonic-gate .asciz "current_thread(): cpu_intr_actv bit already set for PIL" 14157c478bd9Sstevel@tonic-gatecurrent_thread_actv_bit_not_set: 14167c478bd9Sstevel@tonic-gate .asciz "current_thread(): cpu_intr_actv bit not set for PIL" 14177c478bd9Sstevel@tonic-gatecurrent_thread_nested_pil_zero: 14187c478bd9Sstevel@tonic-gate .asciz "current_thread(): timestamp zero for nested PIL %d" 14197c478bd9Sstevel@tonic-gatecurrent_thread_timestamp_zero: 14207c478bd9Sstevel@tonic-gate .asciz "current_thread(): timestamp zero upon handler return" 14217c478bd9Sstevel@tonic-gatecurrent_thread_nested_PIL_not_found: 14227c478bd9Sstevel@tonic-gate .asciz "current_thread: couldn't find nested high-level PIL" 14237c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 14247c478bd9Sstevel@tonic-gate#endif /* lint */ 14257c478bd9Sstevel@tonic-gate 14267c478bd9Sstevel@tonic-gate/* 14277c478bd9Sstevel@tonic-gate * Return a thread's interrupt level. 14287c478bd9Sstevel@tonic-gate * Since this isn't saved anywhere but in %l4 on interrupt entry, we 14297c478bd9Sstevel@tonic-gate * must dig it out of the save area. 14307c478bd9Sstevel@tonic-gate * 14317c478bd9Sstevel@tonic-gate * Caller 'swears' that this really is an interrupt thread. 14327c478bd9Sstevel@tonic-gate * 14337c478bd9Sstevel@tonic-gate * int 14347c478bd9Sstevel@tonic-gate * intr_level(t) 14357c478bd9Sstevel@tonic-gate * kthread_id_t t; 14367c478bd9Sstevel@tonic-gate */ 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate#if defined(lint) 14397c478bd9Sstevel@tonic-gate 14407c478bd9Sstevel@tonic-gate/* ARGSUSED */ 14417c478bd9Sstevel@tonic-gateint 14427c478bd9Sstevel@tonic-gateintr_level(kthread_id_t t) 14437c478bd9Sstevel@tonic-gate{ return (0); } 14447c478bd9Sstevel@tonic-gate 14457c478bd9Sstevel@tonic-gate#else /* lint */ 14467c478bd9Sstevel@tonic-gate 14477c478bd9Sstevel@tonic-gate ENTRY_NP(intr_level) 14487c478bd9Sstevel@tonic-gate retl 14497c478bd9Sstevel@tonic-gate ldub [%o0 + T_PIL], %o0 ! return saved pil 14507c478bd9Sstevel@tonic-gate SET_SIZE(intr_level) 14517c478bd9Sstevel@tonic-gate 14527c478bd9Sstevel@tonic-gate#endif /* lint */ 14537c478bd9Sstevel@tonic-gate 14547c478bd9Sstevel@tonic-gate#if defined(lint) 14557c478bd9Sstevel@tonic-gate 14567c478bd9Sstevel@tonic-gate/* ARGSUSED */ 14577c478bd9Sstevel@tonic-gateint 14587c478bd9Sstevel@tonic-gatedisable_pil_intr() 14597c478bd9Sstevel@tonic-gate{ return (0); } 14607c478bd9Sstevel@tonic-gate 14617c478bd9Sstevel@tonic-gate#else /* lint */ 14627c478bd9Sstevel@tonic-gate 14637c478bd9Sstevel@tonic-gate ENTRY_NP(disable_pil_intr) 14647c478bd9Sstevel@tonic-gate rdpr %pil, %o0 14657c478bd9Sstevel@tonic-gate retl 14667c478bd9Sstevel@tonic-gate wrpr %g0, PIL_MAX, %pil ! disable interrupts (1-15) 14677c478bd9Sstevel@tonic-gate SET_SIZE(disable_pil_intr) 14687c478bd9Sstevel@tonic-gate 14697c478bd9Sstevel@tonic-gate#endif /* lint */ 14707c478bd9Sstevel@tonic-gate 14717c478bd9Sstevel@tonic-gate#if defined(lint) 14727c478bd9Sstevel@tonic-gate 14737c478bd9Sstevel@tonic-gate/* ARGSUSED */ 14747c478bd9Sstevel@tonic-gatevoid 14757c478bd9Sstevel@tonic-gateenable_pil_intr(int pil_save) 14767c478bd9Sstevel@tonic-gate{} 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate#else /* lint */ 14797c478bd9Sstevel@tonic-gate 14807c478bd9Sstevel@tonic-gate ENTRY_NP(enable_pil_intr) 14817c478bd9Sstevel@tonic-gate retl 14827c478bd9Sstevel@tonic-gate wrpr %o0, %pil 14837c478bd9Sstevel@tonic-gate SET_SIZE(enable_pil_intr) 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate#endif /* lint */ 14867c478bd9Sstevel@tonic-gate 14877c478bd9Sstevel@tonic-gate#if defined(lint) 14887c478bd9Sstevel@tonic-gate 14897c478bd9Sstevel@tonic-gate/* ARGSUSED */ 14907c478bd9Sstevel@tonic-gateuint_t 14917c478bd9Sstevel@tonic-gatedisable_vec_intr(void) 14927c478bd9Sstevel@tonic-gate{ return (0); } 14937c478bd9Sstevel@tonic-gate 14947c478bd9Sstevel@tonic-gate#else /* lint */ 14957c478bd9Sstevel@tonic-gate 14967c478bd9Sstevel@tonic-gate ENTRY_NP(disable_vec_intr) 14977c478bd9Sstevel@tonic-gate rdpr %pstate, %o0 14987c478bd9Sstevel@tonic-gate andn %o0, PSTATE_IE, %g1 14997c478bd9Sstevel@tonic-gate retl 15007c478bd9Sstevel@tonic-gate wrpr %g0, %g1, %pstate ! disable interrupt 15017c478bd9Sstevel@tonic-gate SET_SIZE(disable_vec_intr) 15027c478bd9Sstevel@tonic-gate 15037c478bd9Sstevel@tonic-gate#endif /* lint */ 15047c478bd9Sstevel@tonic-gate 15057c478bd9Sstevel@tonic-gate#if defined(lint) 15067c478bd9Sstevel@tonic-gate 15077c478bd9Sstevel@tonic-gate/* ARGSUSED */ 15087c478bd9Sstevel@tonic-gatevoid 15097c478bd9Sstevel@tonic-gateenable_vec_intr(uint_t pstate_save) 15107c478bd9Sstevel@tonic-gate{} 15117c478bd9Sstevel@tonic-gate 15127c478bd9Sstevel@tonic-gate#else /* lint */ 15137c478bd9Sstevel@tonic-gate 15147c478bd9Sstevel@tonic-gate ENTRY_NP(enable_vec_intr) 15157c478bd9Sstevel@tonic-gate retl 15167c478bd9Sstevel@tonic-gate wrpr %g0, %o0, %pstate 15177c478bd9Sstevel@tonic-gate SET_SIZE(enable_vec_intr) 15187c478bd9Sstevel@tonic-gate 15197c478bd9Sstevel@tonic-gate#endif /* lint */ 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate#if defined(lint) 15227c478bd9Sstevel@tonic-gate 15237c478bd9Sstevel@tonic-gatevoid 15247c478bd9Sstevel@tonic-gatecbe_level14(void) 15257c478bd9Sstevel@tonic-gate{} 15267c478bd9Sstevel@tonic-gate 15277c478bd9Sstevel@tonic-gate#else /* lint */ 15287c478bd9Sstevel@tonic-gate 15297c478bd9Sstevel@tonic-gate ENTRY_NP(cbe_level14) 15307c478bd9Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp ! get a new window 15317c478bd9Sstevel@tonic-gate ! 15327c478bd9Sstevel@tonic-gate ! Make sure that this is from TICK_COMPARE; if not just return 15337c478bd9Sstevel@tonic-gate ! 15347c478bd9Sstevel@tonic-gate rd SOFTINT, %l1 15357c478bd9Sstevel@tonic-gate set (TICK_INT_MASK | STICK_INT_MASK), %o2 15367c478bd9Sstevel@tonic-gate andcc %l1, %o2, %g0 15377c478bd9Sstevel@tonic-gate bz,pn %icc, 2f 15387c478bd9Sstevel@tonic-gate nop 15397c478bd9Sstevel@tonic-gate 15407c478bd9Sstevel@tonic-gate CPU_ADDR(%o1, %o2) 15417c478bd9Sstevel@tonic-gate call cyclic_fire 15427c478bd9Sstevel@tonic-gate mov %o1, %o0 15437c478bd9Sstevel@tonic-gate2: 15447c478bd9Sstevel@tonic-gate ret 15457c478bd9Sstevel@tonic-gate restore %g0, 1, %o0 15467c478bd9Sstevel@tonic-gate SET_SIZE(cbe_level14) 15477c478bd9Sstevel@tonic-gate 15487c478bd9Sstevel@tonic-gate#endif /* lint */ 15497c478bd9Sstevel@tonic-gate 15507c478bd9Sstevel@tonic-gate 15517c478bd9Sstevel@tonic-gate#if defined(lint) 15527c478bd9Sstevel@tonic-gate 15537c478bd9Sstevel@tonic-gate/* ARGSUSED */ 15547c478bd9Sstevel@tonic-gatevoid 1555*a1af7ba0Scwbkdi_setsoftint(uint64_t iv_p) 15567c478bd9Sstevel@tonic-gate{} 15577c478bd9Sstevel@tonic-gate 15587c478bd9Sstevel@tonic-gate#else /* lint */ 15597c478bd9Sstevel@tonic-gate 1560*a1af7ba0Scwb ENTRY_NP(kdi_setsoftint) 15617c478bd9Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp ! get a new window 15627c478bd9Sstevel@tonic-gate rdpr %pstate, %l5 15637c478bd9Sstevel@tonic-gate andn %l5, PSTATE_IE, %l1 15647c478bd9Sstevel@tonic-gate wrpr %l1, %pstate ! disable interrupt 15657c478bd9Sstevel@tonic-gate ! 1566b0fc0e77Sgovinda ! We have a pointer to an interrupt vector data structure. 1567b0fc0e77Sgovinda ! Put the request on the cpu's softint priority list and 1568b0fc0e77Sgovinda ! set %set_softint. 15697c478bd9Sstevel@tonic-gate ! 15707c478bd9Sstevel@tonic-gate ! Register usage 1571b0fc0e77Sgovinda ! %i0 - pointer to intr_vec_t (iv) 15727c478bd9Sstevel@tonic-gate ! %l2 - requested pil 1573b0fc0e77Sgovinda ! %l4 - cpu 1574b0fc0e77Sgovinda ! %l5 - pstate 1575b0fc0e77Sgovinda ! %l1, %l3, %l6 - temps 15767c478bd9Sstevel@tonic-gate ! 1577b0fc0e77Sgovinda ! check if a softint is pending for this softint, 1578b0fc0e77Sgovinda ! if one is pending, don't bother queuing another. 15797c478bd9Sstevel@tonic-gate ! 1580b0fc0e77Sgovinda lduh [%i0 + IV_FLAGS], %l1 ! %l1 = iv->iv_flags 1581b0fc0e77Sgovinda and %l1, IV_SOFTINT_PEND, %l6 ! %l6 = iv->iv_flags & IV_SOFTINT_PEND 1582b0fc0e77Sgovinda brnz,pn %l6, 4f ! branch if softint is already pending 1583b0fc0e77Sgovinda or %l1, IV_SOFTINT_PEND, %l2 1584b0fc0e77Sgovinda sth %l2, [%i0 + IV_FLAGS] ! Set IV_SOFTINT_PEND flag 1585b0fc0e77Sgovinda 1586b0fc0e77Sgovinda CPU_ADDR(%l4, %l2) ! %l4 = cpu 1587b0fc0e77Sgovinda lduh [%i0 + IV_PIL], %l2 ! %l2 = iv->iv_pil 1588b0fc0e77Sgovinda 15897c478bd9Sstevel@tonic-gate ! 1590b0fc0e77Sgovinda ! Insert intr_vec_t (iv) to appropriate cpu's softint priority list 15917c478bd9Sstevel@tonic-gate ! 1592b0fc0e77Sgovinda sll %l2, CPTRSHIFT, %l0 ! %l0 = offset to pil entry 1593b0fc0e77Sgovinda add %l4, INTR_TAIL, %l6 ! %l6 = &cpu->m_cpu.intr_tail 1594b0fc0e77Sgovinda ldn [%l6 + %l0], %l1 ! %l1 = cpu->m_cpu.intr_tail[pil] 1595b0fc0e77Sgovinda ! current tail (ct) 1596b0fc0e77Sgovinda brz,pt %l1, 2f ! branch if current tail is NULL 1597b0fc0e77Sgovinda stn %i0, [%l6 + %l0] ! make intr_vec_t (iv) as new tail 15987c478bd9Sstevel@tonic-gate ! 1599b0fc0e77Sgovinda ! there's pending intr_vec_t already 16007c478bd9Sstevel@tonic-gate ! 1601b0fc0e77Sgovinda lduh [%l1 + IV_FLAGS], %l6 ! %l6 = ct->iv_flags 1602b0fc0e77Sgovinda and %l6, IV_SOFTINT_MT, %l6 ! %l6 = ct->iv_flags & IV_SOFTINT_MT 1603b0fc0e77Sgovinda brz,pt %l6, 1f ! check for Multi target softint flag 1604b0fc0e77Sgovinda add %l1, IV_PIL_NEXT, %l3 ! %l3 = &ct->iv_pil_next 1605b0fc0e77Sgovinda ld [%l4 + CPU_ID], %l6 ! for multi target softint, use cpuid 1606b0fc0e77Sgovinda sll %l6, CPTRSHIFT, %l6 ! calculate offset address from cpuid 1607b0fc0e77Sgovinda add %l3, %l6, %l3 ! %l3 = &ct->iv_xpil_next[cpuid] 1608b0fc0e77Sgovinda1: 16097c478bd9Sstevel@tonic-gate ! 1610b0fc0e77Sgovinda ! update old tail 16117c478bd9Sstevel@tonic-gate ! 16127c478bd9Sstevel@tonic-gate ba,pt %xcc, 3f 1613b0fc0e77Sgovinda stn %i0, [%l3] ! [%l3] = iv, set pil_next field 16147c478bd9Sstevel@tonic-gate2: 16157c478bd9Sstevel@tonic-gate ! 1616b0fc0e77Sgovinda ! no pending intr_vec_t; make intr_vec_t as new head 16177c478bd9Sstevel@tonic-gate ! 1618b0fc0e77Sgovinda add %l4, INTR_HEAD, %l6 ! %l6 = &cpu->m_cpu.intr_head[pil] 1619b0fc0e77Sgovinda stn %i0, [%l6 + %l0] ! cpu->m_cpu.intr_head[pil] = iv 16207c478bd9Sstevel@tonic-gate3: 16217c478bd9Sstevel@tonic-gate ! 16227c478bd9Sstevel@tonic-gate ! Write %set_softint with (1<<pil) to cause a "pil" level trap 16237c478bd9Sstevel@tonic-gate ! 1624b0fc0e77Sgovinda mov 1, %l1 ! %l1 = 1 1625b0fc0e77Sgovinda sll %l1, %l2, %l1 ! %l1 = 1 << pil 1626b0fc0e77Sgovinda wr %l1, SET_SOFTINT ! trigger required pil softint 16277c478bd9Sstevel@tonic-gate4: 1628b0fc0e77Sgovinda wrpr %g0, %l5, %pstate ! %pstate = saved %pstate (in %l5) 16297c478bd9Sstevel@tonic-gate ret 16307c478bd9Sstevel@tonic-gate restore 1631*a1af7ba0Scwb SET_SIZE(kdi_setsoftint) 16327c478bd9Sstevel@tonic-gate 16337c478bd9Sstevel@tonic-gate#endif /* lint */ 16347c478bd9Sstevel@tonic-gate 16357c478bd9Sstevel@tonic-gate#if defined(lint) 16367c478bd9Sstevel@tonic-gate 16377c478bd9Sstevel@tonic-gate/*ARGSUSED*/ 16387c478bd9Sstevel@tonic-gatevoid 1639b0fc0e77Sgovindasetsoftint_tl1(uint64_t iv_p, uint64_t dummy) 16407c478bd9Sstevel@tonic-gate{} 16417c478bd9Sstevel@tonic-gate 16427c478bd9Sstevel@tonic-gate#else /* lint */ 16437c478bd9Sstevel@tonic-gate 16447c478bd9Sstevel@tonic-gate ! 16457c478bd9Sstevel@tonic-gate ! Register usage 1646b0fc0e77Sgovinda ! Arguments: 1647b0fc0e77Sgovinda ! %g1 - Pointer to intr_vec_t (iv) 16487c478bd9Sstevel@tonic-gate ! 1649b0fc0e77Sgovinda ! Internal: 1650b0fc0e77Sgovinda ! %g2 - pil 1651b0fc0e77Sgovinda ! %g4 - cpu 1652b0fc0e77Sgovinda ! %g3,%g5-g7 - temps 1653b0fc0e77Sgovinda ! 1654b0fc0e77Sgovinda ENTRY_NP(setsoftint_tl1) 1655b0fc0e77Sgovinda ! 1656b0fc0e77Sgovinda ! We have a pointer to an interrupt vector data structure. 1657b0fc0e77Sgovinda ! Put the request on the cpu's softint priority list and 1658b0fc0e77Sgovinda ! set %set_softint. 1659b0fc0e77Sgovinda ! 1660b0fc0e77Sgovinda CPU_ADDR(%g4, %g2) ! %g4 = cpu 1661b0fc0e77Sgovinda lduh [%g1 + IV_PIL], %g2 ! %g2 = iv->iv_pil 1662b0fc0e77Sgovinda 1663b0fc0e77Sgovinda ! 1664b0fc0e77Sgovinda ! Insert intr_vec_t (iv) to appropriate cpu's softint priority list 1665b0fc0e77Sgovinda ! 1666b0fc0e77Sgovinda sll %g2, CPTRSHIFT, %g7 ! %g7 = offset to pil entry 1667b0fc0e77Sgovinda add %g4, INTR_TAIL, %g6 ! %g6 = &cpu->m_cpu.intr_tail 1668b0fc0e77Sgovinda ldn [%g6 + %g7], %g5 ! %g5 = cpu->m_cpu.intr_tail[pil] 1669b0fc0e77Sgovinda ! current tail (ct) 1670b0fc0e77Sgovinda brz,pt %g5, 1f ! branch if current tail is NULL 1671b0fc0e77Sgovinda stn %g1, [%g6 + %g7] ! make intr_rec_t (iv) as new tail 1672b0fc0e77Sgovinda ! 1673b0fc0e77Sgovinda ! there's pending intr_vec_t already 1674b0fc0e77Sgovinda ! 1675b0fc0e77Sgovinda lduh [%g5 + IV_FLAGS], %g6 ! %g6 = ct->iv_flags 1676b0fc0e77Sgovinda and %g6, IV_SOFTINT_MT, %g6 ! %g6 = ct->iv_flags & IV_SOFTINT_MT 1677b0fc0e77Sgovinda brz,pt %g6, 0f ! check for Multi target softint flag 1678b0fc0e77Sgovinda add %g5, IV_PIL_NEXT, %g3 ! %g3 = &ct->iv_pil_next 1679b0fc0e77Sgovinda ld [%g4 + CPU_ID], %g6 ! for multi target softint, use cpuid 1680b0fc0e77Sgovinda sll %g6, CPTRSHIFT, %g6 ! calculate offset address from cpuid 1681b0fc0e77Sgovinda add %g3, %g6, %g3 ! %g3 = &ct->iv_xpil_next[cpuid] 1682b0fc0e77Sgovinda0: 1683b0fc0e77Sgovinda ! 1684b0fc0e77Sgovinda ! update old tail 1685b0fc0e77Sgovinda ! 1686b0fc0e77Sgovinda ba,pt %xcc, 2f 1687b0fc0e77Sgovinda stn %g1, [%g3] ! [%g3] = iv, set pil_next field 1688b0fc0e77Sgovinda1: 1689b0fc0e77Sgovinda ! 1690b0fc0e77Sgovinda ! no pending intr_vec_t; make intr_vec_t as new head 1691b0fc0e77Sgovinda ! 1692b0fc0e77Sgovinda add %g4, INTR_HEAD, %g6 ! %g6 = &cpu->m_cpu.intr_head[pil] 1693b0fc0e77Sgovinda stn %g1, [%g6 + %g7] ! cpu->m_cpu.intr_head[pil] = iv 1694b0fc0e77Sgovinda2: 1695b0fc0e77Sgovinda#ifdef TRAPTRACE 1696b0fc0e77Sgovinda TRACE_PTR(%g5, %g6) 1697b0fc0e77Sgovinda GET_TRACE_TICK(%g6) 1698b0fc0e77Sgovinda stxa %g6, [%g5 + TRAP_ENT_TICK]%asi ! trap_tick = %tick 1699b0fc0e77Sgovinda TRACE_SAVE_TL_GL_REGS(%g5, %g6) 1700b0fc0e77Sgovinda rdpr %tt, %g6 1701b0fc0e77Sgovinda stha %g6, [%g5 + TRAP_ENT_TT]%asi ! trap_type = %tt 1702b0fc0e77Sgovinda rdpr %tpc, %g6 1703b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_TPC]%asi ! trap_pc = %tpc 1704b0fc0e77Sgovinda rdpr %tstate, %g6 1705b0fc0e77Sgovinda stxa %g6, [%g5 + TRAP_ENT_TSTATE]%asi ! trap_tstate = %tstate 1706b0fc0e77Sgovinda stna %sp, [%g5 + TRAP_ENT_SP]%asi ! trap_sp = %sp 1707b0fc0e77Sgovinda stna %g1, [%g5 + TRAP_ENT_TR]%asi ! trap_tr = iv 1708b0fc0e77Sgovinda ldn [%g1 + IV_PIL_NEXT], %g6 ! 1709b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_F1]%asi ! trap_f1 = iv->iv_pil_next 1710b0fc0e77Sgovinda add %g4, INTR_HEAD, %g6 1711b0fc0e77Sgovinda ldn [%g6 + %g7], %g6 ! %g6=cpu->m_cpu.intr_head[pil] 1712b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_F2]%asi ! trap_f2 = intr_head[pil] 1713b0fc0e77Sgovinda add %g4, INTR_TAIL, %g6 1714b0fc0e77Sgovinda ldn [%g6 + %g7], %g6 ! %g6=cpu->m_cpu.intr_tail[pil] 1715b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_F3]%asi ! trap_f3 = intr_tail[pil] 1716b0fc0e77Sgovinda stna %g2, [%g5 + TRAP_ENT_F4]%asi ! trap_f4 = pil 1717b0fc0e77Sgovinda TRACE_NEXT(%g5, %g6, %g3) 1718b0fc0e77Sgovinda#endif /* TRAPTRACE */ 1719b0fc0e77Sgovinda ! 1720b0fc0e77Sgovinda ! Write %set_softint with (1<<pil) to cause a "pil" level trap 1721b0fc0e77Sgovinda ! 1722b0fc0e77Sgovinda mov 1, %g5 ! %g5 = 1 1723b0fc0e77Sgovinda sll %g5, %g2, %g5 ! %g5 = 1 << pil 1724b0fc0e77Sgovinda wr %g5, SET_SOFTINT ! trigger required pil softint 1725b0fc0e77Sgovinda retry 1726b0fc0e77Sgovinda SET_SIZE(setsoftint_tl1) 1727b0fc0e77Sgovinda 1728b0fc0e77Sgovinda#endif /* lint */ 1729b0fc0e77Sgovinda 1730b0fc0e77Sgovinda#if defined(lint) 1731b0fc0e77Sgovinda 1732b0fc0e77Sgovinda/*ARGSUSED*/ 1733b0fc0e77Sgovindavoid 1734b0fc0e77Sgovindasetvecint_tl1(uint64_t inum, uint64_t dummy) 1735b0fc0e77Sgovinda{} 1736b0fc0e77Sgovinda 1737b0fc0e77Sgovinda#else /* lint */ 1738b0fc0e77Sgovinda 1739b0fc0e77Sgovinda ! 1740b0fc0e77Sgovinda ! Register usage 17417c478bd9Sstevel@tonic-gate ! Arguments: 17427c478bd9Sstevel@tonic-gate ! %g1 - inumber 17437c478bd9Sstevel@tonic-gate ! 17447c478bd9Sstevel@tonic-gate ! Internal: 1745b0fc0e77Sgovinda ! %g1 - softint pil mask 1746b0fc0e77Sgovinda ! %g2 - pil of intr_vec_t 1747b0fc0e77Sgovinda ! %g3 - pointer to current intr_vec_t (iv) 1748b0fc0e77Sgovinda ! %g4 - cpu 17497c478bd9Sstevel@tonic-gate ! %g5, %g6,%g7 - temps 17507c478bd9Sstevel@tonic-gate ! 1751b0fc0e77Sgovinda ENTRY_NP(setvecint_tl1) 17527c478bd9Sstevel@tonic-gate ! 17537c478bd9Sstevel@tonic-gate ! Verify the inumber received (should be inum < MAXIVNUM). 17547c478bd9Sstevel@tonic-gate ! 17557c478bd9Sstevel@tonic-gate set MAXIVNUM, %g2 17567c478bd9Sstevel@tonic-gate cmp %g1, %g2 17577c478bd9Sstevel@tonic-gate bgeu,pn %xcc, .no_ivintr 17587c478bd9Sstevel@tonic-gate clr %g2 ! expected in .no_ivintr 17597c478bd9Sstevel@tonic-gate 17607c478bd9Sstevel@tonic-gate ! 1761b0fc0e77Sgovinda ! Fetch data from intr_vec_table according to the inum. 17627c478bd9Sstevel@tonic-gate ! 1763b0fc0e77Sgovinda ! We have an interrupt number. Fetch the interrupt vector requests 1764b0fc0e77Sgovinda ! from the interrupt vector table for a given interrupt number and 1765b0fc0e77Sgovinda ! insert them into cpu's softint priority lists and set %set_softint. 1766b0fc0e77Sgovinda ! 1767b0fc0e77Sgovinda set intr_vec_table, %g5 ! %g5 = intr_vec_table 1768b0fc0e77Sgovinda sll %g1, CPTRSHIFT, %g6 ! %g6 = offset to inum entry in table 1769b0fc0e77Sgovinda add %g5, %g6, %g5 ! %g5 = &intr_vec_table[inum] 1770b0fc0e77Sgovinda ldn [%g5], %g3 ! %g3 = pointer to first entry of 1771b0fc0e77Sgovinda ! intr_vec_t list 17727c478bd9Sstevel@tonic-gate 1773b0fc0e77Sgovinda ! Verify the first intr_vec_t pointer for a given inum and it should 1774b0fc0e77Sgovinda ! not be NULL. This used to be guarded by DEBUG but broken drivers can 1775b0fc0e77Sgovinda ! cause spurious tick interrupts when the softint register is programmed 1776b0fc0e77Sgovinda ! with 1 << 0 at the end of this routine. Now we always check for a 1777b0fc0e77Sgovinda ! valid intr_vec_t pointer. 1778b0fc0e77Sgovinda brz,pn %g3, .no_ivintr 17797c478bd9Sstevel@tonic-gate nop 17807c478bd9Sstevel@tonic-gate 17817c478bd9Sstevel@tonic-gate ! 1782b0fc0e77Sgovinda ! Traverse the intr_vec_t link list, put each item on to corresponding 1783b0fc0e77Sgovinda ! CPU softint priority queue, and compose the final softint pil mask. 17847c478bd9Sstevel@tonic-gate ! 1785b0fc0e77Sgovinda ! At this point: 1786b0fc0e77Sgovinda ! %g3 = intr_vec_table[inum] 17877c478bd9Sstevel@tonic-gate ! 1788b0fc0e77Sgovinda CPU_ADDR(%g4, %g2) ! %g4 = cpu 1789b0fc0e77Sgovinda mov %g0, %g1 ! %g1 = 0, initialize pil mask to 0 1790b0fc0e77Sgovinda0: 17917c478bd9Sstevel@tonic-gate ! 1792b0fc0e77Sgovinda ! Insert next intr_vec_t (iv) to appropriate cpu's softint priority list 17937c478bd9Sstevel@tonic-gate ! 1794b0fc0e77Sgovinda ! At this point: 1795b0fc0e77Sgovinda ! %g1 = softint pil mask 1796b0fc0e77Sgovinda ! %g3 = pointer to next intr_vec_t (iv) 1797b0fc0e77Sgovinda ! %g4 = cpu 17987c478bd9Sstevel@tonic-gate ! 1799b0fc0e77Sgovinda lduh [%g3 + IV_PIL], %g2 ! %g2 = iv->iv_pil 1800b0fc0e77Sgovinda sll %g2, CPTRSHIFT, %g7 ! %g7 = offset to pil entry 1801b0fc0e77Sgovinda add %g4, INTR_TAIL, %g6 ! %g6 = &cpu->m_cpu.intr_tail 1802b0fc0e77Sgovinda ldn [%g6 + %g7], %g5 ! %g5 = cpu->m_cpu.intr_tail[pil] 1803b0fc0e77Sgovinda ! current tail (ct) 1804b0fc0e77Sgovinda brz,pt %g5, 2f ! branch if current tail is NULL 1805b0fc0e77Sgovinda stn %g3, [%g6 + %g7] ! make intr_vec_t (iv) as new tail 1806b0fc0e77Sgovinda ! cpu->m_cpu.intr_tail[pil] = iv 18077c478bd9Sstevel@tonic-gate ! 1808b0fc0e77Sgovinda ! there's pending intr_vec_t already 1809b0fc0e77Sgovinda ! 1810b0fc0e77Sgovinda lduh [%g5 + IV_FLAGS], %g6 ! %g6 = ct->iv_flags 1811b0fc0e77Sgovinda and %g6, IV_SOFTINT_MT, %g6 ! %g6 = ct->iv_flags & IV_SOFTINT_MT 1812b0fc0e77Sgovinda brz,pt %g6, 1f ! check for Multi target softint flag 1813b0fc0e77Sgovinda add %g5, IV_PIL_NEXT, %g5 ! %g5 = &ct->iv_pil_next 1814b0fc0e77Sgovinda ld [%g4 + CPU_ID], %g6 ! for multi target softint, use cpuid 1815b0fc0e77Sgovinda sll %g6, CPTRSHIFT, %g6 ! calculate offset address from cpuid 1816b0fc0e77Sgovinda add %g5, %g6, %g5 ! %g5 = &ct->iv_xpil_next[cpuid] 1817b0fc0e77Sgovinda1: 1818b0fc0e77Sgovinda ! 1819b0fc0e77Sgovinda ! update old tail 18207c478bd9Sstevel@tonic-gate ! 18217c478bd9Sstevel@tonic-gate ba,pt %xcc, 3f 1822b0fc0e77Sgovinda stn %g3, [%g5] ! [%g5] = iv, set pil_next field 18237c478bd9Sstevel@tonic-gate2: 18247c478bd9Sstevel@tonic-gate ! 1825b0fc0e77Sgovinda ! no pending intr_vec_t; make intr_vec_t as new head 18267c478bd9Sstevel@tonic-gate ! 1827b0fc0e77Sgovinda add %g4, INTR_HEAD, %g6 ! %g6 = &cpu->m_cpu.intr_head[pil] 1828b0fc0e77Sgovinda stn %g3, [%g6 + %g7] ! cpu->m_cpu.intr_head[pil] = iv 18297c478bd9Sstevel@tonic-gate3: 18307c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE 1831b0fc0e77Sgovinda TRACE_PTR(%g5, %g6) 18327c478bd9Sstevel@tonic-gate GET_TRACE_TICK(%g6) 1833b0fc0e77Sgovinda stxa %g6, [%g5 + TRAP_ENT_TICK]%asi ! trap_tick = %tick 1834b0fc0e77Sgovinda TRACE_SAVE_TL_GL_REGS(%g5, %g6) 18357c478bd9Sstevel@tonic-gate rdpr %tt, %g6 1836b0fc0e77Sgovinda stha %g6, [%g5 + TRAP_ENT_TT]%asi ! trap_type = %tt` 18377c478bd9Sstevel@tonic-gate rdpr %tpc, %g6 1838b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_TPC]%asi ! trap_pc = %tpc 18397c478bd9Sstevel@tonic-gate rdpr %tstate, %g6 1840b0fc0e77Sgovinda stxa %g6, [%g5 + TRAP_ENT_TSTATE]%asi ! trap_tstate = %tstate 1841b0fc0e77Sgovinda stna %sp, [%g5 + TRAP_ENT_SP]%asi ! trap_sp = %sp 1842b0fc0e77Sgovinda stna %g3, [%g5 + TRAP_ENT_TR]%asi ! trap_tr = iv 1843b0fc0e77Sgovinda stna %g1, [%g5 + TRAP_ENT_F1]%asi ! trap_f1 = pil mask 18447c478bd9Sstevel@tonic-gate add %g4, INTR_HEAD, %g6 1845b0fc0e77Sgovinda ldn [%g6 + %g7], %g6 ! %g6=cpu->m_cpu.intr_head[pil] 1846b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_F2]%asi ! trap_f2 = intr_head[pil] 18477c478bd9Sstevel@tonic-gate add %g4, INTR_TAIL, %g6 1848b0fc0e77Sgovinda ldn [%g6 + %g7], %g6 ! %g6=cpu->m_cpu.intr_tail[pil] 1849b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_F3]%asi ! trap_f3 = intr_tail[pil] 1850b0fc0e77Sgovinda stna %g2, [%g5 + TRAP_ENT_F4]%asi ! trap_f4 = pil 1851b0fc0e77Sgovinda TRACE_NEXT(%g5, %g6, %g7) 18527c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */ 1853b0fc0e77Sgovinda mov 1, %g6 ! %g6 = 1 1854b0fc0e77Sgovinda sll %g6, %g2, %g6 ! %g6 = 1 << pil 1855b0fc0e77Sgovinda or %g1, %g6, %g1 ! %g1 |= (1 << pil), pil mask 1856b0fc0e77Sgovinda ldn [%g3 + IV_VEC_NEXT], %g3 ! %g3 = pointer to next intr_vec_t (iv) 1857b0fc0e77Sgovinda brnz,pn %g3, 0b ! iv->iv_vec_next is non NULL, goto 0b 1858b0fc0e77Sgovinda nop 1859b0fc0e77Sgovinda wr %g1, SET_SOFTINT ! triggered one or more pil softints 18607c478bd9Sstevel@tonic-gate retry 18617c478bd9Sstevel@tonic-gate 18627c478bd9Sstevel@tonic-gate.no_ivintr: 18637c478bd9Sstevel@tonic-gate ! no_ivintr: arguments: rp, inum (%g1), pil (%g2 == 0) 18647c478bd9Sstevel@tonic-gate mov %g2, %g3 18657c478bd9Sstevel@tonic-gate mov %g1, %g2 18667c478bd9Sstevel@tonic-gate set no_ivintr, %g1 18677c478bd9Sstevel@tonic-gate ba,pt %xcc, sys_trap 18687c478bd9Sstevel@tonic-gate mov PIL_15, %g4 1869b0fc0e77Sgovinda SET_SIZE(setvecint_tl1) 18707c478bd9Sstevel@tonic-gate 18717c478bd9Sstevel@tonic-gate#endif /* lint */ 18727c478bd9Sstevel@tonic-gate 18737c478bd9Sstevel@tonic-gate#if defined(lint) 18747c478bd9Sstevel@tonic-gate 18757c478bd9Sstevel@tonic-gate/*ARGSUSED*/ 18767c478bd9Sstevel@tonic-gatevoid 18777c478bd9Sstevel@tonic-gatewr_clr_softint(uint_t value) 18787c478bd9Sstevel@tonic-gate{} 18797c478bd9Sstevel@tonic-gate 18807c478bd9Sstevel@tonic-gate#else 18817c478bd9Sstevel@tonic-gate 18827c478bd9Sstevel@tonic-gate ENTRY_NP(wr_clr_softint) 18837c478bd9Sstevel@tonic-gate retl 18847c478bd9Sstevel@tonic-gate wr %o0, CLEAR_SOFTINT 18857c478bd9Sstevel@tonic-gate SET_SIZE(wr_clr_softint) 18867c478bd9Sstevel@tonic-gate 18877c478bd9Sstevel@tonic-gate#endif /* lint */ 18887c478bd9Sstevel@tonic-gate 18897c478bd9Sstevel@tonic-gate#if defined(lint) 18907c478bd9Sstevel@tonic-gate 18917c478bd9Sstevel@tonic-gate/*ARGSUSED*/ 18927c478bd9Sstevel@tonic-gatevoid 1893b0fc0e77Sgovindaintr_enqueue_req(uint_t pil, uint64_t inum) 18947c478bd9Sstevel@tonic-gate{} 18957c478bd9Sstevel@tonic-gate 18967c478bd9Sstevel@tonic-gate#else /* lint */ 18977c478bd9Sstevel@tonic-gate 18987c478bd9Sstevel@tonic-gate/* 18997c478bd9Sstevel@tonic-gate * intr_enqueue_req 19007c478bd9Sstevel@tonic-gate * 19017c478bd9Sstevel@tonic-gate * %o0 - pil 1902b0fc0e77Sgovinda * %o1 - pointer to intr_vec_t (iv) 19037c478bd9Sstevel@tonic-gate * %o5 - preserved 19047c478bd9Sstevel@tonic-gate * %g5 - preserved 19057c478bd9Sstevel@tonic-gate */ 19067c478bd9Sstevel@tonic-gate ENTRY_NP(intr_enqueue_req) 1907b0fc0e77Sgovinda ! 1908b0fc0e77Sgovinda CPU_ADDR(%g4, %g1) ! %g4 = cpu 19097c478bd9Sstevel@tonic-gate 1910b0fc0e77Sgovinda ! 1911b0fc0e77Sgovinda ! Insert intr_vec_t (iv) to appropriate cpu's softint priority list 1912b0fc0e77Sgovinda ! 1913b0fc0e77Sgovinda sll %o0, CPTRSHIFT, %o0 ! %o0 = offset to pil entry 1914b0fc0e77Sgovinda add %g4, INTR_TAIL, %g6 ! %g6 = &cpu->m_cpu.intr_tail 1915b0fc0e77Sgovinda ldn [%o0 + %g6], %g1 ! %g1 = cpu->m_cpu.intr_tail[pil] 1916b0fc0e77Sgovinda ! current tail (ct) 1917b0fc0e77Sgovinda brz,pt %g1, 2f ! branch if current tail is NULL 1918b0fc0e77Sgovinda stn %o1, [%g6 + %o0] ! make intr_vec_t (iv) as new tail 19197c478bd9Sstevel@tonic-gate 1920b0fc0e77Sgovinda ! 1921b0fc0e77Sgovinda ! there's pending intr_vec_t already 1922b0fc0e77Sgovinda ! 1923b0fc0e77Sgovinda lduh [%g1 + IV_FLAGS], %g6 ! %g6 = ct->iv_flags 1924b0fc0e77Sgovinda and %g6, IV_SOFTINT_MT, %g6 ! %g6 = ct->iv_flags & IV_SOFTINT_MT 1925b0fc0e77Sgovinda brz,pt %g6, 1f ! check for Multi target softint flag 1926b0fc0e77Sgovinda add %g1, IV_PIL_NEXT, %g3 ! %g3 = &ct->iv_pil_next 1927b0fc0e77Sgovinda ld [%g4 + CPU_ID], %g6 ! for multi target softint, use cpuid 1928b0fc0e77Sgovinda sll %g6, CPTRSHIFT, %g6 ! calculate offset address from cpuid 1929b0fc0e77Sgovinda add %g3, %g6, %g3 ! %g3 = &ct->iv_xpil_next[cpuid] 1930b0fc0e77Sgovinda1: 1931b0fc0e77Sgovinda ! 1932b0fc0e77Sgovinda ! update old tail 1933b0fc0e77Sgovinda ! 19347c478bd9Sstevel@tonic-gate ba,pt %xcc, 3f 1935b0fc0e77Sgovinda stn %o1, [%g3] ! {%g5] = iv, set pil_next field 19367c478bd9Sstevel@tonic-gate2: 1937b0fc0e77Sgovinda ! 1938b0fc0e77Sgovinda ! no intr_vec_t's queued so make intr_vec_t as new head 1939b0fc0e77Sgovinda ! 1940b0fc0e77Sgovinda add %g4, INTR_HEAD, %g6 ! %g6 = &cpu->m_cpu.intr_head[pil] 1941b0fc0e77Sgovinda stn %o1, [%g6 + %o0] ! cpu->m_cpu.intr_head[pil] = iv 19427c478bd9Sstevel@tonic-gate3: 19437c478bd9Sstevel@tonic-gate retl 19447c478bd9Sstevel@tonic-gate nop 19457c478bd9Sstevel@tonic-gate SET_SIZE(intr_enqueue_req) 19467c478bd9Sstevel@tonic-gate 19477c478bd9Sstevel@tonic-gate#endif /* lint */ 19487c478bd9Sstevel@tonic-gate 19497c478bd9Sstevel@tonic-gate/* 19507c478bd9Sstevel@tonic-gate * Set CPU's base SPL level, based on which interrupt levels are active. 19517c478bd9Sstevel@tonic-gate * Called at spl7 or above. 19527c478bd9Sstevel@tonic-gate */ 19537c478bd9Sstevel@tonic-gate 19547c478bd9Sstevel@tonic-gate#if defined(lint) 19557c478bd9Sstevel@tonic-gate 19567c478bd9Sstevel@tonic-gatevoid 19577c478bd9Sstevel@tonic-gateset_base_spl(void) 19587c478bd9Sstevel@tonic-gate{} 19597c478bd9Sstevel@tonic-gate 19607c478bd9Sstevel@tonic-gate#else /* lint */ 19617c478bd9Sstevel@tonic-gate 19627c478bd9Sstevel@tonic-gate ENTRY_NP(set_base_spl) 19637c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CPU], %o2 ! load CPU pointer 19647c478bd9Sstevel@tonic-gate ld [%o2 + CPU_INTR_ACTV], %o5 ! load active interrupts mask 19657c478bd9Sstevel@tonic-gate 19667c478bd9Sstevel@tonic-gate/* 19677c478bd9Sstevel@tonic-gate * WARNING: non-standard callinq sequence; do not call from C 19687c478bd9Sstevel@tonic-gate * %o2 = pointer to CPU 19697c478bd9Sstevel@tonic-gate * %o5 = updated CPU_INTR_ACTV 19707c478bd9Sstevel@tonic-gate */ 19717c478bd9Sstevel@tonic-gate_intr_set_spl: ! intr_thread_exit enters here 19727c478bd9Sstevel@tonic-gate ! 19737c478bd9Sstevel@tonic-gate ! Determine highest interrupt level active. Several could be blocked 19747c478bd9Sstevel@tonic-gate ! at higher levels than this one, so must convert flags to a PIL 19757c478bd9Sstevel@tonic-gate ! Normally nothing will be blocked, so test this first. 19767c478bd9Sstevel@tonic-gate ! 19777c478bd9Sstevel@tonic-gate brz,pt %o5, 1f ! nothing active 19787c478bd9Sstevel@tonic-gate sra %o5, 11, %o3 ! delay - set %o3 to bits 15-11 19797c478bd9Sstevel@tonic-gate set _intr_flag_table, %o1 19807c478bd9Sstevel@tonic-gate tst %o3 ! see if any of the bits set 19817c478bd9Sstevel@tonic-gate ldub [%o1 + %o3], %o3 ! load bit number 19827c478bd9Sstevel@tonic-gate bnz,a,pn %xcc, 1f ! yes, add 10 and we're done 19837c478bd9Sstevel@tonic-gate add %o3, 11-1, %o3 ! delay - add bit number - 1 19847c478bd9Sstevel@tonic-gate 19857c478bd9Sstevel@tonic-gate sra %o5, 6, %o3 ! test bits 10-6 19867c478bd9Sstevel@tonic-gate tst %o3 19877c478bd9Sstevel@tonic-gate ldub [%o1 + %o3], %o3 19887c478bd9Sstevel@tonic-gate bnz,a,pn %xcc, 1f 19897c478bd9Sstevel@tonic-gate add %o3, 6-1, %o3 19907c478bd9Sstevel@tonic-gate 19917c478bd9Sstevel@tonic-gate sra %o5, 1, %o3 ! test bits 5-1 19927c478bd9Sstevel@tonic-gate ldub [%o1 + %o3], %o3 19937c478bd9Sstevel@tonic-gate 19947c478bd9Sstevel@tonic-gate ! 19957c478bd9Sstevel@tonic-gate ! highest interrupt level number active is in %l6 19967c478bd9Sstevel@tonic-gate ! 19977c478bd9Sstevel@tonic-gate1: 19987c478bd9Sstevel@tonic-gate retl 19997c478bd9Sstevel@tonic-gate st %o3, [%o2 + CPU_BASE_SPL] ! delay - store base priority 20007c478bd9Sstevel@tonic-gate SET_SIZE(set_base_spl) 20017c478bd9Sstevel@tonic-gate 20027c478bd9Sstevel@tonic-gate/* 20037c478bd9Sstevel@tonic-gate * Table that finds the most significant bit set in a five bit field. 20047c478bd9Sstevel@tonic-gate * Each entry is the high-order bit number + 1 of it's index in the table. 20057c478bd9Sstevel@tonic-gate * This read-only data is in the text segment. 20067c478bd9Sstevel@tonic-gate */ 20077c478bd9Sstevel@tonic-gate_intr_flag_table: 20087c478bd9Sstevel@tonic-gate .byte 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4 20097c478bd9Sstevel@tonic-gate .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 20107c478bd9Sstevel@tonic-gate .align 4 20117c478bd9Sstevel@tonic-gate 20127c478bd9Sstevel@tonic-gate#endif /* lint */ 20137c478bd9Sstevel@tonic-gate 20147c478bd9Sstevel@tonic-gate/* 20157c478bd9Sstevel@tonic-gate * int 20167c478bd9Sstevel@tonic-gate * intr_passivate(from, to) 20177c478bd9Sstevel@tonic-gate * kthread_id_t from; interrupt thread 20187c478bd9Sstevel@tonic-gate * kthread_id_t to; interrupted thread 20197c478bd9Sstevel@tonic-gate */ 20207c478bd9Sstevel@tonic-gate 20217c478bd9Sstevel@tonic-gate#if defined(lint) 20227c478bd9Sstevel@tonic-gate 20237c478bd9Sstevel@tonic-gate/* ARGSUSED */ 20247c478bd9Sstevel@tonic-gateint 20257c478bd9Sstevel@tonic-gateintr_passivate(kthread_id_t from, kthread_id_t to) 20267c478bd9Sstevel@tonic-gate{ return (0); } 20277c478bd9Sstevel@tonic-gate 20287c478bd9Sstevel@tonic-gate#else /* lint */ 20297c478bd9Sstevel@tonic-gate 20307c478bd9Sstevel@tonic-gate ENTRY_NP(intr_passivate) 20317c478bd9Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp ! get a new window 20327c478bd9Sstevel@tonic-gate 20337c478bd9Sstevel@tonic-gate flushw ! force register windows to stack 20347c478bd9Sstevel@tonic-gate ! 20357c478bd9Sstevel@tonic-gate ! restore registers from the base of the stack of the interrupt thread. 20367c478bd9Sstevel@tonic-gate ! 20377c478bd9Sstevel@tonic-gate ldn [%i0 + T_STACK], %i2 ! get stack save area pointer 20387c478bd9Sstevel@tonic-gate ldn [%i2 + (0*GREGSIZE)], %l0 ! load locals 20397c478bd9Sstevel@tonic-gate ldn [%i2 + (1*GREGSIZE)], %l1 20407c478bd9Sstevel@tonic-gate ldn [%i2 + (2*GREGSIZE)], %l2 20417c478bd9Sstevel@tonic-gate ldn [%i2 + (3*GREGSIZE)], %l3 20427c478bd9Sstevel@tonic-gate ldn [%i2 + (4*GREGSIZE)], %l4 20437c478bd9Sstevel@tonic-gate ldn [%i2 + (5*GREGSIZE)], %l5 20447c478bd9Sstevel@tonic-gate ldn [%i2 + (6*GREGSIZE)], %l6 20457c478bd9Sstevel@tonic-gate ldn [%i2 + (7*GREGSIZE)], %l7 20467c478bd9Sstevel@tonic-gate ldn [%i2 + (8*GREGSIZE)], %o0 ! put ins from stack in outs 20477c478bd9Sstevel@tonic-gate ldn [%i2 + (9*GREGSIZE)], %o1 20487c478bd9Sstevel@tonic-gate ldn [%i2 + (10*GREGSIZE)], %o2 20497c478bd9Sstevel@tonic-gate ldn [%i2 + (11*GREGSIZE)], %o3 20507c478bd9Sstevel@tonic-gate ldn [%i2 + (12*GREGSIZE)], %o4 20517c478bd9Sstevel@tonic-gate ldn [%i2 + (13*GREGSIZE)], %o5 20527c478bd9Sstevel@tonic-gate ldn [%i2 + (14*GREGSIZE)], %i4 20537c478bd9Sstevel@tonic-gate ! copy stack/pointer without using %sp 20547c478bd9Sstevel@tonic-gate ldn [%i2 + (15*GREGSIZE)], %i5 20557c478bd9Sstevel@tonic-gate ! 20567c478bd9Sstevel@tonic-gate ! put registers into the save area at the top of the interrupted 20577c478bd9Sstevel@tonic-gate ! thread's stack, pointed to by %l7 in the save area just loaded. 20587c478bd9Sstevel@tonic-gate ! 20597c478bd9Sstevel@tonic-gate ldn [%i1 + T_SP], %i3 ! get stack save area pointer 20607c478bd9Sstevel@tonic-gate stn %l0, [%i3 + STACK_BIAS + (0*GREGSIZE)] ! save locals 20617c478bd9Sstevel@tonic-gate stn %l1, [%i3 + STACK_BIAS + (1*GREGSIZE)] 20627c478bd9Sstevel@tonic-gate stn %l2, [%i3 + STACK_BIAS + (2*GREGSIZE)] 20637c478bd9Sstevel@tonic-gate stn %l3, [%i3 + STACK_BIAS + (3*GREGSIZE)] 20647c478bd9Sstevel@tonic-gate stn %l4, [%i3 + STACK_BIAS + (4*GREGSIZE)] 20657c478bd9Sstevel@tonic-gate stn %l5, [%i3 + STACK_BIAS + (5*GREGSIZE)] 20667c478bd9Sstevel@tonic-gate stn %l6, [%i3 + STACK_BIAS + (6*GREGSIZE)] 20677c478bd9Sstevel@tonic-gate stn %l7, [%i3 + STACK_BIAS + (7*GREGSIZE)] 20687c478bd9Sstevel@tonic-gate stn %o0, [%i3 + STACK_BIAS + (8*GREGSIZE)] ! save ins using outs 20697c478bd9Sstevel@tonic-gate stn %o1, [%i3 + STACK_BIAS + (9*GREGSIZE)] 20707c478bd9Sstevel@tonic-gate stn %o2, [%i3 + STACK_BIAS + (10*GREGSIZE)] 20717c478bd9Sstevel@tonic-gate stn %o3, [%i3 + STACK_BIAS + (11*GREGSIZE)] 20727c478bd9Sstevel@tonic-gate stn %o4, [%i3 + STACK_BIAS + (12*GREGSIZE)] 20737c478bd9Sstevel@tonic-gate stn %o5, [%i3 + STACK_BIAS + (13*GREGSIZE)] 20747c478bd9Sstevel@tonic-gate stn %i4, [%i3 + STACK_BIAS + (14*GREGSIZE)] 20757c478bd9Sstevel@tonic-gate ! fp, %i7 copied using %i4 20767c478bd9Sstevel@tonic-gate stn %i5, [%i3 + STACK_BIAS + (15*GREGSIZE)] 20777c478bd9Sstevel@tonic-gate stn %g0, [%i2 + ((8+6)*GREGSIZE)] 20787c478bd9Sstevel@tonic-gate ! clear fp in save area 20797c478bd9Sstevel@tonic-gate 20807c478bd9Sstevel@tonic-gate ! load saved pil for return 20817c478bd9Sstevel@tonic-gate ldub [%i0 + T_PIL], %i0 20827c478bd9Sstevel@tonic-gate ret 20837c478bd9Sstevel@tonic-gate restore 20847c478bd9Sstevel@tonic-gate SET_SIZE(intr_passivate) 20857c478bd9Sstevel@tonic-gate 20867c478bd9Sstevel@tonic-gate#endif /* lint */ 20877c478bd9Sstevel@tonic-gate 20887c478bd9Sstevel@tonic-gate#if defined(lint) 20897c478bd9Sstevel@tonic-gate 20907c478bd9Sstevel@tonic-gate/* 20917c478bd9Sstevel@tonic-gate * intr_get_time() is a resource for interrupt handlers to determine how 20927c478bd9Sstevel@tonic-gate * much time has been spent handling the current interrupt. Such a function 20937c478bd9Sstevel@tonic-gate * is needed because higher level interrupts can arrive during the 20947c478bd9Sstevel@tonic-gate * processing of an interrupt, thus making direct comparisons of %tick by 20957c478bd9Sstevel@tonic-gate * the handler inaccurate. intr_get_time() only returns time spent in the 20967c478bd9Sstevel@tonic-gate * current interrupt handler. 20977c478bd9Sstevel@tonic-gate * 20987c478bd9Sstevel@tonic-gate * The caller must be calling from an interrupt handler running at a pil 20997c478bd9Sstevel@tonic-gate * below or at lock level. Timings are not provided for high-level 21007c478bd9Sstevel@tonic-gate * interrupts. 21017c478bd9Sstevel@tonic-gate * 21027c478bd9Sstevel@tonic-gate * The first time intr_get_time() is called while handling an interrupt, 21037c478bd9Sstevel@tonic-gate * it returns the time since the interrupt handler was invoked. Subsequent 21047c478bd9Sstevel@tonic-gate * calls will return the time since the prior call to intr_get_time(). Time 21057c478bd9Sstevel@tonic-gate * is returned as ticks, adjusted for any clock divisor due to power 21067c478bd9Sstevel@tonic-gate * management. Use tick2ns() to convert ticks to nsec. Warning: ticks may 21077c478bd9Sstevel@tonic-gate * not be the same across CPUs. 21087c478bd9Sstevel@tonic-gate * 21097c478bd9Sstevel@tonic-gate * Theory Of Intrstat[][]: 21107c478bd9Sstevel@tonic-gate * 21117c478bd9Sstevel@tonic-gate * uint64_t intrstat[pil][0..1] is an array indexed by pil level, with two 21127c478bd9Sstevel@tonic-gate * uint64_ts per pil. 21137c478bd9Sstevel@tonic-gate * 21147c478bd9Sstevel@tonic-gate * intrstat[pil][0] is a cumulative count of the number of ticks spent 21157c478bd9Sstevel@tonic-gate * handling all interrupts at the specified pil on this CPU. It is 21167c478bd9Sstevel@tonic-gate * exported via kstats to the user. 21177c478bd9Sstevel@tonic-gate * 21187c478bd9Sstevel@tonic-gate * intrstat[pil][1] is always a count of ticks less than or equal to the 21197c478bd9Sstevel@tonic-gate * value in [0]. The difference between [1] and [0] is the value returned 21207c478bd9Sstevel@tonic-gate * by a call to intr_get_time(). At the start of interrupt processing, 21217c478bd9Sstevel@tonic-gate * [0] and [1] will be equal (or nearly so). As the interrupt consumes 21227c478bd9Sstevel@tonic-gate * time, [0] will increase, but [1] will remain the same. A call to 21237c478bd9Sstevel@tonic-gate * intr_get_time() will return the difference, then update [1] to be the 21247c478bd9Sstevel@tonic-gate * same as [0]. Future calls will return the time since the last call. 21257c478bd9Sstevel@tonic-gate * Finally, when the interrupt completes, [1] is updated to the same as [0]. 21267c478bd9Sstevel@tonic-gate * 21277c478bd9Sstevel@tonic-gate * Implementation: 21287c478bd9Sstevel@tonic-gate * 21297c478bd9Sstevel@tonic-gate * intr_get_time() works much like a higher level interrupt arriving. It 21307c478bd9Sstevel@tonic-gate * "checkpoints" the timing information by incrementing intrstat[pil][0] 21317c478bd9Sstevel@tonic-gate * to include elapsed running time, and by setting t_intr_start to %tick. 21327c478bd9Sstevel@tonic-gate * It then sets the return value to intrstat[pil][0] - intrstat[pil][1], 21337c478bd9Sstevel@tonic-gate * and updates intrstat[pil][1] to be the same as the new value of 21347c478bd9Sstevel@tonic-gate * intrstat[pil][0]. 21357c478bd9Sstevel@tonic-gate * 21367c478bd9Sstevel@tonic-gate * In the normal handling of interrupts, after an interrupt handler returns 21377c478bd9Sstevel@tonic-gate * and the code in intr_thread() updates intrstat[pil][0], it then sets 21387c478bd9Sstevel@tonic-gate * intrstat[pil][1] to the new value of intrstat[pil][0]. When [0] == [1], 21397c478bd9Sstevel@tonic-gate * the timings are reset, i.e. intr_get_time() will return [0] - [1] which 21407c478bd9Sstevel@tonic-gate * is 0. 21417c478bd9Sstevel@tonic-gate * 21427c478bd9Sstevel@tonic-gate * Whenever interrupts arrive on a CPU which is handling a lower pil 21437c478bd9Sstevel@tonic-gate * interrupt, they update the lower pil's [0] to show time spent in the 21447c478bd9Sstevel@tonic-gate * handler that they've interrupted. This results in a growing discrepancy 21457c478bd9Sstevel@tonic-gate * between [0] and [1], which is returned the next time intr_get_time() is 21467c478bd9Sstevel@tonic-gate * called. Time spent in the higher-pil interrupt will not be returned in 21477c478bd9Sstevel@tonic-gate * the next intr_get_time() call from the original interrupt, because 21487c478bd9Sstevel@tonic-gate * the higher-pil interrupt's time is accumulated in intrstat[higherpil][]. 21497c478bd9Sstevel@tonic-gate */ 21507c478bd9Sstevel@tonic-gate 21517c478bd9Sstevel@tonic-gate/*ARGSUSED*/ 21527c478bd9Sstevel@tonic-gateuint64_t 21537c478bd9Sstevel@tonic-gateintr_get_time(void) 21547c478bd9Sstevel@tonic-gate{ return 0; } 21557c478bd9Sstevel@tonic-gate#else /* lint */ 21567c478bd9Sstevel@tonic-gate 21577c478bd9Sstevel@tonic-gate ENTRY_NP(intr_get_time) 21587c478bd9Sstevel@tonic-gate#ifdef DEBUG 21597c478bd9Sstevel@tonic-gate ! 21607c478bd9Sstevel@tonic-gate ! Lots of asserts, but just check panic_quiesce first. 21617c478bd9Sstevel@tonic-gate ! Don't bother with lots of tests if we're just ignoring them. 21627c478bd9Sstevel@tonic-gate ! 21637c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %o0 21647c478bd9Sstevel@tonic-gate ld [%o0 + %lo(panic_quiesce)], %o0 21657c478bd9Sstevel@tonic-gate brnz,pn %o0, 2f 21667c478bd9Sstevel@tonic-gate nop 21677c478bd9Sstevel@tonic-gate ! 21687c478bd9Sstevel@tonic-gate ! ASSERT(%pil <= LOCK_LEVEL) 21697c478bd9Sstevel@tonic-gate ! 21707c478bd9Sstevel@tonic-gate rdpr %pil, %o1 21717c478bd9Sstevel@tonic-gate cmp %o1, LOCK_LEVEL 21727c478bd9Sstevel@tonic-gate ble,pt %xcc, 0f 21737c478bd9Sstevel@tonic-gate sethi %hi(intr_get_time_high_pil), %o0 ! delay 21747c478bd9Sstevel@tonic-gate call panic 21757c478bd9Sstevel@tonic-gate or %o0, %lo(intr_get_time_high_pil), %o0 21767c478bd9Sstevel@tonic-gate0: 21777c478bd9Sstevel@tonic-gate ! 21787c478bd9Sstevel@tonic-gate ! ASSERT((t_flags & T_INTR_THREAD) != 0 && t_pil > 0) 21797c478bd9Sstevel@tonic-gate ! 21807c478bd9Sstevel@tonic-gate lduh [THREAD_REG + T_FLAGS], %o2 21817c478bd9Sstevel@tonic-gate andcc %o2, T_INTR_THREAD, %g0 21827c478bd9Sstevel@tonic-gate bz,pn %xcc, 1f 21837c478bd9Sstevel@tonic-gate ldub [THREAD_REG + T_PIL], %o1 ! delay 21847c478bd9Sstevel@tonic-gate brnz,pt %o1, 0f 21857c478bd9Sstevel@tonic-gate1: 21867c478bd9Sstevel@tonic-gate sethi %hi(intr_get_time_not_intr), %o0 21877c478bd9Sstevel@tonic-gate call panic 21887c478bd9Sstevel@tonic-gate or %o0, %lo(intr_get_time_not_intr), %o0 21897c478bd9Sstevel@tonic-gate0: 21907c478bd9Sstevel@tonic-gate ! 21917c478bd9Sstevel@tonic-gate ! ASSERT(t_intr_start != 0) 21927c478bd9Sstevel@tonic-gate ! 21937c478bd9Sstevel@tonic-gate ldx [THREAD_REG + T_INTR_START], %o1 21947c478bd9Sstevel@tonic-gate brnz,pt %o1, 2f 21957c478bd9Sstevel@tonic-gate sethi %hi(intr_get_time_no_start_time), %o0 ! delay 21967c478bd9Sstevel@tonic-gate call panic 21977c478bd9Sstevel@tonic-gate or %o0, %lo(intr_get_time_no_start_time), %o0 21987c478bd9Sstevel@tonic-gate2: 21997c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 22007c478bd9Sstevel@tonic-gate ! 22017c478bd9Sstevel@tonic-gate ! %o0 = elapsed time and return value 22027c478bd9Sstevel@tonic-gate ! %o1 = pil 22037c478bd9Sstevel@tonic-gate ! %o2 = scratch 22047c478bd9Sstevel@tonic-gate ! %o3 = scratch 22057c478bd9Sstevel@tonic-gate ! %o4 = scratch 22067c478bd9Sstevel@tonic-gate ! %o5 = cpu 22077c478bd9Sstevel@tonic-gate ! 22087c478bd9Sstevel@tonic-gate wrpr %g0, PIL_MAX, %pil ! make this easy -- block normal intrs 22097c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CPU], %o5 22107c478bd9Sstevel@tonic-gate ldub [THREAD_REG + T_PIL], %o1 22117c478bd9Sstevel@tonic-gate ldx [THREAD_REG + T_INTR_START], %o3 ! %o3 = t_intr_start 22127c478bd9Sstevel@tonic-gate ! 22137c478bd9Sstevel@tonic-gate ! Calculate elapsed time since t_intr_start. Update t_intr_start, 22147c478bd9Sstevel@tonic-gate ! get delta, and multiply by cpu_divisor if necessary. 22157c478bd9Sstevel@tonic-gate ! 22167c478bd9Sstevel@tonic-gate rdpr %tick, %o2 22177c478bd9Sstevel@tonic-gate sllx %o2, 1, %o2 22187c478bd9Sstevel@tonic-gate srlx %o2, 1, %o2 22197c478bd9Sstevel@tonic-gate stx %o2, [THREAD_REG + T_INTR_START] 22207c478bd9Sstevel@tonic-gate sub %o2, %o3, %o0 22217c478bd9Sstevel@tonic-gate 22227c478bd9Sstevel@tonic-gate lduh [%o5 + CPU_DIVISOR], %o4 22237c478bd9Sstevel@tonic-gate cmp %o4, 1 22247c478bd9Sstevel@tonic-gate bg,a,pn %xcc, 1f 22257c478bd9Sstevel@tonic-gate mulx %o0, %o4, %o0 ! multiply interval by clock divisor iff > 1 22267c478bd9Sstevel@tonic-gate1: 2227eda89462Sesolom ! Update intracct[] 2228eda89462Sesolom lduh [%o5 + CPU_MSTATE], %o4 2229eda89462Sesolom sllx %o4, 3, %o4 2230eda89462Sesolom add %o4, CPU_INTRACCT, %o4 2231eda89462Sesolom ldx [%o5 + %o4], %o2 2232eda89462Sesolom add %o2, %o0, %o2 2233eda89462Sesolom stx %o2, [%o5 + %o4] 2234eda89462Sesolom 22357c478bd9Sstevel@tonic-gate ! 22367c478bd9Sstevel@tonic-gate ! Increment cpu_m.intrstat[pil][0]. Calculate elapsed time since 22377c478bd9Sstevel@tonic-gate ! cpu_m.intrstat[pil][1], which is either when the interrupt was 22387c478bd9Sstevel@tonic-gate ! first entered, or the last time intr_get_time() was invoked. Then 22397c478bd9Sstevel@tonic-gate ! update cpu_m.intrstat[pil][1] to match [0]. 22407c478bd9Sstevel@tonic-gate ! 22417c478bd9Sstevel@tonic-gate sllx %o1, 4, %o3 22427c478bd9Sstevel@tonic-gate add %o3, CPU_MCPU, %o3 22437c478bd9Sstevel@tonic-gate add %o3, MCPU_INTRSTAT, %o3 22447c478bd9Sstevel@tonic-gate add %o3, %o5, %o3 ! %o3 = cpu_m.intrstat[pil][0] 22457c478bd9Sstevel@tonic-gate ldx [%o3], %o2 22467c478bd9Sstevel@tonic-gate add %o2, %o0, %o2 ! %o2 = new value for intrstat 22477c478bd9Sstevel@tonic-gate stx %o2, [%o3] 22487c478bd9Sstevel@tonic-gate ldx [%o3 + 8], %o4 ! %o4 = cpu_m.intrstat[pil][1] 22497c478bd9Sstevel@tonic-gate sub %o2, %o4, %o0 ! %o0 is elapsed time since %o4 22507c478bd9Sstevel@tonic-gate stx %o2, [%o3 + 8] ! make [1] match [0], resetting time 22517c478bd9Sstevel@tonic-gate 22527c478bd9Sstevel@tonic-gate ld [%o5 + CPU_BASE_SPL], %o2 ! restore %pil to the greater 22537c478bd9Sstevel@tonic-gate cmp %o2, %o1 ! of either our pil %o1 or 22547c478bd9Sstevel@tonic-gate movl %xcc, %o1, %o2 ! cpu_base_spl. 22557c478bd9Sstevel@tonic-gate retl 22567c478bd9Sstevel@tonic-gate wrpr %g0, %o2, %pil 22577c478bd9Sstevel@tonic-gate SET_SIZE(intr_get_time) 22587c478bd9Sstevel@tonic-gate 22597c478bd9Sstevel@tonic-gate#ifdef DEBUG 22607c478bd9Sstevel@tonic-gateintr_get_time_high_pil: 22617c478bd9Sstevel@tonic-gate .asciz "intr_get_time(): %pil > LOCK_LEVEL" 22627c478bd9Sstevel@tonic-gateintr_get_time_not_intr: 22637c478bd9Sstevel@tonic-gate .asciz "intr_get_time(): not called from an interrupt thread" 22647c478bd9Sstevel@tonic-gateintr_get_time_no_start_time: 22657c478bd9Sstevel@tonic-gate .asciz "intr_get_time(): t_intr_start == 0" 22667c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 22677c478bd9Sstevel@tonic-gate#endif /* lint */ 2268