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/* 22*023e71deSHaik Aftandilian * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate#if defined(lint) 277c478bd9Sstevel@tonic-gate#include <sys/types.h> 287c478bd9Sstevel@tonic-gate#include <sys/thread.h> 297c478bd9Sstevel@tonic-gate#else /* lint */ 307c478bd9Sstevel@tonic-gate#include "assym.h" 317c478bd9Sstevel@tonic-gate#endif /* lint */ 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate#include <sys/cmn_err.h> 347c478bd9Sstevel@tonic-gate#include <sys/ftrace.h> 357c478bd9Sstevel@tonic-gate#include <sys/asm_linkage.h> 367c478bd9Sstevel@tonic-gate#include <sys/machthread.h> 377c478bd9Sstevel@tonic-gate#include <sys/machcpuvar.h> 387c478bd9Sstevel@tonic-gate#include <sys/intreg.h> 39b0fc0e77Sgovinda#include <sys/ivintr.h> 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE 427c478bd9Sstevel@tonic-gate#include <sys/traptrace.h> 437c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */ 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate#if defined(lint) 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate/* ARGSUSED */ 487c478bd9Sstevel@tonic-gatevoid 497c478bd9Sstevel@tonic-gatepil_interrupt(int level) 507c478bd9Sstevel@tonic-gate{} 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate#else /* lint */ 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate/* 567c478bd9Sstevel@tonic-gate * (TT 0x40..0x4F, TL>0) Interrupt Level N Handler (N == 1..15) 577c478bd9Sstevel@tonic-gate * Register passed from LEVEL_INTERRUPT(level) 587c478bd9Sstevel@tonic-gate * %g4 - interrupt request level 597c478bd9Sstevel@tonic-gate */ 607c478bd9Sstevel@tonic-gate ENTRY_NP(pil_interrupt) 617c478bd9Sstevel@tonic-gate ! 627c478bd9Sstevel@tonic-gate ! Register usage 637c478bd9Sstevel@tonic-gate ! %g1 - cpu 64b0fc0e77Sgovinda ! %g2 - pointer to intr_vec_t (iv) 657c478bd9Sstevel@tonic-gate ! %g4 - pil 66b0fc0e77Sgovinda ! %g3, %g5, %g6, %g7 - temps 677c478bd9Sstevel@tonic-gate ! 68b0fc0e77Sgovinda ! Grab the first or list head intr_vec_t off the intr_head[pil] 69b0fc0e77Sgovinda ! and panic immediately if list head is NULL. Otherwise, update 70b0fc0e77Sgovinda ! intr_head[pil] to next intr_vec_t on the list and clear softint 71b0fc0e77Sgovinda ! %clear_softint, if next intr_vec_t is NULL. 727c478bd9Sstevel@tonic-gate ! 73b0fc0e77Sgovinda CPU_ADDR(%g1, %g5) ! %g1 = cpu 747c478bd9Sstevel@tonic-gate ! 757c478bd9Sstevel@tonic-gate ALTENTRY(pil_interrupt_common) 76b0fc0e77Sgovinda sll %g4, CPTRSHIFT, %g5 ! %g5 = offset to the pil entry 77b0fc0e77Sgovinda add %g1, INTR_HEAD, %g6 ! %g6 = &cpu->m_cpu.intr_head 78b0fc0e77Sgovinda add %g6, %g5, %g6 ! %g6 = &cpu->m_cpu.intr_head[pil] 79b0fc0e77Sgovinda ldn [%g6], %g2 ! %g2 = cpu->m_cpu.intr_head[pil] 80b0fc0e77Sgovinda brnz,pt %g2, 0f ! check list head (iv) is NULL 817c478bd9Sstevel@tonic-gate nop 82b0fc0e77Sgovinda ba ptl1_panic ! panic, list head (iv) is NULL 83b0fc0e77Sgovinda mov PTL1_BAD_INTR_VEC, %g1 84b0fc0e77Sgovinda0: 85b0fc0e77Sgovinda lduh [%g2 + IV_FLAGS], %g7 ! %g7 = iv->iv_flags 86b0fc0e77Sgovinda and %g7, IV_SOFTINT_MT, %g3 ! %g3 = iv->iv_flags & IV_SOFTINT_MT 87b0fc0e77Sgovinda brz,pt %g3, 1f ! check for multi target softint 88b0fc0e77Sgovinda add %g2, IV_PIL_NEXT, %g7 ! g7% = &iv->iv_pil_next 89b0fc0e77Sgovinda ld [%g1 + CPU_ID], %g3 ! for multi target softint, use cpuid 90b0fc0e77Sgovinda sll %g3, CPTRSHIFT, %g3 ! convert cpuid to offset address 91b0fc0e77Sgovinda add %g7, %g3, %g7 ! %g5 = &iv->iv_xpil_next[cpuid] 927c478bd9Sstevel@tonic-gate1: 93b0fc0e77Sgovinda ldn [%g7], %g3 ! %g3 = next intr_vec_t 94b0fc0e77Sgovinda brnz,pn %g3, 2f ! branch if next intr_vec_t non NULL 95b0fc0e77Sgovinda stn %g3, [%g6] ! update cpu->m_cpu.intr_head[pil] 96b0fc0e77Sgovinda add %g1, INTR_TAIL, %g6 ! %g6 = &cpu->m_cpu.intr_tail 97b0fc0e77Sgovinda stn %g0, [%g5 + %g6] ! clear cpu->m_cpu.intr_tail[pil] 98b0fc0e77Sgovinda mov 1, %g5 ! %g5 = 1 99b0fc0e77Sgovinda sll %g5, %g4, %g5 ! %g5 = 1 << pil 100b0fc0e77Sgovinda wr %g5, CLEAR_SOFTINT ! clear interrupt on this pil 101b0fc0e77Sgovinda2: 1027c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE 1037c478bd9Sstevel@tonic-gate TRACE_PTR(%g5, %g6) 1047c478bd9Sstevel@tonic-gate TRACE_SAVE_TL_GL_REGS(%g5, %g6) 1057c478bd9Sstevel@tonic-gate rdpr %tt, %g6 106b0fc0e77Sgovinda stha %g6, [%g5 + TRAP_ENT_TT]%asi ! trap_type = %tt 1077c478bd9Sstevel@tonic-gate rdpr %tpc, %g6 108b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_TPC]%asi ! trap_pc = %tpc 1097c478bd9Sstevel@tonic-gate rdpr %tstate, %g6 110b0fc0e77Sgovinda stxa %g6, [%g5 + TRAP_ENT_TSTATE]%asi ! trap_tstate = %tstate 111b0fc0e77Sgovinda stna %sp, [%g5 + TRAP_ENT_SP]%asi ! trap_sp = %sp 112b0fc0e77Sgovinda stna %g2, [%g5 + TRAP_ENT_TR]%asi ! trap_tr = first intr_vec 113b0fc0e77Sgovinda stna %g3, [%g5 + TRAP_ENT_F1]%asi ! trap_f1 = next intr_vec 114*023e71deSHaik Aftandilian GET_TRACE_TICK(%g6, %g3) 115*023e71deSHaik Aftandilian stxa %g6, [%g5 + TRAP_ENT_TICK]%asi ! trap_tick = %tick 1167c478bd9Sstevel@tonic-gate sll %g4, CPTRSHIFT, %g3 1177c478bd9Sstevel@tonic-gate add %g1, INTR_HEAD, %g6 118b0fc0e77Sgovinda ldn [%g6 + %g3], %g6 ! %g6=cpu->m_cpu.intr_head[pil] 119b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_F2]%asi ! trap_f2 = intr_head[pil] 1207c478bd9Sstevel@tonic-gate add %g1, INTR_TAIL, %g6 121b0fc0e77Sgovinda ldn [%g6 + %g3], %g6 ! %g6=cpu->m_cpu.intr_tail[pil] 122b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_F3]%asi ! trap_f3 = intr_tail[pil] 123b0fc0e77Sgovinda stna %g4, [%g5 + TRAP_ENT_F4]%asi ! trap_f4 = pil 1247c478bd9Sstevel@tonic-gate TRACE_NEXT(%g5, %g6, %g3) 1257c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */ 1267c478bd9Sstevel@tonic-gate ! 127b0fc0e77Sgovinda ! clear the iv_pending flag for this interrupt request 1287c478bd9Sstevel@tonic-gate ! 129b0fc0e77Sgovinda lduh [%g2 + IV_FLAGS], %g3 ! %g3 = iv->iv_flags 130b0fc0e77Sgovinda andn %g3, IV_SOFTINT_PEND, %g3 ! %g3 = !(iv->iv_flags & PEND) 131b0fc0e77Sgovinda sth %g3, [%g2 + IV_FLAGS] ! clear IV_SOFTINT_PEND flag 132b0fc0e77Sgovinda stn %g0, [%g7] ! clear iv->iv_pil_next or 133b0fc0e77Sgovinda ! iv->iv_pil_xnext 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate ! 1367c478bd9Sstevel@tonic-gate ! Prepare for sys_trap() 1377c478bd9Sstevel@tonic-gate ! 1387c478bd9Sstevel@tonic-gate ! Registers passed to sys_trap() 1397c478bd9Sstevel@tonic-gate ! %g1 - interrupt handler at TL==0 140b0fc0e77Sgovinda ! %g2 - pointer to current intr_vec_t (iv), 141b0fc0e77Sgovinda ! job queue for intr_thread or current_thread 1427c478bd9Sstevel@tonic-gate ! %g3 - pil 1437c478bd9Sstevel@tonic-gate ! %g4 - initial pil for handler 1447c478bd9Sstevel@tonic-gate ! 1457c478bd9Sstevel@tonic-gate ! figure which handler to run and which %pil it starts at 1467c478bd9Sstevel@tonic-gate ! intr_thread starts at DISP_LEVEL to prevent preemption 1477c478bd9Sstevel@tonic-gate ! current_thread starts at PIL_MAX to protect cpu_intr_actv 1487c478bd9Sstevel@tonic-gate ! 149b0fc0e77Sgovinda mov %g4, %g3 ! %g3 = %g4, pil 1507c478bd9Sstevel@tonic-gate cmp %g4, LOCK_LEVEL 151b0fc0e77Sgovinda bg,a,pt %xcc, 3f ! branch if pil > LOCK_LEVEL 152b0fc0e77Sgovinda mov PIL_MAX, %g4 ! %g4 = PIL_MAX (15) 153b0fc0e77Sgovinda sethi %hi(intr_thread), %g1 ! %g1 = intr_thread 154b0fc0e77Sgovinda mov DISP_LEVEL, %g4 ! %g4 = DISP_LEVEL (11) 1557c478bd9Sstevel@tonic-gate ba,pt %xcc, sys_trap 1567c478bd9Sstevel@tonic-gate or %g1, %lo(intr_thread), %g1 157b0fc0e77Sgovinda3: 158b0fc0e77Sgovinda sethi %hi(current_thread), %g1 ! %g1 = current_thread 1597c478bd9Sstevel@tonic-gate ba,pt %xcc, sys_trap 1607c478bd9Sstevel@tonic-gate or %g1, %lo(current_thread), %g1 1617c478bd9Sstevel@tonic-gate SET_SIZE(pil_interrupt_common) 1627c478bd9Sstevel@tonic-gate SET_SIZE(pil_interrupt) 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate#endif /* lint */ 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate#ifndef lint 1687c478bd9Sstevel@tonic-gate_spurious: 1697c478bd9Sstevel@tonic-gate .asciz "!interrupt 0x%x at level %d not serviced" 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate/* 1727c478bd9Sstevel@tonic-gate * SERVE_INTR_PRE is called once, just before the first invocation 1737c478bd9Sstevel@tonic-gate * of SERVE_INTR. 1747c478bd9Sstevel@tonic-gate * 1757c478bd9Sstevel@tonic-gate * Registers on entry: 1767c478bd9Sstevel@tonic-gate * 177b0fc0e77Sgovinda * iv_p, cpu, regs: may be out-registers 1787c478bd9Sstevel@tonic-gate * ls1, ls2: local scratch registers 1797c478bd9Sstevel@tonic-gate * os1, os2, os3: scratch registers, may be out 1807c478bd9Sstevel@tonic-gate */ 1817c478bd9Sstevel@tonic-gate 182b0fc0e77Sgovinda#define SERVE_INTR_PRE(iv_p, cpu, ls1, ls2, os1, os2, os3, regs) \ 183b0fc0e77Sgovinda mov iv_p, ls1; \ 184b0fc0e77Sgovinda mov iv_p, ls2; \ 185b0fc0e77Sgovinda SERVE_INTR_TRACE(iv_p, os1, os2, os3, regs); 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate/* 1887c478bd9Sstevel@tonic-gate * SERVE_INTR is called immediately after either SERVE_INTR_PRE or 1897c478bd9Sstevel@tonic-gate * SERVE_INTR_NEXT, without intervening code. No register values 1907c478bd9Sstevel@tonic-gate * may be modified. 1917c478bd9Sstevel@tonic-gate * 1927c478bd9Sstevel@tonic-gate * After calling SERVE_INTR, the caller must check if os3 is set. If 1937c478bd9Sstevel@tonic-gate * so, there is another interrupt to process. The caller must call 1947c478bd9Sstevel@tonic-gate * SERVE_INTR_NEXT, immediately followed by SERVE_INTR. 1957c478bd9Sstevel@tonic-gate * 1967c478bd9Sstevel@tonic-gate * Before calling SERVE_INTR_NEXT, the caller may perform accounting 1977c478bd9Sstevel@tonic-gate * and other actions which need to occur after invocation of an interrupt 1987c478bd9Sstevel@tonic-gate * handler. However, the values of ls1 and os3 *must* be preserved and 1997c478bd9Sstevel@tonic-gate * passed unmodified into SERVE_INTR_NEXT. 2007c478bd9Sstevel@tonic-gate * 2017c478bd9Sstevel@tonic-gate * Registers on return from SERVE_INTR: 2027c478bd9Sstevel@tonic-gate * 2037c478bd9Sstevel@tonic-gate * ls1 - the pil just processed 204b0fc0e77Sgovinda * ls2 - the pointer to intr_vec_t (iv) just processed 2057c478bd9Sstevel@tonic-gate * os3 - if set, another interrupt needs to be processed 2067c478bd9Sstevel@tonic-gate * cpu, ls1, os3 - must be preserved if os3 is set 2077c478bd9Sstevel@tonic-gate */ 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate#define SERVE_INTR(os5, cpu, ls1, ls2, os1, os2, os3, os4) \ 2107c478bd9Sstevel@tonic-gate ldn [ls1 + IV_HANDLER], os2; \ 211b0fc0e77Sgovinda ldn [ls1 + IV_ARG1], %o0; \ 212b0fc0e77Sgovinda ldn [ls1 + IV_ARG2], %o1; \ 2137c478bd9Sstevel@tonic-gate call os2; \ 2147c478bd9Sstevel@tonic-gate lduh [ls1 + IV_PIL], ls1; \ 2157c478bd9Sstevel@tonic-gate brnz,pt %o0, 2f; \ 2167c478bd9Sstevel@tonic-gate mov CE_WARN, %o0; \ 2177c478bd9Sstevel@tonic-gate set _spurious, %o1; \ 2187c478bd9Sstevel@tonic-gate mov ls2, %o2; \ 2197c478bd9Sstevel@tonic-gate call cmn_err; \ 2207c478bd9Sstevel@tonic-gate rdpr %pil, %o3; \ 2217c478bd9Sstevel@tonic-gate2: ldn [THREAD_REG + T_CPU], cpu; \ 2227c478bd9Sstevel@tonic-gate sll ls1, 3, os1; \ 2237c478bd9Sstevel@tonic-gate add os1, CPU_STATS_SYS_INTR - 8, os2; \ 2247c478bd9Sstevel@tonic-gate ldx [cpu + os2], os3; \ 2257c478bd9Sstevel@tonic-gate inc os3; \ 2267c478bd9Sstevel@tonic-gate stx os3, [cpu + os2]; \ 2277c478bd9Sstevel@tonic-gate sll ls1, CPTRSHIFT, os2; \ 2287c478bd9Sstevel@tonic-gate add cpu, INTR_HEAD, os1; \ 2297c478bd9Sstevel@tonic-gate add os1, os2, os1; \ 2307c478bd9Sstevel@tonic-gate ldn [os1], os3; 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate/* 2337c478bd9Sstevel@tonic-gate * Registers on entry: 2347c478bd9Sstevel@tonic-gate * 2357c478bd9Sstevel@tonic-gate * cpu - cpu pointer (clobbered, set to cpu upon completion) 2367c478bd9Sstevel@tonic-gate * ls1, os3 - preserved from prior call to SERVE_INTR 2377c478bd9Sstevel@tonic-gate * ls2 - local scratch reg (not preserved) 2387c478bd9Sstevel@tonic-gate * os1, os2, os4, os5 - scratch reg, can be out (not preserved) 2397c478bd9Sstevel@tonic-gate */ 2407c478bd9Sstevel@tonic-gate#define SERVE_INTR_NEXT(os5, cpu, ls1, ls2, os1, os2, os3, os4) \ 2417c478bd9Sstevel@tonic-gate sll ls1, CPTRSHIFT, os4; \ 2427c478bd9Sstevel@tonic-gate add cpu, INTR_HEAD, os1; \ 2437c478bd9Sstevel@tonic-gate rdpr %pstate, ls2; \ 2447c478bd9Sstevel@tonic-gate wrpr ls2, PSTATE_IE, %pstate; \ 245b0fc0e77Sgovinda lduh [os3 + IV_FLAGS], os2; \ 246b0fc0e77Sgovinda and os2, IV_SOFTINT_MT, os2; \ 247b0fc0e77Sgovinda brz,pt os2, 4f; \ 248b0fc0e77Sgovinda add os3, IV_PIL_NEXT, os2; \ 249b0fc0e77Sgovinda ld [cpu + CPU_ID], os5; \ 250b0fc0e77Sgovinda sll os5, CPTRSHIFT, os5; \ 251b0fc0e77Sgovinda add os2, os5, os2; \ 252b0fc0e77Sgovinda4: ldn [os2], os5; \ 253b0fc0e77Sgovinda brnz,pn os5, 5f; \ 254b0fc0e77Sgovinda stn os5, [os1 + os4]; \ 2557c478bd9Sstevel@tonic-gate add cpu, INTR_TAIL, os1; \ 2567c478bd9Sstevel@tonic-gate stn %g0, [os1 + os4]; \ 2577c478bd9Sstevel@tonic-gate mov 1, os1; \ 2587c478bd9Sstevel@tonic-gate sll os1, ls1, os1; \ 2597c478bd9Sstevel@tonic-gate wr os1, CLEAR_SOFTINT; \ 260b0fc0e77Sgovinda5: lduh [os3 + IV_FLAGS], ls1; \ 261b0fc0e77Sgovinda andn ls1, IV_SOFTINT_PEND, ls1; \ 262b0fc0e77Sgovinda sth ls1, [os3 + IV_FLAGS]; \ 263b0fc0e77Sgovinda stn %g0, [os2]; \ 2647c478bd9Sstevel@tonic-gate wrpr %g0, ls2, %pstate; \ 265b0fc0e77Sgovinda mov os3, ls1; \ 266b0fc0e77Sgovinda mov os3, ls2; \ 267b0fc0e77Sgovinda SERVE_INTR_TRACE2(os5, os1, os2, os3, os4); 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE 2707c478bd9Sstevel@tonic-gate/* 2717c478bd9Sstevel@tonic-gate * inum - not modified, _spurious depends on it. 2727c478bd9Sstevel@tonic-gate */ 2737c478bd9Sstevel@tonic-gate#define SERVE_INTR_TRACE(inum, os1, os2, os3, os4) \ 2747c478bd9Sstevel@tonic-gate rdpr %pstate, os3; \ 2757c478bd9Sstevel@tonic-gate andn os3, PSTATE_IE | PSTATE_AM, os2; \ 2767c478bd9Sstevel@tonic-gate wrpr %g0, os2, %pstate; \ 2777c478bd9Sstevel@tonic-gate TRACE_PTR(os1, os2); \ 2787c478bd9Sstevel@tonic-gate ldn [os4 + PC_OFF], os2; \ 2797c478bd9Sstevel@tonic-gate stna os2, [os1 + TRAP_ENT_TPC]%asi; \ 2807c478bd9Sstevel@tonic-gate ldx [os4 + TSTATE_OFF], os2; \ 2817c478bd9Sstevel@tonic-gate stxa os2, [os1 + TRAP_ENT_TSTATE]%asi; \ 2827c478bd9Sstevel@tonic-gate mov os3, os4; \ 283*023e71deSHaik Aftandilian GET_TRACE_TICK(os2, os3); \ 2847c478bd9Sstevel@tonic-gate stxa os2, [os1 + TRAP_ENT_TICK]%asi; \ 2857c478bd9Sstevel@tonic-gate TRACE_SAVE_TL_GL_REGS(os1, os2); \ 2867c478bd9Sstevel@tonic-gate set TT_SERVE_INTR, os2; \ 2877c478bd9Sstevel@tonic-gate rdpr %pil, os3; \ 2887c478bd9Sstevel@tonic-gate or os2, os3, os2; \ 2897c478bd9Sstevel@tonic-gate stha os2, [os1 + TRAP_ENT_TT]%asi; \ 2907c478bd9Sstevel@tonic-gate stna %sp, [os1 + TRAP_ENT_SP]%asi; \ 2917c478bd9Sstevel@tonic-gate stna inum, [os1 + TRAP_ENT_TR]%asi; \ 2927c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_F1]%asi; \ 2937c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_F2]%asi; \ 2947c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_F3]%asi; \ 2957c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_F4]%asi; \ 2967c478bd9Sstevel@tonic-gate TRACE_NEXT(os1, os2, os3); \ 2977c478bd9Sstevel@tonic-gate wrpr %g0, os4, %pstate 2987c478bd9Sstevel@tonic-gate#else /* TRAPTRACE */ 2997c478bd9Sstevel@tonic-gate#define SERVE_INTR_TRACE(inum, os1, os2, os3, os4) 3007c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */ 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE 3037c478bd9Sstevel@tonic-gate/* 3047c478bd9Sstevel@tonic-gate * inum - not modified, _spurious depends on it. 3057c478bd9Sstevel@tonic-gate */ 3067c478bd9Sstevel@tonic-gate#define SERVE_INTR_TRACE2(inum, os1, os2, os3, os4) \ 3077c478bd9Sstevel@tonic-gate rdpr %pstate, os3; \ 3087c478bd9Sstevel@tonic-gate andn os3, PSTATE_IE | PSTATE_AM, os2; \ 3097c478bd9Sstevel@tonic-gate wrpr %g0, os2, %pstate; \ 3107c478bd9Sstevel@tonic-gate TRACE_PTR(os1, os2); \ 3117c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_TPC]%asi; \ 3127c478bd9Sstevel@tonic-gate stxa %g0, [os1 + TRAP_ENT_TSTATE]%asi; \ 3137c478bd9Sstevel@tonic-gate mov os3, os4; \ 314*023e71deSHaik Aftandilian GET_TRACE_TICK(os2, os3); \ 3157c478bd9Sstevel@tonic-gate stxa os2, [os1 + TRAP_ENT_TICK]%asi; \ 3167c478bd9Sstevel@tonic-gate TRACE_SAVE_TL_GL_REGS(os1, os2); \ 3177c478bd9Sstevel@tonic-gate set TT_SERVE_INTR, os2; \ 3187c478bd9Sstevel@tonic-gate rdpr %pil, os3; \ 3197c478bd9Sstevel@tonic-gate or os2, os3, os2; \ 3207c478bd9Sstevel@tonic-gate stha os2, [os1 + TRAP_ENT_TT]%asi; \ 3217c478bd9Sstevel@tonic-gate stna %sp, [os1 + TRAP_ENT_SP]%asi; \ 3227c478bd9Sstevel@tonic-gate stna inum, [os1 + TRAP_ENT_TR]%asi; \ 3237c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_F1]%asi; \ 3247c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_F2]%asi; \ 3257c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_F3]%asi; \ 3267c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_F4]%asi; \ 3277c478bd9Sstevel@tonic-gate TRACE_NEXT(os1, os2, os3); \ 3287c478bd9Sstevel@tonic-gate wrpr %g0, os4, %pstate 3297c478bd9Sstevel@tonic-gate#else /* TRAPTRACE */ 3307c478bd9Sstevel@tonic-gate#define SERVE_INTR_TRACE2(inum, os1, os2, os3, os4) 3317c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */ 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate#endif /* lint */ 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate#if defined(lint) 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate/*ARGSUSED*/ 3387c478bd9Sstevel@tonic-gatevoid 339b0fc0e77Sgovindaintr_thread(struct regs *regs, uint64_t iv_p, uint_t pil) 3407c478bd9Sstevel@tonic-gate{} 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate#else /* lint */ 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate#define INTRCNT_LIMIT 16 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate/* 3477c478bd9Sstevel@tonic-gate * Handle an interrupt in a new thread. 3487c478bd9Sstevel@tonic-gate * Entry: 3497c478bd9Sstevel@tonic-gate * %o0 = pointer to regs structure 350b0fc0e77Sgovinda * %o1 = pointer to current intr_vec_t (iv) to be processed 3517c478bd9Sstevel@tonic-gate * %o2 = pil 3527c478bd9Sstevel@tonic-gate * %sp = on current thread's kernel stack 3537c478bd9Sstevel@tonic-gate * %o7 = return linkage to trap code 3547c478bd9Sstevel@tonic-gate * %g7 = current thread 3557c478bd9Sstevel@tonic-gate * %pstate = normal globals, interrupts enabled, 3567c478bd9Sstevel@tonic-gate * privileged, fp disabled 3577c478bd9Sstevel@tonic-gate * %pil = DISP_LEVEL 3587c478bd9Sstevel@tonic-gate * 3597c478bd9Sstevel@tonic-gate * Register Usage 3607c478bd9Sstevel@tonic-gate * %l0 = return linkage 3617c478bd9Sstevel@tonic-gate * %l1 = pil 3627c478bd9Sstevel@tonic-gate * %l2 - %l3 = scratch 3637c478bd9Sstevel@tonic-gate * %l4 - %l7 = reserved for sys_trap 3647c478bd9Sstevel@tonic-gate * %o2 = cpu 3657c478bd9Sstevel@tonic-gate * %o3 = intr thread 3667c478bd9Sstevel@tonic-gate * %o0 = scratch 3677c478bd9Sstevel@tonic-gate * %o4 - %o5 = scratch 3687c478bd9Sstevel@tonic-gate */ 3697c478bd9Sstevel@tonic-gate ENTRY_NP(intr_thread) 3707c478bd9Sstevel@tonic-gate mov %o7, %l0 3717c478bd9Sstevel@tonic-gate mov %o2, %l1 3727c478bd9Sstevel@tonic-gate ! 3737c478bd9Sstevel@tonic-gate ! See if we are interrupting another interrupt thread. 3747c478bd9Sstevel@tonic-gate ! 3757c478bd9Sstevel@tonic-gate lduh [THREAD_REG + T_FLAGS], %o3 3767c478bd9Sstevel@tonic-gate andcc %o3, T_INTR_THREAD, %g0 3777c478bd9Sstevel@tonic-gate bz,pt %xcc, 1f 3787c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CPU], %o2 ! delay - load CPU pointer 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate ! We have interrupted an interrupt thread. Take a timestamp, 3817c478bd9Sstevel@tonic-gate ! compute its interval, and update its cumulative counter. 3827c478bd9Sstevel@tonic-gate add THREAD_REG, T_INTR_START, %o5 3837c478bd9Sstevel@tonic-gate0: 3847c478bd9Sstevel@tonic-gate ldx [%o5], %o3 3857c478bd9Sstevel@tonic-gate brz,pn %o3, 1f 3867c478bd9Sstevel@tonic-gate ! We came in on top of an interrupt thread that had no timestamp. 3877c478bd9Sstevel@tonic-gate ! This could happen if, for instance, an interrupt thread which had 3887c478bd9Sstevel@tonic-gate ! previously blocked is being set up to run again in resume(), but 3897c478bd9Sstevel@tonic-gate ! resume() hasn't yet stored a timestamp for it. Or, it could be in 3907c478bd9Sstevel@tonic-gate ! swtch() after its slice has been accounted for. 3917c478bd9Sstevel@tonic-gate ! Only account for the time slice if the starting timestamp is non-zero. 392*023e71deSHaik Aftandilian RD_TICK(%o4,%l2,%l3,__LINE__) 3937c478bd9Sstevel@tonic-gate sub %o4, %o3, %o4 ! o4 has interval 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate ! A high-level interrupt in current_thread() interrupting here 3967c478bd9Sstevel@tonic-gate ! will account for the interrupted thread's time slice, but 3977c478bd9Sstevel@tonic-gate ! only if t_intr_start is non-zero. Since this code is going to account 3987c478bd9Sstevel@tonic-gate ! for the time slice, we want to "atomically" load the thread's 3997c478bd9Sstevel@tonic-gate ! starting timestamp, calculate the interval with %tick, and zero 4007c478bd9Sstevel@tonic-gate ! its starting timestamp. 4017c478bd9Sstevel@tonic-gate ! To do this, we do a casx on the t_intr_start field, and store 0 to it. 4027c478bd9Sstevel@tonic-gate ! If it has changed since we loaded it above, we need to re-compute the 4037c478bd9Sstevel@tonic-gate ! interval, since a changed t_intr_start implies current_thread placed 4047c478bd9Sstevel@tonic-gate ! a new, later timestamp there after running a high-level interrupt, 4057c478bd9Sstevel@tonic-gate ! and the %tick val in %o4 had become stale. 4067c478bd9Sstevel@tonic-gate mov %g0, %l2 4077c478bd9Sstevel@tonic-gate casx [%o5], %o3, %l2 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate ! If %l2 == %o3, our casx was successful. If not, the starting timestamp 4107c478bd9Sstevel@tonic-gate ! changed between loading it (after label 0b) and computing the 4117c478bd9Sstevel@tonic-gate ! interval above. 4127c478bd9Sstevel@tonic-gate cmp %l2, %o3 4137c478bd9Sstevel@tonic-gate bne,pn %xcc, 0b 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate ! Check for Energy Star mode 4167c478bd9Sstevel@tonic-gate lduh [%o2 + CPU_DIVISOR], %l2 ! delay -- %l2 = clock divisor 4177c478bd9Sstevel@tonic-gate cmp %l2, 1 4187c478bd9Sstevel@tonic-gate bg,a,pn %xcc, 2f 4197c478bd9Sstevel@tonic-gate mulx %o4, %l2, %o4 ! multiply interval by clock divisor iff > 1 4207c478bd9Sstevel@tonic-gate2: 4217c478bd9Sstevel@tonic-gate ! We now know that a valid interval for the interrupted interrupt 4227c478bd9Sstevel@tonic-gate ! thread is in %o4. Update its cumulative counter. 4237c478bd9Sstevel@tonic-gate ldub [THREAD_REG + T_PIL], %l3 ! load PIL 4247c478bd9Sstevel@tonic-gate sllx %l3, 4, %l3 ! convert PIL index to byte offset 4257c478bd9Sstevel@tonic-gate add %l3, CPU_MCPU, %l3 ! CPU_INTRSTAT is too big for use 4267c478bd9Sstevel@tonic-gate add %l3, MCPU_INTRSTAT, %l3 ! as const, add offsets separately 4277c478bd9Sstevel@tonic-gate ldx [%o2 + %l3], %o5 ! old counter in o5 4287c478bd9Sstevel@tonic-gate add %o5, %o4, %o5 ! new counter in o5 4297c478bd9Sstevel@tonic-gate stx %o5, [%o2 + %l3] ! store new counter 4307c478bd9Sstevel@tonic-gate 431eda89462Sesolom ! Also update intracct[] 432eda89462Sesolom lduh [%o2 + CPU_MSTATE], %l3 433eda89462Sesolom sllx %l3, 3, %l3 434eda89462Sesolom add %l3, CPU_INTRACCT, %l3 435eda89462Sesolom add %l3, %o2, %l3 436eda89462Sesolom0: 437eda89462Sesolom ldx [%l3], %o5 438eda89462Sesolom add %o5, %o4, %o3 439eda89462Sesolom casx [%l3], %o5, %o3 440eda89462Sesolom cmp %o5, %o3 441eda89462Sesolom bne,pn %xcc, 0b 442eda89462Sesolom nop 443eda89462Sesolom 4447c478bd9Sstevel@tonic-gate1: 4457c478bd9Sstevel@tonic-gate ! 4467c478bd9Sstevel@tonic-gate ! Get set to run interrupt thread. 4477c478bd9Sstevel@tonic-gate ! There should always be an interrupt thread since we allocate one 4487c478bd9Sstevel@tonic-gate ! for each level on the CPU. 4497c478bd9Sstevel@tonic-gate ! 4507c478bd9Sstevel@tonic-gate ! Note that the code in kcpc_overflow_intr -relies- on the ordering 4517c478bd9Sstevel@tonic-gate ! of events here -- in particular that t->t_lwp of the interrupt thread 4527c478bd9Sstevel@tonic-gate ! is set to the pinned thread *before* curthread is changed. 4537c478bd9Sstevel@tonic-gate ! 4547c478bd9Sstevel@tonic-gate ldn [%o2 + CPU_INTR_THREAD], %o3 ! interrupt thread pool 4557c478bd9Sstevel@tonic-gate ldn [%o3 + T_LINK], %o4 ! unlink thread from CPU's list 4567c478bd9Sstevel@tonic-gate stn %o4, [%o2 + CPU_INTR_THREAD] 4577c478bd9Sstevel@tonic-gate ! 4587c478bd9Sstevel@tonic-gate ! Set bit for this level in CPU's active interrupt bitmask. 4597c478bd9Sstevel@tonic-gate ! 4607c478bd9Sstevel@tonic-gate ld [%o2 + CPU_INTR_ACTV], %o5 4617c478bd9Sstevel@tonic-gate mov 1, %o4 4627c478bd9Sstevel@tonic-gate sll %o4, %l1, %o4 4637c478bd9Sstevel@tonic-gate#ifdef DEBUG 4647c478bd9Sstevel@tonic-gate ! 4657c478bd9Sstevel@tonic-gate ! ASSERT(!(CPU->cpu_intr_actv & (1 << PIL))) 4667c478bd9Sstevel@tonic-gate ! 4677c478bd9Sstevel@tonic-gate andcc %o5, %o4, %g0 4687c478bd9Sstevel@tonic-gate bz,pt %xcc, 0f 4697c478bd9Sstevel@tonic-gate nop 4707c478bd9Sstevel@tonic-gate ! Do not call panic if a panic is already in progress. 4717c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l2 4727c478bd9Sstevel@tonic-gate ld [%l2 + %lo(panic_quiesce)], %l2 4737c478bd9Sstevel@tonic-gate brnz,pn %l2, 0f 4747c478bd9Sstevel@tonic-gate nop 4757c478bd9Sstevel@tonic-gate sethi %hi(intr_thread_actv_bit_set), %o0 4767c478bd9Sstevel@tonic-gate call panic 4777c478bd9Sstevel@tonic-gate or %o0, %lo(intr_thread_actv_bit_set), %o0 4787c478bd9Sstevel@tonic-gate0: 4797c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 4807c478bd9Sstevel@tonic-gate or %o5, %o4, %o5 4817c478bd9Sstevel@tonic-gate st %o5, [%o2 + CPU_INTR_ACTV] 4827c478bd9Sstevel@tonic-gate ! 4837c478bd9Sstevel@tonic-gate ! Consider the new thread part of the same LWP so that 4847c478bd9Sstevel@tonic-gate ! window overflow code can find the PCB. 4857c478bd9Sstevel@tonic-gate ! 4867c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_LWP], %o4 4877c478bd9Sstevel@tonic-gate stn %o4, [%o3 + T_LWP] 4887c478bd9Sstevel@tonic-gate ! 4897c478bd9Sstevel@tonic-gate ! Threads on the interrupt thread free list could have state already 4907c478bd9Sstevel@tonic-gate ! set to TS_ONPROC, but it helps in debugging if they're TS_FREE 4917c478bd9Sstevel@tonic-gate ! Could eliminate the next two instructions with a little work. 4927c478bd9Sstevel@tonic-gate ! 4937c478bd9Sstevel@tonic-gate mov TS_ONPROC, %o4 4947c478bd9Sstevel@tonic-gate st %o4, [%o3 + T_STATE] 4957c478bd9Sstevel@tonic-gate ! 4967c478bd9Sstevel@tonic-gate ! Push interrupted thread onto list from new thread. 4977c478bd9Sstevel@tonic-gate ! Set the new thread as the current one. 4987c478bd9Sstevel@tonic-gate ! Set interrupted thread's T_SP because if it is the idle thread, 4997c478bd9Sstevel@tonic-gate ! resume may use that stack between threads. 5007c478bd9Sstevel@tonic-gate ! 5017c478bd9Sstevel@tonic-gate stn %o7, [THREAD_REG + T_PC] ! mark pc for resume 5027c478bd9Sstevel@tonic-gate stn %sp, [THREAD_REG + T_SP] ! mark stack for resume 5037c478bd9Sstevel@tonic-gate stn THREAD_REG, [%o3 + T_INTR] ! push old thread 5047c478bd9Sstevel@tonic-gate stn %o3, [%o2 + CPU_THREAD] ! set new thread 5057c478bd9Sstevel@tonic-gate mov %o3, THREAD_REG ! set global curthread register 5067c478bd9Sstevel@tonic-gate ldn [%o3 + T_STACK], %o4 ! interrupt stack pointer 5077c478bd9Sstevel@tonic-gate sub %o4, STACK_BIAS, %sp 5087c478bd9Sstevel@tonic-gate ! 5097c478bd9Sstevel@tonic-gate ! Initialize thread priority level from intr_pri 5107c478bd9Sstevel@tonic-gate ! 5117c478bd9Sstevel@tonic-gate sethi %hi(intr_pri), %o4 5127c478bd9Sstevel@tonic-gate ldsh [%o4 + %lo(intr_pri)], %o4 ! grab base interrupt priority 5137c478bd9Sstevel@tonic-gate add %l1, %o4, %o4 ! convert level to dispatch priority 5147c478bd9Sstevel@tonic-gate sth %o4, [THREAD_REG + T_PRI] 5157c478bd9Sstevel@tonic-gate stub %l1, [THREAD_REG + T_PIL] ! save pil for intr_passivate 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate ! Store starting timestamp in thread structure. 5187c478bd9Sstevel@tonic-gate add THREAD_REG, T_INTR_START, %o3 5197c478bd9Sstevel@tonic-gate1: 5207c478bd9Sstevel@tonic-gate ldx [%o3], %o5 521*023e71deSHaik Aftandilian RD_TICK(%o4,%l2,%l3,__LINE__) 5227c478bd9Sstevel@tonic-gate casx [%o3], %o5, %o4 5237c478bd9Sstevel@tonic-gate cmp %o4, %o5 5247c478bd9Sstevel@tonic-gate ! If a high-level interrupt occurred while we were attempting to store 5257c478bd9Sstevel@tonic-gate ! the timestamp, try again. 5267c478bd9Sstevel@tonic-gate bne,pn %xcc, 1b 5277c478bd9Sstevel@tonic-gate nop 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate wrpr %g0, %l1, %pil ! lower %pil to new level 5307c478bd9Sstevel@tonic-gate ! 5317c478bd9Sstevel@tonic-gate ! Fast event tracing. 5327c478bd9Sstevel@tonic-gate ! 5337c478bd9Sstevel@tonic-gate ld [%o2 + CPU_FTRACE_STATE], %o4 ! %o2 = curthread->t_cpu 5347c478bd9Sstevel@tonic-gate btst FTRACE_ENABLED, %o4 5357c478bd9Sstevel@tonic-gate be,pt %icc, 1f ! skip if ftrace disabled 5367c478bd9Sstevel@tonic-gate mov %l1, %o5 5377c478bd9Sstevel@tonic-gate ! 5387c478bd9Sstevel@tonic-gate ! Tracing is enabled - write the trace entry. 5397c478bd9Sstevel@tonic-gate ! 5407c478bd9Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp 5417c478bd9Sstevel@tonic-gate set ftrace_intr_thread_format_str, %o0 5427c478bd9Sstevel@tonic-gate mov %i0, %o1 5437c478bd9Sstevel@tonic-gate mov %i1, %o2 5447c478bd9Sstevel@tonic-gate mov %i5, %o3 5454df4bd60Sbs21162 call ftrace_3 5464df4bd60Sbs21162 ldn [%i0 + PC_OFF], %o4 5477c478bd9Sstevel@tonic-gate restore 5487c478bd9Sstevel@tonic-gate1: 5497c478bd9Sstevel@tonic-gate ! 5507c478bd9Sstevel@tonic-gate ! call the handler 5517c478bd9Sstevel@tonic-gate ! 5527c478bd9Sstevel@tonic-gate SERVE_INTR_PRE(%o1, %o2, %l1, %l3, %o4, %o5, %o3, %o0) 5537c478bd9Sstevel@tonic-gate ! 5547c478bd9Sstevel@tonic-gate ! %o0 and %o1 are now available as scratch registers. 5557c478bd9Sstevel@tonic-gate ! 5567c478bd9Sstevel@tonic-gate0: 5577c478bd9Sstevel@tonic-gate SERVE_INTR(%o1, %o2, %l1, %l3, %o4, %o5, %o3, %o0) 5587c478bd9Sstevel@tonic-gate ! 559b0fc0e77Sgovinda ! If %o3 is set, we must call serve_intr_next, and both %l1 and %o3 5607c478bd9Sstevel@tonic-gate ! must be preserved. %l1 holds our pil, %l3 holds our inum. 5617c478bd9Sstevel@tonic-gate ! 5627c478bd9Sstevel@tonic-gate ! Note: %l1 is the pil level we're processing, but we may have a 5637c478bd9Sstevel@tonic-gate ! higher effective pil because a higher-level interrupt may have 5647c478bd9Sstevel@tonic-gate ! blocked. 5657c478bd9Sstevel@tonic-gate ! 5667c478bd9Sstevel@tonic-gate wrpr %g0, DISP_LEVEL, %pil 5677c478bd9Sstevel@tonic-gate ! 5687c478bd9Sstevel@tonic-gate ! Take timestamp, compute interval, update cumulative counter. 5697c478bd9Sstevel@tonic-gate ! 5707c478bd9Sstevel@tonic-gate add THREAD_REG, T_INTR_START, %o5 5717c478bd9Sstevel@tonic-gate1: 5727c478bd9Sstevel@tonic-gate ldx [%o5], %o0 5737c478bd9Sstevel@tonic-gate#ifdef DEBUG 5747c478bd9Sstevel@tonic-gate brnz %o0, 9f 5757c478bd9Sstevel@tonic-gate nop 5767c478bd9Sstevel@tonic-gate ! Do not call panic if a panic is already in progress. 5777c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %o1 5787c478bd9Sstevel@tonic-gate ld [%o1 + %lo(panic_quiesce)], %o1 5797c478bd9Sstevel@tonic-gate brnz,pn %o1, 9f 5807c478bd9Sstevel@tonic-gate nop 5817c478bd9Sstevel@tonic-gate sethi %hi(intr_thread_t_intr_start_zero), %o0 5827c478bd9Sstevel@tonic-gate call panic 5837c478bd9Sstevel@tonic-gate or %o0, %lo(intr_thread_t_intr_start_zero), %o0 5847c478bd9Sstevel@tonic-gate9: 5857c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 586*023e71deSHaik Aftandilian RD_TICK(%o1,%l2,%l3,__LINE__) 5877c478bd9Sstevel@tonic-gate sub %o1, %o0, %l2 ! l2 has interval 5887c478bd9Sstevel@tonic-gate ! 5897c478bd9Sstevel@tonic-gate ! The general outline of what the code here does is: 5907c478bd9Sstevel@tonic-gate ! 1. load t_intr_start, %tick, and calculate the delta 5917c478bd9Sstevel@tonic-gate ! 2. replace t_intr_start with %tick (if %o3 is set) or 0. 5927c478bd9Sstevel@tonic-gate ! 5937c478bd9Sstevel@tonic-gate ! The problem is that a high-level interrupt could arrive at any time. 5947c478bd9Sstevel@tonic-gate ! It will account for (%tick - t_intr_start) for us when it starts, 5957c478bd9Sstevel@tonic-gate ! unless we have set t_intr_start to zero, and then set t_intr_start 5967c478bd9Sstevel@tonic-gate ! to a new %tick when it finishes. To account for this, our first step 5977c478bd9Sstevel@tonic-gate ! is to load t_intr_start and the last is to use casx to store the new 5987c478bd9Sstevel@tonic-gate ! t_intr_start. This guarantees atomicity in reading t_intr_start, 5997c478bd9Sstevel@tonic-gate ! reading %tick, and updating t_intr_start. 6007c478bd9Sstevel@tonic-gate ! 6017c478bd9Sstevel@tonic-gate movrz %o3, %g0, %o1 6027c478bd9Sstevel@tonic-gate casx [%o5], %o0, %o1 6037c478bd9Sstevel@tonic-gate cmp %o0, %o1 6047c478bd9Sstevel@tonic-gate bne,pn %xcc, 1b 6057c478bd9Sstevel@tonic-gate ! 6067c478bd9Sstevel@tonic-gate ! Check for Energy Star mode 6077c478bd9Sstevel@tonic-gate ! 6087c478bd9Sstevel@tonic-gate lduh [%o2 + CPU_DIVISOR], %o0 ! delay -- %o0 = clock divisor 6097c478bd9Sstevel@tonic-gate cmp %o0, 1 6107c478bd9Sstevel@tonic-gate bg,a,pn %xcc, 2f 6117c478bd9Sstevel@tonic-gate mulx %l2, %o0, %l2 ! multiply interval by clock divisor iff > 1 6127c478bd9Sstevel@tonic-gate2: 6137c478bd9Sstevel@tonic-gate ! 6147c478bd9Sstevel@tonic-gate ! Update cpu_intrstat. If o3 is set then we will be processing another 6157c478bd9Sstevel@tonic-gate ! interrupt. Above we have set t_intr_start to %tick, not 0. This 6167c478bd9Sstevel@tonic-gate ! means a high-level interrupt can arrive and update the same stats 6177c478bd9Sstevel@tonic-gate ! we're updating. Need to use casx. 6187c478bd9Sstevel@tonic-gate ! 6197c478bd9Sstevel@tonic-gate sllx %l1, 4, %o1 ! delay - PIL as byte offset 6207c478bd9Sstevel@tonic-gate add %o1, CPU_MCPU, %o1 ! CPU_INTRSTAT const too big 6217c478bd9Sstevel@tonic-gate add %o1, MCPU_INTRSTAT, %o1 ! add parts separately 6227c478bd9Sstevel@tonic-gate add %o1, %o2, %o1 6237c478bd9Sstevel@tonic-gate1: 6247c478bd9Sstevel@tonic-gate ldx [%o1], %o5 ! old counter in o5 6257c478bd9Sstevel@tonic-gate add %o5, %l2, %o0 ! new counter in o0 6267c478bd9Sstevel@tonic-gate stx %o0, [%o1 + 8] ! store into intrstat[pil][1] 6277c478bd9Sstevel@tonic-gate casx [%o1], %o5, %o0 ! and into intrstat[pil][0] 6287c478bd9Sstevel@tonic-gate cmp %o5, %o0 6297c478bd9Sstevel@tonic-gate bne,pn %xcc, 1b 6307c478bd9Sstevel@tonic-gate nop 631eda89462Sesolom 632eda89462Sesolom ! Also update intracct[] 633eda89462Sesolom lduh [%o2 + CPU_MSTATE], %o1 634eda89462Sesolom sllx %o1, 3, %o1 635eda89462Sesolom add %o1, CPU_INTRACCT, %o1 636eda89462Sesolom add %o1, %o2, %o1 637eda89462Sesolom1: 638eda89462Sesolom ldx [%o1], %o5 639eda89462Sesolom add %o5, %l2, %o0 640eda89462Sesolom casx [%o1], %o5, %o0 641eda89462Sesolom cmp %o5, %o0 642eda89462Sesolom bne,pn %xcc, 1b 643eda89462Sesolom nop 644eda89462Sesolom 6457c478bd9Sstevel@tonic-gate ! 6467c478bd9Sstevel@tonic-gate ! Don't keep a pinned process pinned indefinitely. Bump cpu_intrcnt 6477c478bd9Sstevel@tonic-gate ! for each interrupt handler we invoke. If we hit INTRCNT_LIMIT, then 6487c478bd9Sstevel@tonic-gate ! we've crossed the threshold and we should unpin the pinned threads 6497c478bd9Sstevel@tonic-gate ! by preempt()ing ourselves, which will bubble up the t_intr chain 6507c478bd9Sstevel@tonic-gate ! until hitting the non-interrupt thread, which will then in turn 6517c478bd9Sstevel@tonic-gate ! preempt itself allowing the interrupt processing to resume. Finally, 6527c478bd9Sstevel@tonic-gate ! the scheduler takes over and picks the next thread to run. 6537c478bd9Sstevel@tonic-gate ! 6547c478bd9Sstevel@tonic-gate ! If our CPU is quiesced, we cannot preempt because the idle thread 6557c478bd9Sstevel@tonic-gate ! won't ever re-enter the scheduler, and the interrupt will be forever 6567c478bd9Sstevel@tonic-gate ! blocked. 6577c478bd9Sstevel@tonic-gate ! 6587c478bd9Sstevel@tonic-gate ! If t_intr is NULL, we're not pinning anyone, so we use a simpler 6597c478bd9Sstevel@tonic-gate ! algorithm. Just check for cpu_kprunrun, and if set then preempt. 6607c478bd9Sstevel@tonic-gate ! This insures we enter the scheduler if a higher-priority thread 6617c478bd9Sstevel@tonic-gate ! has become runnable. 6627c478bd9Sstevel@tonic-gate ! 6637c478bd9Sstevel@tonic-gate lduh [%o2 + CPU_FLAGS], %o5 ! don't preempt if quiesced 6647c478bd9Sstevel@tonic-gate andcc %o5, CPU_QUIESCED, %g0 6657c478bd9Sstevel@tonic-gate bnz,pn %xcc, 1f 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_INTR], %o5 ! pinning anything? 6687c478bd9Sstevel@tonic-gate brz,pn %o5, 3f ! if not, don't inc intrcnt 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate ldub [%o2 + CPU_INTRCNT], %o5 ! delay - %o5 = cpu_intrcnt 6717c478bd9Sstevel@tonic-gate inc %o5 6727c478bd9Sstevel@tonic-gate cmp %o5, INTRCNT_LIMIT ! have we hit the limit? 6737c478bd9Sstevel@tonic-gate bl,a,pt %xcc, 1f ! no preempt if < INTRCNT_LIMIT 6747c478bd9Sstevel@tonic-gate stub %o5, [%o2 + CPU_INTRCNT] ! delay annul - inc CPU_INTRCNT 6757c478bd9Sstevel@tonic-gate bg,pn %xcc, 2f ! don't inc stats again 6767c478bd9Sstevel@tonic-gate ! 6777c478bd9Sstevel@tonic-gate ! We've reached the limit. Set cpu_intrcnt and cpu_kprunrun, and do 6787c478bd9Sstevel@tonic-gate ! CPU_STATS_ADDQ(cp, sys, intrunpin, 1). Then call preempt. 6797c478bd9Sstevel@tonic-gate ! 6807c478bd9Sstevel@tonic-gate mov 1, %o4 ! delay 6817c478bd9Sstevel@tonic-gate stub %o4, [%o2 + CPU_KPRUNRUN] 6827c478bd9Sstevel@tonic-gate ldx [%o2 + CPU_STATS_SYS_INTRUNPIN], %o4 6837c478bd9Sstevel@tonic-gate inc %o4 6847c478bd9Sstevel@tonic-gate stx %o4, [%o2 + CPU_STATS_SYS_INTRUNPIN] 6857c478bd9Sstevel@tonic-gate ba 2f 6867c478bd9Sstevel@tonic-gate stub %o5, [%o2 + CPU_INTRCNT] ! delay 6877c478bd9Sstevel@tonic-gate3: 6887c478bd9Sstevel@tonic-gate ! Code for t_intr == NULL 6897c478bd9Sstevel@tonic-gate ldub [%o2 + CPU_KPRUNRUN], %o5 6907c478bd9Sstevel@tonic-gate brz,pt %o5, 1f ! don't preempt unless kprunrun 6917c478bd9Sstevel@tonic-gate2: 6927c478bd9Sstevel@tonic-gate ! Time to call preempt 6937c478bd9Sstevel@tonic-gate mov %o2, %l3 ! delay - save %o2 6947c478bd9Sstevel@tonic-gate call preempt 6957c478bd9Sstevel@tonic-gate mov %o3, %l2 ! delay - save %o3. 6967c478bd9Sstevel@tonic-gate mov %l3, %o2 ! restore %o2 6977c478bd9Sstevel@tonic-gate mov %l2, %o3 ! restore %o3 6987c478bd9Sstevel@tonic-gate wrpr %g0, DISP_LEVEL, %pil ! up from cpu_base_spl 6997c478bd9Sstevel@tonic-gate1: 7007c478bd9Sstevel@tonic-gate ! 701b0fc0e77Sgovinda ! Do we need to call serve_intr_next and do this again? 7027c478bd9Sstevel@tonic-gate ! 7037c478bd9Sstevel@tonic-gate brz,a,pt %o3, 0f 7047c478bd9Sstevel@tonic-gate ld [%o2 + CPU_INTR_ACTV], %o5 ! delay annulled 7057c478bd9Sstevel@tonic-gate ! 7067c478bd9Sstevel@tonic-gate ! Restore %pil before calling serve_intr() again. We must check 7077c478bd9Sstevel@tonic-gate ! CPU_BASE_SPL and set %pil to max(our-pil, CPU_BASE_SPL) 7087c478bd9Sstevel@tonic-gate ! 7097c478bd9Sstevel@tonic-gate ld [%o2 + CPU_BASE_SPL], %o4 7107c478bd9Sstevel@tonic-gate cmp %o4, %l1 7117c478bd9Sstevel@tonic-gate movl %xcc, %l1, %o4 7127c478bd9Sstevel@tonic-gate wrpr %g0, %o4, %pil 7137c478bd9Sstevel@tonic-gate SERVE_INTR_NEXT(%o1, %o2, %l1, %l3, %o4, %o5, %o3, %o0) 7147c478bd9Sstevel@tonic-gate ba 0b ! compute new stats 7157c478bd9Sstevel@tonic-gate nop 7167c478bd9Sstevel@tonic-gate0: 7177c478bd9Sstevel@tonic-gate ! 7187c478bd9Sstevel@tonic-gate ! Clear bit for this level in CPU's interrupt active bitmask. 7197c478bd9Sstevel@tonic-gate ! 7207c478bd9Sstevel@tonic-gate mov 1, %o4 7217c478bd9Sstevel@tonic-gate sll %o4, %l1, %o4 7227c478bd9Sstevel@tonic-gate#ifdef DEBUG 7237c478bd9Sstevel@tonic-gate ! 7247c478bd9Sstevel@tonic-gate ! ASSERT(CPU->cpu_intr_actv & (1 << PIL)) 7257c478bd9Sstevel@tonic-gate ! 7267c478bd9Sstevel@tonic-gate andcc %o4, %o5, %g0 7277c478bd9Sstevel@tonic-gate bnz,pt %xcc, 0f 7287c478bd9Sstevel@tonic-gate nop 7297c478bd9Sstevel@tonic-gate ! Do not call panic if a panic is already in progress. 7307c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l2 7317c478bd9Sstevel@tonic-gate ld [%l2 + %lo(panic_quiesce)], %l2 7327c478bd9Sstevel@tonic-gate brnz,pn %l2, 0f 7337c478bd9Sstevel@tonic-gate nop 7347c478bd9Sstevel@tonic-gate sethi %hi(intr_thread_actv_bit_not_set), %o0 7357c478bd9Sstevel@tonic-gate call panic 7367c478bd9Sstevel@tonic-gate or %o0, %lo(intr_thread_actv_bit_not_set), %o0 7377c478bd9Sstevel@tonic-gate0: 7387c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 7397c478bd9Sstevel@tonic-gate andn %o5, %o4, %o5 7407c478bd9Sstevel@tonic-gate st %o5, [%o2 + CPU_INTR_ACTV] 7417c478bd9Sstevel@tonic-gate ! 7427c478bd9Sstevel@tonic-gate ! If there is still an interrupted thread underneath this one, 7437c478bd9Sstevel@tonic-gate ! then the interrupt was never blocked and the return is fairly 7447c478bd9Sstevel@tonic-gate ! simple. Otherwise jump to intr_thread_exit. 7457c478bd9Sstevel@tonic-gate ! 7467c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_INTR], %o4 ! pinned thread 7477c478bd9Sstevel@tonic-gate brz,pn %o4, intr_thread_exit ! branch if none 7487c478bd9Sstevel@tonic-gate nop 7497c478bd9Sstevel@tonic-gate ! 7507c478bd9Sstevel@tonic-gate ! link the thread back onto the interrupt thread pool 7517c478bd9Sstevel@tonic-gate ! 7527c478bd9Sstevel@tonic-gate ldn [%o2 + CPU_INTR_THREAD], %o3 7537c478bd9Sstevel@tonic-gate stn %o3, [THREAD_REG + T_LINK] 7547c478bd9Sstevel@tonic-gate stn THREAD_REG, [%o2 + CPU_INTR_THREAD] 7557c478bd9Sstevel@tonic-gate ! 7567c478bd9Sstevel@tonic-gate ! set the thread state to free so kernel debuggers don't see it 7577c478bd9Sstevel@tonic-gate ! 7587c478bd9Sstevel@tonic-gate mov TS_FREE, %o5 7597c478bd9Sstevel@tonic-gate st %o5, [THREAD_REG + T_STATE] 7607c478bd9Sstevel@tonic-gate ! 7617c478bd9Sstevel@tonic-gate ! Switch back to the interrupted thread and return 7627c478bd9Sstevel@tonic-gate ! 7637c478bd9Sstevel@tonic-gate stn %o4, [%o2 + CPU_THREAD] 76425cf1a30Sjl139090 membar #StoreLoad ! sync with mutex_exit() 7657c478bd9Sstevel@tonic-gate mov %o4, THREAD_REG 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate ! If we pinned an interrupt thread, store its starting timestamp. 7687c478bd9Sstevel@tonic-gate lduh [THREAD_REG + T_FLAGS], %o5 7697c478bd9Sstevel@tonic-gate andcc %o5, T_INTR_THREAD, %g0 7707c478bd9Sstevel@tonic-gate bz,pt %xcc, 1f 7717c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_SP], %sp ! delay - restore %sp 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate add THREAD_REG, T_INTR_START, %o3 ! o3 has &curthread->t_intr_star 7747c478bd9Sstevel@tonic-gate0: 7757c478bd9Sstevel@tonic-gate ldx [%o3], %o4 ! o4 = t_intr_start before 776*023e71deSHaik Aftandilian RD_TICK(%o5,%l2,%l3,__LINE__) 7777c478bd9Sstevel@tonic-gate casx [%o3], %o4, %o5 ! put o5 in ts if o4 == ts after 7787c478bd9Sstevel@tonic-gate cmp %o4, %o5 7797c478bd9Sstevel@tonic-gate ! If a high-level interrupt occurred while we were attempting to store 7807c478bd9Sstevel@tonic-gate ! the timestamp, try again. 7817c478bd9Sstevel@tonic-gate bne,pn %xcc, 0b 7827c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_SP], %sp ! delay - restore %sp 7837c478bd9Sstevel@tonic-gate1: 7847c478bd9Sstevel@tonic-gate ! If the thread being restarted isn't pinning anyone, and no interrupts 7857c478bd9Sstevel@tonic-gate ! are pending, zero out cpu_intrcnt 7867c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_INTR], %o4 7877c478bd9Sstevel@tonic-gate brnz,pn %o4, 2f 7887c478bd9Sstevel@tonic-gate rd SOFTINT, %o4 ! delay 7897c478bd9Sstevel@tonic-gate set SOFTINT_MASK, %o5 7907c478bd9Sstevel@tonic-gate andcc %o4, %o5, %g0 7917c478bd9Sstevel@tonic-gate bz,a,pt %xcc, 2f 7927c478bd9Sstevel@tonic-gate stub %g0, [%o2 + CPU_INTRCNT] ! delay annul 7937c478bd9Sstevel@tonic-gate2: 7947c478bd9Sstevel@tonic-gate jmp %l0 + 8 7957c478bd9Sstevel@tonic-gate nop 7967c478bd9Sstevel@tonic-gate SET_SIZE(intr_thread) 7977c478bd9Sstevel@tonic-gate /* Not Reached */ 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate ! 8007c478bd9Sstevel@tonic-gate ! An interrupt returned on what was once (and still might be) 8017c478bd9Sstevel@tonic-gate ! an interrupt thread stack, but the interrupted process is no longer 8027c478bd9Sstevel@tonic-gate ! there. This means the interrupt must have blocked. 8037c478bd9Sstevel@tonic-gate ! 8047c478bd9Sstevel@tonic-gate ! There is no longer a thread under this one, so put this thread back 8057c478bd9Sstevel@tonic-gate ! on the CPU's free list and resume the idle thread which will dispatch 8067c478bd9Sstevel@tonic-gate ! the next thread to run. 8077c478bd9Sstevel@tonic-gate ! 8087c478bd9Sstevel@tonic-gate ! All traps below DISP_LEVEL are disabled here, but the mondo interrupt 8097c478bd9Sstevel@tonic-gate ! is enabled. 8107c478bd9Sstevel@tonic-gate ! 8117c478bd9Sstevel@tonic-gate ENTRY_NP(intr_thread_exit) 8127c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE 8137c478bd9Sstevel@tonic-gate rdpr %pstate, %l2 8147c478bd9Sstevel@tonic-gate andn %l2, PSTATE_IE | PSTATE_AM, %o4 8157c478bd9Sstevel@tonic-gate wrpr %g0, %o4, %pstate ! cpu to known state 8167c478bd9Sstevel@tonic-gate TRACE_PTR(%o4, %o5) 817*023e71deSHaik Aftandilian GET_TRACE_TICK(%o5, %o0) 8187c478bd9Sstevel@tonic-gate stxa %o5, [%o4 + TRAP_ENT_TICK]%asi 8197c478bd9Sstevel@tonic-gate TRACE_SAVE_TL_GL_REGS(%o4, %o5) 8207c478bd9Sstevel@tonic-gate set TT_INTR_EXIT, %o5 8217c478bd9Sstevel@tonic-gate stha %o5, [%o4 + TRAP_ENT_TT]%asi 8227c478bd9Sstevel@tonic-gate stna %g0, [%o4 + TRAP_ENT_TPC]%asi 8237c478bd9Sstevel@tonic-gate stxa %g0, [%o4 + TRAP_ENT_TSTATE]%asi 8247c478bd9Sstevel@tonic-gate stna %sp, [%o4 + TRAP_ENT_SP]%asi 8257c478bd9Sstevel@tonic-gate stna THREAD_REG, [%o4 + TRAP_ENT_TR]%asi 8267c478bd9Sstevel@tonic-gate ld [%o2 + CPU_BASE_SPL], %o5 8277c478bd9Sstevel@tonic-gate stna %o5, [%o4 + TRAP_ENT_F1]%asi 8287c478bd9Sstevel@tonic-gate stna %g0, [%o4 + TRAP_ENT_F2]%asi 8297c478bd9Sstevel@tonic-gate stna %g0, [%o4 + TRAP_ENT_F3]%asi 8307c478bd9Sstevel@tonic-gate stna %g0, [%o4 + TRAP_ENT_F4]%asi 8317c478bd9Sstevel@tonic-gate TRACE_NEXT(%o4, %o5, %o0) 8327c478bd9Sstevel@tonic-gate wrpr %g0, %l2, %pstate 8337c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */ 8347c478bd9Sstevel@tonic-gate ! cpu_stats.sys.intrblk++ 8357c478bd9Sstevel@tonic-gate ldx [%o2 + CPU_STATS_SYS_INTRBLK], %o4 8367c478bd9Sstevel@tonic-gate inc %o4 8377c478bd9Sstevel@tonic-gate stx %o4, [%o2 + CPU_STATS_SYS_INTRBLK] 8387c478bd9Sstevel@tonic-gate ! 8397c478bd9Sstevel@tonic-gate ! Put thread back on the interrupt thread list. 8407c478bd9Sstevel@tonic-gate ! 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate ! 8437c478bd9Sstevel@tonic-gate ! Set the CPU's base SPL level. 8447c478bd9Sstevel@tonic-gate ! 8457c478bd9Sstevel@tonic-gate#ifdef DEBUG 8467c478bd9Sstevel@tonic-gate ! 8477c478bd9Sstevel@tonic-gate ! ASSERT(!(CPU->cpu_intr_actv & (1 << PIL))) 8487c478bd9Sstevel@tonic-gate ! 8497c478bd9Sstevel@tonic-gate ld [%o2 + CPU_INTR_ACTV], %o5 8507c478bd9Sstevel@tonic-gate mov 1, %o4 8517c478bd9Sstevel@tonic-gate sll %o4, %l1, %o4 8527c478bd9Sstevel@tonic-gate and %o5, %o4, %o4 8537c478bd9Sstevel@tonic-gate brz,pt %o4, 0f 8547c478bd9Sstevel@tonic-gate nop 8557c478bd9Sstevel@tonic-gate ! Do not call panic if a panic is already in progress. 8567c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l2 8577c478bd9Sstevel@tonic-gate ld [%l2 + %lo(panic_quiesce)], %l2 8587c478bd9Sstevel@tonic-gate brnz,pn %l2, 0f 8597c478bd9Sstevel@tonic-gate nop 8607c478bd9Sstevel@tonic-gate sethi %hi(intr_thread_exit_actv_bit_set), %o0 8617c478bd9Sstevel@tonic-gate call panic 8627c478bd9Sstevel@tonic-gate or %o0, %lo(intr_thread_exit_actv_bit_set), %o0 8637c478bd9Sstevel@tonic-gate0: 8647c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 8657c478bd9Sstevel@tonic-gate call _intr_set_spl ! set CPU's base SPL level 8667c478bd9Sstevel@tonic-gate ld [%o2 + CPU_INTR_ACTV], %o5 ! delay - load active mask 8677c478bd9Sstevel@tonic-gate ! 8687c478bd9Sstevel@tonic-gate ! set the thread state to free so kernel debuggers don't see it 8697c478bd9Sstevel@tonic-gate ! 8707c478bd9Sstevel@tonic-gate mov TS_FREE, %o4 8717c478bd9Sstevel@tonic-gate st %o4, [THREAD_REG + T_STATE] 8727c478bd9Sstevel@tonic-gate ! 8737c478bd9Sstevel@tonic-gate ! Put thread on either the interrupt pool or the free pool and 8747c478bd9Sstevel@tonic-gate ! call swtch() to resume another thread. 8757c478bd9Sstevel@tonic-gate ! 8767c478bd9Sstevel@tonic-gate ldn [%o2 + CPU_INTR_THREAD], %o5 ! get list pointer 8777c478bd9Sstevel@tonic-gate stn %o5, [THREAD_REG + T_LINK] 8787c478bd9Sstevel@tonic-gate call swtch ! switch to best thread 8797c478bd9Sstevel@tonic-gate stn THREAD_REG, [%o2 + CPU_INTR_THREAD] ! delay - put thread on list 8807c478bd9Sstevel@tonic-gate ba,a,pt %xcc, . ! swtch() shouldn't return 8817c478bd9Sstevel@tonic-gate SET_SIZE(intr_thread_exit) 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate .global ftrace_intr_thread_format_str 8847c478bd9Sstevel@tonic-gateftrace_intr_thread_format_str: 8857c478bd9Sstevel@tonic-gate .asciz "intr_thread(): regs=0x%lx, int=0x%lx, pil=0x%lx" 8867c478bd9Sstevel@tonic-gate#ifdef DEBUG 8877c478bd9Sstevel@tonic-gateintr_thread_actv_bit_set: 8887c478bd9Sstevel@tonic-gate .asciz "intr_thread(): cpu_intr_actv bit already set for PIL" 8897c478bd9Sstevel@tonic-gateintr_thread_actv_bit_not_set: 8907c478bd9Sstevel@tonic-gate .asciz "intr_thread(): cpu_intr_actv bit not set for PIL" 8917c478bd9Sstevel@tonic-gateintr_thread_exit_actv_bit_set: 8927c478bd9Sstevel@tonic-gate .asciz "intr_thread_exit(): cpu_intr_actv bit erroneously set for PIL" 8937c478bd9Sstevel@tonic-gateintr_thread_t_intr_start_zero: 8947c478bd9Sstevel@tonic-gate .asciz "intr_thread(): t_intr_start zero upon handler return" 8957c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 8967c478bd9Sstevel@tonic-gate#endif /* lint */ 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate#if defined(lint) 8997c478bd9Sstevel@tonic-gate 9007c478bd9Sstevel@tonic-gate/* 9017c478bd9Sstevel@tonic-gate * Handle an interrupt in the current thread 9027c478bd9Sstevel@tonic-gate * Entry: 9037c478bd9Sstevel@tonic-gate * %o0 = pointer to regs structure 904b0fc0e77Sgovinda * %o1 = pointer to current intr_vec_t (iv) to be processed 9057c478bd9Sstevel@tonic-gate * %o2 = pil 9067c478bd9Sstevel@tonic-gate * %sp = on current thread's kernel stack 9077c478bd9Sstevel@tonic-gate * %o7 = return linkage to trap code 9087c478bd9Sstevel@tonic-gate * %g7 = current thread 9097c478bd9Sstevel@tonic-gate * %pstate = normal globals, interrupts enabled, 9107c478bd9Sstevel@tonic-gate * privileged, fp disabled 9117c478bd9Sstevel@tonic-gate * %pil = PIL_MAX 9127c478bd9Sstevel@tonic-gate * 9137c478bd9Sstevel@tonic-gate * Register Usage 9147c478bd9Sstevel@tonic-gate * %l0 = return linkage 9157c478bd9Sstevel@tonic-gate * %l1 = old stack 9167c478bd9Sstevel@tonic-gate * %l2 - %l3 = scratch 9177c478bd9Sstevel@tonic-gate * %l4 - %l7 = reserved for sys_trap 9187c478bd9Sstevel@tonic-gate * %o3 = cpu 9197c478bd9Sstevel@tonic-gate * %o0 = scratch 9207c478bd9Sstevel@tonic-gate * %o4 - %o5 = scratch 9217c478bd9Sstevel@tonic-gate */ 9227c478bd9Sstevel@tonic-gate/* ARGSUSED */ 9237c478bd9Sstevel@tonic-gatevoid 924b0fc0e77Sgovindacurrent_thread(struct regs *regs, uint64_t iv_p, uint_t pil) 9257c478bd9Sstevel@tonic-gate{} 9267c478bd9Sstevel@tonic-gate 9277c478bd9Sstevel@tonic-gate#else /* lint */ 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate ENTRY_NP(current_thread) 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate mov %o7, %l0 9327c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CPU], %o3 93326046578Svb70745 93426046578Svb70745 ldn [THREAD_REG + T_ONFAULT], %l2 93526046578Svb70745 brz,pt %l2, no_onfault ! branch if no onfault label set 93626046578Svb70745 nop 93726046578Svb70745 stn %g0, [THREAD_REG + T_ONFAULT]! clear onfault label 93826046578Svb70745 ldn [THREAD_REG + T_LOFAULT], %l3 93926046578Svb70745 stn %g0, [THREAD_REG + T_LOFAULT]! clear lofault data 94026046578Svb70745 94126046578Svb70745 sub %o2, LOCK_LEVEL + 1, %o5 94226046578Svb70745 sll %o5, CPTRSHIFT, %o5 94326046578Svb70745 add %o5, CPU_OFD, %o4 ! %o4 has on_fault data offset 94426046578Svb70745 stn %l2, [%o3 + %o4] ! save onfault label for pil %o2 94526046578Svb70745 add %o5, CPU_LFD, %o4 ! %o4 has lofault data offset 94626046578Svb70745 stn %l3, [%o3 + %o4] ! save lofault data for pil %o2 94726046578Svb70745 94826046578Svb70745no_onfault: 94926046578Svb70745 ldn [THREAD_REG + T_ONTRAP], %l2 95026046578Svb70745 brz,pt %l2, 6f ! branch if no on_trap protection 95126046578Svb70745 nop 95226046578Svb70745 stn %g0, [THREAD_REG + T_ONTRAP]! clear on_trap protection 95326046578Svb70745 sub %o2, LOCK_LEVEL + 1, %o5 95426046578Svb70745 sll %o5, CPTRSHIFT, %o5 95526046578Svb70745 add %o5, CPU_OTD, %o4 ! %o4 has on_trap data offset 95626046578Svb70745 stn %l2, [%o3 + %o4] ! save on_trap label for pil %o2 95726046578Svb70745 9587c478bd9Sstevel@tonic-gate ! 9597c478bd9Sstevel@tonic-gate ! Set bit for this level in CPU's active interrupt bitmask. 9607c478bd9Sstevel@tonic-gate ! 96126046578Svb707456: ld [%o3 + CPU_INTR_ACTV], %o5 ! o5 has cpu_intr_actv b4 chng 9627c478bd9Sstevel@tonic-gate mov 1, %o4 9637c478bd9Sstevel@tonic-gate sll %o4, %o2, %o4 ! construct mask for level 9647c478bd9Sstevel@tonic-gate#ifdef DEBUG 9657c478bd9Sstevel@tonic-gate ! 9667c478bd9Sstevel@tonic-gate ! ASSERT(!(CPU->cpu_intr_actv & (1 << PIL))) 9677c478bd9Sstevel@tonic-gate ! 9687c478bd9Sstevel@tonic-gate andcc %o5, %o4, %g0 9697c478bd9Sstevel@tonic-gate bz,pt %xcc, 0f 9707c478bd9Sstevel@tonic-gate nop 9717c478bd9Sstevel@tonic-gate ! Do not call panic if a panic is already in progress. 9727c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l2 9737c478bd9Sstevel@tonic-gate ld [%l2 + %lo(panic_quiesce)], %l2 9747c478bd9Sstevel@tonic-gate brnz,pn %l2, 0f 9757c478bd9Sstevel@tonic-gate nop 9767c478bd9Sstevel@tonic-gate sethi %hi(current_thread_actv_bit_set), %o0 9777c478bd9Sstevel@tonic-gate call panic 9787c478bd9Sstevel@tonic-gate or %o0, %lo(current_thread_actv_bit_set), %o0 9797c478bd9Sstevel@tonic-gate0: 9807c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 9817c478bd9Sstevel@tonic-gate or %o5, %o4, %o4 9827c478bd9Sstevel@tonic-gate ! 9837c478bd9Sstevel@tonic-gate ! See if we are interrupting another high-level interrupt. 9847c478bd9Sstevel@tonic-gate ! 9857c478bd9Sstevel@tonic-gate srl %o5, LOCK_LEVEL + 1, %o5 ! only look at high-level bits 9867c478bd9Sstevel@tonic-gate brz,pt %o5, 1f 9877c478bd9Sstevel@tonic-gate st %o4, [%o3 + CPU_INTR_ACTV] ! delay - store active mask 9887c478bd9Sstevel@tonic-gate ! 9897c478bd9Sstevel@tonic-gate ! We have interrupted another high-level interrupt. Find its PIL, 9907c478bd9Sstevel@tonic-gate ! compute the interval it ran for, and update its cumulative counter. 9917c478bd9Sstevel@tonic-gate ! 9927c478bd9Sstevel@tonic-gate ! Register usage: 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate ! o2 = PIL of this interrupt 9957c478bd9Sstevel@tonic-gate ! o5 = high PIL bits of INTR_ACTV (not including this PIL) 9967c478bd9Sstevel@tonic-gate ! l1 = bitmask used to find other active high-level PIL 9977c478bd9Sstevel@tonic-gate ! o4 = index of bit set in l1 9987c478bd9Sstevel@tonic-gate ! Use cpu_intr_actv to find the cpu_pil_high_start[] offset for the 9997c478bd9Sstevel@tonic-gate ! interrupted high-level interrupt. 10007c478bd9Sstevel@tonic-gate ! Create mask for cpu_intr_actv. Begin by looking for bits set 10017c478bd9Sstevel@tonic-gate ! at one level below the current PIL. Since %o5 contains the active 10027c478bd9Sstevel@tonic-gate ! mask already shifted right by (LOCK_LEVEL + 1), we start by looking 10037c478bd9Sstevel@tonic-gate ! at bit (current_pil - (LOCK_LEVEL + 2)). 10047c478bd9Sstevel@tonic-gate sub %o2, LOCK_LEVEL + 2, %o4 10057c478bd9Sstevel@tonic-gate mov 1, %l1 10067c478bd9Sstevel@tonic-gate sll %l1, %o4, %l1 10077c478bd9Sstevel@tonic-gate2: 10087c478bd9Sstevel@tonic-gate#ifdef DEBUG 10097c478bd9Sstevel@tonic-gate ! ASSERT(%l1 != 0) (we didn't shift the bit off the right edge) 10107c478bd9Sstevel@tonic-gate brnz,pt %l1, 9f 10117c478bd9Sstevel@tonic-gate nop 10127c478bd9Sstevel@tonic-gate 10137c478bd9Sstevel@tonic-gate ! Don't panic if a panic is already in progress. 10147c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l3 10157c478bd9Sstevel@tonic-gate ld [%l3 + %lo(panic_quiesce)], %l3 10167c478bd9Sstevel@tonic-gate brnz,pn %l3, 9f 10177c478bd9Sstevel@tonic-gate nop 10187c478bd9Sstevel@tonic-gate sethi %hi(current_thread_nested_PIL_not_found), %o0 10197c478bd9Sstevel@tonic-gate call panic 10207c478bd9Sstevel@tonic-gate or %o0, %lo(current_thread_nested_PIL_not_found), %o0 10217c478bd9Sstevel@tonic-gate9: 10227c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 10237c478bd9Sstevel@tonic-gate andcc %l1, %o5, %g0 ! test mask against high-level bits of 10247c478bd9Sstevel@tonic-gate bnz %xcc, 3f ! cpu_intr_actv 10257c478bd9Sstevel@tonic-gate nop 10267c478bd9Sstevel@tonic-gate srl %l1, 1, %l1 ! No match. Try next lower PIL. 10277c478bd9Sstevel@tonic-gate ba,pt %xcc, 2b 10287c478bd9Sstevel@tonic-gate sub %o4, 1, %o4 ! delay - decrement PIL 10297c478bd9Sstevel@tonic-gate3: 10307c478bd9Sstevel@tonic-gate sll %o4, 3, %o4 ! index to byte offset 10317c478bd9Sstevel@tonic-gate add %o4, CPU_MCPU, %l1 ! CPU_PIL_HIGH_START is too large 10327c478bd9Sstevel@tonic-gate add %l1, MCPU_PIL_HIGH_START, %l1 10337c478bd9Sstevel@tonic-gate ldx [%o3 + %l1], %l3 ! load starting timestamp 10347c478bd9Sstevel@tonic-gate#ifdef DEBUG 10357c478bd9Sstevel@tonic-gate brnz,pt %l3, 9f 10367c478bd9Sstevel@tonic-gate nop 10377c478bd9Sstevel@tonic-gate ! Don't panic if a panic is already in progress. 10387c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l1 10397c478bd9Sstevel@tonic-gate ld [%l1 + %lo(panic_quiesce)], %l1 10407c478bd9Sstevel@tonic-gate brnz,pn %l1, 9f 10417c478bd9Sstevel@tonic-gate nop 10427c478bd9Sstevel@tonic-gate srl %o4, 3, %o1 ! Find interrupted PIL for panic 10437c478bd9Sstevel@tonic-gate add %o1, LOCK_LEVEL + 1, %o1 10447c478bd9Sstevel@tonic-gate sethi %hi(current_thread_nested_pil_zero), %o0 10457c478bd9Sstevel@tonic-gate call panic 10467c478bd9Sstevel@tonic-gate or %o0, %lo(current_thread_nested_pil_zero), %o0 10477c478bd9Sstevel@tonic-gate9: 10487c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 1049*023e71deSHaik Aftandilian RD_TICK_NO_SUSPEND_CHECK(%l1, %l2) 10507c478bd9Sstevel@tonic-gate sub %l1, %l3, %l3 ! interval in %l3 10517c478bd9Sstevel@tonic-gate ! 10527c478bd9Sstevel@tonic-gate ! Check for Energy Star mode 10537c478bd9Sstevel@tonic-gate ! 10547c478bd9Sstevel@tonic-gate lduh [%o3 + CPU_DIVISOR], %l1 ! %l1 = clock divisor 10557c478bd9Sstevel@tonic-gate cmp %l1, 1 10567c478bd9Sstevel@tonic-gate bg,a,pn %xcc, 2f 10577c478bd9Sstevel@tonic-gate mulx %l3, %l1, %l3 ! multiply interval by clock divisor iff > 1 10587c478bd9Sstevel@tonic-gate2: 10597c478bd9Sstevel@tonic-gate ! 10607c478bd9Sstevel@tonic-gate ! We need to find the CPU offset of the cumulative counter. We start 10617c478bd9Sstevel@tonic-gate ! with %o4, which has (PIL - (LOCK_LEVEL + 1)) * 8. We need PIL * 16, 10627c478bd9Sstevel@tonic-gate ! so we shift left 1, then add (LOCK_LEVEL + 1) * 16, which is 10637c478bd9Sstevel@tonic-gate ! CPU_INTRSTAT_LOW_PIL_OFFSET. 10647c478bd9Sstevel@tonic-gate ! 10657c478bd9Sstevel@tonic-gate sll %o4, 1, %o4 10667c478bd9Sstevel@tonic-gate add %o4, CPU_MCPU, %o4 ! CPU_INTRSTAT const too large 10677c478bd9Sstevel@tonic-gate add %o4, MCPU_INTRSTAT, %o4 ! add parts separately 10687c478bd9Sstevel@tonic-gate add %o4, CPU_INTRSTAT_LOW_PIL_OFFSET, %o4 10697c478bd9Sstevel@tonic-gate ldx [%o3 + %o4], %l1 ! old counter in l1 10707c478bd9Sstevel@tonic-gate add %l1, %l3, %l1 ! new counter in l1 1071eda89462Sesolom stx %l1, [%o3 + %o4] ! store new counter 1072eda89462Sesolom 1073eda89462Sesolom ! Also update intracct[] 1074eda89462Sesolom lduh [%o3 + CPU_MSTATE], %o4 1075eda89462Sesolom sllx %o4, 3, %o4 1076eda89462Sesolom add %o4, CPU_INTRACCT, %o4 1077eda89462Sesolom ldx [%o3 + %o4], %l1 1078eda89462Sesolom add %l1, %l3, %l1 10797c478bd9Sstevel@tonic-gate ! Another high-level interrupt is active below this one, so 10807c478bd9Sstevel@tonic-gate ! there is no need to check for an interrupt thread. That will be 10817c478bd9Sstevel@tonic-gate ! done by the lowest priority high-level interrupt active. 10827c478bd9Sstevel@tonic-gate ba,pt %xcc, 5f 10837c478bd9Sstevel@tonic-gate stx %l1, [%o3 + %o4] ! delay - store new counter 10847c478bd9Sstevel@tonic-gate1: 10857c478bd9Sstevel@tonic-gate ! If we haven't interrupted another high-level interrupt, we may be 10867c478bd9Sstevel@tonic-gate ! interrupting a low level interrupt thread. If so, compute its interval 10877c478bd9Sstevel@tonic-gate ! and update its cumulative counter. 10887c478bd9Sstevel@tonic-gate lduh [THREAD_REG + T_FLAGS], %o4 10897c478bd9Sstevel@tonic-gate andcc %o4, T_INTR_THREAD, %g0 10907c478bd9Sstevel@tonic-gate bz,pt %xcc, 4f 10917c478bd9Sstevel@tonic-gate nop 10927c478bd9Sstevel@tonic-gate 10937c478bd9Sstevel@tonic-gate ! We have interrupted an interrupt thread. Take timestamp, compute 10947c478bd9Sstevel@tonic-gate ! interval, update cumulative counter. 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate ! Check t_intr_start. If it is zero, either intr_thread() or 10977c478bd9Sstevel@tonic-gate ! current_thread() (at a lower PIL, of course) already did 10987c478bd9Sstevel@tonic-gate ! the accounting for the underlying interrupt thread. 10997c478bd9Sstevel@tonic-gate ldx [THREAD_REG + T_INTR_START], %o5 11007c478bd9Sstevel@tonic-gate brz,pn %o5, 4f 11017c478bd9Sstevel@tonic-gate nop 11027c478bd9Sstevel@tonic-gate 11037c478bd9Sstevel@tonic-gate stx %g0, [THREAD_REG + T_INTR_START] 1104*023e71deSHaik Aftandilian RD_TICK_NO_SUSPEND_CHECK(%o4, %l2) 11057c478bd9Sstevel@tonic-gate sub %o4, %o5, %o5 ! o5 has the interval 11067c478bd9Sstevel@tonic-gate 11077c478bd9Sstevel@tonic-gate ! Check for Energy Star mode 11087c478bd9Sstevel@tonic-gate lduh [%o3 + CPU_DIVISOR], %o4 ! %o4 = clock divisor 11097c478bd9Sstevel@tonic-gate cmp %o4, 1 11107c478bd9Sstevel@tonic-gate bg,a,pn %xcc, 2f 11117c478bd9Sstevel@tonic-gate mulx %o5, %o4, %o5 ! multiply interval by clock divisor iff > 1 11127c478bd9Sstevel@tonic-gate2: 11137c478bd9Sstevel@tonic-gate ldub [THREAD_REG + T_PIL], %o4 11147c478bd9Sstevel@tonic-gate sllx %o4, 4, %o4 ! PIL index to byte offset 11157c478bd9Sstevel@tonic-gate add %o4, CPU_MCPU, %o4 ! CPU_INTRSTAT const too large 11167c478bd9Sstevel@tonic-gate add %o4, MCPU_INTRSTAT, %o4 ! add parts separately 11177c478bd9Sstevel@tonic-gate ldx [%o3 + %o4], %l2 ! old counter in l2 11187c478bd9Sstevel@tonic-gate add %l2, %o5, %l2 ! new counter in l2 11197c478bd9Sstevel@tonic-gate stx %l2, [%o3 + %o4] ! store new counter 11207c478bd9Sstevel@tonic-gate 1121eda89462Sesolom ! Also update intracct[] 1122eda89462Sesolom lduh [%o3 + CPU_MSTATE], %o4 1123eda89462Sesolom sllx %o4, 3, %o4 1124eda89462Sesolom add %o4, CPU_INTRACCT, %o4 1125eda89462Sesolom ldx [%o3 + %o4], %l2 1126eda89462Sesolom add %l2, %o5, %l2 1127eda89462Sesolom stx %l2, [%o3 + %o4] 11287c478bd9Sstevel@tonic-gate4: 11297c478bd9Sstevel@tonic-gate ! 11307c478bd9Sstevel@tonic-gate ! Handle high-level interrupts on separate interrupt stack. 11317c478bd9Sstevel@tonic-gate ! No other high-level interrupts are active, so switch to int stack. 11327c478bd9Sstevel@tonic-gate ! 11337c478bd9Sstevel@tonic-gate mov %sp, %l1 11347c478bd9Sstevel@tonic-gate ldn [%o3 + CPU_INTR_STACK], %l3 11357c478bd9Sstevel@tonic-gate sub %l3, STACK_BIAS, %sp 11367c478bd9Sstevel@tonic-gate 11377c478bd9Sstevel@tonic-gate5: 11387c478bd9Sstevel@tonic-gate#ifdef DEBUG 11397c478bd9Sstevel@tonic-gate ! 11407c478bd9Sstevel@tonic-gate ! ASSERT(%o2 > LOCK_LEVEL) 11417c478bd9Sstevel@tonic-gate ! 11427c478bd9Sstevel@tonic-gate cmp %o2, LOCK_LEVEL 11437c478bd9Sstevel@tonic-gate bg,pt %xcc, 3f 11447c478bd9Sstevel@tonic-gate nop 11457c478bd9Sstevel@tonic-gate mov CE_PANIC, %o0 11467c478bd9Sstevel@tonic-gate sethi %hi(current_thread_wrong_pil), %o1 11477c478bd9Sstevel@tonic-gate call cmn_err ! %o2 has the %pil already 11487c478bd9Sstevel@tonic-gate or %o1, %lo(current_thread_wrong_pil), %o1 11497c478bd9Sstevel@tonic-gate#endif 11507c478bd9Sstevel@tonic-gate3: 11517c478bd9Sstevel@tonic-gate ! Store starting timestamp for this PIL in CPU structure at 11527c478bd9Sstevel@tonic-gate ! cpu.cpu_m.pil_high_start[PIL - (LOCK_LEVEL + 1)] 11537c478bd9Sstevel@tonic-gate sub %o2, LOCK_LEVEL + 1, %o4 ! convert PIL to array index 11547c478bd9Sstevel@tonic-gate sllx %o4, 3, %o4 ! index to byte offset 11557c478bd9Sstevel@tonic-gate add %o4, CPU_MCPU, %o4 ! CPU_PIL_HIGH_START is too large 11567c478bd9Sstevel@tonic-gate add %o4, MCPU_PIL_HIGH_START, %o4 1157*023e71deSHaik Aftandilian RD_TICK_NO_SUSPEND_CHECK(%o5, %l2) 11587c478bd9Sstevel@tonic-gate stx %o5, [%o3 + %o4] 11597c478bd9Sstevel@tonic-gate 11607c478bd9Sstevel@tonic-gate wrpr %g0, %o2, %pil ! enable interrupts 11617c478bd9Sstevel@tonic-gate 11627c478bd9Sstevel@tonic-gate ! 11637c478bd9Sstevel@tonic-gate ! call the handler 11647c478bd9Sstevel@tonic-gate ! 11657c478bd9Sstevel@tonic-gate SERVE_INTR_PRE(%o1, %o3, %l2, %l3, %o4, %o5, %o2, %o0) 11667c478bd9Sstevel@tonic-gate1: 11677c478bd9Sstevel@tonic-gate SERVE_INTR(%o1, %o3, %l2, %l3, %o4, %o5, %o2, %o0) 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate brz,a,pt %o2, 0f ! if %o2, more intrs await 11707c478bd9Sstevel@tonic-gate rdpr %pil, %o2 ! delay annulled 11717c478bd9Sstevel@tonic-gate SERVE_INTR_NEXT(%o1, %o3, %l2, %l3, %o4, %o5, %o2, %o0) 11727c478bd9Sstevel@tonic-gate ba 1b 11737c478bd9Sstevel@tonic-gate nop 11747c478bd9Sstevel@tonic-gate0: 11757c478bd9Sstevel@tonic-gate wrpr %g0, PIL_MAX, %pil ! disable interrupts (1-15) 11767c478bd9Sstevel@tonic-gate 11777c478bd9Sstevel@tonic-gate cmp %o2, PIL_15 11787c478bd9Sstevel@tonic-gate bne,pt %xcc, 3f 11797c478bd9Sstevel@tonic-gate nop 11807c478bd9Sstevel@tonic-gate 11817c478bd9Sstevel@tonic-gate sethi %hi(cpc_level15_inum), %o1 1182b0fc0e77Sgovinda ldx [%o1 + %lo(cpc_level15_inum)], %o1 ! arg for intr_enqueue_req 11837c478bd9Sstevel@tonic-gate brz %o1, 3f 11847c478bd9Sstevel@tonic-gate nop 11857c478bd9Sstevel@tonic-gate 11867c478bd9Sstevel@tonic-gate rdpr %pstate, %g5 11877c478bd9Sstevel@tonic-gate andn %g5, PSTATE_IE, %g1 11887c478bd9Sstevel@tonic-gate wrpr %g0, %g1, %pstate ! Disable vec interrupts 11897c478bd9Sstevel@tonic-gate 11907c478bd9Sstevel@tonic-gate call intr_enqueue_req ! preserves %g5 11917c478bd9Sstevel@tonic-gate mov PIL_15, %o0 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate ! clear perfcntr overflow 11947c478bd9Sstevel@tonic-gate mov 1, %o0 11957c478bd9Sstevel@tonic-gate sllx %o0, PIL_15, %o0 11967c478bd9Sstevel@tonic-gate wr %o0, CLEAR_SOFTINT 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate wrpr %g0, %g5, %pstate ! Enable vec interrupts 11997c478bd9Sstevel@tonic-gate 12007c478bd9Sstevel@tonic-gate3: 12017c478bd9Sstevel@tonic-gate cmp %o2, PIL_14 12027c478bd9Sstevel@tonic-gate be tick_rtt ! cpu-specific tick processing 12037c478bd9Sstevel@tonic-gate nop 12047c478bd9Sstevel@tonic-gate .global current_thread_complete 12057c478bd9Sstevel@tonic-gatecurrent_thread_complete: 12067c478bd9Sstevel@tonic-gate ! 12077c478bd9Sstevel@tonic-gate ! Register usage: 12087c478bd9Sstevel@tonic-gate ! 12097c478bd9Sstevel@tonic-gate ! %l1 = stack pointer 12107c478bd9Sstevel@tonic-gate ! %l2 = CPU_INTR_ACTV >> (LOCK_LEVEL + 1) 12117c478bd9Sstevel@tonic-gate ! %o2 = PIL 12127c478bd9Sstevel@tonic-gate ! %o3 = CPU pointer 12137c478bd9Sstevel@tonic-gate ! %o4, %o5, %l3, %l4, %l5 = scratch 12147c478bd9Sstevel@tonic-gate ! 12157c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CPU], %o3 12167c478bd9Sstevel@tonic-gate ! 12177c478bd9Sstevel@tonic-gate ! Clear bit for this level in CPU's interrupt active bitmask. 12187c478bd9Sstevel@tonic-gate ! 12197c478bd9Sstevel@tonic-gate ld [%o3 + CPU_INTR_ACTV], %l2 12207c478bd9Sstevel@tonic-gate mov 1, %o5 12217c478bd9Sstevel@tonic-gate sll %o5, %o2, %o5 12227c478bd9Sstevel@tonic-gate#ifdef DEBUG 12237c478bd9Sstevel@tonic-gate ! 12247c478bd9Sstevel@tonic-gate ! ASSERT(CPU->cpu_intr_actv & (1 << PIL)) 12257c478bd9Sstevel@tonic-gate ! 12267c478bd9Sstevel@tonic-gate andcc %l2, %o5, %g0 12277c478bd9Sstevel@tonic-gate bnz,pt %xcc, 0f 12287c478bd9Sstevel@tonic-gate nop 12297c478bd9Sstevel@tonic-gate ! Do not call panic if a panic is already in progress. 12307c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l2 12317c478bd9Sstevel@tonic-gate ld [%l2 + %lo(panic_quiesce)], %l2 12327c478bd9Sstevel@tonic-gate brnz,pn %l2, 0f 12337c478bd9Sstevel@tonic-gate nop 12347c478bd9Sstevel@tonic-gate sethi %hi(current_thread_actv_bit_not_set), %o0 12357c478bd9Sstevel@tonic-gate call panic 12367c478bd9Sstevel@tonic-gate or %o0, %lo(current_thread_actv_bit_not_set), %o0 12377c478bd9Sstevel@tonic-gate0: 12387c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 12397c478bd9Sstevel@tonic-gate andn %l2, %o5, %l2 12407c478bd9Sstevel@tonic-gate st %l2, [%o3 + CPU_INTR_ACTV] 12417c478bd9Sstevel@tonic-gate 12427c478bd9Sstevel@tonic-gate ! Take timestamp, compute interval, update cumulative counter. 12437c478bd9Sstevel@tonic-gate sub %o2, LOCK_LEVEL + 1, %o4 ! PIL to array index 12447c478bd9Sstevel@tonic-gate sllx %o4, 3, %o4 ! index to byte offset 12457c478bd9Sstevel@tonic-gate add %o4, CPU_MCPU, %o4 ! CPU_PIL_HIGH_START is too large 12467c478bd9Sstevel@tonic-gate add %o4, MCPU_PIL_HIGH_START, %o4 1247*023e71deSHaik Aftandilian RD_TICK_NO_SUSPEND_CHECK(%o5, %o0) 12487c478bd9Sstevel@tonic-gate ldx [%o3 + %o4], %o0 12497c478bd9Sstevel@tonic-gate#ifdef DEBUG 12507c478bd9Sstevel@tonic-gate ! ASSERT(cpu.cpu_m.pil_high_start[pil - (LOCK_LEVEL + 1)] != 0) 12517c478bd9Sstevel@tonic-gate brnz,pt %o0, 9f 12527c478bd9Sstevel@tonic-gate nop 12537c478bd9Sstevel@tonic-gate ! Don't panic if a panic is already in progress. 12547c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l2 12557c478bd9Sstevel@tonic-gate ld [%l2 + %lo(panic_quiesce)], %l2 12567c478bd9Sstevel@tonic-gate brnz,pn %l2, 9f 12577c478bd9Sstevel@tonic-gate nop 12587c478bd9Sstevel@tonic-gate sethi %hi(current_thread_timestamp_zero), %o0 12597c478bd9Sstevel@tonic-gate call panic 12607c478bd9Sstevel@tonic-gate or %o0, %lo(current_thread_timestamp_zero), %o0 12617c478bd9Sstevel@tonic-gate9: 12627c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 12637c478bd9Sstevel@tonic-gate stx %g0, [%o3 + %o4] 12647c478bd9Sstevel@tonic-gate sub %o5, %o0, %o5 ! interval in o5 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate ! Check for Energy Star mode 12677c478bd9Sstevel@tonic-gate lduh [%o3 + CPU_DIVISOR], %o4 ! %o4 = clock divisor 12687c478bd9Sstevel@tonic-gate cmp %o4, 1 12697c478bd9Sstevel@tonic-gate bg,a,pn %xcc, 2f 12707c478bd9Sstevel@tonic-gate mulx %o5, %o4, %o5 ! multiply interval by clock divisor iff > 1 12717c478bd9Sstevel@tonic-gate2: 12727c478bd9Sstevel@tonic-gate sllx %o2, 4, %o4 ! PIL index to byte offset 12737c478bd9Sstevel@tonic-gate add %o4, CPU_MCPU, %o4 ! CPU_INTRSTAT too large 12747c478bd9Sstevel@tonic-gate add %o4, MCPU_INTRSTAT, %o4 ! add parts separately 12757c478bd9Sstevel@tonic-gate ldx [%o3 + %o4], %o0 ! old counter in o0 12767c478bd9Sstevel@tonic-gate add %o0, %o5, %o0 ! new counter in o0 12777c478bd9Sstevel@tonic-gate stx %o0, [%o3 + %o4] ! store new counter 12787c478bd9Sstevel@tonic-gate 1279eda89462Sesolom ! Also update intracct[] 1280eda89462Sesolom lduh [%o3 + CPU_MSTATE], %o4 1281eda89462Sesolom sllx %o4, 3, %o4 1282eda89462Sesolom add %o4, CPU_INTRACCT, %o4 1283eda89462Sesolom ldx [%o3 + %o4], %o0 1284eda89462Sesolom add %o0, %o5, %o0 1285eda89462Sesolom stx %o0, [%o3 + %o4] 1286eda89462Sesolom 12877c478bd9Sstevel@tonic-gate ! 12887c478bd9Sstevel@tonic-gate ! get back on current thread's stack 12897c478bd9Sstevel@tonic-gate ! 12907c478bd9Sstevel@tonic-gate srl %l2, LOCK_LEVEL + 1, %l2 12917c478bd9Sstevel@tonic-gate tst %l2 ! any more high-level ints? 12927c478bd9Sstevel@tonic-gate movz %xcc, %l1, %sp 12937c478bd9Sstevel@tonic-gate ! 12947c478bd9Sstevel@tonic-gate ! Current register usage: 12957c478bd9Sstevel@tonic-gate ! o2 = PIL 12967c478bd9Sstevel@tonic-gate ! o3 = CPU pointer 12977c478bd9Sstevel@tonic-gate ! l0 = return address 12987c478bd9Sstevel@tonic-gate ! l2 = intr_actv shifted right 12997c478bd9Sstevel@tonic-gate ! 13007c478bd9Sstevel@tonic-gate bz,pt %xcc, 3f ! if l2 was zero, no more ints 13017c478bd9Sstevel@tonic-gate nop 13027c478bd9Sstevel@tonic-gate ! 13037c478bd9Sstevel@tonic-gate ! We found another high-level interrupt active below the one that just 13047c478bd9Sstevel@tonic-gate ! returned. Store a starting timestamp for it in the CPU structure. 13057c478bd9Sstevel@tonic-gate ! 13067c478bd9Sstevel@tonic-gate ! Use cpu_intr_actv to find the cpu_pil_high_start[] offset for the 13077c478bd9Sstevel@tonic-gate ! interrupted high-level interrupt. 13087c478bd9Sstevel@tonic-gate ! Create mask for cpu_intr_actv. Begin by looking for bits set 13097c478bd9Sstevel@tonic-gate ! at one level below the current PIL. Since %l2 contains the active 13107c478bd9Sstevel@tonic-gate ! mask already shifted right by (LOCK_LEVEL + 1), we start by looking 13117c478bd9Sstevel@tonic-gate ! at bit (current_pil - (LOCK_LEVEL + 2)). 13127c478bd9Sstevel@tonic-gate ! %l1 = mask, %o5 = index of bit set in mask 13137c478bd9Sstevel@tonic-gate ! 13147c478bd9Sstevel@tonic-gate mov 1, %l1 13157c478bd9Sstevel@tonic-gate sub %o2, LOCK_LEVEL + 2, %o5 13167c478bd9Sstevel@tonic-gate sll %l1, %o5, %l1 ! l1 = mask for level 13177c478bd9Sstevel@tonic-gate1: 13187c478bd9Sstevel@tonic-gate#ifdef DEBUG 13197c478bd9Sstevel@tonic-gate ! ASSERT(%l1 != 0) (we didn't shift the bit off the right edge) 13207c478bd9Sstevel@tonic-gate brnz,pt %l1, 9f 13217c478bd9Sstevel@tonic-gate nop 13227c478bd9Sstevel@tonic-gate sethi %hi(current_thread_nested_PIL_not_found), %o0 13237c478bd9Sstevel@tonic-gate call panic 13247c478bd9Sstevel@tonic-gate or %o0, %lo(current_thread_nested_PIL_not_found), %o0 13257c478bd9Sstevel@tonic-gate9: 13267c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 13277c478bd9Sstevel@tonic-gate andcc %l1, %l2, %g0 ! test mask against high-level bits of 13287c478bd9Sstevel@tonic-gate bnz %xcc, 2f ! cpu_intr_actv 13297c478bd9Sstevel@tonic-gate nop 13307c478bd9Sstevel@tonic-gate srl %l1, 1, %l1 ! No match. Try next lower PIL. 13317c478bd9Sstevel@tonic-gate ba,pt %xcc, 1b 13327c478bd9Sstevel@tonic-gate sub %o5, 1, %o5 ! delay - decrement PIL 13337c478bd9Sstevel@tonic-gate2: 13347c478bd9Sstevel@tonic-gate sll %o5, 3, %o5 ! convert array index to byte offset 13357c478bd9Sstevel@tonic-gate add %o5, CPU_MCPU, %o5 ! CPU_PIL_HIGH_START is too large 13367c478bd9Sstevel@tonic-gate add %o5, MCPU_PIL_HIGH_START, %o5 1337*023e71deSHaik Aftandilian RD_TICK_NO_SUSPEND_CHECK(%o4, %l2) 13387c478bd9Sstevel@tonic-gate ! Another high-level interrupt is active below this one, so 13397c478bd9Sstevel@tonic-gate ! there is no need to check for an interrupt thread. That will be 13407c478bd9Sstevel@tonic-gate ! done by the lowest priority high-level interrupt active. 134126046578Svb70745 ba,pt %xcc, 7f 13427c478bd9Sstevel@tonic-gate stx %o4, [%o3 + %o5] ! delay - store timestamp 13437c478bd9Sstevel@tonic-gate3: 13447c478bd9Sstevel@tonic-gate ! If we haven't interrupted another high-level interrupt, we may have 13457c478bd9Sstevel@tonic-gate ! interrupted a low level interrupt thread. If so, store a starting 13467c478bd9Sstevel@tonic-gate ! timestamp in its thread structure. 13477c478bd9Sstevel@tonic-gate lduh [THREAD_REG + T_FLAGS], %o4 13487c478bd9Sstevel@tonic-gate andcc %o4, T_INTR_THREAD, %g0 134926046578Svb70745 bz,pt %xcc, 7f 13507c478bd9Sstevel@tonic-gate nop 13517c478bd9Sstevel@tonic-gate 1352*023e71deSHaik Aftandilian RD_TICK_NO_SUSPEND_CHECK(%o4, %l2) 13537c478bd9Sstevel@tonic-gate stx %o4, [THREAD_REG + T_INTR_START] 135426046578Svb70745 135526046578Svb707457: 135626046578Svb70745 sub %o2, LOCK_LEVEL + 1, %o4 135726046578Svb70745 sll %o4, CPTRSHIFT, %o5 135826046578Svb70745 135926046578Svb70745 ! Check on_trap saved area and restore as needed 136026046578Svb70745 add %o5, CPU_OTD, %o4 136126046578Svb70745 ldn [%o3 + %o4], %l2 136226046578Svb70745 brz,pt %l2, no_ontrp_restore 136326046578Svb70745 nop 136426046578Svb70745 stn %l2, [THREAD_REG + T_ONTRAP] ! restore 136526046578Svb70745 stn %g0, [%o3 + %o4] ! clear 136626046578Svb70745 136726046578Svb70745no_ontrp_restore: 136826046578Svb70745 ! Check on_fault saved area and restore as needed 136926046578Svb70745 add %o5, CPU_OFD, %o4 137026046578Svb70745 ldn [%o3 + %o4], %l2 137126046578Svb70745 brz,pt %l2, 8f 137226046578Svb70745 nop 137326046578Svb70745 stn %l2, [THREAD_REG + T_ONFAULT] ! restore 137426046578Svb70745 stn %g0, [%o3 + %o4] ! clear 137526046578Svb70745 add %o5, CPU_LFD, %o4 137626046578Svb70745 ldn [%o3 + %o4], %l2 137726046578Svb70745 stn %l2, [THREAD_REG + T_LOFAULT] ! restore 137826046578Svb70745 stn %g0, [%o3 + %o4] ! clear 137926046578Svb70745 138026046578Svb70745 138126046578Svb707458: 13827c478bd9Sstevel@tonic-gate ! Enable interrupts and return 13837c478bd9Sstevel@tonic-gate jmp %l0 + 8 13847c478bd9Sstevel@tonic-gate wrpr %g0, %o2, %pil ! enable interrupts 13857c478bd9Sstevel@tonic-gate SET_SIZE(current_thread) 13867c478bd9Sstevel@tonic-gate 13877c478bd9Sstevel@tonic-gate 13887c478bd9Sstevel@tonic-gate#ifdef DEBUG 13897c478bd9Sstevel@tonic-gatecurrent_thread_wrong_pil: 13907c478bd9Sstevel@tonic-gate .asciz "current_thread: unexpected pil level: %d" 13917c478bd9Sstevel@tonic-gatecurrent_thread_actv_bit_set: 13927c478bd9Sstevel@tonic-gate .asciz "current_thread(): cpu_intr_actv bit already set for PIL" 13937c478bd9Sstevel@tonic-gatecurrent_thread_actv_bit_not_set: 13947c478bd9Sstevel@tonic-gate .asciz "current_thread(): cpu_intr_actv bit not set for PIL" 13957c478bd9Sstevel@tonic-gatecurrent_thread_nested_pil_zero: 13967c478bd9Sstevel@tonic-gate .asciz "current_thread(): timestamp zero for nested PIL %d" 13977c478bd9Sstevel@tonic-gatecurrent_thread_timestamp_zero: 13987c478bd9Sstevel@tonic-gate .asciz "current_thread(): timestamp zero upon handler return" 13997c478bd9Sstevel@tonic-gatecurrent_thread_nested_PIL_not_found: 14007c478bd9Sstevel@tonic-gate .asciz "current_thread: couldn't find nested high-level PIL" 14017c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 14027c478bd9Sstevel@tonic-gate#endif /* lint */ 14037c478bd9Sstevel@tonic-gate 14047c478bd9Sstevel@tonic-gate/* 14057c478bd9Sstevel@tonic-gate * Return a thread's interrupt level. 14067c478bd9Sstevel@tonic-gate * Since this isn't saved anywhere but in %l4 on interrupt entry, we 14077c478bd9Sstevel@tonic-gate * must dig it out of the save area. 14087c478bd9Sstevel@tonic-gate * 14097c478bd9Sstevel@tonic-gate * Caller 'swears' that this really is an interrupt thread. 14107c478bd9Sstevel@tonic-gate * 14117c478bd9Sstevel@tonic-gate * int 14127c478bd9Sstevel@tonic-gate * intr_level(t) 14137c478bd9Sstevel@tonic-gate * kthread_id_t t; 14147c478bd9Sstevel@tonic-gate */ 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate#if defined(lint) 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate/* ARGSUSED */ 14197c478bd9Sstevel@tonic-gateint 14207c478bd9Sstevel@tonic-gateintr_level(kthread_id_t t) 14217c478bd9Sstevel@tonic-gate{ return (0); } 14227c478bd9Sstevel@tonic-gate 14237c478bd9Sstevel@tonic-gate#else /* lint */ 14247c478bd9Sstevel@tonic-gate 14257c478bd9Sstevel@tonic-gate ENTRY_NP(intr_level) 14267c478bd9Sstevel@tonic-gate retl 14277c478bd9Sstevel@tonic-gate ldub [%o0 + T_PIL], %o0 ! return saved pil 14287c478bd9Sstevel@tonic-gate SET_SIZE(intr_level) 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate#endif /* lint */ 14317c478bd9Sstevel@tonic-gate 14327c478bd9Sstevel@tonic-gate#if defined(lint) 14337c478bd9Sstevel@tonic-gate 14347c478bd9Sstevel@tonic-gate/* ARGSUSED */ 14357c478bd9Sstevel@tonic-gateint 14367c478bd9Sstevel@tonic-gatedisable_pil_intr() 14377c478bd9Sstevel@tonic-gate{ return (0); } 14387c478bd9Sstevel@tonic-gate 14397c478bd9Sstevel@tonic-gate#else /* lint */ 14407c478bd9Sstevel@tonic-gate 14417c478bd9Sstevel@tonic-gate ENTRY_NP(disable_pil_intr) 14427c478bd9Sstevel@tonic-gate rdpr %pil, %o0 14437c478bd9Sstevel@tonic-gate retl 14447c478bd9Sstevel@tonic-gate wrpr %g0, PIL_MAX, %pil ! disable interrupts (1-15) 14457c478bd9Sstevel@tonic-gate SET_SIZE(disable_pil_intr) 14467c478bd9Sstevel@tonic-gate 14477c478bd9Sstevel@tonic-gate#endif /* lint */ 14487c478bd9Sstevel@tonic-gate 14497c478bd9Sstevel@tonic-gate#if defined(lint) 14507c478bd9Sstevel@tonic-gate 14517c478bd9Sstevel@tonic-gate/* ARGSUSED */ 14527c478bd9Sstevel@tonic-gatevoid 14537c478bd9Sstevel@tonic-gateenable_pil_intr(int pil_save) 14547c478bd9Sstevel@tonic-gate{} 14557c478bd9Sstevel@tonic-gate 14567c478bd9Sstevel@tonic-gate#else /* lint */ 14577c478bd9Sstevel@tonic-gate 14587c478bd9Sstevel@tonic-gate ENTRY_NP(enable_pil_intr) 14597c478bd9Sstevel@tonic-gate retl 14607c478bd9Sstevel@tonic-gate wrpr %o0, %pil 14617c478bd9Sstevel@tonic-gate SET_SIZE(enable_pil_intr) 14627c478bd9Sstevel@tonic-gate 14637c478bd9Sstevel@tonic-gate#endif /* lint */ 14647c478bd9Sstevel@tonic-gate 14657c478bd9Sstevel@tonic-gate#if defined(lint) 14667c478bd9Sstevel@tonic-gate 14677c478bd9Sstevel@tonic-gate/* ARGSUSED */ 14687c478bd9Sstevel@tonic-gateuint_t 14697c478bd9Sstevel@tonic-gatedisable_vec_intr(void) 14707c478bd9Sstevel@tonic-gate{ return (0); } 14717c478bd9Sstevel@tonic-gate 14727c478bd9Sstevel@tonic-gate#else /* lint */ 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate ENTRY_NP(disable_vec_intr) 14757c478bd9Sstevel@tonic-gate rdpr %pstate, %o0 14767c478bd9Sstevel@tonic-gate andn %o0, PSTATE_IE, %g1 14777c478bd9Sstevel@tonic-gate retl 14787c478bd9Sstevel@tonic-gate wrpr %g0, %g1, %pstate ! disable interrupt 14797c478bd9Sstevel@tonic-gate SET_SIZE(disable_vec_intr) 14807c478bd9Sstevel@tonic-gate 14817c478bd9Sstevel@tonic-gate#endif /* lint */ 14827c478bd9Sstevel@tonic-gate 14837c478bd9Sstevel@tonic-gate#if defined(lint) 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate/* ARGSUSED */ 14867c478bd9Sstevel@tonic-gatevoid 14877c478bd9Sstevel@tonic-gateenable_vec_intr(uint_t pstate_save) 14887c478bd9Sstevel@tonic-gate{} 14897c478bd9Sstevel@tonic-gate 14907c478bd9Sstevel@tonic-gate#else /* lint */ 14917c478bd9Sstevel@tonic-gate 14927c478bd9Sstevel@tonic-gate ENTRY_NP(enable_vec_intr) 14937c478bd9Sstevel@tonic-gate retl 14947c478bd9Sstevel@tonic-gate wrpr %g0, %o0, %pstate 14957c478bd9Sstevel@tonic-gate SET_SIZE(enable_vec_intr) 14967c478bd9Sstevel@tonic-gate 14977c478bd9Sstevel@tonic-gate#endif /* lint */ 14987c478bd9Sstevel@tonic-gate 14997c478bd9Sstevel@tonic-gate#if defined(lint) 15007c478bd9Sstevel@tonic-gate 15017c478bd9Sstevel@tonic-gatevoid 15027c478bd9Sstevel@tonic-gatecbe_level14(void) 15037c478bd9Sstevel@tonic-gate{} 15047c478bd9Sstevel@tonic-gate 15057c478bd9Sstevel@tonic-gate#else /* lint */ 15067c478bd9Sstevel@tonic-gate 15077c478bd9Sstevel@tonic-gate ENTRY_NP(cbe_level14) 15087c478bd9Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp ! get a new window 15097c478bd9Sstevel@tonic-gate ! 15107c478bd9Sstevel@tonic-gate ! Make sure that this is from TICK_COMPARE; if not just return 15117c478bd9Sstevel@tonic-gate ! 15127c478bd9Sstevel@tonic-gate rd SOFTINT, %l1 15137c478bd9Sstevel@tonic-gate set (TICK_INT_MASK | STICK_INT_MASK), %o2 15147c478bd9Sstevel@tonic-gate andcc %l1, %o2, %g0 15157c478bd9Sstevel@tonic-gate bz,pn %icc, 2f 15167c478bd9Sstevel@tonic-gate nop 15177c478bd9Sstevel@tonic-gate 15187c478bd9Sstevel@tonic-gate CPU_ADDR(%o1, %o2) 15197c478bd9Sstevel@tonic-gate call cyclic_fire 15207c478bd9Sstevel@tonic-gate mov %o1, %o0 15217c478bd9Sstevel@tonic-gate2: 15227c478bd9Sstevel@tonic-gate ret 15237c478bd9Sstevel@tonic-gate restore %g0, 1, %o0 15247c478bd9Sstevel@tonic-gate SET_SIZE(cbe_level14) 15257c478bd9Sstevel@tonic-gate 15267c478bd9Sstevel@tonic-gate#endif /* lint */ 15277c478bd9Sstevel@tonic-gate 15287c478bd9Sstevel@tonic-gate 15297c478bd9Sstevel@tonic-gate#if defined(lint) 15307c478bd9Sstevel@tonic-gate 15317c478bd9Sstevel@tonic-gate/* ARGSUSED */ 15327c478bd9Sstevel@tonic-gatevoid 1533a1af7ba0Scwbkdi_setsoftint(uint64_t iv_p) 15347c478bd9Sstevel@tonic-gate{} 15357c478bd9Sstevel@tonic-gate 15367c478bd9Sstevel@tonic-gate#else /* lint */ 15377c478bd9Sstevel@tonic-gate 1538a1af7ba0Scwb ENTRY_NP(kdi_setsoftint) 15397c478bd9Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp ! get a new window 15407c478bd9Sstevel@tonic-gate rdpr %pstate, %l5 15417c478bd9Sstevel@tonic-gate andn %l5, PSTATE_IE, %l1 15427c478bd9Sstevel@tonic-gate wrpr %l1, %pstate ! disable interrupt 15437c478bd9Sstevel@tonic-gate ! 1544b0fc0e77Sgovinda ! We have a pointer to an interrupt vector data structure. 1545b0fc0e77Sgovinda ! Put the request on the cpu's softint priority list and 1546b0fc0e77Sgovinda ! set %set_softint. 15477c478bd9Sstevel@tonic-gate ! 15487c478bd9Sstevel@tonic-gate ! Register usage 1549b0fc0e77Sgovinda ! %i0 - pointer to intr_vec_t (iv) 15507c478bd9Sstevel@tonic-gate ! %l2 - requested pil 1551b0fc0e77Sgovinda ! %l4 - cpu 1552b0fc0e77Sgovinda ! %l5 - pstate 1553b0fc0e77Sgovinda ! %l1, %l3, %l6 - temps 15547c478bd9Sstevel@tonic-gate ! 1555b0fc0e77Sgovinda ! check if a softint is pending for this softint, 1556b0fc0e77Sgovinda ! if one is pending, don't bother queuing another. 15577c478bd9Sstevel@tonic-gate ! 1558b0fc0e77Sgovinda lduh [%i0 + IV_FLAGS], %l1 ! %l1 = iv->iv_flags 1559b0fc0e77Sgovinda and %l1, IV_SOFTINT_PEND, %l6 ! %l6 = iv->iv_flags & IV_SOFTINT_PEND 1560b0fc0e77Sgovinda brnz,pn %l6, 4f ! branch if softint is already pending 1561b0fc0e77Sgovinda or %l1, IV_SOFTINT_PEND, %l2 1562b0fc0e77Sgovinda sth %l2, [%i0 + IV_FLAGS] ! Set IV_SOFTINT_PEND flag 1563b0fc0e77Sgovinda 1564b0fc0e77Sgovinda CPU_ADDR(%l4, %l2) ! %l4 = cpu 1565b0fc0e77Sgovinda lduh [%i0 + IV_PIL], %l2 ! %l2 = iv->iv_pil 1566b0fc0e77Sgovinda 15677c478bd9Sstevel@tonic-gate ! 1568b0fc0e77Sgovinda ! Insert intr_vec_t (iv) to appropriate cpu's softint priority list 15697c478bd9Sstevel@tonic-gate ! 1570b0fc0e77Sgovinda sll %l2, CPTRSHIFT, %l0 ! %l0 = offset to pil entry 1571b0fc0e77Sgovinda add %l4, INTR_TAIL, %l6 ! %l6 = &cpu->m_cpu.intr_tail 1572b0fc0e77Sgovinda ldn [%l6 + %l0], %l1 ! %l1 = cpu->m_cpu.intr_tail[pil] 1573b0fc0e77Sgovinda ! current tail (ct) 1574b0fc0e77Sgovinda brz,pt %l1, 2f ! branch if current tail is NULL 1575b0fc0e77Sgovinda stn %i0, [%l6 + %l0] ! make intr_vec_t (iv) as new tail 15767c478bd9Sstevel@tonic-gate ! 1577b0fc0e77Sgovinda ! there's pending intr_vec_t already 15787c478bd9Sstevel@tonic-gate ! 1579b0fc0e77Sgovinda lduh [%l1 + IV_FLAGS], %l6 ! %l6 = ct->iv_flags 1580b0fc0e77Sgovinda and %l6, IV_SOFTINT_MT, %l6 ! %l6 = ct->iv_flags & IV_SOFTINT_MT 1581b0fc0e77Sgovinda brz,pt %l6, 1f ! check for Multi target softint flag 1582b0fc0e77Sgovinda add %l1, IV_PIL_NEXT, %l3 ! %l3 = &ct->iv_pil_next 1583b0fc0e77Sgovinda ld [%l4 + CPU_ID], %l6 ! for multi target softint, use cpuid 1584b0fc0e77Sgovinda sll %l6, CPTRSHIFT, %l6 ! calculate offset address from cpuid 1585b0fc0e77Sgovinda add %l3, %l6, %l3 ! %l3 = &ct->iv_xpil_next[cpuid] 1586b0fc0e77Sgovinda1: 15877c478bd9Sstevel@tonic-gate ! 1588b0fc0e77Sgovinda ! update old tail 15897c478bd9Sstevel@tonic-gate ! 15907c478bd9Sstevel@tonic-gate ba,pt %xcc, 3f 1591b0fc0e77Sgovinda stn %i0, [%l3] ! [%l3] = iv, set pil_next field 15927c478bd9Sstevel@tonic-gate2: 15937c478bd9Sstevel@tonic-gate ! 1594b0fc0e77Sgovinda ! no pending intr_vec_t; make intr_vec_t as new head 15957c478bd9Sstevel@tonic-gate ! 1596b0fc0e77Sgovinda add %l4, INTR_HEAD, %l6 ! %l6 = &cpu->m_cpu.intr_head[pil] 1597b0fc0e77Sgovinda stn %i0, [%l6 + %l0] ! cpu->m_cpu.intr_head[pil] = iv 15987c478bd9Sstevel@tonic-gate3: 15997c478bd9Sstevel@tonic-gate ! 16007c478bd9Sstevel@tonic-gate ! Write %set_softint with (1<<pil) to cause a "pil" level trap 16017c478bd9Sstevel@tonic-gate ! 1602b0fc0e77Sgovinda mov 1, %l1 ! %l1 = 1 1603b0fc0e77Sgovinda sll %l1, %l2, %l1 ! %l1 = 1 << pil 1604b0fc0e77Sgovinda wr %l1, SET_SOFTINT ! trigger required pil softint 16057c478bd9Sstevel@tonic-gate4: 1606b0fc0e77Sgovinda wrpr %g0, %l5, %pstate ! %pstate = saved %pstate (in %l5) 16077c478bd9Sstevel@tonic-gate ret 16087c478bd9Sstevel@tonic-gate restore 1609a1af7ba0Scwb SET_SIZE(kdi_setsoftint) 16107c478bd9Sstevel@tonic-gate 16117c478bd9Sstevel@tonic-gate#endif /* lint */ 16127c478bd9Sstevel@tonic-gate 16137c478bd9Sstevel@tonic-gate#if defined(lint) 16147c478bd9Sstevel@tonic-gate 16157c478bd9Sstevel@tonic-gate/*ARGSUSED*/ 16167c478bd9Sstevel@tonic-gatevoid 1617b0fc0e77Sgovindasetsoftint_tl1(uint64_t iv_p, uint64_t dummy) 16187c478bd9Sstevel@tonic-gate{} 16197c478bd9Sstevel@tonic-gate 16207c478bd9Sstevel@tonic-gate#else /* lint */ 16217c478bd9Sstevel@tonic-gate 16227c478bd9Sstevel@tonic-gate ! 16237c478bd9Sstevel@tonic-gate ! Register usage 1624b0fc0e77Sgovinda ! Arguments: 1625b0fc0e77Sgovinda ! %g1 - Pointer to intr_vec_t (iv) 16267c478bd9Sstevel@tonic-gate ! 1627b0fc0e77Sgovinda ! Internal: 1628b0fc0e77Sgovinda ! %g2 - pil 1629b0fc0e77Sgovinda ! %g4 - cpu 1630b0fc0e77Sgovinda ! %g3,%g5-g7 - temps 1631b0fc0e77Sgovinda ! 1632b0fc0e77Sgovinda ENTRY_NP(setsoftint_tl1) 1633b0fc0e77Sgovinda ! 1634b0fc0e77Sgovinda ! We have a pointer to an interrupt vector data structure. 1635b0fc0e77Sgovinda ! Put the request on the cpu's softint priority list and 1636b0fc0e77Sgovinda ! set %set_softint. 1637b0fc0e77Sgovinda ! 1638b0fc0e77Sgovinda CPU_ADDR(%g4, %g2) ! %g4 = cpu 1639b0fc0e77Sgovinda lduh [%g1 + IV_PIL], %g2 ! %g2 = iv->iv_pil 1640b0fc0e77Sgovinda 1641b0fc0e77Sgovinda ! 1642b0fc0e77Sgovinda ! Insert intr_vec_t (iv) to appropriate cpu's softint priority list 1643b0fc0e77Sgovinda ! 1644b0fc0e77Sgovinda sll %g2, CPTRSHIFT, %g7 ! %g7 = offset to pil entry 1645b0fc0e77Sgovinda add %g4, INTR_TAIL, %g6 ! %g6 = &cpu->m_cpu.intr_tail 1646b0fc0e77Sgovinda ldn [%g6 + %g7], %g5 ! %g5 = cpu->m_cpu.intr_tail[pil] 1647b0fc0e77Sgovinda ! current tail (ct) 1648b0fc0e77Sgovinda brz,pt %g5, 1f ! branch if current tail is NULL 1649b0fc0e77Sgovinda stn %g1, [%g6 + %g7] ! make intr_rec_t (iv) as new tail 1650b0fc0e77Sgovinda ! 1651b0fc0e77Sgovinda ! there's pending intr_vec_t already 1652b0fc0e77Sgovinda ! 1653b0fc0e77Sgovinda lduh [%g5 + IV_FLAGS], %g6 ! %g6 = ct->iv_flags 1654b0fc0e77Sgovinda and %g6, IV_SOFTINT_MT, %g6 ! %g6 = ct->iv_flags & IV_SOFTINT_MT 1655b0fc0e77Sgovinda brz,pt %g6, 0f ! check for Multi target softint flag 1656b0fc0e77Sgovinda add %g5, IV_PIL_NEXT, %g3 ! %g3 = &ct->iv_pil_next 1657b0fc0e77Sgovinda ld [%g4 + CPU_ID], %g6 ! for multi target softint, use cpuid 1658b0fc0e77Sgovinda sll %g6, CPTRSHIFT, %g6 ! calculate offset address from cpuid 1659b0fc0e77Sgovinda add %g3, %g6, %g3 ! %g3 = &ct->iv_xpil_next[cpuid] 1660b0fc0e77Sgovinda0: 1661b0fc0e77Sgovinda ! 1662b0fc0e77Sgovinda ! update old tail 1663b0fc0e77Sgovinda ! 1664b0fc0e77Sgovinda ba,pt %xcc, 2f 1665b0fc0e77Sgovinda stn %g1, [%g3] ! [%g3] = iv, set pil_next field 1666b0fc0e77Sgovinda1: 1667b0fc0e77Sgovinda ! 1668b0fc0e77Sgovinda ! no pending intr_vec_t; make intr_vec_t as new head 1669b0fc0e77Sgovinda ! 1670b0fc0e77Sgovinda add %g4, INTR_HEAD, %g6 ! %g6 = &cpu->m_cpu.intr_head[pil] 1671b0fc0e77Sgovinda stn %g1, [%g6 + %g7] ! cpu->m_cpu.intr_head[pil] = iv 1672b0fc0e77Sgovinda2: 1673b0fc0e77Sgovinda#ifdef TRAPTRACE 1674b0fc0e77Sgovinda TRACE_PTR(%g5, %g6) 1675*023e71deSHaik Aftandilian GET_TRACE_TICK(%g6, %g3) 1676b0fc0e77Sgovinda stxa %g6, [%g5 + TRAP_ENT_TICK]%asi ! trap_tick = %tick 1677b0fc0e77Sgovinda TRACE_SAVE_TL_GL_REGS(%g5, %g6) 1678b0fc0e77Sgovinda rdpr %tt, %g6 1679b0fc0e77Sgovinda stha %g6, [%g5 + TRAP_ENT_TT]%asi ! trap_type = %tt 1680b0fc0e77Sgovinda rdpr %tpc, %g6 1681b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_TPC]%asi ! trap_pc = %tpc 1682b0fc0e77Sgovinda rdpr %tstate, %g6 1683b0fc0e77Sgovinda stxa %g6, [%g5 + TRAP_ENT_TSTATE]%asi ! trap_tstate = %tstate 1684b0fc0e77Sgovinda stna %sp, [%g5 + TRAP_ENT_SP]%asi ! trap_sp = %sp 1685b0fc0e77Sgovinda stna %g1, [%g5 + TRAP_ENT_TR]%asi ! trap_tr = iv 1686b0fc0e77Sgovinda ldn [%g1 + IV_PIL_NEXT], %g6 ! 1687b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_F1]%asi ! trap_f1 = iv->iv_pil_next 1688b0fc0e77Sgovinda add %g4, INTR_HEAD, %g6 1689b0fc0e77Sgovinda ldn [%g6 + %g7], %g6 ! %g6=cpu->m_cpu.intr_head[pil] 1690b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_F2]%asi ! trap_f2 = intr_head[pil] 1691b0fc0e77Sgovinda add %g4, INTR_TAIL, %g6 1692b0fc0e77Sgovinda ldn [%g6 + %g7], %g6 ! %g6=cpu->m_cpu.intr_tail[pil] 1693b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_F3]%asi ! trap_f3 = intr_tail[pil] 1694b0fc0e77Sgovinda stna %g2, [%g5 + TRAP_ENT_F4]%asi ! trap_f4 = pil 1695b0fc0e77Sgovinda TRACE_NEXT(%g5, %g6, %g3) 1696b0fc0e77Sgovinda#endif /* TRAPTRACE */ 1697b0fc0e77Sgovinda ! 1698b0fc0e77Sgovinda ! Write %set_softint with (1<<pil) to cause a "pil" level trap 1699b0fc0e77Sgovinda ! 1700b0fc0e77Sgovinda mov 1, %g5 ! %g5 = 1 1701b0fc0e77Sgovinda sll %g5, %g2, %g5 ! %g5 = 1 << pil 1702b0fc0e77Sgovinda wr %g5, SET_SOFTINT ! trigger required pil softint 1703b0fc0e77Sgovinda retry 1704b0fc0e77Sgovinda SET_SIZE(setsoftint_tl1) 1705b0fc0e77Sgovinda 1706b0fc0e77Sgovinda#endif /* lint */ 1707b0fc0e77Sgovinda 1708b0fc0e77Sgovinda#if defined(lint) 1709b0fc0e77Sgovinda 1710b0fc0e77Sgovinda/*ARGSUSED*/ 1711b0fc0e77Sgovindavoid 1712b0fc0e77Sgovindasetvecint_tl1(uint64_t inum, uint64_t dummy) 1713b0fc0e77Sgovinda{} 1714b0fc0e77Sgovinda 1715b0fc0e77Sgovinda#else /* lint */ 1716b0fc0e77Sgovinda 1717b0fc0e77Sgovinda ! 1718b0fc0e77Sgovinda ! Register usage 17197c478bd9Sstevel@tonic-gate ! Arguments: 17207c478bd9Sstevel@tonic-gate ! %g1 - inumber 17217c478bd9Sstevel@tonic-gate ! 17227c478bd9Sstevel@tonic-gate ! Internal: 1723b0fc0e77Sgovinda ! %g1 - softint pil mask 1724b0fc0e77Sgovinda ! %g2 - pil of intr_vec_t 1725b0fc0e77Sgovinda ! %g3 - pointer to current intr_vec_t (iv) 1726b0fc0e77Sgovinda ! %g4 - cpu 17277c478bd9Sstevel@tonic-gate ! %g5, %g6,%g7 - temps 17287c478bd9Sstevel@tonic-gate ! 1729b0fc0e77Sgovinda ENTRY_NP(setvecint_tl1) 17307c478bd9Sstevel@tonic-gate ! 17317c478bd9Sstevel@tonic-gate ! Verify the inumber received (should be inum < MAXIVNUM). 17327c478bd9Sstevel@tonic-gate ! 17337c478bd9Sstevel@tonic-gate set MAXIVNUM, %g2 17347c478bd9Sstevel@tonic-gate cmp %g1, %g2 17357c478bd9Sstevel@tonic-gate bgeu,pn %xcc, .no_ivintr 17367c478bd9Sstevel@tonic-gate clr %g2 ! expected in .no_ivintr 17377c478bd9Sstevel@tonic-gate 17387c478bd9Sstevel@tonic-gate ! 1739b0fc0e77Sgovinda ! Fetch data from intr_vec_table according to the inum. 17407c478bd9Sstevel@tonic-gate ! 1741b0fc0e77Sgovinda ! We have an interrupt number. Fetch the interrupt vector requests 1742b0fc0e77Sgovinda ! from the interrupt vector table for a given interrupt number and 1743b0fc0e77Sgovinda ! insert them into cpu's softint priority lists and set %set_softint. 1744b0fc0e77Sgovinda ! 1745b0fc0e77Sgovinda set intr_vec_table, %g5 ! %g5 = intr_vec_table 1746b0fc0e77Sgovinda sll %g1, CPTRSHIFT, %g6 ! %g6 = offset to inum entry in table 1747b0fc0e77Sgovinda add %g5, %g6, %g5 ! %g5 = &intr_vec_table[inum] 1748b0fc0e77Sgovinda ldn [%g5], %g3 ! %g3 = pointer to first entry of 1749b0fc0e77Sgovinda ! intr_vec_t list 17507c478bd9Sstevel@tonic-gate 1751b0fc0e77Sgovinda ! Verify the first intr_vec_t pointer for a given inum and it should 1752b0fc0e77Sgovinda ! not be NULL. This used to be guarded by DEBUG but broken drivers can 1753b0fc0e77Sgovinda ! cause spurious tick interrupts when the softint register is programmed 1754b0fc0e77Sgovinda ! with 1 << 0 at the end of this routine. Now we always check for a 1755b0fc0e77Sgovinda ! valid intr_vec_t pointer. 1756b0fc0e77Sgovinda brz,pn %g3, .no_ivintr 17577c478bd9Sstevel@tonic-gate nop 17587c478bd9Sstevel@tonic-gate 17597c478bd9Sstevel@tonic-gate ! 1760b0fc0e77Sgovinda ! Traverse the intr_vec_t link list, put each item on to corresponding 1761b0fc0e77Sgovinda ! CPU softint priority queue, and compose the final softint pil mask. 17627c478bd9Sstevel@tonic-gate ! 1763b0fc0e77Sgovinda ! At this point: 1764b0fc0e77Sgovinda ! %g3 = intr_vec_table[inum] 17657c478bd9Sstevel@tonic-gate ! 1766b0fc0e77Sgovinda CPU_ADDR(%g4, %g2) ! %g4 = cpu 1767b0fc0e77Sgovinda mov %g0, %g1 ! %g1 = 0, initialize pil mask to 0 1768b0fc0e77Sgovinda0: 17697c478bd9Sstevel@tonic-gate ! 1770b0fc0e77Sgovinda ! Insert next intr_vec_t (iv) to appropriate cpu's softint priority list 17717c478bd9Sstevel@tonic-gate ! 1772b0fc0e77Sgovinda ! At this point: 1773b0fc0e77Sgovinda ! %g1 = softint pil mask 1774b0fc0e77Sgovinda ! %g3 = pointer to next intr_vec_t (iv) 1775b0fc0e77Sgovinda ! %g4 = cpu 17767c478bd9Sstevel@tonic-gate ! 1777b0fc0e77Sgovinda lduh [%g3 + IV_PIL], %g2 ! %g2 = iv->iv_pil 1778b0fc0e77Sgovinda sll %g2, CPTRSHIFT, %g7 ! %g7 = offset to pil entry 1779b0fc0e77Sgovinda add %g4, INTR_TAIL, %g6 ! %g6 = &cpu->m_cpu.intr_tail 1780b0fc0e77Sgovinda ldn [%g6 + %g7], %g5 ! %g5 = cpu->m_cpu.intr_tail[pil] 1781b0fc0e77Sgovinda ! current tail (ct) 1782b0fc0e77Sgovinda brz,pt %g5, 2f ! branch if current tail is NULL 1783b0fc0e77Sgovinda stn %g3, [%g6 + %g7] ! make intr_vec_t (iv) as new tail 1784b0fc0e77Sgovinda ! cpu->m_cpu.intr_tail[pil] = iv 17857c478bd9Sstevel@tonic-gate ! 1786b0fc0e77Sgovinda ! there's pending intr_vec_t already 1787b0fc0e77Sgovinda ! 1788b0fc0e77Sgovinda lduh [%g5 + IV_FLAGS], %g6 ! %g6 = ct->iv_flags 1789b0fc0e77Sgovinda and %g6, IV_SOFTINT_MT, %g6 ! %g6 = ct->iv_flags & IV_SOFTINT_MT 1790b0fc0e77Sgovinda brz,pt %g6, 1f ! check for Multi target softint flag 1791b0fc0e77Sgovinda add %g5, IV_PIL_NEXT, %g5 ! %g5 = &ct->iv_pil_next 1792b0fc0e77Sgovinda ld [%g4 + CPU_ID], %g6 ! for multi target softint, use cpuid 1793b0fc0e77Sgovinda sll %g6, CPTRSHIFT, %g6 ! calculate offset address from cpuid 1794b0fc0e77Sgovinda add %g5, %g6, %g5 ! %g5 = &ct->iv_xpil_next[cpuid] 1795b0fc0e77Sgovinda1: 1796b0fc0e77Sgovinda ! 1797b0fc0e77Sgovinda ! update old tail 17987c478bd9Sstevel@tonic-gate ! 17997c478bd9Sstevel@tonic-gate ba,pt %xcc, 3f 1800b0fc0e77Sgovinda stn %g3, [%g5] ! [%g5] = iv, set pil_next field 18017c478bd9Sstevel@tonic-gate2: 18027c478bd9Sstevel@tonic-gate ! 1803b0fc0e77Sgovinda ! no pending intr_vec_t; make intr_vec_t as new head 18047c478bd9Sstevel@tonic-gate ! 1805b0fc0e77Sgovinda add %g4, INTR_HEAD, %g6 ! %g6 = &cpu->m_cpu.intr_head[pil] 1806b0fc0e77Sgovinda stn %g3, [%g6 + %g7] ! cpu->m_cpu.intr_head[pil] = iv 18077c478bd9Sstevel@tonic-gate3: 18087c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE 1809b0fc0e77Sgovinda TRACE_PTR(%g5, %g6) 1810b0fc0e77Sgovinda TRACE_SAVE_TL_GL_REGS(%g5, %g6) 18117c478bd9Sstevel@tonic-gate rdpr %tt, %g6 1812b0fc0e77Sgovinda stha %g6, [%g5 + TRAP_ENT_TT]%asi ! trap_type = %tt` 18137c478bd9Sstevel@tonic-gate rdpr %tpc, %g6 1814b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_TPC]%asi ! trap_pc = %tpc 18157c478bd9Sstevel@tonic-gate rdpr %tstate, %g6 1816b0fc0e77Sgovinda stxa %g6, [%g5 + TRAP_ENT_TSTATE]%asi ! trap_tstate = %tstate 1817b0fc0e77Sgovinda stna %sp, [%g5 + TRAP_ENT_SP]%asi ! trap_sp = %sp 1818b0fc0e77Sgovinda stna %g3, [%g5 + TRAP_ENT_TR]%asi ! trap_tr = iv 1819b0fc0e77Sgovinda stna %g1, [%g5 + TRAP_ENT_F1]%asi ! trap_f1 = pil mask 18207c478bd9Sstevel@tonic-gate add %g4, INTR_HEAD, %g6 1821b0fc0e77Sgovinda ldn [%g6 + %g7], %g6 ! %g6=cpu->m_cpu.intr_head[pil] 1822b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_F2]%asi ! trap_f2 = intr_head[pil] 18237c478bd9Sstevel@tonic-gate add %g4, INTR_TAIL, %g6 1824b0fc0e77Sgovinda ldn [%g6 + %g7], %g6 ! %g6=cpu->m_cpu.intr_tail[pil] 1825b0fc0e77Sgovinda stna %g6, [%g5 + TRAP_ENT_F3]%asi ! trap_f3 = intr_tail[pil] 1826b0fc0e77Sgovinda stna %g2, [%g5 + TRAP_ENT_F4]%asi ! trap_f4 = pil 1827*023e71deSHaik Aftandilian GET_TRACE_TICK(%g6, %g7) 1828*023e71deSHaik Aftandilian stxa %g6, [%g5 + TRAP_ENT_TICK]%asi ! trap_tick = %tick 1829b0fc0e77Sgovinda TRACE_NEXT(%g5, %g6, %g7) 18307c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */ 1831b0fc0e77Sgovinda mov 1, %g6 ! %g6 = 1 1832b0fc0e77Sgovinda sll %g6, %g2, %g6 ! %g6 = 1 << pil 1833b0fc0e77Sgovinda or %g1, %g6, %g1 ! %g1 |= (1 << pil), pil mask 1834b0fc0e77Sgovinda ldn [%g3 + IV_VEC_NEXT], %g3 ! %g3 = pointer to next intr_vec_t (iv) 1835b0fc0e77Sgovinda brnz,pn %g3, 0b ! iv->iv_vec_next is non NULL, goto 0b 1836b0fc0e77Sgovinda nop 1837b0fc0e77Sgovinda wr %g1, SET_SOFTINT ! triggered one or more pil softints 18387c478bd9Sstevel@tonic-gate retry 18397c478bd9Sstevel@tonic-gate 18407c478bd9Sstevel@tonic-gate.no_ivintr: 18417c478bd9Sstevel@tonic-gate ! no_ivintr: arguments: rp, inum (%g1), pil (%g2 == 0) 18427c478bd9Sstevel@tonic-gate mov %g2, %g3 18437c478bd9Sstevel@tonic-gate mov %g1, %g2 18447c478bd9Sstevel@tonic-gate set no_ivintr, %g1 18457c478bd9Sstevel@tonic-gate ba,pt %xcc, sys_trap 18467c478bd9Sstevel@tonic-gate mov PIL_15, %g4 1847b0fc0e77Sgovinda SET_SIZE(setvecint_tl1) 18487c478bd9Sstevel@tonic-gate 18497c478bd9Sstevel@tonic-gate#endif /* lint */ 18507c478bd9Sstevel@tonic-gate 18517c478bd9Sstevel@tonic-gate#if defined(lint) 18527c478bd9Sstevel@tonic-gate 18537c478bd9Sstevel@tonic-gate/*ARGSUSED*/ 18547c478bd9Sstevel@tonic-gatevoid 18557c478bd9Sstevel@tonic-gatewr_clr_softint(uint_t value) 18567c478bd9Sstevel@tonic-gate{} 18577c478bd9Sstevel@tonic-gate 18587c478bd9Sstevel@tonic-gate#else 18597c478bd9Sstevel@tonic-gate 18607c478bd9Sstevel@tonic-gate ENTRY_NP(wr_clr_softint) 18617c478bd9Sstevel@tonic-gate retl 18627c478bd9Sstevel@tonic-gate wr %o0, CLEAR_SOFTINT 18637c478bd9Sstevel@tonic-gate SET_SIZE(wr_clr_softint) 18647c478bd9Sstevel@tonic-gate 18657c478bd9Sstevel@tonic-gate#endif /* lint */ 18667c478bd9Sstevel@tonic-gate 18677c478bd9Sstevel@tonic-gate#if defined(lint) 18687c478bd9Sstevel@tonic-gate 18697c478bd9Sstevel@tonic-gate/*ARGSUSED*/ 18707c478bd9Sstevel@tonic-gatevoid 1871b0fc0e77Sgovindaintr_enqueue_req(uint_t pil, uint64_t inum) 18727c478bd9Sstevel@tonic-gate{} 18737c478bd9Sstevel@tonic-gate 18747c478bd9Sstevel@tonic-gate#else /* lint */ 18757c478bd9Sstevel@tonic-gate 18767c478bd9Sstevel@tonic-gate/* 18777c478bd9Sstevel@tonic-gate * intr_enqueue_req 18787c478bd9Sstevel@tonic-gate * 18797c478bd9Sstevel@tonic-gate * %o0 - pil 1880b0fc0e77Sgovinda * %o1 - pointer to intr_vec_t (iv) 18817c478bd9Sstevel@tonic-gate * %o5 - preserved 18827c478bd9Sstevel@tonic-gate * %g5 - preserved 18837c478bd9Sstevel@tonic-gate */ 18847c478bd9Sstevel@tonic-gate ENTRY_NP(intr_enqueue_req) 1885b0fc0e77Sgovinda ! 1886b0fc0e77Sgovinda CPU_ADDR(%g4, %g1) ! %g4 = cpu 18877c478bd9Sstevel@tonic-gate 1888b0fc0e77Sgovinda ! 1889b0fc0e77Sgovinda ! Insert intr_vec_t (iv) to appropriate cpu's softint priority list 1890b0fc0e77Sgovinda ! 1891b0fc0e77Sgovinda sll %o0, CPTRSHIFT, %o0 ! %o0 = offset to pil entry 1892b0fc0e77Sgovinda add %g4, INTR_TAIL, %g6 ! %g6 = &cpu->m_cpu.intr_tail 1893b0fc0e77Sgovinda ldn [%o0 + %g6], %g1 ! %g1 = cpu->m_cpu.intr_tail[pil] 1894b0fc0e77Sgovinda ! current tail (ct) 1895b0fc0e77Sgovinda brz,pt %g1, 2f ! branch if current tail is NULL 1896b0fc0e77Sgovinda stn %o1, [%g6 + %o0] ! make intr_vec_t (iv) as new tail 18977c478bd9Sstevel@tonic-gate 1898b0fc0e77Sgovinda ! 1899b0fc0e77Sgovinda ! there's pending intr_vec_t already 1900b0fc0e77Sgovinda ! 1901b0fc0e77Sgovinda lduh [%g1 + IV_FLAGS], %g6 ! %g6 = ct->iv_flags 1902b0fc0e77Sgovinda and %g6, IV_SOFTINT_MT, %g6 ! %g6 = ct->iv_flags & IV_SOFTINT_MT 1903b0fc0e77Sgovinda brz,pt %g6, 1f ! check for Multi target softint flag 1904b0fc0e77Sgovinda add %g1, IV_PIL_NEXT, %g3 ! %g3 = &ct->iv_pil_next 1905b0fc0e77Sgovinda ld [%g4 + CPU_ID], %g6 ! for multi target softint, use cpuid 1906b0fc0e77Sgovinda sll %g6, CPTRSHIFT, %g6 ! calculate offset address from cpuid 1907b0fc0e77Sgovinda add %g3, %g6, %g3 ! %g3 = &ct->iv_xpil_next[cpuid] 1908b0fc0e77Sgovinda1: 1909b0fc0e77Sgovinda ! 1910b0fc0e77Sgovinda ! update old tail 1911b0fc0e77Sgovinda ! 19127c478bd9Sstevel@tonic-gate ba,pt %xcc, 3f 1913b0fc0e77Sgovinda stn %o1, [%g3] ! {%g5] = iv, set pil_next field 19147c478bd9Sstevel@tonic-gate2: 1915b0fc0e77Sgovinda ! 1916b0fc0e77Sgovinda ! no intr_vec_t's queued so make intr_vec_t as new head 1917b0fc0e77Sgovinda ! 1918b0fc0e77Sgovinda add %g4, INTR_HEAD, %g6 ! %g6 = &cpu->m_cpu.intr_head[pil] 1919b0fc0e77Sgovinda stn %o1, [%g6 + %o0] ! cpu->m_cpu.intr_head[pil] = iv 19207c478bd9Sstevel@tonic-gate3: 19217c478bd9Sstevel@tonic-gate retl 19227c478bd9Sstevel@tonic-gate nop 19237c478bd9Sstevel@tonic-gate SET_SIZE(intr_enqueue_req) 19247c478bd9Sstevel@tonic-gate 19257c478bd9Sstevel@tonic-gate#endif /* lint */ 19267c478bd9Sstevel@tonic-gate 19277c478bd9Sstevel@tonic-gate/* 19287c478bd9Sstevel@tonic-gate * Set CPU's base SPL level, based on which interrupt levels are active. 19297c478bd9Sstevel@tonic-gate * Called at spl7 or above. 19307c478bd9Sstevel@tonic-gate */ 19317c478bd9Sstevel@tonic-gate 19327c478bd9Sstevel@tonic-gate#if defined(lint) 19337c478bd9Sstevel@tonic-gate 19347c478bd9Sstevel@tonic-gatevoid 19357c478bd9Sstevel@tonic-gateset_base_spl(void) 19367c478bd9Sstevel@tonic-gate{} 19377c478bd9Sstevel@tonic-gate 19387c478bd9Sstevel@tonic-gate#else /* lint */ 19397c478bd9Sstevel@tonic-gate 19407c478bd9Sstevel@tonic-gate ENTRY_NP(set_base_spl) 19417c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CPU], %o2 ! load CPU pointer 19427c478bd9Sstevel@tonic-gate ld [%o2 + CPU_INTR_ACTV], %o5 ! load active interrupts mask 19437c478bd9Sstevel@tonic-gate 19447c478bd9Sstevel@tonic-gate/* 19457c478bd9Sstevel@tonic-gate * WARNING: non-standard callinq sequence; do not call from C 19467c478bd9Sstevel@tonic-gate * %o2 = pointer to CPU 19477c478bd9Sstevel@tonic-gate * %o5 = updated CPU_INTR_ACTV 19487c478bd9Sstevel@tonic-gate */ 19497c478bd9Sstevel@tonic-gate_intr_set_spl: ! intr_thread_exit enters here 19507c478bd9Sstevel@tonic-gate ! 19517c478bd9Sstevel@tonic-gate ! Determine highest interrupt level active. Several could be blocked 19527c478bd9Sstevel@tonic-gate ! at higher levels than this one, so must convert flags to a PIL 19537c478bd9Sstevel@tonic-gate ! Normally nothing will be blocked, so test this first. 19547c478bd9Sstevel@tonic-gate ! 19557c478bd9Sstevel@tonic-gate brz,pt %o5, 1f ! nothing active 19567c478bd9Sstevel@tonic-gate sra %o5, 11, %o3 ! delay - set %o3 to bits 15-11 19577c478bd9Sstevel@tonic-gate set _intr_flag_table, %o1 19587c478bd9Sstevel@tonic-gate tst %o3 ! see if any of the bits set 19597c478bd9Sstevel@tonic-gate ldub [%o1 + %o3], %o3 ! load bit number 19607c478bd9Sstevel@tonic-gate bnz,a,pn %xcc, 1f ! yes, add 10 and we're done 19617c478bd9Sstevel@tonic-gate add %o3, 11-1, %o3 ! delay - add bit number - 1 19627c478bd9Sstevel@tonic-gate 19637c478bd9Sstevel@tonic-gate sra %o5, 6, %o3 ! test bits 10-6 19647c478bd9Sstevel@tonic-gate tst %o3 19657c478bd9Sstevel@tonic-gate ldub [%o1 + %o3], %o3 19667c478bd9Sstevel@tonic-gate bnz,a,pn %xcc, 1f 19677c478bd9Sstevel@tonic-gate add %o3, 6-1, %o3 19687c478bd9Sstevel@tonic-gate 19697c478bd9Sstevel@tonic-gate sra %o5, 1, %o3 ! test bits 5-1 19707c478bd9Sstevel@tonic-gate ldub [%o1 + %o3], %o3 19717c478bd9Sstevel@tonic-gate 19727c478bd9Sstevel@tonic-gate ! 19737c478bd9Sstevel@tonic-gate ! highest interrupt level number active is in %l6 19747c478bd9Sstevel@tonic-gate ! 19757c478bd9Sstevel@tonic-gate1: 19767c478bd9Sstevel@tonic-gate retl 19777c478bd9Sstevel@tonic-gate st %o3, [%o2 + CPU_BASE_SPL] ! delay - store base priority 19787c478bd9Sstevel@tonic-gate SET_SIZE(set_base_spl) 19797c478bd9Sstevel@tonic-gate 19807c478bd9Sstevel@tonic-gate/* 19817c478bd9Sstevel@tonic-gate * Table that finds the most significant bit set in a five bit field. 19827c478bd9Sstevel@tonic-gate * Each entry is the high-order bit number + 1 of it's index in the table. 19837c478bd9Sstevel@tonic-gate * This read-only data is in the text segment. 19847c478bd9Sstevel@tonic-gate */ 19857c478bd9Sstevel@tonic-gate_intr_flag_table: 19867c478bd9Sstevel@tonic-gate .byte 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4 19877c478bd9Sstevel@tonic-gate .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 19887c478bd9Sstevel@tonic-gate .align 4 19897c478bd9Sstevel@tonic-gate 19907c478bd9Sstevel@tonic-gate#endif /* lint */ 19917c478bd9Sstevel@tonic-gate 19927c478bd9Sstevel@tonic-gate/* 19937c478bd9Sstevel@tonic-gate * int 19947c478bd9Sstevel@tonic-gate * intr_passivate(from, to) 19957c478bd9Sstevel@tonic-gate * kthread_id_t from; interrupt thread 19967c478bd9Sstevel@tonic-gate * kthread_id_t to; interrupted thread 19977c478bd9Sstevel@tonic-gate */ 19987c478bd9Sstevel@tonic-gate 19997c478bd9Sstevel@tonic-gate#if defined(lint) 20007c478bd9Sstevel@tonic-gate 20017c478bd9Sstevel@tonic-gate/* ARGSUSED */ 20027c478bd9Sstevel@tonic-gateint 20037c478bd9Sstevel@tonic-gateintr_passivate(kthread_id_t from, kthread_id_t to) 20047c478bd9Sstevel@tonic-gate{ return (0); } 20057c478bd9Sstevel@tonic-gate 20067c478bd9Sstevel@tonic-gate#else /* lint */ 20077c478bd9Sstevel@tonic-gate 20087c478bd9Sstevel@tonic-gate ENTRY_NP(intr_passivate) 20097c478bd9Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp ! get a new window 20107c478bd9Sstevel@tonic-gate 20117c478bd9Sstevel@tonic-gate flushw ! force register windows to stack 20127c478bd9Sstevel@tonic-gate ! 20137c478bd9Sstevel@tonic-gate ! restore registers from the base of the stack of the interrupt thread. 20147c478bd9Sstevel@tonic-gate ! 20157c478bd9Sstevel@tonic-gate ldn [%i0 + T_STACK], %i2 ! get stack save area pointer 20167c478bd9Sstevel@tonic-gate ldn [%i2 + (0*GREGSIZE)], %l0 ! load locals 20177c478bd9Sstevel@tonic-gate ldn [%i2 + (1*GREGSIZE)], %l1 20187c478bd9Sstevel@tonic-gate ldn [%i2 + (2*GREGSIZE)], %l2 20197c478bd9Sstevel@tonic-gate ldn [%i2 + (3*GREGSIZE)], %l3 20207c478bd9Sstevel@tonic-gate ldn [%i2 + (4*GREGSIZE)], %l4 20217c478bd9Sstevel@tonic-gate ldn [%i2 + (5*GREGSIZE)], %l5 20227c478bd9Sstevel@tonic-gate ldn [%i2 + (6*GREGSIZE)], %l6 20237c478bd9Sstevel@tonic-gate ldn [%i2 + (7*GREGSIZE)], %l7 20247c478bd9Sstevel@tonic-gate ldn [%i2 + (8*GREGSIZE)], %o0 ! put ins from stack in outs 20257c478bd9Sstevel@tonic-gate ldn [%i2 + (9*GREGSIZE)], %o1 20267c478bd9Sstevel@tonic-gate ldn [%i2 + (10*GREGSIZE)], %o2 20277c478bd9Sstevel@tonic-gate ldn [%i2 + (11*GREGSIZE)], %o3 20287c478bd9Sstevel@tonic-gate ldn [%i2 + (12*GREGSIZE)], %o4 20297c478bd9Sstevel@tonic-gate ldn [%i2 + (13*GREGSIZE)], %o5 20307c478bd9Sstevel@tonic-gate ldn [%i2 + (14*GREGSIZE)], %i4 20317c478bd9Sstevel@tonic-gate ! copy stack/pointer without using %sp 20327c478bd9Sstevel@tonic-gate ldn [%i2 + (15*GREGSIZE)], %i5 20337c478bd9Sstevel@tonic-gate ! 20347c478bd9Sstevel@tonic-gate ! put registers into the save area at the top of the interrupted 20357c478bd9Sstevel@tonic-gate ! thread's stack, pointed to by %l7 in the save area just loaded. 20367c478bd9Sstevel@tonic-gate ! 20377c478bd9Sstevel@tonic-gate ldn [%i1 + T_SP], %i3 ! get stack save area pointer 20387c478bd9Sstevel@tonic-gate stn %l0, [%i3 + STACK_BIAS + (0*GREGSIZE)] ! save locals 20397c478bd9Sstevel@tonic-gate stn %l1, [%i3 + STACK_BIAS + (1*GREGSIZE)] 20407c478bd9Sstevel@tonic-gate stn %l2, [%i3 + STACK_BIAS + (2*GREGSIZE)] 20417c478bd9Sstevel@tonic-gate stn %l3, [%i3 + STACK_BIAS + (3*GREGSIZE)] 20427c478bd9Sstevel@tonic-gate stn %l4, [%i3 + STACK_BIAS + (4*GREGSIZE)] 20437c478bd9Sstevel@tonic-gate stn %l5, [%i3 + STACK_BIAS + (5*GREGSIZE)] 20447c478bd9Sstevel@tonic-gate stn %l6, [%i3 + STACK_BIAS + (6*GREGSIZE)] 20457c478bd9Sstevel@tonic-gate stn %l7, [%i3 + STACK_BIAS + (7*GREGSIZE)] 20467c478bd9Sstevel@tonic-gate stn %o0, [%i3 + STACK_BIAS + (8*GREGSIZE)] ! save ins using outs 20477c478bd9Sstevel@tonic-gate stn %o1, [%i3 + STACK_BIAS + (9*GREGSIZE)] 20487c478bd9Sstevel@tonic-gate stn %o2, [%i3 + STACK_BIAS + (10*GREGSIZE)] 20497c478bd9Sstevel@tonic-gate stn %o3, [%i3 + STACK_BIAS + (11*GREGSIZE)] 20507c478bd9Sstevel@tonic-gate stn %o4, [%i3 + STACK_BIAS + (12*GREGSIZE)] 20517c478bd9Sstevel@tonic-gate stn %o5, [%i3 + STACK_BIAS + (13*GREGSIZE)] 20527c478bd9Sstevel@tonic-gate stn %i4, [%i3 + STACK_BIAS + (14*GREGSIZE)] 20537c478bd9Sstevel@tonic-gate ! fp, %i7 copied using %i4 20547c478bd9Sstevel@tonic-gate stn %i5, [%i3 + STACK_BIAS + (15*GREGSIZE)] 20557c478bd9Sstevel@tonic-gate stn %g0, [%i2 + ((8+6)*GREGSIZE)] 20567c478bd9Sstevel@tonic-gate ! clear fp in save area 20577c478bd9Sstevel@tonic-gate 20587c478bd9Sstevel@tonic-gate ! load saved pil for return 20597c478bd9Sstevel@tonic-gate ldub [%i0 + T_PIL], %i0 20607c478bd9Sstevel@tonic-gate ret 20617c478bd9Sstevel@tonic-gate restore 20627c478bd9Sstevel@tonic-gate SET_SIZE(intr_passivate) 20637c478bd9Sstevel@tonic-gate 20647c478bd9Sstevel@tonic-gate#endif /* lint */ 20657c478bd9Sstevel@tonic-gate 20667c478bd9Sstevel@tonic-gate#if defined(lint) 20677c478bd9Sstevel@tonic-gate 20687c478bd9Sstevel@tonic-gate/* 20697c478bd9Sstevel@tonic-gate * intr_get_time() is a resource for interrupt handlers to determine how 20707c478bd9Sstevel@tonic-gate * much time has been spent handling the current interrupt. Such a function 20717c478bd9Sstevel@tonic-gate * is needed because higher level interrupts can arrive during the 20727c478bd9Sstevel@tonic-gate * processing of an interrupt, thus making direct comparisons of %tick by 20737c478bd9Sstevel@tonic-gate * the handler inaccurate. intr_get_time() only returns time spent in the 20747c478bd9Sstevel@tonic-gate * current interrupt handler. 20757c478bd9Sstevel@tonic-gate * 20767c478bd9Sstevel@tonic-gate * The caller must be calling from an interrupt handler running at a pil 20777c478bd9Sstevel@tonic-gate * below or at lock level. Timings are not provided for high-level 20787c478bd9Sstevel@tonic-gate * interrupts. 20797c478bd9Sstevel@tonic-gate * 20807c478bd9Sstevel@tonic-gate * The first time intr_get_time() is called while handling an interrupt, 20817c478bd9Sstevel@tonic-gate * it returns the time since the interrupt handler was invoked. Subsequent 20827c478bd9Sstevel@tonic-gate * calls will return the time since the prior call to intr_get_time(). Time 20837c478bd9Sstevel@tonic-gate * is returned as ticks, adjusted for any clock divisor due to power 20847c478bd9Sstevel@tonic-gate * management. Use tick2ns() to convert ticks to nsec. Warning: ticks may 20857c478bd9Sstevel@tonic-gate * not be the same across CPUs. 20867c478bd9Sstevel@tonic-gate * 20877c478bd9Sstevel@tonic-gate * Theory Of Intrstat[][]: 20887c478bd9Sstevel@tonic-gate * 20897c478bd9Sstevel@tonic-gate * uint64_t intrstat[pil][0..1] is an array indexed by pil level, with two 20907c478bd9Sstevel@tonic-gate * uint64_ts per pil. 20917c478bd9Sstevel@tonic-gate * 20927c478bd9Sstevel@tonic-gate * intrstat[pil][0] is a cumulative count of the number of ticks spent 20937c478bd9Sstevel@tonic-gate * handling all interrupts at the specified pil on this CPU. It is 20947c478bd9Sstevel@tonic-gate * exported via kstats to the user. 20957c478bd9Sstevel@tonic-gate * 20967c478bd9Sstevel@tonic-gate * intrstat[pil][1] is always a count of ticks less than or equal to the 20977c478bd9Sstevel@tonic-gate * value in [0]. The difference between [1] and [0] is the value returned 20987c478bd9Sstevel@tonic-gate * by a call to intr_get_time(). At the start of interrupt processing, 20997c478bd9Sstevel@tonic-gate * [0] and [1] will be equal (or nearly so). As the interrupt consumes 21007c478bd9Sstevel@tonic-gate * time, [0] will increase, but [1] will remain the same. A call to 21017c478bd9Sstevel@tonic-gate * intr_get_time() will return the difference, then update [1] to be the 21027c478bd9Sstevel@tonic-gate * same as [0]. Future calls will return the time since the last call. 21037c478bd9Sstevel@tonic-gate * Finally, when the interrupt completes, [1] is updated to the same as [0]. 21047c478bd9Sstevel@tonic-gate * 21057c478bd9Sstevel@tonic-gate * Implementation: 21067c478bd9Sstevel@tonic-gate * 21077c478bd9Sstevel@tonic-gate * intr_get_time() works much like a higher level interrupt arriving. It 21087c478bd9Sstevel@tonic-gate * "checkpoints" the timing information by incrementing intrstat[pil][0] 21097c478bd9Sstevel@tonic-gate * to include elapsed running time, and by setting t_intr_start to %tick. 21107c478bd9Sstevel@tonic-gate * It then sets the return value to intrstat[pil][0] - intrstat[pil][1], 21117c478bd9Sstevel@tonic-gate * and updates intrstat[pil][1] to be the same as the new value of 21127c478bd9Sstevel@tonic-gate * intrstat[pil][0]. 21137c478bd9Sstevel@tonic-gate * 21147c478bd9Sstevel@tonic-gate * In the normal handling of interrupts, after an interrupt handler returns 21157c478bd9Sstevel@tonic-gate * and the code in intr_thread() updates intrstat[pil][0], it then sets 21167c478bd9Sstevel@tonic-gate * intrstat[pil][1] to the new value of intrstat[pil][0]. When [0] == [1], 21177c478bd9Sstevel@tonic-gate * the timings are reset, i.e. intr_get_time() will return [0] - [1] which 21187c478bd9Sstevel@tonic-gate * is 0. 21197c478bd9Sstevel@tonic-gate * 21207c478bd9Sstevel@tonic-gate * Whenever interrupts arrive on a CPU which is handling a lower pil 21217c478bd9Sstevel@tonic-gate * interrupt, they update the lower pil's [0] to show time spent in the 21227c478bd9Sstevel@tonic-gate * handler that they've interrupted. This results in a growing discrepancy 21237c478bd9Sstevel@tonic-gate * between [0] and [1], which is returned the next time intr_get_time() is 21247c478bd9Sstevel@tonic-gate * called. Time spent in the higher-pil interrupt will not be returned in 21257c478bd9Sstevel@tonic-gate * the next intr_get_time() call from the original interrupt, because 21267c478bd9Sstevel@tonic-gate * the higher-pil interrupt's time is accumulated in intrstat[higherpil][]. 21277c478bd9Sstevel@tonic-gate */ 21287c478bd9Sstevel@tonic-gate 21297c478bd9Sstevel@tonic-gate/*ARGSUSED*/ 21307c478bd9Sstevel@tonic-gateuint64_t 21317c478bd9Sstevel@tonic-gateintr_get_time(void) 21327c478bd9Sstevel@tonic-gate{ return 0; } 21337c478bd9Sstevel@tonic-gate#else /* lint */ 21347c478bd9Sstevel@tonic-gate 21357c478bd9Sstevel@tonic-gate ENTRY_NP(intr_get_time) 21367c478bd9Sstevel@tonic-gate#ifdef DEBUG 21377c478bd9Sstevel@tonic-gate ! 21387c478bd9Sstevel@tonic-gate ! Lots of asserts, but just check panic_quiesce first. 21397c478bd9Sstevel@tonic-gate ! Don't bother with lots of tests if we're just ignoring them. 21407c478bd9Sstevel@tonic-gate ! 21417c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %o0 21427c478bd9Sstevel@tonic-gate ld [%o0 + %lo(panic_quiesce)], %o0 21437c478bd9Sstevel@tonic-gate brnz,pn %o0, 2f 21447c478bd9Sstevel@tonic-gate nop 21457c478bd9Sstevel@tonic-gate ! 21467c478bd9Sstevel@tonic-gate ! ASSERT(%pil <= LOCK_LEVEL) 21477c478bd9Sstevel@tonic-gate ! 21487c478bd9Sstevel@tonic-gate rdpr %pil, %o1 21497c478bd9Sstevel@tonic-gate cmp %o1, LOCK_LEVEL 21507c478bd9Sstevel@tonic-gate ble,pt %xcc, 0f 21517c478bd9Sstevel@tonic-gate sethi %hi(intr_get_time_high_pil), %o0 ! delay 21527c478bd9Sstevel@tonic-gate call panic 21537c478bd9Sstevel@tonic-gate or %o0, %lo(intr_get_time_high_pil), %o0 21547c478bd9Sstevel@tonic-gate0: 21557c478bd9Sstevel@tonic-gate ! 21567c478bd9Sstevel@tonic-gate ! ASSERT((t_flags & T_INTR_THREAD) != 0 && t_pil > 0) 21577c478bd9Sstevel@tonic-gate ! 21587c478bd9Sstevel@tonic-gate lduh [THREAD_REG + T_FLAGS], %o2 21597c478bd9Sstevel@tonic-gate andcc %o2, T_INTR_THREAD, %g0 21607c478bd9Sstevel@tonic-gate bz,pn %xcc, 1f 21617c478bd9Sstevel@tonic-gate ldub [THREAD_REG + T_PIL], %o1 ! delay 21627c478bd9Sstevel@tonic-gate brnz,pt %o1, 0f 21637c478bd9Sstevel@tonic-gate1: 21647c478bd9Sstevel@tonic-gate sethi %hi(intr_get_time_not_intr), %o0 21657c478bd9Sstevel@tonic-gate call panic 21667c478bd9Sstevel@tonic-gate or %o0, %lo(intr_get_time_not_intr), %o0 21677c478bd9Sstevel@tonic-gate0: 21687c478bd9Sstevel@tonic-gate ! 21697c478bd9Sstevel@tonic-gate ! ASSERT(t_intr_start != 0) 21707c478bd9Sstevel@tonic-gate ! 21717c478bd9Sstevel@tonic-gate ldx [THREAD_REG + T_INTR_START], %o1 21727c478bd9Sstevel@tonic-gate brnz,pt %o1, 2f 21737c478bd9Sstevel@tonic-gate sethi %hi(intr_get_time_no_start_time), %o0 ! delay 21747c478bd9Sstevel@tonic-gate call panic 21757c478bd9Sstevel@tonic-gate or %o0, %lo(intr_get_time_no_start_time), %o0 21767c478bd9Sstevel@tonic-gate2: 21777c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 21787c478bd9Sstevel@tonic-gate ! 21797c478bd9Sstevel@tonic-gate ! %o0 = elapsed time and return value 21807c478bd9Sstevel@tonic-gate ! %o1 = pil 21817c478bd9Sstevel@tonic-gate ! %o2 = scratch 21827c478bd9Sstevel@tonic-gate ! %o3 = scratch 21837c478bd9Sstevel@tonic-gate ! %o4 = scratch 21847c478bd9Sstevel@tonic-gate ! %o5 = cpu 21857c478bd9Sstevel@tonic-gate ! 21867c478bd9Sstevel@tonic-gate wrpr %g0, PIL_MAX, %pil ! make this easy -- block normal intrs 21877c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CPU], %o5 21887c478bd9Sstevel@tonic-gate ldub [THREAD_REG + T_PIL], %o1 21897c478bd9Sstevel@tonic-gate ldx [THREAD_REG + T_INTR_START], %o3 ! %o3 = t_intr_start 21907c478bd9Sstevel@tonic-gate ! 21917c478bd9Sstevel@tonic-gate ! Calculate elapsed time since t_intr_start. Update t_intr_start, 21927c478bd9Sstevel@tonic-gate ! get delta, and multiply by cpu_divisor if necessary. 21937c478bd9Sstevel@tonic-gate ! 2194*023e71deSHaik Aftandilian RD_TICK_NO_SUSPEND_CHECK(%o2, %o0) 21957c478bd9Sstevel@tonic-gate stx %o2, [THREAD_REG + T_INTR_START] 21967c478bd9Sstevel@tonic-gate sub %o2, %o3, %o0 21977c478bd9Sstevel@tonic-gate 21987c478bd9Sstevel@tonic-gate lduh [%o5 + CPU_DIVISOR], %o4 21997c478bd9Sstevel@tonic-gate cmp %o4, 1 22007c478bd9Sstevel@tonic-gate bg,a,pn %xcc, 1f 22017c478bd9Sstevel@tonic-gate mulx %o0, %o4, %o0 ! multiply interval by clock divisor iff > 1 22027c478bd9Sstevel@tonic-gate1: 2203eda89462Sesolom ! Update intracct[] 2204eda89462Sesolom lduh [%o5 + CPU_MSTATE], %o4 2205eda89462Sesolom sllx %o4, 3, %o4 2206eda89462Sesolom add %o4, CPU_INTRACCT, %o4 2207eda89462Sesolom ldx [%o5 + %o4], %o2 2208eda89462Sesolom add %o2, %o0, %o2 2209eda89462Sesolom stx %o2, [%o5 + %o4] 2210eda89462Sesolom 22117c478bd9Sstevel@tonic-gate ! 22127c478bd9Sstevel@tonic-gate ! Increment cpu_m.intrstat[pil][0]. Calculate elapsed time since 22137c478bd9Sstevel@tonic-gate ! cpu_m.intrstat[pil][1], which is either when the interrupt was 22147c478bd9Sstevel@tonic-gate ! first entered, or the last time intr_get_time() was invoked. Then 22157c478bd9Sstevel@tonic-gate ! update cpu_m.intrstat[pil][1] to match [0]. 22167c478bd9Sstevel@tonic-gate ! 22177c478bd9Sstevel@tonic-gate sllx %o1, 4, %o3 22187c478bd9Sstevel@tonic-gate add %o3, CPU_MCPU, %o3 22197c478bd9Sstevel@tonic-gate add %o3, MCPU_INTRSTAT, %o3 22207c478bd9Sstevel@tonic-gate add %o3, %o5, %o3 ! %o3 = cpu_m.intrstat[pil][0] 22217c478bd9Sstevel@tonic-gate ldx [%o3], %o2 22227c478bd9Sstevel@tonic-gate add %o2, %o0, %o2 ! %o2 = new value for intrstat 22237c478bd9Sstevel@tonic-gate stx %o2, [%o3] 22247c478bd9Sstevel@tonic-gate ldx [%o3 + 8], %o4 ! %o4 = cpu_m.intrstat[pil][1] 22257c478bd9Sstevel@tonic-gate sub %o2, %o4, %o0 ! %o0 is elapsed time since %o4 22267c478bd9Sstevel@tonic-gate stx %o2, [%o3 + 8] ! make [1] match [0], resetting time 22277c478bd9Sstevel@tonic-gate 22287c478bd9Sstevel@tonic-gate ld [%o5 + CPU_BASE_SPL], %o2 ! restore %pil to the greater 22297c478bd9Sstevel@tonic-gate cmp %o2, %o1 ! of either our pil %o1 or 22307c478bd9Sstevel@tonic-gate movl %xcc, %o1, %o2 ! cpu_base_spl. 22317c478bd9Sstevel@tonic-gate retl 22327c478bd9Sstevel@tonic-gate wrpr %g0, %o2, %pil 22337c478bd9Sstevel@tonic-gate SET_SIZE(intr_get_time) 22347c478bd9Sstevel@tonic-gate 22357c478bd9Sstevel@tonic-gate#ifdef DEBUG 22367c478bd9Sstevel@tonic-gateintr_get_time_high_pil: 22377c478bd9Sstevel@tonic-gate .asciz "intr_get_time(): %pil > LOCK_LEVEL" 22387c478bd9Sstevel@tonic-gateintr_get_time_not_intr: 22397c478bd9Sstevel@tonic-gate .asciz "intr_get_time(): not called from an interrupt thread" 22407c478bd9Sstevel@tonic-gateintr_get_time_no_start_time: 22417c478bd9Sstevel@tonic-gate .asciz "intr_get_time(): t_intr_start == 0" 22427c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 22437c478bd9Sstevel@tonic-gate#endif /* lint */ 2244