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 5*25cf1a30Sjl139090 * Common Development and Distribution License (the "License"). 6*25cf1a30Sjl139090 * 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*25cf1a30Sjl139090 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate#pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate#if defined(lint) 297c478bd9Sstevel@tonic-gate#include <sys/types.h> 307c478bd9Sstevel@tonic-gate#include <sys/thread.h> 317c478bd9Sstevel@tonic-gate#else /* lint */ 327c478bd9Sstevel@tonic-gate#include "assym.h" 337c478bd9Sstevel@tonic-gate#endif /* lint */ 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate#include <sys/cmn_err.h> 367c478bd9Sstevel@tonic-gate#include <sys/ftrace.h> 377c478bd9Sstevel@tonic-gate#include <sys/asm_linkage.h> 387c478bd9Sstevel@tonic-gate#include <sys/machthread.h> 397c478bd9Sstevel@tonic-gate#include <sys/machcpuvar.h> 407c478bd9Sstevel@tonic-gate#include <sys/intreg.h> 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE 437c478bd9Sstevel@tonic-gate#include <sys/traptrace.h> 447c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */ 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate#if defined(lint) 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate/* ARGSUSED */ 517c478bd9Sstevel@tonic-gatevoid 527c478bd9Sstevel@tonic-gatepil_interrupt(int level) 537c478bd9Sstevel@tonic-gate{} 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate#else /* lint */ 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate/* 597c478bd9Sstevel@tonic-gate * (TT 0x40..0x4F, TL>0) Interrupt Level N Handler (N == 1..15) 607c478bd9Sstevel@tonic-gate * Register passed from LEVEL_INTERRUPT(level) 617c478bd9Sstevel@tonic-gate * %g4 - interrupt request level 627c478bd9Sstevel@tonic-gate */ 637c478bd9Sstevel@tonic-gate ENTRY_NP(pil_interrupt) 647c478bd9Sstevel@tonic-gate ! 657c478bd9Sstevel@tonic-gate ! Register usage 667c478bd9Sstevel@tonic-gate ! %g1 - cpu 677c478bd9Sstevel@tonic-gate ! %g3 - intr_req 687c478bd9Sstevel@tonic-gate ! %g4 - pil 697c478bd9Sstevel@tonic-gate ! %g2, %g5, %g6 - temps 707c478bd9Sstevel@tonic-gate ! 717c478bd9Sstevel@tonic-gate ! grab the 1st intr_req off the list 727c478bd9Sstevel@tonic-gate ! if the list is empty, clear %clear_softint 737c478bd9Sstevel@tonic-gate ! 747c478bd9Sstevel@tonic-gate CPU_ADDR(%g1, %g5) 757c478bd9Sstevel@tonic-gate ! 767c478bd9Sstevel@tonic-gate ALTENTRY(pil_interrupt_common) 777c478bd9Sstevel@tonic-gate sll %g4, CPTRSHIFT, %g5 787c478bd9Sstevel@tonic-gate add %g1, INTR_HEAD, %g6 ! intr_head[0] 797c478bd9Sstevel@tonic-gate add %g6, %g5, %g6 ! intr_head[pil] 807c478bd9Sstevel@tonic-gate ldn [%g6], %g3 ! g3 = intr_req 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate#ifndef DEBUG 837c478bd9Sstevel@tonic-gate brnz,pt %g3, 5f 847c478bd9Sstevel@tonic-gate nop 857c478bd9Sstevel@tonic-gate#else 867c478bd9Sstevel@tonic-gate ! 877c478bd9Sstevel@tonic-gate ! Verify the address of intr_req; it should be within the 887c478bd9Sstevel@tonic-gate ! address range of intr_pool and intr_head 897c478bd9Sstevel@tonic-gate ! or the address range of intr_add_head and intr_add_tail. 907c478bd9Sstevel@tonic-gate ! The range of intr_add_head and intr_add_tail is subdivided 917c478bd9Sstevel@tonic-gate ! by cpu, but the subdivision is not verified here. 927c478bd9Sstevel@tonic-gate ! 937c478bd9Sstevel@tonic-gate ! Registers passed to sys_trap() 947c478bd9Sstevel@tonic-gate ! %g1 - no_intr_req 957c478bd9Sstevel@tonic-gate ! %g2 - intr_req 967c478bd9Sstevel@tonic-gate ! %g3 - %pil 977c478bd9Sstevel@tonic-gate ! %g4 - current pil 987c478bd9Sstevel@tonic-gate ! 997c478bd9Sstevel@tonic-gate add %g1, INTR_POOL, %g2 1007c478bd9Sstevel@tonic-gate cmp %g3, %g2 1017c478bd9Sstevel@tonic-gate blu,pn %xcc, 8f 1027c478bd9Sstevel@tonic-gate nop 1037c478bd9Sstevel@tonic-gate add %g1, INTR_HEAD, %g2 1047c478bd9Sstevel@tonic-gate cmp %g2, %g3 1057c478bd9Sstevel@tonic-gate bgeu,pt %xcc, 5f 1067c478bd9Sstevel@tonic-gate nop 1077c478bd9Sstevel@tonic-gate8: 1087c478bd9Sstevel@tonic-gate sethi %hi(intr_add_head), %g2 1097c478bd9Sstevel@tonic-gate ldn [%g2 + %lo(intr_add_head)], %g2 1107c478bd9Sstevel@tonic-gate brz,pn %g2, 4f ! intr_add_head can be NULL 1117c478bd9Sstevel@tonic-gate cmp %g3, %g2 1127c478bd9Sstevel@tonic-gate blu,pn %xcc, 4f 1137c478bd9Sstevel@tonic-gate nop 1147c478bd9Sstevel@tonic-gate sethi %hi(intr_add_tail), %g2 1157c478bd9Sstevel@tonic-gate ldn [%g2 + %lo(intr_add_tail)], %g2 1167c478bd9Sstevel@tonic-gate cmp %g2, %g3 1177c478bd9Sstevel@tonic-gate bgeu,pt %xcc, 5f 1187c478bd9Sstevel@tonic-gate nop 1197c478bd9Sstevel@tonic-gate4: 1207c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 1217c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE 1227c478bd9Sstevel@tonic-gate TRACE_PTR(%g5, %g2) 1237c478bd9Sstevel@tonic-gate GET_TRACE_TICK(%g2) 1247c478bd9Sstevel@tonic-gate stxa %g2, [%g5 + TRAP_ENT_TICK]%asi 1257c478bd9Sstevel@tonic-gate TRACE_SAVE_TL_GL_REGS(%g5, %g2) 1267c478bd9Sstevel@tonic-gate mov 0xbad, %g2 1277c478bd9Sstevel@tonic-gate stha %g2, [%g5 + TRAP_ENT_TT]%asi 1287c478bd9Sstevel@tonic-gate rdpr %tpc, %g2 1297c478bd9Sstevel@tonic-gate stna %g2, [%g5 + TRAP_ENT_TPC]%asi 1307c478bd9Sstevel@tonic-gate rdpr %tstate, %g2 1317c478bd9Sstevel@tonic-gate stxa %g2, [%g5 + TRAP_ENT_TSTATE]%asi 1327c478bd9Sstevel@tonic-gate stna %g0, [%g5 + TRAP_ENT_SP]%asi 1337c478bd9Sstevel@tonic-gate stna %g1, [%g5 + TRAP_ENT_TR]%asi 1347c478bd9Sstevel@tonic-gate rd SOFTINT, %g2 1357c478bd9Sstevel@tonic-gate stna %g2, [%g5 + TRAP_ENT_F1]%asi 1367c478bd9Sstevel@tonic-gate stna %g3, [%g5 + TRAP_ENT_F2]%asi 1377c478bd9Sstevel@tonic-gate stna %g4, [%g5 + TRAP_ENT_F3]%asi 1387c478bd9Sstevel@tonic-gate stna %g6, [%g5 + TRAP_ENT_F4]%asi 1397c478bd9Sstevel@tonic-gate TRACE_NEXT(%g5, %g2, %g1) 1407c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */ 1417c478bd9Sstevel@tonic-gate ba ptl1_panic 1427c478bd9Sstevel@tonic-gate mov PTL1_BAD_INTR_REQ, %g1 1437c478bd9Sstevel@tonic-gate5: 1447c478bd9Sstevel@tonic-gate ldn [%g3 + INTR_NEXT], %g2 ! 2nd entry 1457c478bd9Sstevel@tonic-gate brnz,pn %g2, 1f ! branch if list not empty 1467c478bd9Sstevel@tonic-gate stn %g2, [%g6] 1477c478bd9Sstevel@tonic-gate add %g1, INTR_TAIL, %g6 ! intr_tail[0] 1487c478bd9Sstevel@tonic-gate stn %g0, [%g5 + %g6] ! update intr_tail[pil] 1497c478bd9Sstevel@tonic-gate mov 1, %g5 1507c478bd9Sstevel@tonic-gate sll %g5, %g4, %g5 1517c478bd9Sstevel@tonic-gate wr %g5, CLEAR_SOFTINT 1527c478bd9Sstevel@tonic-gate1: 1537c478bd9Sstevel@tonic-gate ! 1547c478bd9Sstevel@tonic-gate ! put intr_req on free list 1557c478bd9Sstevel@tonic-gate ! %g2 - inumber 1567c478bd9Sstevel@tonic-gate ! 1577c478bd9Sstevel@tonic-gate ldn [%g1 + INTR_HEAD], %g5 ! current head of free list 1587c478bd9Sstevel@tonic-gate lduw [%g3 + INTR_NUMBER], %g2 1597c478bd9Sstevel@tonic-gate stn %g3, [%g1 + INTR_HEAD] 1607c478bd9Sstevel@tonic-gate stn %g5, [%g3 + INTR_NEXT] 1617c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE 1627c478bd9Sstevel@tonic-gate TRACE_PTR(%g5, %g6) 1637c478bd9Sstevel@tonic-gate GET_TRACE_TICK(%g6) 1647c478bd9Sstevel@tonic-gate stxa %g6, [%g5 + TRAP_ENT_TICK]%asi 1657c478bd9Sstevel@tonic-gate TRACE_SAVE_TL_GL_REGS(%g5, %g6) 1667c478bd9Sstevel@tonic-gate rdpr %tt, %g6 1677c478bd9Sstevel@tonic-gate stha %g6, [%g5 + TRAP_ENT_TT]%asi 1687c478bd9Sstevel@tonic-gate rdpr %tpc, %g6 1697c478bd9Sstevel@tonic-gate stna %g6, [%g5 + TRAP_ENT_TPC]%asi 1707c478bd9Sstevel@tonic-gate rdpr %tstate, %g6 1717c478bd9Sstevel@tonic-gate stxa %g6, [%g5 + TRAP_ENT_TSTATE]%asi 1727c478bd9Sstevel@tonic-gate stna %sp, [%g5 + TRAP_ENT_SP]%asi 1737c478bd9Sstevel@tonic-gate stna %g3, [%g5 + TRAP_ENT_TR]%asi 1747c478bd9Sstevel@tonic-gate stna %g2, [%g5 + TRAP_ENT_F1]%asi 1757c478bd9Sstevel@tonic-gate sll %g4, CPTRSHIFT, %g3 1767c478bd9Sstevel@tonic-gate add %g1, INTR_HEAD, %g6 1777c478bd9Sstevel@tonic-gate ldn [%g6 + %g3], %g6 ! intr_head[pil] 1787c478bd9Sstevel@tonic-gate stna %g6, [%g5 + TRAP_ENT_F2]%asi 1797c478bd9Sstevel@tonic-gate add %g1, INTR_TAIL, %g6 1807c478bd9Sstevel@tonic-gate ldn [%g6 + %g3], %g6 ! intr_tail[pil] 1817c478bd9Sstevel@tonic-gate stna %g4, [%g5 + TRAP_ENT_F3]%asi 1827c478bd9Sstevel@tonic-gate stna %g6, [%g5 + TRAP_ENT_F4]%asi 1837c478bd9Sstevel@tonic-gate TRACE_NEXT(%g5, %g6, %g3) 1847c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */ 1857c478bd9Sstevel@tonic-gate ! 1867c478bd9Sstevel@tonic-gate ! clear the iv_pending flag for this inum 1877c478bd9Sstevel@tonic-gate ! 1887c478bd9Sstevel@tonic-gate set intr_vector, %g5; 1897c478bd9Sstevel@tonic-gate sll %g2, INTR_VECTOR_SHIFT, %g6; 1907c478bd9Sstevel@tonic-gate add %g5, %g6, %g5; ! &intr_vector[inum] 1917c478bd9Sstevel@tonic-gate sth %g0, [%g5 + IV_PENDING] 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate ! 1947c478bd9Sstevel@tonic-gate ! Prepare for sys_trap() 1957c478bd9Sstevel@tonic-gate ! 1967c478bd9Sstevel@tonic-gate ! Registers passed to sys_trap() 1977c478bd9Sstevel@tonic-gate ! %g1 - interrupt handler at TL==0 1987c478bd9Sstevel@tonic-gate ! %g2 - inumber 1997c478bd9Sstevel@tonic-gate ! %g3 - pil 2007c478bd9Sstevel@tonic-gate ! %g4 - initial pil for handler 2017c478bd9Sstevel@tonic-gate ! 2027c478bd9Sstevel@tonic-gate ! figure which handler to run and which %pil it starts at 2037c478bd9Sstevel@tonic-gate ! intr_thread starts at DISP_LEVEL to prevent preemption 2047c478bd9Sstevel@tonic-gate ! current_thread starts at PIL_MAX to protect cpu_intr_actv 2057c478bd9Sstevel@tonic-gate ! 2067c478bd9Sstevel@tonic-gate mov %g4, %g3 2077c478bd9Sstevel@tonic-gate cmp %g4, LOCK_LEVEL 2087c478bd9Sstevel@tonic-gate bg,a,pt %xcc, 4f ! branch if pil > LOCK_LEVEL 2097c478bd9Sstevel@tonic-gate mov PIL_MAX, %g4 2107c478bd9Sstevel@tonic-gate sethi %hi(intr_thread), %g1 2117c478bd9Sstevel@tonic-gate mov DISP_LEVEL, %g4 2127c478bd9Sstevel@tonic-gate ba,pt %xcc, sys_trap 2137c478bd9Sstevel@tonic-gate or %g1, %lo(intr_thread), %g1 2147c478bd9Sstevel@tonic-gate4: 2157c478bd9Sstevel@tonic-gate sethi %hi(current_thread), %g1 2167c478bd9Sstevel@tonic-gate ba,pt %xcc, sys_trap 2177c478bd9Sstevel@tonic-gate or %g1, %lo(current_thread), %g1 2187c478bd9Sstevel@tonic-gate SET_SIZE(pil_interrupt_common) 2197c478bd9Sstevel@tonic-gate SET_SIZE(pil_interrupt) 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate#endif /* lint */ 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate#ifndef lint 2257c478bd9Sstevel@tonic-gate_spurious: 2267c478bd9Sstevel@tonic-gate .asciz "!interrupt 0x%x at level %d not serviced" 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate/* 2297c478bd9Sstevel@tonic-gate * SERVE_INTR_PRE is called once, just before the first invocation 2307c478bd9Sstevel@tonic-gate * of SERVE_INTR. 2317c478bd9Sstevel@tonic-gate * 2327c478bd9Sstevel@tonic-gate * Registers on entry: 2337c478bd9Sstevel@tonic-gate * 2347c478bd9Sstevel@tonic-gate * inum, cpu, regs: may be out-registers 2357c478bd9Sstevel@tonic-gate * ls1, ls2: local scratch registers 2367c478bd9Sstevel@tonic-gate * os1, os2, os3: scratch registers, may be out 2377c478bd9Sstevel@tonic-gate */ 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate#define SERVE_INTR_PRE(inum, cpu, ls1, ls2, os1, os2, os3, regs) \ 2407c478bd9Sstevel@tonic-gate set intr_vector, ls1; \ 2417c478bd9Sstevel@tonic-gate sll inum, INTR_VECTOR_SHIFT, os1; \ 2427c478bd9Sstevel@tonic-gate add ls1, os1, ls1; \ 2437c478bd9Sstevel@tonic-gate SERVE_INTR_TRACE(inum, os1, os2, os3, regs); \ 2447c478bd9Sstevel@tonic-gate mov inum, ls2; 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate/* 2477c478bd9Sstevel@tonic-gate * SERVE_INTR is called immediately after either SERVE_INTR_PRE or 2487c478bd9Sstevel@tonic-gate * SERVE_INTR_NEXT, without intervening code. No register values 2497c478bd9Sstevel@tonic-gate * may be modified. 2507c478bd9Sstevel@tonic-gate * 2517c478bd9Sstevel@tonic-gate * After calling SERVE_INTR, the caller must check if os3 is set. If 2527c478bd9Sstevel@tonic-gate * so, there is another interrupt to process. The caller must call 2537c478bd9Sstevel@tonic-gate * SERVE_INTR_NEXT, immediately followed by SERVE_INTR. 2547c478bd9Sstevel@tonic-gate * 2557c478bd9Sstevel@tonic-gate * Before calling SERVE_INTR_NEXT, the caller may perform accounting 2567c478bd9Sstevel@tonic-gate * and other actions which need to occur after invocation of an interrupt 2577c478bd9Sstevel@tonic-gate * handler. However, the values of ls1 and os3 *must* be preserved and 2587c478bd9Sstevel@tonic-gate * passed unmodified into SERVE_INTR_NEXT. 2597c478bd9Sstevel@tonic-gate * 2607c478bd9Sstevel@tonic-gate * Registers on return from SERVE_INTR: 2617c478bd9Sstevel@tonic-gate * 2627c478bd9Sstevel@tonic-gate * ls1 - the pil just processed 2637c478bd9Sstevel@tonic-gate * ls2 - the inum just processed 2647c478bd9Sstevel@tonic-gate * os3 - if set, another interrupt needs to be processed 2657c478bd9Sstevel@tonic-gate * cpu, ls1, os3 - must be preserved if os3 is set 2667c478bd9Sstevel@tonic-gate */ 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate#define SERVE_INTR(os5, cpu, ls1, ls2, os1, os2, os3, os4) \ 2697c478bd9Sstevel@tonic-gate ldn [ls1 + IV_HANDLER], os2; \ 2707c478bd9Sstevel@tonic-gate ldn [ls1 + IV_ARG], %o0; \ 2717c478bd9Sstevel@tonic-gate ldn [ls1 + IV_SOFTINT_ARG2], %o1; \ 2727c478bd9Sstevel@tonic-gate call os2; \ 2737c478bd9Sstevel@tonic-gate lduh [ls1 + IV_PIL], ls1; \ 2747c478bd9Sstevel@tonic-gate brnz,pt %o0, 2f; \ 2757c478bd9Sstevel@tonic-gate mov CE_WARN, %o0; \ 2767c478bd9Sstevel@tonic-gate set _spurious, %o1; \ 2777c478bd9Sstevel@tonic-gate mov ls2, %o2; \ 2787c478bd9Sstevel@tonic-gate call cmn_err; \ 2797c478bd9Sstevel@tonic-gate rdpr %pil, %o3; \ 2807c478bd9Sstevel@tonic-gate2: ldn [THREAD_REG + T_CPU], cpu; \ 2817c478bd9Sstevel@tonic-gate sll ls1, 3, os1; \ 2827c478bd9Sstevel@tonic-gate add os1, CPU_STATS_SYS_INTR - 8, os2; \ 2837c478bd9Sstevel@tonic-gate ldx [cpu + os2], os3; \ 2847c478bd9Sstevel@tonic-gate inc os3; \ 2857c478bd9Sstevel@tonic-gate stx os3, [cpu + os2]; \ 2867c478bd9Sstevel@tonic-gate sll ls1, CPTRSHIFT, os2; \ 2877c478bd9Sstevel@tonic-gate add cpu, INTR_HEAD, os1; \ 2887c478bd9Sstevel@tonic-gate add os1, os2, os1; \ 2897c478bd9Sstevel@tonic-gate ldn [os1], os3; 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate/* 2927c478bd9Sstevel@tonic-gate * Registers on entry: 2937c478bd9Sstevel@tonic-gate * 2947c478bd9Sstevel@tonic-gate * cpu - cpu pointer (clobbered, set to cpu upon completion) 2957c478bd9Sstevel@tonic-gate * ls1, os3 - preserved from prior call to SERVE_INTR 2967c478bd9Sstevel@tonic-gate * ls2 - local scratch reg (not preserved) 2977c478bd9Sstevel@tonic-gate * os1, os2, os4, os5 - scratch reg, can be out (not preserved) 2987c478bd9Sstevel@tonic-gate */ 2997c478bd9Sstevel@tonic-gate#define SERVE_INTR_NEXT(os5, cpu, ls1, ls2, os1, os2, os3, os4) \ 3007c478bd9Sstevel@tonic-gate sll ls1, CPTRSHIFT, os4; \ 3017c478bd9Sstevel@tonic-gate add cpu, INTR_HEAD, os1; \ 3027c478bd9Sstevel@tonic-gate rdpr %pstate, ls2; \ 3037c478bd9Sstevel@tonic-gate wrpr ls2, PSTATE_IE, %pstate; \ 3047c478bd9Sstevel@tonic-gate ldn [os3 + INTR_NEXT], os2; \ 3057c478bd9Sstevel@tonic-gate brnz,pn os2, 4f; \ 3067c478bd9Sstevel@tonic-gate stn os2, [os1 + os4]; \ 3077c478bd9Sstevel@tonic-gate add cpu, INTR_TAIL, os1; \ 3087c478bd9Sstevel@tonic-gate stn %g0, [os1 + os4]; \ 3097c478bd9Sstevel@tonic-gate mov 1, os1; \ 3107c478bd9Sstevel@tonic-gate sll os1, ls1, os1; \ 3117c478bd9Sstevel@tonic-gate wr os1, CLEAR_SOFTINT; \ 3127c478bd9Sstevel@tonic-gate4: ldn [cpu + INTR_HEAD], os1; \ 3137c478bd9Sstevel@tonic-gate ld [os3 + INTR_NUMBER], os5; \ 3147c478bd9Sstevel@tonic-gate stn os3, [cpu + INTR_HEAD]; \ 3157c478bd9Sstevel@tonic-gate stn os1, [os3 + INTR_NEXT]; \ 3167c478bd9Sstevel@tonic-gate set intr_vector, ls1; \ 3177c478bd9Sstevel@tonic-gate sll os5, INTR_VECTOR_SHIFT, os1; \ 3187c478bd9Sstevel@tonic-gate add ls1, os1, ls1; \ 3197c478bd9Sstevel@tonic-gate sth %g0, [ls1 + IV_PENDING]; \ 3207c478bd9Sstevel@tonic-gate wrpr %g0, ls2, %pstate; \ 3217c478bd9Sstevel@tonic-gate SERVE_INTR_TRACE2(os5, os1, os2, os3, os4); \ 3227c478bd9Sstevel@tonic-gate mov os5, ls2; 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE 3257c478bd9Sstevel@tonic-gate/* 3267c478bd9Sstevel@tonic-gate * inum - not modified, _spurious depends on it. 3277c478bd9Sstevel@tonic-gate */ 3287c478bd9Sstevel@tonic-gate#define SERVE_INTR_TRACE(inum, os1, os2, os3, os4) \ 3297c478bd9Sstevel@tonic-gate rdpr %pstate, os3; \ 3307c478bd9Sstevel@tonic-gate andn os3, PSTATE_IE | PSTATE_AM, os2; \ 3317c478bd9Sstevel@tonic-gate wrpr %g0, os2, %pstate; \ 3327c478bd9Sstevel@tonic-gate TRACE_PTR(os1, os2); \ 3337c478bd9Sstevel@tonic-gate ldn [os4 + PC_OFF], os2; \ 3347c478bd9Sstevel@tonic-gate stna os2, [os1 + TRAP_ENT_TPC]%asi; \ 3357c478bd9Sstevel@tonic-gate ldx [os4 + TSTATE_OFF], os2; \ 3367c478bd9Sstevel@tonic-gate stxa os2, [os1 + TRAP_ENT_TSTATE]%asi; \ 3377c478bd9Sstevel@tonic-gate mov os3, os4; \ 3387c478bd9Sstevel@tonic-gate GET_TRACE_TICK(os2); \ 3397c478bd9Sstevel@tonic-gate stxa os2, [os1 + TRAP_ENT_TICK]%asi; \ 3407c478bd9Sstevel@tonic-gate TRACE_SAVE_TL_GL_REGS(os1, os2); \ 3417c478bd9Sstevel@tonic-gate set TT_SERVE_INTR, os2; \ 3427c478bd9Sstevel@tonic-gate rdpr %pil, os3; \ 3437c478bd9Sstevel@tonic-gate or os2, os3, os2; \ 3447c478bd9Sstevel@tonic-gate stha os2, [os1 + TRAP_ENT_TT]%asi; \ 3457c478bd9Sstevel@tonic-gate stna %sp, [os1 + TRAP_ENT_SP]%asi; \ 3467c478bd9Sstevel@tonic-gate stna inum, [os1 + TRAP_ENT_TR]%asi; \ 3477c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_F1]%asi; \ 3487c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_F2]%asi; \ 3497c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_F3]%asi; \ 3507c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_F4]%asi; \ 3517c478bd9Sstevel@tonic-gate TRACE_NEXT(os1, os2, os3); \ 3527c478bd9Sstevel@tonic-gate wrpr %g0, os4, %pstate 3537c478bd9Sstevel@tonic-gate#else /* TRAPTRACE */ 3547c478bd9Sstevel@tonic-gate#define SERVE_INTR_TRACE(inum, os1, os2, os3, os4) 3557c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */ 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE 3587c478bd9Sstevel@tonic-gate/* 3597c478bd9Sstevel@tonic-gate * inum - not modified, _spurious depends on it. 3607c478bd9Sstevel@tonic-gate */ 3617c478bd9Sstevel@tonic-gate#define SERVE_INTR_TRACE2(inum, os1, os2, os3, os4) \ 3627c478bd9Sstevel@tonic-gate rdpr %pstate, os3; \ 3637c478bd9Sstevel@tonic-gate andn os3, PSTATE_IE | PSTATE_AM, os2; \ 3647c478bd9Sstevel@tonic-gate wrpr %g0, os2, %pstate; \ 3657c478bd9Sstevel@tonic-gate TRACE_PTR(os1, os2); \ 3667c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_TPC]%asi; \ 3677c478bd9Sstevel@tonic-gate stxa %g0, [os1 + TRAP_ENT_TSTATE]%asi; \ 3687c478bd9Sstevel@tonic-gate mov os3, os4; \ 3697c478bd9Sstevel@tonic-gate GET_TRACE_TICK(os2); \ 3707c478bd9Sstevel@tonic-gate stxa os2, [os1 + TRAP_ENT_TICK]%asi; \ 3717c478bd9Sstevel@tonic-gate TRACE_SAVE_TL_GL_REGS(os1, os2); \ 3727c478bd9Sstevel@tonic-gate set TT_SERVE_INTR, os2; \ 3737c478bd9Sstevel@tonic-gate rdpr %pil, os3; \ 3747c478bd9Sstevel@tonic-gate or os2, os3, os2; \ 3757c478bd9Sstevel@tonic-gate stha os2, [os1 + TRAP_ENT_TT]%asi; \ 3767c478bd9Sstevel@tonic-gate stna %sp, [os1 + TRAP_ENT_SP]%asi; \ 3777c478bd9Sstevel@tonic-gate stna inum, [os1 + TRAP_ENT_TR]%asi; \ 3787c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_F1]%asi; \ 3797c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_F2]%asi; \ 3807c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_F3]%asi; \ 3817c478bd9Sstevel@tonic-gate stna %g0, [os1 + TRAP_ENT_F4]%asi; \ 3827c478bd9Sstevel@tonic-gate TRACE_NEXT(os1, os2, os3); \ 3837c478bd9Sstevel@tonic-gate wrpr %g0, os4, %pstate 3847c478bd9Sstevel@tonic-gate#else /* TRAPTRACE */ 3857c478bd9Sstevel@tonic-gate#define SERVE_INTR_TRACE2(inum, os1, os2, os3, os4) 3867c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */ 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate#endif /* lint */ 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate#if defined(lint) 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate/*ARGSUSED*/ 3937c478bd9Sstevel@tonic-gatevoid 3947c478bd9Sstevel@tonic-gateintr_thread(struct regs *regs, uint_t inumber, uint_t pil) 3957c478bd9Sstevel@tonic-gate{} 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate#else /* lint */ 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate#define INTRCNT_LIMIT 16 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate/* 4027c478bd9Sstevel@tonic-gate * Handle an interrupt in a new thread. 4037c478bd9Sstevel@tonic-gate * Entry: 4047c478bd9Sstevel@tonic-gate * %o0 = pointer to regs structure 4057c478bd9Sstevel@tonic-gate * %o1 = inumber 4067c478bd9Sstevel@tonic-gate * %o2 = pil 4077c478bd9Sstevel@tonic-gate * %sp = on current thread's kernel stack 4087c478bd9Sstevel@tonic-gate * %o7 = return linkage to trap code 4097c478bd9Sstevel@tonic-gate * %g7 = current thread 4107c478bd9Sstevel@tonic-gate * %pstate = normal globals, interrupts enabled, 4117c478bd9Sstevel@tonic-gate * privileged, fp disabled 4127c478bd9Sstevel@tonic-gate * %pil = DISP_LEVEL 4137c478bd9Sstevel@tonic-gate * 4147c478bd9Sstevel@tonic-gate * Register Usage 4157c478bd9Sstevel@tonic-gate * %l0 = return linkage 4167c478bd9Sstevel@tonic-gate * %l1 = pil 4177c478bd9Sstevel@tonic-gate * %l2 - %l3 = scratch 4187c478bd9Sstevel@tonic-gate * %l4 - %l7 = reserved for sys_trap 4197c478bd9Sstevel@tonic-gate * %o2 = cpu 4207c478bd9Sstevel@tonic-gate * %o3 = intr thread 4217c478bd9Sstevel@tonic-gate * %o0 = scratch 4227c478bd9Sstevel@tonic-gate * %o4 - %o5 = scratch 4237c478bd9Sstevel@tonic-gate */ 4247c478bd9Sstevel@tonic-gate ENTRY_NP(intr_thread) 4257c478bd9Sstevel@tonic-gate mov %o7, %l0 4267c478bd9Sstevel@tonic-gate mov %o2, %l1 4277c478bd9Sstevel@tonic-gate ! 4287c478bd9Sstevel@tonic-gate ! See if we are interrupting another interrupt thread. 4297c478bd9Sstevel@tonic-gate ! 4307c478bd9Sstevel@tonic-gate lduh [THREAD_REG + T_FLAGS], %o3 4317c478bd9Sstevel@tonic-gate andcc %o3, T_INTR_THREAD, %g0 4327c478bd9Sstevel@tonic-gate bz,pt %xcc, 1f 4337c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CPU], %o2 ! delay - load CPU pointer 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate ! We have interrupted an interrupt thread. Take a timestamp, 4367c478bd9Sstevel@tonic-gate ! compute its interval, and update its cumulative counter. 4377c478bd9Sstevel@tonic-gate add THREAD_REG, T_INTR_START, %o5 4387c478bd9Sstevel@tonic-gate0: 4397c478bd9Sstevel@tonic-gate ldx [%o5], %o3 4407c478bd9Sstevel@tonic-gate brz,pn %o3, 1f 4417c478bd9Sstevel@tonic-gate ! We came in on top of an interrupt thread that had no timestamp. 4427c478bd9Sstevel@tonic-gate ! This could happen if, for instance, an interrupt thread which had 4437c478bd9Sstevel@tonic-gate ! previously blocked is being set up to run again in resume(), but 4447c478bd9Sstevel@tonic-gate ! resume() hasn't yet stored a timestamp for it. Or, it could be in 4457c478bd9Sstevel@tonic-gate ! swtch() after its slice has been accounted for. 4467c478bd9Sstevel@tonic-gate ! Only account for the time slice if the starting timestamp is non-zero. 4477c478bd9Sstevel@tonic-gate rdpr %tick, %o4 ! delay 4487c478bd9Sstevel@tonic-gate sllx %o4, 1, %o4 ! shift off NPT bit 4497c478bd9Sstevel@tonic-gate srlx %o4, 1, %o4 4507c478bd9Sstevel@tonic-gate sub %o4, %o3, %o4 ! o4 has interval 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate ! A high-level interrupt in current_thread() interrupting here 4537c478bd9Sstevel@tonic-gate ! will account for the interrupted thread's time slice, but 4547c478bd9Sstevel@tonic-gate ! only if t_intr_start is non-zero. Since this code is going to account 4557c478bd9Sstevel@tonic-gate ! for the time slice, we want to "atomically" load the thread's 4567c478bd9Sstevel@tonic-gate ! starting timestamp, calculate the interval with %tick, and zero 4577c478bd9Sstevel@tonic-gate ! its starting timestamp. 4587c478bd9Sstevel@tonic-gate ! To do this, we do a casx on the t_intr_start field, and store 0 to it. 4597c478bd9Sstevel@tonic-gate ! If it has changed since we loaded it above, we need to re-compute the 4607c478bd9Sstevel@tonic-gate ! interval, since a changed t_intr_start implies current_thread placed 4617c478bd9Sstevel@tonic-gate ! a new, later timestamp there after running a high-level interrupt, 4627c478bd9Sstevel@tonic-gate ! and the %tick val in %o4 had become stale. 4637c478bd9Sstevel@tonic-gate mov %g0, %l2 4647c478bd9Sstevel@tonic-gate casx [%o5], %o3, %l2 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate ! If %l2 == %o3, our casx was successful. If not, the starting timestamp 4677c478bd9Sstevel@tonic-gate ! changed between loading it (after label 0b) and computing the 4687c478bd9Sstevel@tonic-gate ! interval above. 4697c478bd9Sstevel@tonic-gate cmp %l2, %o3 4707c478bd9Sstevel@tonic-gate bne,pn %xcc, 0b 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate ! Check for Energy Star mode 4737c478bd9Sstevel@tonic-gate lduh [%o2 + CPU_DIVISOR], %l2 ! delay -- %l2 = clock divisor 4747c478bd9Sstevel@tonic-gate cmp %l2, 1 4757c478bd9Sstevel@tonic-gate bg,a,pn %xcc, 2f 4767c478bd9Sstevel@tonic-gate mulx %o4, %l2, %o4 ! multiply interval by clock divisor iff > 1 4777c478bd9Sstevel@tonic-gate2: 4787c478bd9Sstevel@tonic-gate ! We now know that a valid interval for the interrupted interrupt 4797c478bd9Sstevel@tonic-gate ! thread is in %o4. Update its cumulative counter. 4807c478bd9Sstevel@tonic-gate ldub [THREAD_REG + T_PIL], %l3 ! load PIL 4817c478bd9Sstevel@tonic-gate sllx %l3, 4, %l3 ! convert PIL index to byte offset 4827c478bd9Sstevel@tonic-gate add %l3, CPU_MCPU, %l3 ! CPU_INTRSTAT is too big for use 4837c478bd9Sstevel@tonic-gate add %l3, MCPU_INTRSTAT, %l3 ! as const, add offsets separately 4847c478bd9Sstevel@tonic-gate ldx [%o2 + %l3], %o5 ! old counter in o5 4857c478bd9Sstevel@tonic-gate add %o5, %o4, %o5 ! new counter in o5 4867c478bd9Sstevel@tonic-gate stx %o5, [%o2 + %l3] ! store new counter 4877c478bd9Sstevel@tonic-gate 488eda89462Sesolom ! Also update intracct[] 489eda89462Sesolom lduh [%o2 + CPU_MSTATE], %l3 490eda89462Sesolom sllx %l3, 3, %l3 491eda89462Sesolom add %l3, CPU_INTRACCT, %l3 492eda89462Sesolom add %l3, %o2, %l3 493eda89462Sesolom0: 494eda89462Sesolom ldx [%l3], %o5 495eda89462Sesolom add %o5, %o4, %o3 496eda89462Sesolom casx [%l3], %o5, %o3 497eda89462Sesolom cmp %o5, %o3 498eda89462Sesolom bne,pn %xcc, 0b 499eda89462Sesolom nop 500eda89462Sesolom 5017c478bd9Sstevel@tonic-gate1: 5027c478bd9Sstevel@tonic-gate ! 5037c478bd9Sstevel@tonic-gate ! Get set to run interrupt thread. 5047c478bd9Sstevel@tonic-gate ! There should always be an interrupt thread since we allocate one 5057c478bd9Sstevel@tonic-gate ! for each level on the CPU. 5067c478bd9Sstevel@tonic-gate ! 5077c478bd9Sstevel@tonic-gate ! Note that the code in kcpc_overflow_intr -relies- on the ordering 5087c478bd9Sstevel@tonic-gate ! of events here -- in particular that t->t_lwp of the interrupt thread 5097c478bd9Sstevel@tonic-gate ! is set to the pinned thread *before* curthread is changed. 5107c478bd9Sstevel@tonic-gate ! 5117c478bd9Sstevel@tonic-gate ldn [%o2 + CPU_INTR_THREAD], %o3 ! interrupt thread pool 5127c478bd9Sstevel@tonic-gate ldn [%o3 + T_LINK], %o4 ! unlink thread from CPU's list 5137c478bd9Sstevel@tonic-gate stn %o4, [%o2 + CPU_INTR_THREAD] 5147c478bd9Sstevel@tonic-gate ! 5157c478bd9Sstevel@tonic-gate ! Set bit for this level in CPU's active interrupt bitmask. 5167c478bd9Sstevel@tonic-gate ! 5177c478bd9Sstevel@tonic-gate ld [%o2 + CPU_INTR_ACTV], %o5 5187c478bd9Sstevel@tonic-gate mov 1, %o4 5197c478bd9Sstevel@tonic-gate sll %o4, %l1, %o4 5207c478bd9Sstevel@tonic-gate#ifdef DEBUG 5217c478bd9Sstevel@tonic-gate ! 5227c478bd9Sstevel@tonic-gate ! ASSERT(!(CPU->cpu_intr_actv & (1 << PIL))) 5237c478bd9Sstevel@tonic-gate ! 5247c478bd9Sstevel@tonic-gate andcc %o5, %o4, %g0 5257c478bd9Sstevel@tonic-gate bz,pt %xcc, 0f 5267c478bd9Sstevel@tonic-gate nop 5277c478bd9Sstevel@tonic-gate ! Do not call panic if a panic is already in progress. 5287c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l2 5297c478bd9Sstevel@tonic-gate ld [%l2 + %lo(panic_quiesce)], %l2 5307c478bd9Sstevel@tonic-gate brnz,pn %l2, 0f 5317c478bd9Sstevel@tonic-gate nop 5327c478bd9Sstevel@tonic-gate sethi %hi(intr_thread_actv_bit_set), %o0 5337c478bd9Sstevel@tonic-gate call panic 5347c478bd9Sstevel@tonic-gate or %o0, %lo(intr_thread_actv_bit_set), %o0 5357c478bd9Sstevel@tonic-gate0: 5367c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 5377c478bd9Sstevel@tonic-gate or %o5, %o4, %o5 5387c478bd9Sstevel@tonic-gate st %o5, [%o2 + CPU_INTR_ACTV] 5397c478bd9Sstevel@tonic-gate ! 5407c478bd9Sstevel@tonic-gate ! Consider the new thread part of the same LWP so that 5417c478bd9Sstevel@tonic-gate ! window overflow code can find the PCB. 5427c478bd9Sstevel@tonic-gate ! 5437c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_LWP], %o4 5447c478bd9Sstevel@tonic-gate stn %o4, [%o3 + T_LWP] 5457c478bd9Sstevel@tonic-gate ! 5467c478bd9Sstevel@tonic-gate ! Threads on the interrupt thread free list could have state already 5477c478bd9Sstevel@tonic-gate ! set to TS_ONPROC, but it helps in debugging if they're TS_FREE 5487c478bd9Sstevel@tonic-gate ! Could eliminate the next two instructions with a little work. 5497c478bd9Sstevel@tonic-gate ! 5507c478bd9Sstevel@tonic-gate mov TS_ONPROC, %o4 5517c478bd9Sstevel@tonic-gate st %o4, [%o3 + T_STATE] 5527c478bd9Sstevel@tonic-gate ! 5537c478bd9Sstevel@tonic-gate ! Push interrupted thread onto list from new thread. 5547c478bd9Sstevel@tonic-gate ! Set the new thread as the current one. 5557c478bd9Sstevel@tonic-gate ! Set interrupted thread's T_SP because if it is the idle thread, 5567c478bd9Sstevel@tonic-gate ! resume may use that stack between threads. 5577c478bd9Sstevel@tonic-gate ! 5587c478bd9Sstevel@tonic-gate stn %o7, [THREAD_REG + T_PC] ! mark pc for resume 5597c478bd9Sstevel@tonic-gate stn %sp, [THREAD_REG + T_SP] ! mark stack for resume 5607c478bd9Sstevel@tonic-gate stn THREAD_REG, [%o3 + T_INTR] ! push old thread 5617c478bd9Sstevel@tonic-gate stn %o3, [%o2 + CPU_THREAD] ! set new thread 5627c478bd9Sstevel@tonic-gate mov %o3, THREAD_REG ! set global curthread register 5637c478bd9Sstevel@tonic-gate ldn [%o3 + T_STACK], %o4 ! interrupt stack pointer 5647c478bd9Sstevel@tonic-gate sub %o4, STACK_BIAS, %sp 5657c478bd9Sstevel@tonic-gate ! 5667c478bd9Sstevel@tonic-gate ! Initialize thread priority level from intr_pri 5677c478bd9Sstevel@tonic-gate ! 5687c478bd9Sstevel@tonic-gate sethi %hi(intr_pri), %o4 5697c478bd9Sstevel@tonic-gate ldsh [%o4 + %lo(intr_pri)], %o4 ! grab base interrupt priority 5707c478bd9Sstevel@tonic-gate add %l1, %o4, %o4 ! convert level to dispatch priority 5717c478bd9Sstevel@tonic-gate sth %o4, [THREAD_REG + T_PRI] 5727c478bd9Sstevel@tonic-gate stub %l1, [THREAD_REG + T_PIL] ! save pil for intr_passivate 5737c478bd9Sstevel@tonic-gate 5747c478bd9Sstevel@tonic-gate ! Store starting timestamp in thread structure. 5757c478bd9Sstevel@tonic-gate add THREAD_REG, T_INTR_START, %o3 5767c478bd9Sstevel@tonic-gate1: 5777c478bd9Sstevel@tonic-gate ldx [%o3], %o5 5787c478bd9Sstevel@tonic-gate rdpr %tick, %o4 5797c478bd9Sstevel@tonic-gate sllx %o4, 1, %o4 5807c478bd9Sstevel@tonic-gate srlx %o4, 1, %o4 ! shift off NPT bit 5817c478bd9Sstevel@tonic-gate casx [%o3], %o5, %o4 5827c478bd9Sstevel@tonic-gate cmp %o4, %o5 5837c478bd9Sstevel@tonic-gate ! If a high-level interrupt occurred while we were attempting to store 5847c478bd9Sstevel@tonic-gate ! the timestamp, try again. 5857c478bd9Sstevel@tonic-gate bne,pn %xcc, 1b 5867c478bd9Sstevel@tonic-gate nop 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate wrpr %g0, %l1, %pil ! lower %pil to new level 5897c478bd9Sstevel@tonic-gate ! 5907c478bd9Sstevel@tonic-gate ! Fast event tracing. 5917c478bd9Sstevel@tonic-gate ! 5927c478bd9Sstevel@tonic-gate ld [%o2 + CPU_FTRACE_STATE], %o4 ! %o2 = curthread->t_cpu 5937c478bd9Sstevel@tonic-gate btst FTRACE_ENABLED, %o4 5947c478bd9Sstevel@tonic-gate be,pt %icc, 1f ! skip if ftrace disabled 5957c478bd9Sstevel@tonic-gate mov %l1, %o5 5967c478bd9Sstevel@tonic-gate ! 5977c478bd9Sstevel@tonic-gate ! Tracing is enabled - write the trace entry. 5987c478bd9Sstevel@tonic-gate ! 5997c478bd9Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp 6007c478bd9Sstevel@tonic-gate set ftrace_intr_thread_format_str, %o0 6017c478bd9Sstevel@tonic-gate mov %i0, %o1 6027c478bd9Sstevel@tonic-gate mov %i1, %o2 6037c478bd9Sstevel@tonic-gate call ftrace_3 6047c478bd9Sstevel@tonic-gate mov %i5, %o3 6057c478bd9Sstevel@tonic-gate restore 6067c478bd9Sstevel@tonic-gate1: 6077c478bd9Sstevel@tonic-gate ! 6087c478bd9Sstevel@tonic-gate ! call the handler 6097c478bd9Sstevel@tonic-gate ! 6107c478bd9Sstevel@tonic-gate SERVE_INTR_PRE(%o1, %o2, %l1, %l3, %o4, %o5, %o3, %o0) 6117c478bd9Sstevel@tonic-gate ! 6127c478bd9Sstevel@tonic-gate ! %o0 and %o1 are now available as scratch registers. 6137c478bd9Sstevel@tonic-gate ! 6147c478bd9Sstevel@tonic-gate0: 6157c478bd9Sstevel@tonic-gate SERVE_INTR(%o1, %o2, %l1, %l3, %o4, %o5, %o3, %o0) 6167c478bd9Sstevel@tonic-gate ! 6177c478bd9Sstevel@tonic-gate ! If %o3 is set, we must call serve_intr_post, and both %l1 and %o3 6187c478bd9Sstevel@tonic-gate ! must be preserved. %l1 holds our pil, %l3 holds our inum. 6197c478bd9Sstevel@tonic-gate ! 6207c478bd9Sstevel@tonic-gate ! Note: %l1 is the pil level we're processing, but we may have a 6217c478bd9Sstevel@tonic-gate ! higher effective pil because a higher-level interrupt may have 6227c478bd9Sstevel@tonic-gate ! blocked. 6237c478bd9Sstevel@tonic-gate ! 6247c478bd9Sstevel@tonic-gate wrpr %g0, DISP_LEVEL, %pil 6257c478bd9Sstevel@tonic-gate ! 6267c478bd9Sstevel@tonic-gate ! Take timestamp, compute interval, update cumulative counter. 6277c478bd9Sstevel@tonic-gate ! 6287c478bd9Sstevel@tonic-gate add THREAD_REG, T_INTR_START, %o5 6297c478bd9Sstevel@tonic-gate1: 6307c478bd9Sstevel@tonic-gate ldx [%o5], %o0 6317c478bd9Sstevel@tonic-gate#ifdef DEBUG 6327c478bd9Sstevel@tonic-gate brnz %o0, 9f 6337c478bd9Sstevel@tonic-gate nop 6347c478bd9Sstevel@tonic-gate ! Do not call panic if a panic is already in progress. 6357c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %o1 6367c478bd9Sstevel@tonic-gate ld [%o1 + %lo(panic_quiesce)], %o1 6377c478bd9Sstevel@tonic-gate brnz,pn %o1, 9f 6387c478bd9Sstevel@tonic-gate nop 6397c478bd9Sstevel@tonic-gate sethi %hi(intr_thread_t_intr_start_zero), %o0 6407c478bd9Sstevel@tonic-gate call panic 6417c478bd9Sstevel@tonic-gate or %o0, %lo(intr_thread_t_intr_start_zero), %o0 6427c478bd9Sstevel@tonic-gate9: 6437c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 6447c478bd9Sstevel@tonic-gate rdpr %tick, %o1 6457c478bd9Sstevel@tonic-gate sllx %o1, 1, %o1 6467c478bd9Sstevel@tonic-gate srlx %o1, 1, %o1 ! shift off NPT bit 6477c478bd9Sstevel@tonic-gate sub %o1, %o0, %l2 ! l2 has interval 6487c478bd9Sstevel@tonic-gate ! 6497c478bd9Sstevel@tonic-gate ! The general outline of what the code here does is: 6507c478bd9Sstevel@tonic-gate ! 1. load t_intr_start, %tick, and calculate the delta 6517c478bd9Sstevel@tonic-gate ! 2. replace t_intr_start with %tick (if %o3 is set) or 0. 6527c478bd9Sstevel@tonic-gate ! 6537c478bd9Sstevel@tonic-gate ! The problem is that a high-level interrupt could arrive at any time. 6547c478bd9Sstevel@tonic-gate ! It will account for (%tick - t_intr_start) for us when it starts, 6557c478bd9Sstevel@tonic-gate ! unless we have set t_intr_start to zero, and then set t_intr_start 6567c478bd9Sstevel@tonic-gate ! to a new %tick when it finishes. To account for this, our first step 6577c478bd9Sstevel@tonic-gate ! is to load t_intr_start and the last is to use casx to store the new 6587c478bd9Sstevel@tonic-gate ! t_intr_start. This guarantees atomicity in reading t_intr_start, 6597c478bd9Sstevel@tonic-gate ! reading %tick, and updating t_intr_start. 6607c478bd9Sstevel@tonic-gate ! 6617c478bd9Sstevel@tonic-gate movrz %o3, %g0, %o1 6627c478bd9Sstevel@tonic-gate casx [%o5], %o0, %o1 6637c478bd9Sstevel@tonic-gate cmp %o0, %o1 6647c478bd9Sstevel@tonic-gate bne,pn %xcc, 1b 6657c478bd9Sstevel@tonic-gate ! 6667c478bd9Sstevel@tonic-gate ! Check for Energy Star mode 6677c478bd9Sstevel@tonic-gate ! 6687c478bd9Sstevel@tonic-gate lduh [%o2 + CPU_DIVISOR], %o0 ! delay -- %o0 = clock divisor 6697c478bd9Sstevel@tonic-gate cmp %o0, 1 6707c478bd9Sstevel@tonic-gate bg,a,pn %xcc, 2f 6717c478bd9Sstevel@tonic-gate mulx %l2, %o0, %l2 ! multiply interval by clock divisor iff > 1 6727c478bd9Sstevel@tonic-gate2: 6737c478bd9Sstevel@tonic-gate ! 6747c478bd9Sstevel@tonic-gate ! Update cpu_intrstat. If o3 is set then we will be processing another 6757c478bd9Sstevel@tonic-gate ! interrupt. Above we have set t_intr_start to %tick, not 0. This 6767c478bd9Sstevel@tonic-gate ! means a high-level interrupt can arrive and update the same stats 6777c478bd9Sstevel@tonic-gate ! we're updating. Need to use casx. 6787c478bd9Sstevel@tonic-gate ! 6797c478bd9Sstevel@tonic-gate sllx %l1, 4, %o1 ! delay - PIL as byte offset 6807c478bd9Sstevel@tonic-gate add %o1, CPU_MCPU, %o1 ! CPU_INTRSTAT const too big 6817c478bd9Sstevel@tonic-gate add %o1, MCPU_INTRSTAT, %o1 ! add parts separately 6827c478bd9Sstevel@tonic-gate add %o1, %o2, %o1 6837c478bd9Sstevel@tonic-gate1: 6847c478bd9Sstevel@tonic-gate ldx [%o1], %o5 ! old counter in o5 6857c478bd9Sstevel@tonic-gate add %o5, %l2, %o0 ! new counter in o0 6867c478bd9Sstevel@tonic-gate stx %o0, [%o1 + 8] ! store into intrstat[pil][1] 6877c478bd9Sstevel@tonic-gate casx [%o1], %o5, %o0 ! and into intrstat[pil][0] 6887c478bd9Sstevel@tonic-gate cmp %o5, %o0 6897c478bd9Sstevel@tonic-gate bne,pn %xcc, 1b 6907c478bd9Sstevel@tonic-gate nop 691eda89462Sesolom 692eda89462Sesolom ! Also update intracct[] 693eda89462Sesolom lduh [%o2 + CPU_MSTATE], %o1 694eda89462Sesolom sllx %o1, 3, %o1 695eda89462Sesolom add %o1, CPU_INTRACCT, %o1 696eda89462Sesolom add %o1, %o2, %o1 697eda89462Sesolom1: 698eda89462Sesolom ldx [%o1], %o5 699eda89462Sesolom add %o5, %l2, %o0 700eda89462Sesolom casx [%o1], %o5, %o0 701eda89462Sesolom cmp %o5, %o0 702eda89462Sesolom bne,pn %xcc, 1b 703eda89462Sesolom nop 704eda89462Sesolom 7057c478bd9Sstevel@tonic-gate ! 7067c478bd9Sstevel@tonic-gate ! Don't keep a pinned process pinned indefinitely. Bump cpu_intrcnt 7077c478bd9Sstevel@tonic-gate ! for each interrupt handler we invoke. If we hit INTRCNT_LIMIT, then 7087c478bd9Sstevel@tonic-gate ! we've crossed the threshold and we should unpin the pinned threads 7097c478bd9Sstevel@tonic-gate ! by preempt()ing ourselves, which will bubble up the t_intr chain 7107c478bd9Sstevel@tonic-gate ! until hitting the non-interrupt thread, which will then in turn 7117c478bd9Sstevel@tonic-gate ! preempt itself allowing the interrupt processing to resume. Finally, 7127c478bd9Sstevel@tonic-gate ! the scheduler takes over and picks the next thread to run. 7137c478bd9Sstevel@tonic-gate ! 7147c478bd9Sstevel@tonic-gate ! If our CPU is quiesced, we cannot preempt because the idle thread 7157c478bd9Sstevel@tonic-gate ! won't ever re-enter the scheduler, and the interrupt will be forever 7167c478bd9Sstevel@tonic-gate ! blocked. 7177c478bd9Sstevel@tonic-gate ! 7187c478bd9Sstevel@tonic-gate ! If t_intr is NULL, we're not pinning anyone, so we use a simpler 7197c478bd9Sstevel@tonic-gate ! algorithm. Just check for cpu_kprunrun, and if set then preempt. 7207c478bd9Sstevel@tonic-gate ! This insures we enter the scheduler if a higher-priority thread 7217c478bd9Sstevel@tonic-gate ! has become runnable. 7227c478bd9Sstevel@tonic-gate ! 7237c478bd9Sstevel@tonic-gate lduh [%o2 + CPU_FLAGS], %o5 ! don't preempt if quiesced 7247c478bd9Sstevel@tonic-gate andcc %o5, CPU_QUIESCED, %g0 7257c478bd9Sstevel@tonic-gate bnz,pn %xcc, 1f 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_INTR], %o5 ! pinning anything? 7287c478bd9Sstevel@tonic-gate brz,pn %o5, 3f ! if not, don't inc intrcnt 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate ldub [%o2 + CPU_INTRCNT], %o5 ! delay - %o5 = cpu_intrcnt 7317c478bd9Sstevel@tonic-gate inc %o5 7327c478bd9Sstevel@tonic-gate cmp %o5, INTRCNT_LIMIT ! have we hit the limit? 7337c478bd9Sstevel@tonic-gate bl,a,pt %xcc, 1f ! no preempt if < INTRCNT_LIMIT 7347c478bd9Sstevel@tonic-gate stub %o5, [%o2 + CPU_INTRCNT] ! delay annul - inc CPU_INTRCNT 7357c478bd9Sstevel@tonic-gate bg,pn %xcc, 2f ! don't inc stats again 7367c478bd9Sstevel@tonic-gate ! 7377c478bd9Sstevel@tonic-gate ! We've reached the limit. Set cpu_intrcnt and cpu_kprunrun, and do 7387c478bd9Sstevel@tonic-gate ! CPU_STATS_ADDQ(cp, sys, intrunpin, 1). Then call preempt. 7397c478bd9Sstevel@tonic-gate ! 7407c478bd9Sstevel@tonic-gate mov 1, %o4 ! delay 7417c478bd9Sstevel@tonic-gate stub %o4, [%o2 + CPU_KPRUNRUN] 7427c478bd9Sstevel@tonic-gate ldx [%o2 + CPU_STATS_SYS_INTRUNPIN], %o4 7437c478bd9Sstevel@tonic-gate inc %o4 7447c478bd9Sstevel@tonic-gate stx %o4, [%o2 + CPU_STATS_SYS_INTRUNPIN] 7457c478bd9Sstevel@tonic-gate ba 2f 7467c478bd9Sstevel@tonic-gate stub %o5, [%o2 + CPU_INTRCNT] ! delay 7477c478bd9Sstevel@tonic-gate3: 7487c478bd9Sstevel@tonic-gate ! Code for t_intr == NULL 7497c478bd9Sstevel@tonic-gate ldub [%o2 + CPU_KPRUNRUN], %o5 7507c478bd9Sstevel@tonic-gate brz,pt %o5, 1f ! don't preempt unless kprunrun 7517c478bd9Sstevel@tonic-gate2: 7527c478bd9Sstevel@tonic-gate ! Time to call preempt 7537c478bd9Sstevel@tonic-gate mov %o2, %l3 ! delay - save %o2 7547c478bd9Sstevel@tonic-gate call preempt 7557c478bd9Sstevel@tonic-gate mov %o3, %l2 ! delay - save %o3. 7567c478bd9Sstevel@tonic-gate mov %l3, %o2 ! restore %o2 7577c478bd9Sstevel@tonic-gate mov %l2, %o3 ! restore %o3 7587c478bd9Sstevel@tonic-gate wrpr %g0, DISP_LEVEL, %pil ! up from cpu_base_spl 7597c478bd9Sstevel@tonic-gate1: 7607c478bd9Sstevel@tonic-gate ! 7617c478bd9Sstevel@tonic-gate ! Do we need to call serve_intr_post and do this again? 7627c478bd9Sstevel@tonic-gate ! 7637c478bd9Sstevel@tonic-gate brz,a,pt %o3, 0f 7647c478bd9Sstevel@tonic-gate ld [%o2 + CPU_INTR_ACTV], %o5 ! delay annulled 7657c478bd9Sstevel@tonic-gate ! 7667c478bd9Sstevel@tonic-gate ! Restore %pil before calling serve_intr() again. We must check 7677c478bd9Sstevel@tonic-gate ! CPU_BASE_SPL and set %pil to max(our-pil, CPU_BASE_SPL) 7687c478bd9Sstevel@tonic-gate ! 7697c478bd9Sstevel@tonic-gate ld [%o2 + CPU_BASE_SPL], %o4 7707c478bd9Sstevel@tonic-gate cmp %o4, %l1 7717c478bd9Sstevel@tonic-gate movl %xcc, %l1, %o4 7727c478bd9Sstevel@tonic-gate wrpr %g0, %o4, %pil 7737c478bd9Sstevel@tonic-gate SERVE_INTR_NEXT(%o1, %o2, %l1, %l3, %o4, %o5, %o3, %o0) 7747c478bd9Sstevel@tonic-gate ba 0b ! compute new stats 7757c478bd9Sstevel@tonic-gate nop 7767c478bd9Sstevel@tonic-gate0: 7777c478bd9Sstevel@tonic-gate ! 7787c478bd9Sstevel@tonic-gate ! Clear bit for this level in CPU's interrupt active bitmask. 7797c478bd9Sstevel@tonic-gate ! 7807c478bd9Sstevel@tonic-gate mov 1, %o4 7817c478bd9Sstevel@tonic-gate sll %o4, %l1, %o4 7827c478bd9Sstevel@tonic-gate#ifdef DEBUG 7837c478bd9Sstevel@tonic-gate ! 7847c478bd9Sstevel@tonic-gate ! ASSERT(CPU->cpu_intr_actv & (1 << PIL)) 7857c478bd9Sstevel@tonic-gate ! 7867c478bd9Sstevel@tonic-gate andcc %o4, %o5, %g0 7877c478bd9Sstevel@tonic-gate bnz,pt %xcc, 0f 7887c478bd9Sstevel@tonic-gate nop 7897c478bd9Sstevel@tonic-gate ! Do not call panic if a panic is already in progress. 7907c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l2 7917c478bd9Sstevel@tonic-gate ld [%l2 + %lo(panic_quiesce)], %l2 7927c478bd9Sstevel@tonic-gate brnz,pn %l2, 0f 7937c478bd9Sstevel@tonic-gate nop 7947c478bd9Sstevel@tonic-gate sethi %hi(intr_thread_actv_bit_not_set), %o0 7957c478bd9Sstevel@tonic-gate call panic 7967c478bd9Sstevel@tonic-gate or %o0, %lo(intr_thread_actv_bit_not_set), %o0 7977c478bd9Sstevel@tonic-gate0: 7987c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 7997c478bd9Sstevel@tonic-gate andn %o5, %o4, %o5 8007c478bd9Sstevel@tonic-gate st %o5, [%o2 + CPU_INTR_ACTV] 8017c478bd9Sstevel@tonic-gate ! 8027c478bd9Sstevel@tonic-gate ! If there is still an interrupted thread underneath this one, 8037c478bd9Sstevel@tonic-gate ! then the interrupt was never blocked and the return is fairly 8047c478bd9Sstevel@tonic-gate ! simple. Otherwise jump to intr_thread_exit. 8057c478bd9Sstevel@tonic-gate ! 8067c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_INTR], %o4 ! pinned thread 8077c478bd9Sstevel@tonic-gate brz,pn %o4, intr_thread_exit ! branch if none 8087c478bd9Sstevel@tonic-gate nop 8097c478bd9Sstevel@tonic-gate ! 8107c478bd9Sstevel@tonic-gate ! link the thread back onto the interrupt thread pool 8117c478bd9Sstevel@tonic-gate ! 8127c478bd9Sstevel@tonic-gate ldn [%o2 + CPU_INTR_THREAD], %o3 8137c478bd9Sstevel@tonic-gate stn %o3, [THREAD_REG + T_LINK] 8147c478bd9Sstevel@tonic-gate stn THREAD_REG, [%o2 + CPU_INTR_THREAD] 8157c478bd9Sstevel@tonic-gate ! 8167c478bd9Sstevel@tonic-gate ! set the thread state to free so kernel debuggers don't see it 8177c478bd9Sstevel@tonic-gate ! 8187c478bd9Sstevel@tonic-gate mov TS_FREE, %o5 8197c478bd9Sstevel@tonic-gate st %o5, [THREAD_REG + T_STATE] 8207c478bd9Sstevel@tonic-gate ! 8217c478bd9Sstevel@tonic-gate ! Switch back to the interrupted thread and return 8227c478bd9Sstevel@tonic-gate ! 8237c478bd9Sstevel@tonic-gate stn %o4, [%o2 + CPU_THREAD] 824*25cf1a30Sjl139090 membar #StoreLoad ! sync with mutex_exit() 8257c478bd9Sstevel@tonic-gate mov %o4, THREAD_REG 8267c478bd9Sstevel@tonic-gate 8277c478bd9Sstevel@tonic-gate ! If we pinned an interrupt thread, store its starting timestamp. 8287c478bd9Sstevel@tonic-gate lduh [THREAD_REG + T_FLAGS], %o5 8297c478bd9Sstevel@tonic-gate andcc %o5, T_INTR_THREAD, %g0 8307c478bd9Sstevel@tonic-gate bz,pt %xcc, 1f 8317c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_SP], %sp ! delay - restore %sp 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate add THREAD_REG, T_INTR_START, %o3 ! o3 has &curthread->t_intr_star 8347c478bd9Sstevel@tonic-gate0: 8357c478bd9Sstevel@tonic-gate ldx [%o3], %o4 ! o4 = t_intr_start before 8367c478bd9Sstevel@tonic-gate rdpr %tick, %o5 8377c478bd9Sstevel@tonic-gate sllx %o5, 1, %o5 8387c478bd9Sstevel@tonic-gate srlx %o5, 1, %o5 ! shift off NPT bit 8397c478bd9Sstevel@tonic-gate casx [%o3], %o4, %o5 ! put o5 in ts if o4 == ts after 8407c478bd9Sstevel@tonic-gate cmp %o4, %o5 8417c478bd9Sstevel@tonic-gate ! If a high-level interrupt occurred while we were attempting to store 8427c478bd9Sstevel@tonic-gate ! the timestamp, try again. 8437c478bd9Sstevel@tonic-gate bne,pn %xcc, 0b 8447c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_SP], %sp ! delay - restore %sp 8457c478bd9Sstevel@tonic-gate1: 8467c478bd9Sstevel@tonic-gate ! If the thread being restarted isn't pinning anyone, and no interrupts 8477c478bd9Sstevel@tonic-gate ! are pending, zero out cpu_intrcnt 8487c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_INTR], %o4 8497c478bd9Sstevel@tonic-gate brnz,pn %o4, 2f 8507c478bd9Sstevel@tonic-gate rd SOFTINT, %o4 ! delay 8517c478bd9Sstevel@tonic-gate set SOFTINT_MASK, %o5 8527c478bd9Sstevel@tonic-gate andcc %o4, %o5, %g0 8537c478bd9Sstevel@tonic-gate bz,a,pt %xcc, 2f 8547c478bd9Sstevel@tonic-gate stub %g0, [%o2 + CPU_INTRCNT] ! delay annul 8557c478bd9Sstevel@tonic-gate2: 8567c478bd9Sstevel@tonic-gate jmp %l0 + 8 8577c478bd9Sstevel@tonic-gate nop 8587c478bd9Sstevel@tonic-gate SET_SIZE(intr_thread) 8597c478bd9Sstevel@tonic-gate /* Not Reached */ 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate ! 8627c478bd9Sstevel@tonic-gate ! An interrupt returned on what was once (and still might be) 8637c478bd9Sstevel@tonic-gate ! an interrupt thread stack, but the interrupted process is no longer 8647c478bd9Sstevel@tonic-gate ! there. This means the interrupt must have blocked. 8657c478bd9Sstevel@tonic-gate ! 8667c478bd9Sstevel@tonic-gate ! There is no longer a thread under this one, so put this thread back 8677c478bd9Sstevel@tonic-gate ! on the CPU's free list and resume the idle thread which will dispatch 8687c478bd9Sstevel@tonic-gate ! the next thread to run. 8697c478bd9Sstevel@tonic-gate ! 8707c478bd9Sstevel@tonic-gate ! All traps below DISP_LEVEL are disabled here, but the mondo interrupt 8717c478bd9Sstevel@tonic-gate ! is enabled. 8727c478bd9Sstevel@tonic-gate ! 8737c478bd9Sstevel@tonic-gate ENTRY_NP(intr_thread_exit) 8747c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE 8757c478bd9Sstevel@tonic-gate rdpr %pstate, %l2 8767c478bd9Sstevel@tonic-gate andn %l2, PSTATE_IE | PSTATE_AM, %o4 8777c478bd9Sstevel@tonic-gate wrpr %g0, %o4, %pstate ! cpu to known state 8787c478bd9Sstevel@tonic-gate TRACE_PTR(%o4, %o5) 8797c478bd9Sstevel@tonic-gate GET_TRACE_TICK(%o5) 8807c478bd9Sstevel@tonic-gate stxa %o5, [%o4 + TRAP_ENT_TICK]%asi 8817c478bd9Sstevel@tonic-gate TRACE_SAVE_TL_GL_REGS(%o4, %o5) 8827c478bd9Sstevel@tonic-gate set TT_INTR_EXIT, %o5 8837c478bd9Sstevel@tonic-gate stha %o5, [%o4 + TRAP_ENT_TT]%asi 8847c478bd9Sstevel@tonic-gate stna %g0, [%o4 + TRAP_ENT_TPC]%asi 8857c478bd9Sstevel@tonic-gate stxa %g0, [%o4 + TRAP_ENT_TSTATE]%asi 8867c478bd9Sstevel@tonic-gate stna %sp, [%o4 + TRAP_ENT_SP]%asi 8877c478bd9Sstevel@tonic-gate stna THREAD_REG, [%o4 + TRAP_ENT_TR]%asi 8887c478bd9Sstevel@tonic-gate ld [%o2 + CPU_BASE_SPL], %o5 8897c478bd9Sstevel@tonic-gate stna %o5, [%o4 + TRAP_ENT_F1]%asi 8907c478bd9Sstevel@tonic-gate stna %g0, [%o4 + TRAP_ENT_F2]%asi 8917c478bd9Sstevel@tonic-gate stna %g0, [%o4 + TRAP_ENT_F3]%asi 8927c478bd9Sstevel@tonic-gate stna %g0, [%o4 + TRAP_ENT_F4]%asi 8937c478bd9Sstevel@tonic-gate TRACE_NEXT(%o4, %o5, %o0) 8947c478bd9Sstevel@tonic-gate wrpr %g0, %l2, %pstate 8957c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */ 8967c478bd9Sstevel@tonic-gate ! cpu_stats.sys.intrblk++ 8977c478bd9Sstevel@tonic-gate ldx [%o2 + CPU_STATS_SYS_INTRBLK], %o4 8987c478bd9Sstevel@tonic-gate inc %o4 8997c478bd9Sstevel@tonic-gate stx %o4, [%o2 + CPU_STATS_SYS_INTRBLK] 9007c478bd9Sstevel@tonic-gate ! 9017c478bd9Sstevel@tonic-gate ! Put thread back on the interrupt thread list. 9027c478bd9Sstevel@tonic-gate ! 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate ! 9057c478bd9Sstevel@tonic-gate ! Set the CPU's base SPL level. 9067c478bd9Sstevel@tonic-gate ! 9077c478bd9Sstevel@tonic-gate#ifdef DEBUG 9087c478bd9Sstevel@tonic-gate ! 9097c478bd9Sstevel@tonic-gate ! ASSERT(!(CPU->cpu_intr_actv & (1 << PIL))) 9107c478bd9Sstevel@tonic-gate ! 9117c478bd9Sstevel@tonic-gate ld [%o2 + CPU_INTR_ACTV], %o5 9127c478bd9Sstevel@tonic-gate mov 1, %o4 9137c478bd9Sstevel@tonic-gate sll %o4, %l1, %o4 9147c478bd9Sstevel@tonic-gate and %o5, %o4, %o4 9157c478bd9Sstevel@tonic-gate brz,pt %o4, 0f 9167c478bd9Sstevel@tonic-gate nop 9177c478bd9Sstevel@tonic-gate ! Do not call panic if a panic is already in progress. 9187c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l2 9197c478bd9Sstevel@tonic-gate ld [%l2 + %lo(panic_quiesce)], %l2 9207c478bd9Sstevel@tonic-gate brnz,pn %l2, 0f 9217c478bd9Sstevel@tonic-gate nop 9227c478bd9Sstevel@tonic-gate sethi %hi(intr_thread_exit_actv_bit_set), %o0 9237c478bd9Sstevel@tonic-gate call panic 9247c478bd9Sstevel@tonic-gate or %o0, %lo(intr_thread_exit_actv_bit_set), %o0 9257c478bd9Sstevel@tonic-gate0: 9267c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 9277c478bd9Sstevel@tonic-gate call _intr_set_spl ! set CPU's base SPL level 9287c478bd9Sstevel@tonic-gate ld [%o2 + CPU_INTR_ACTV], %o5 ! delay - load active mask 9297c478bd9Sstevel@tonic-gate ! 9307c478bd9Sstevel@tonic-gate ! set the thread state to free so kernel debuggers don't see it 9317c478bd9Sstevel@tonic-gate ! 9327c478bd9Sstevel@tonic-gate mov TS_FREE, %o4 9337c478bd9Sstevel@tonic-gate st %o4, [THREAD_REG + T_STATE] 9347c478bd9Sstevel@tonic-gate ! 9357c478bd9Sstevel@tonic-gate ! Put thread on either the interrupt pool or the free pool and 9367c478bd9Sstevel@tonic-gate ! call swtch() to resume another thread. 9377c478bd9Sstevel@tonic-gate ! 9387c478bd9Sstevel@tonic-gate ldn [%o2 + CPU_INTR_THREAD], %o5 ! get list pointer 9397c478bd9Sstevel@tonic-gate stn %o5, [THREAD_REG + T_LINK] 9407c478bd9Sstevel@tonic-gate call swtch ! switch to best thread 9417c478bd9Sstevel@tonic-gate stn THREAD_REG, [%o2 + CPU_INTR_THREAD] ! delay - put thread on list 9427c478bd9Sstevel@tonic-gate ba,a,pt %xcc, . ! swtch() shouldn't return 9437c478bd9Sstevel@tonic-gate SET_SIZE(intr_thread_exit) 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate .global ftrace_intr_thread_format_str 9467c478bd9Sstevel@tonic-gateftrace_intr_thread_format_str: 9477c478bd9Sstevel@tonic-gate .asciz "intr_thread(): regs=0x%lx, int=0x%lx, pil=0x%lx" 9487c478bd9Sstevel@tonic-gate#ifdef DEBUG 9497c478bd9Sstevel@tonic-gateintr_thread_actv_bit_set: 9507c478bd9Sstevel@tonic-gate .asciz "intr_thread(): cpu_intr_actv bit already set for PIL" 9517c478bd9Sstevel@tonic-gateintr_thread_actv_bit_not_set: 9527c478bd9Sstevel@tonic-gate .asciz "intr_thread(): cpu_intr_actv bit not set for PIL" 9537c478bd9Sstevel@tonic-gateintr_thread_exit_actv_bit_set: 9547c478bd9Sstevel@tonic-gate .asciz "intr_thread_exit(): cpu_intr_actv bit erroneously set for PIL" 9557c478bd9Sstevel@tonic-gateintr_thread_t_intr_start_zero: 9567c478bd9Sstevel@tonic-gate .asciz "intr_thread(): t_intr_start zero upon handler return" 9577c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 9587c478bd9Sstevel@tonic-gate#endif /* lint */ 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate#if defined(lint) 9617c478bd9Sstevel@tonic-gate 9627c478bd9Sstevel@tonic-gate/* 9637c478bd9Sstevel@tonic-gate * Handle an interrupt in the current thread 9647c478bd9Sstevel@tonic-gate * Entry: 9657c478bd9Sstevel@tonic-gate * %o0 = pointer to regs structure 9667c478bd9Sstevel@tonic-gate * %o1 = inumber 9677c478bd9Sstevel@tonic-gate * %o2 = pil 9687c478bd9Sstevel@tonic-gate * %sp = on current thread's kernel stack 9697c478bd9Sstevel@tonic-gate * %o7 = return linkage to trap code 9707c478bd9Sstevel@tonic-gate * %g7 = current thread 9717c478bd9Sstevel@tonic-gate * %pstate = normal globals, interrupts enabled, 9727c478bd9Sstevel@tonic-gate * privileged, fp disabled 9737c478bd9Sstevel@tonic-gate * %pil = PIL_MAX 9747c478bd9Sstevel@tonic-gate * 9757c478bd9Sstevel@tonic-gate * Register Usage 9767c478bd9Sstevel@tonic-gate * %l0 = return linkage 9777c478bd9Sstevel@tonic-gate * %l1 = old stack 9787c478bd9Sstevel@tonic-gate * %l2 - %l3 = scratch 9797c478bd9Sstevel@tonic-gate * %l4 - %l7 = reserved for sys_trap 9807c478bd9Sstevel@tonic-gate * %o3 = cpu 9817c478bd9Sstevel@tonic-gate * %o0 = scratch 9827c478bd9Sstevel@tonic-gate * %o4 - %o5 = scratch 9837c478bd9Sstevel@tonic-gate */ 9847c478bd9Sstevel@tonic-gate/* ARGSUSED */ 9857c478bd9Sstevel@tonic-gatevoid 9867c478bd9Sstevel@tonic-gatecurrent_thread(struct regs *regs, uint_t inumber, uint_t pil) 9877c478bd9Sstevel@tonic-gate{} 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate#else /* lint */ 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate ENTRY_NP(current_thread) 9927c478bd9Sstevel@tonic-gate 9937c478bd9Sstevel@tonic-gate mov %o7, %l0 9947c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CPU], %o3 9957c478bd9Sstevel@tonic-gate ! 9967c478bd9Sstevel@tonic-gate ! Set bit for this level in CPU's active interrupt bitmask. 9977c478bd9Sstevel@tonic-gate ! 9987c478bd9Sstevel@tonic-gate ld [%o3 + CPU_INTR_ACTV], %o5 ! o5 has cpu_intr_actv b4 chng 9997c478bd9Sstevel@tonic-gate mov 1, %o4 10007c478bd9Sstevel@tonic-gate sll %o4, %o2, %o4 ! construct mask for level 10017c478bd9Sstevel@tonic-gate#ifdef DEBUG 10027c478bd9Sstevel@tonic-gate ! 10037c478bd9Sstevel@tonic-gate ! ASSERT(!(CPU->cpu_intr_actv & (1 << PIL))) 10047c478bd9Sstevel@tonic-gate ! 10057c478bd9Sstevel@tonic-gate andcc %o5, %o4, %g0 10067c478bd9Sstevel@tonic-gate bz,pt %xcc, 0f 10077c478bd9Sstevel@tonic-gate nop 10087c478bd9Sstevel@tonic-gate ! Do not call panic if a panic is already in progress. 10097c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l2 10107c478bd9Sstevel@tonic-gate ld [%l2 + %lo(panic_quiesce)], %l2 10117c478bd9Sstevel@tonic-gate brnz,pn %l2, 0f 10127c478bd9Sstevel@tonic-gate nop 10137c478bd9Sstevel@tonic-gate sethi %hi(current_thread_actv_bit_set), %o0 10147c478bd9Sstevel@tonic-gate call panic 10157c478bd9Sstevel@tonic-gate or %o0, %lo(current_thread_actv_bit_set), %o0 10167c478bd9Sstevel@tonic-gate0: 10177c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 10187c478bd9Sstevel@tonic-gate or %o5, %o4, %o4 10197c478bd9Sstevel@tonic-gate ! 10207c478bd9Sstevel@tonic-gate ! See if we are interrupting another high-level interrupt. 10217c478bd9Sstevel@tonic-gate ! 10227c478bd9Sstevel@tonic-gate srl %o5, LOCK_LEVEL + 1, %o5 ! only look at high-level bits 10237c478bd9Sstevel@tonic-gate brz,pt %o5, 1f 10247c478bd9Sstevel@tonic-gate st %o4, [%o3 + CPU_INTR_ACTV] ! delay - store active mask 10257c478bd9Sstevel@tonic-gate ! 10267c478bd9Sstevel@tonic-gate ! We have interrupted another high-level interrupt. Find its PIL, 10277c478bd9Sstevel@tonic-gate ! compute the interval it ran for, and update its cumulative counter. 10287c478bd9Sstevel@tonic-gate ! 10297c478bd9Sstevel@tonic-gate ! Register usage: 10307c478bd9Sstevel@tonic-gate 10317c478bd9Sstevel@tonic-gate ! o2 = PIL of this interrupt 10327c478bd9Sstevel@tonic-gate ! o5 = high PIL bits of INTR_ACTV (not including this PIL) 10337c478bd9Sstevel@tonic-gate ! l1 = bitmask used to find other active high-level PIL 10347c478bd9Sstevel@tonic-gate ! o4 = index of bit set in l1 10357c478bd9Sstevel@tonic-gate ! Use cpu_intr_actv to find the cpu_pil_high_start[] offset for the 10367c478bd9Sstevel@tonic-gate ! interrupted high-level interrupt. 10377c478bd9Sstevel@tonic-gate ! Create mask for cpu_intr_actv. Begin by looking for bits set 10387c478bd9Sstevel@tonic-gate ! at one level below the current PIL. Since %o5 contains the active 10397c478bd9Sstevel@tonic-gate ! mask already shifted right by (LOCK_LEVEL + 1), we start by looking 10407c478bd9Sstevel@tonic-gate ! at bit (current_pil - (LOCK_LEVEL + 2)). 10417c478bd9Sstevel@tonic-gate sub %o2, LOCK_LEVEL + 2, %o4 10427c478bd9Sstevel@tonic-gate mov 1, %l1 10437c478bd9Sstevel@tonic-gate sll %l1, %o4, %l1 10447c478bd9Sstevel@tonic-gate2: 10457c478bd9Sstevel@tonic-gate#ifdef DEBUG 10467c478bd9Sstevel@tonic-gate ! ASSERT(%l1 != 0) (we didn't shift the bit off the right edge) 10477c478bd9Sstevel@tonic-gate brnz,pt %l1, 9f 10487c478bd9Sstevel@tonic-gate nop 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate ! Don't panic if a panic is already in progress. 10517c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l3 10527c478bd9Sstevel@tonic-gate ld [%l3 + %lo(panic_quiesce)], %l3 10537c478bd9Sstevel@tonic-gate brnz,pn %l3, 9f 10547c478bd9Sstevel@tonic-gate nop 10557c478bd9Sstevel@tonic-gate sethi %hi(current_thread_nested_PIL_not_found), %o0 10567c478bd9Sstevel@tonic-gate call panic 10577c478bd9Sstevel@tonic-gate or %o0, %lo(current_thread_nested_PIL_not_found), %o0 10587c478bd9Sstevel@tonic-gate9: 10597c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 10607c478bd9Sstevel@tonic-gate andcc %l1, %o5, %g0 ! test mask against high-level bits of 10617c478bd9Sstevel@tonic-gate bnz %xcc, 3f ! cpu_intr_actv 10627c478bd9Sstevel@tonic-gate nop 10637c478bd9Sstevel@tonic-gate srl %l1, 1, %l1 ! No match. Try next lower PIL. 10647c478bd9Sstevel@tonic-gate ba,pt %xcc, 2b 10657c478bd9Sstevel@tonic-gate sub %o4, 1, %o4 ! delay - decrement PIL 10667c478bd9Sstevel@tonic-gate3: 10677c478bd9Sstevel@tonic-gate sll %o4, 3, %o4 ! index to byte offset 10687c478bd9Sstevel@tonic-gate add %o4, CPU_MCPU, %l1 ! CPU_PIL_HIGH_START is too large 10697c478bd9Sstevel@tonic-gate add %l1, MCPU_PIL_HIGH_START, %l1 10707c478bd9Sstevel@tonic-gate ldx [%o3 + %l1], %l3 ! load starting timestamp 10717c478bd9Sstevel@tonic-gate#ifdef DEBUG 10727c478bd9Sstevel@tonic-gate brnz,pt %l3, 9f 10737c478bd9Sstevel@tonic-gate nop 10747c478bd9Sstevel@tonic-gate ! Don't panic if a panic is already in progress. 10757c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l1 10767c478bd9Sstevel@tonic-gate ld [%l1 + %lo(panic_quiesce)], %l1 10777c478bd9Sstevel@tonic-gate brnz,pn %l1, 9f 10787c478bd9Sstevel@tonic-gate nop 10797c478bd9Sstevel@tonic-gate srl %o4, 3, %o1 ! Find interrupted PIL for panic 10807c478bd9Sstevel@tonic-gate add %o1, LOCK_LEVEL + 1, %o1 10817c478bd9Sstevel@tonic-gate sethi %hi(current_thread_nested_pil_zero), %o0 10827c478bd9Sstevel@tonic-gate call panic 10837c478bd9Sstevel@tonic-gate or %o0, %lo(current_thread_nested_pil_zero), %o0 10847c478bd9Sstevel@tonic-gate9: 10857c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 10867c478bd9Sstevel@tonic-gate rdpr %tick, %l1 10877c478bd9Sstevel@tonic-gate sllx %l1, 1, %l1 10887c478bd9Sstevel@tonic-gate srlx %l1, 1, %l1 ! shake off NPT bit 10897c478bd9Sstevel@tonic-gate sub %l1, %l3, %l3 ! interval in %l3 10907c478bd9Sstevel@tonic-gate ! 10917c478bd9Sstevel@tonic-gate ! Check for Energy Star mode 10927c478bd9Sstevel@tonic-gate ! 10937c478bd9Sstevel@tonic-gate lduh [%o3 + CPU_DIVISOR], %l1 ! %l1 = clock divisor 10947c478bd9Sstevel@tonic-gate cmp %l1, 1 10957c478bd9Sstevel@tonic-gate bg,a,pn %xcc, 2f 10967c478bd9Sstevel@tonic-gate mulx %l3, %l1, %l3 ! multiply interval by clock divisor iff > 1 10977c478bd9Sstevel@tonic-gate2: 10987c478bd9Sstevel@tonic-gate ! 10997c478bd9Sstevel@tonic-gate ! We need to find the CPU offset of the cumulative counter. We start 11007c478bd9Sstevel@tonic-gate ! with %o4, which has (PIL - (LOCK_LEVEL + 1)) * 8. We need PIL * 16, 11017c478bd9Sstevel@tonic-gate ! so we shift left 1, then add (LOCK_LEVEL + 1) * 16, which is 11027c478bd9Sstevel@tonic-gate ! CPU_INTRSTAT_LOW_PIL_OFFSET. 11037c478bd9Sstevel@tonic-gate ! 11047c478bd9Sstevel@tonic-gate sll %o4, 1, %o4 11057c478bd9Sstevel@tonic-gate add %o4, CPU_MCPU, %o4 ! CPU_INTRSTAT const too large 11067c478bd9Sstevel@tonic-gate add %o4, MCPU_INTRSTAT, %o4 ! add parts separately 11077c478bd9Sstevel@tonic-gate add %o4, CPU_INTRSTAT_LOW_PIL_OFFSET, %o4 11087c478bd9Sstevel@tonic-gate ldx [%o3 + %o4], %l1 ! old counter in l1 11097c478bd9Sstevel@tonic-gate add %l1, %l3, %l1 ! new counter in l1 1110eda89462Sesolom stx %l1, [%o3 + %o4] ! store new counter 1111eda89462Sesolom 1112eda89462Sesolom ! Also update intracct[] 1113eda89462Sesolom lduh [%o3 + CPU_MSTATE], %o4 1114eda89462Sesolom sllx %o4, 3, %o4 1115eda89462Sesolom add %o4, CPU_INTRACCT, %o4 1116eda89462Sesolom ldx [%o3 + %o4], %l1 1117eda89462Sesolom add %l1, %l3, %l1 11187c478bd9Sstevel@tonic-gate ! Another high-level interrupt is active below this one, so 11197c478bd9Sstevel@tonic-gate ! there is no need to check for an interrupt thread. That will be 11207c478bd9Sstevel@tonic-gate ! done by the lowest priority high-level interrupt active. 11217c478bd9Sstevel@tonic-gate ba,pt %xcc, 5f 11227c478bd9Sstevel@tonic-gate stx %l1, [%o3 + %o4] ! delay - store new counter 11237c478bd9Sstevel@tonic-gate1: 11247c478bd9Sstevel@tonic-gate ! If we haven't interrupted another high-level interrupt, we may be 11257c478bd9Sstevel@tonic-gate ! interrupting a low level interrupt thread. If so, compute its interval 11267c478bd9Sstevel@tonic-gate ! and update its cumulative counter. 11277c478bd9Sstevel@tonic-gate lduh [THREAD_REG + T_FLAGS], %o4 11287c478bd9Sstevel@tonic-gate andcc %o4, T_INTR_THREAD, %g0 11297c478bd9Sstevel@tonic-gate bz,pt %xcc, 4f 11307c478bd9Sstevel@tonic-gate nop 11317c478bd9Sstevel@tonic-gate 11327c478bd9Sstevel@tonic-gate ! We have interrupted an interrupt thread. Take timestamp, compute 11337c478bd9Sstevel@tonic-gate ! interval, update cumulative counter. 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate ! Check t_intr_start. If it is zero, either intr_thread() or 11367c478bd9Sstevel@tonic-gate ! current_thread() (at a lower PIL, of course) already did 11377c478bd9Sstevel@tonic-gate ! the accounting for the underlying interrupt thread. 11387c478bd9Sstevel@tonic-gate ldx [THREAD_REG + T_INTR_START], %o5 11397c478bd9Sstevel@tonic-gate brz,pn %o5, 4f 11407c478bd9Sstevel@tonic-gate nop 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate stx %g0, [THREAD_REG + T_INTR_START] 11437c478bd9Sstevel@tonic-gate rdpr %tick, %o4 11447c478bd9Sstevel@tonic-gate sllx %o4, 1, %o4 11457c478bd9Sstevel@tonic-gate srlx %o4, 1, %o4 ! shake off NPT bit 11467c478bd9Sstevel@tonic-gate sub %o4, %o5, %o5 ! o5 has the interval 11477c478bd9Sstevel@tonic-gate 11487c478bd9Sstevel@tonic-gate ! Check for Energy Star mode 11497c478bd9Sstevel@tonic-gate lduh [%o3 + CPU_DIVISOR], %o4 ! %o4 = clock divisor 11507c478bd9Sstevel@tonic-gate cmp %o4, 1 11517c478bd9Sstevel@tonic-gate bg,a,pn %xcc, 2f 11527c478bd9Sstevel@tonic-gate mulx %o5, %o4, %o5 ! multiply interval by clock divisor iff > 1 11537c478bd9Sstevel@tonic-gate2: 11547c478bd9Sstevel@tonic-gate ldub [THREAD_REG + T_PIL], %o4 11557c478bd9Sstevel@tonic-gate sllx %o4, 4, %o4 ! PIL index to byte offset 11567c478bd9Sstevel@tonic-gate add %o4, CPU_MCPU, %o4 ! CPU_INTRSTAT const too large 11577c478bd9Sstevel@tonic-gate add %o4, MCPU_INTRSTAT, %o4 ! add parts separately 11587c478bd9Sstevel@tonic-gate ldx [%o3 + %o4], %l2 ! old counter in l2 11597c478bd9Sstevel@tonic-gate add %l2, %o5, %l2 ! new counter in l2 11607c478bd9Sstevel@tonic-gate stx %l2, [%o3 + %o4] ! store new counter 11617c478bd9Sstevel@tonic-gate 1162eda89462Sesolom ! Also update intracct[] 1163eda89462Sesolom lduh [%o3 + CPU_MSTATE], %o4 1164eda89462Sesolom sllx %o4, 3, %o4 1165eda89462Sesolom add %o4, CPU_INTRACCT, %o4 1166eda89462Sesolom ldx [%o3 + %o4], %l2 1167eda89462Sesolom add %l2, %o5, %l2 1168eda89462Sesolom stx %l2, [%o3 + %o4] 11697c478bd9Sstevel@tonic-gate4: 11707c478bd9Sstevel@tonic-gate ! 11717c478bd9Sstevel@tonic-gate ! Handle high-level interrupts on separate interrupt stack. 11727c478bd9Sstevel@tonic-gate ! No other high-level interrupts are active, so switch to int stack. 11737c478bd9Sstevel@tonic-gate ! 11747c478bd9Sstevel@tonic-gate mov %sp, %l1 11757c478bd9Sstevel@tonic-gate ldn [%o3 + CPU_INTR_STACK], %l3 11767c478bd9Sstevel@tonic-gate sub %l3, STACK_BIAS, %sp 11777c478bd9Sstevel@tonic-gate 11787c478bd9Sstevel@tonic-gate5: 11797c478bd9Sstevel@tonic-gate#ifdef DEBUG 11807c478bd9Sstevel@tonic-gate ! 11817c478bd9Sstevel@tonic-gate ! ASSERT(%o2 > LOCK_LEVEL) 11827c478bd9Sstevel@tonic-gate ! 11837c478bd9Sstevel@tonic-gate cmp %o2, LOCK_LEVEL 11847c478bd9Sstevel@tonic-gate bg,pt %xcc, 3f 11857c478bd9Sstevel@tonic-gate nop 11867c478bd9Sstevel@tonic-gate mov CE_PANIC, %o0 11877c478bd9Sstevel@tonic-gate sethi %hi(current_thread_wrong_pil), %o1 11887c478bd9Sstevel@tonic-gate call cmn_err ! %o2 has the %pil already 11897c478bd9Sstevel@tonic-gate or %o1, %lo(current_thread_wrong_pil), %o1 11907c478bd9Sstevel@tonic-gate#endif 11917c478bd9Sstevel@tonic-gate3: 11927c478bd9Sstevel@tonic-gate ! Store starting timestamp for this PIL in CPU structure at 11937c478bd9Sstevel@tonic-gate ! cpu.cpu_m.pil_high_start[PIL - (LOCK_LEVEL + 1)] 11947c478bd9Sstevel@tonic-gate sub %o2, LOCK_LEVEL + 1, %o4 ! convert PIL to array index 11957c478bd9Sstevel@tonic-gate sllx %o4, 3, %o4 ! index to byte offset 11967c478bd9Sstevel@tonic-gate add %o4, CPU_MCPU, %o4 ! CPU_PIL_HIGH_START is too large 11977c478bd9Sstevel@tonic-gate add %o4, MCPU_PIL_HIGH_START, %o4 11987c478bd9Sstevel@tonic-gate rdpr %tick, %o5 11997c478bd9Sstevel@tonic-gate sllx %o5, 1, %o5 12007c478bd9Sstevel@tonic-gate srlx %o5, 1, %o5 12017c478bd9Sstevel@tonic-gate stx %o5, [%o3 + %o4] 12027c478bd9Sstevel@tonic-gate 12037c478bd9Sstevel@tonic-gate wrpr %g0, %o2, %pil ! enable interrupts 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate ! 12067c478bd9Sstevel@tonic-gate ! call the handler 12077c478bd9Sstevel@tonic-gate ! 12087c478bd9Sstevel@tonic-gate SERVE_INTR_PRE(%o1, %o3, %l2, %l3, %o4, %o5, %o2, %o0) 12097c478bd9Sstevel@tonic-gate1: 12107c478bd9Sstevel@tonic-gate SERVE_INTR(%o1, %o3, %l2, %l3, %o4, %o5, %o2, %o0) 12117c478bd9Sstevel@tonic-gate 12127c478bd9Sstevel@tonic-gate brz,a,pt %o2, 0f ! if %o2, more intrs await 12137c478bd9Sstevel@tonic-gate rdpr %pil, %o2 ! delay annulled 12147c478bd9Sstevel@tonic-gate SERVE_INTR_NEXT(%o1, %o3, %l2, %l3, %o4, %o5, %o2, %o0) 12157c478bd9Sstevel@tonic-gate ba 1b 12167c478bd9Sstevel@tonic-gate nop 12177c478bd9Sstevel@tonic-gate0: 12187c478bd9Sstevel@tonic-gate wrpr %g0, PIL_MAX, %pil ! disable interrupts (1-15) 12197c478bd9Sstevel@tonic-gate 12207c478bd9Sstevel@tonic-gate cmp %o2, PIL_15 12217c478bd9Sstevel@tonic-gate bne,pt %xcc, 3f 12227c478bd9Sstevel@tonic-gate nop 12237c478bd9Sstevel@tonic-gate 12247c478bd9Sstevel@tonic-gate sethi %hi(cpc_level15_inum), %o1 12257c478bd9Sstevel@tonic-gate ld [%o1 + %lo(cpc_level15_inum)], %o1 ! arg for intr_enqueue_req 12267c478bd9Sstevel@tonic-gate brz %o1, 3f 12277c478bd9Sstevel@tonic-gate nop 12287c478bd9Sstevel@tonic-gate 12297c478bd9Sstevel@tonic-gate rdpr %pstate, %g5 12307c478bd9Sstevel@tonic-gate andn %g5, PSTATE_IE, %g1 12317c478bd9Sstevel@tonic-gate wrpr %g0, %g1, %pstate ! Disable vec interrupts 12327c478bd9Sstevel@tonic-gate 12337c478bd9Sstevel@tonic-gate call intr_enqueue_req ! preserves %g5 12347c478bd9Sstevel@tonic-gate mov PIL_15, %o0 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate ! clear perfcntr overflow 12377c478bd9Sstevel@tonic-gate mov 1, %o0 12387c478bd9Sstevel@tonic-gate sllx %o0, PIL_15, %o0 12397c478bd9Sstevel@tonic-gate wr %o0, CLEAR_SOFTINT 12407c478bd9Sstevel@tonic-gate 12417c478bd9Sstevel@tonic-gate wrpr %g0, %g5, %pstate ! Enable vec interrupts 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate3: 12447c478bd9Sstevel@tonic-gate cmp %o2, PIL_14 12457c478bd9Sstevel@tonic-gate be tick_rtt ! cpu-specific tick processing 12467c478bd9Sstevel@tonic-gate nop 12477c478bd9Sstevel@tonic-gate .global current_thread_complete 12487c478bd9Sstevel@tonic-gatecurrent_thread_complete: 12497c478bd9Sstevel@tonic-gate ! 12507c478bd9Sstevel@tonic-gate ! Register usage: 12517c478bd9Sstevel@tonic-gate ! 12527c478bd9Sstevel@tonic-gate ! %l1 = stack pointer 12537c478bd9Sstevel@tonic-gate ! %l2 = CPU_INTR_ACTV >> (LOCK_LEVEL + 1) 12547c478bd9Sstevel@tonic-gate ! %o2 = PIL 12557c478bd9Sstevel@tonic-gate ! %o3 = CPU pointer 12567c478bd9Sstevel@tonic-gate ! %o4, %o5, %l3, %l4, %l5 = scratch 12577c478bd9Sstevel@tonic-gate ! 12587c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CPU], %o3 12597c478bd9Sstevel@tonic-gate ! 12607c478bd9Sstevel@tonic-gate ! Clear bit for this level in CPU's interrupt active bitmask. 12617c478bd9Sstevel@tonic-gate ! 12627c478bd9Sstevel@tonic-gate ld [%o3 + CPU_INTR_ACTV], %l2 12637c478bd9Sstevel@tonic-gate mov 1, %o5 12647c478bd9Sstevel@tonic-gate sll %o5, %o2, %o5 12657c478bd9Sstevel@tonic-gate#ifdef DEBUG 12667c478bd9Sstevel@tonic-gate ! 12677c478bd9Sstevel@tonic-gate ! ASSERT(CPU->cpu_intr_actv & (1 << PIL)) 12687c478bd9Sstevel@tonic-gate ! 12697c478bd9Sstevel@tonic-gate andcc %l2, %o5, %g0 12707c478bd9Sstevel@tonic-gate bnz,pt %xcc, 0f 12717c478bd9Sstevel@tonic-gate nop 12727c478bd9Sstevel@tonic-gate ! Do not call panic if a panic is already in progress. 12737c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l2 12747c478bd9Sstevel@tonic-gate ld [%l2 + %lo(panic_quiesce)], %l2 12757c478bd9Sstevel@tonic-gate brnz,pn %l2, 0f 12767c478bd9Sstevel@tonic-gate nop 12777c478bd9Sstevel@tonic-gate sethi %hi(current_thread_actv_bit_not_set), %o0 12787c478bd9Sstevel@tonic-gate call panic 12797c478bd9Sstevel@tonic-gate or %o0, %lo(current_thread_actv_bit_not_set), %o0 12807c478bd9Sstevel@tonic-gate0: 12817c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 12827c478bd9Sstevel@tonic-gate andn %l2, %o5, %l2 12837c478bd9Sstevel@tonic-gate st %l2, [%o3 + CPU_INTR_ACTV] 12847c478bd9Sstevel@tonic-gate 12857c478bd9Sstevel@tonic-gate ! Take timestamp, compute interval, update cumulative counter. 12867c478bd9Sstevel@tonic-gate sub %o2, LOCK_LEVEL + 1, %o4 ! PIL to array index 12877c478bd9Sstevel@tonic-gate sllx %o4, 3, %o4 ! index to byte offset 12887c478bd9Sstevel@tonic-gate add %o4, CPU_MCPU, %o4 ! CPU_PIL_HIGH_START is too large 12897c478bd9Sstevel@tonic-gate add %o4, MCPU_PIL_HIGH_START, %o4 12907c478bd9Sstevel@tonic-gate rdpr %tick, %o5 12917c478bd9Sstevel@tonic-gate sllx %o5, 1, %o5 12927c478bd9Sstevel@tonic-gate srlx %o5, 1, %o5 12937c478bd9Sstevel@tonic-gate ldx [%o3 + %o4], %o0 12947c478bd9Sstevel@tonic-gate#ifdef DEBUG 12957c478bd9Sstevel@tonic-gate ! ASSERT(cpu.cpu_m.pil_high_start[pil - (LOCK_LEVEL + 1)] != 0) 12967c478bd9Sstevel@tonic-gate brnz,pt %o0, 9f 12977c478bd9Sstevel@tonic-gate nop 12987c478bd9Sstevel@tonic-gate ! Don't panic if a panic is already in progress. 12997c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %l2 13007c478bd9Sstevel@tonic-gate ld [%l2 + %lo(panic_quiesce)], %l2 13017c478bd9Sstevel@tonic-gate brnz,pn %l2, 9f 13027c478bd9Sstevel@tonic-gate nop 13037c478bd9Sstevel@tonic-gate sethi %hi(current_thread_timestamp_zero), %o0 13047c478bd9Sstevel@tonic-gate call panic 13057c478bd9Sstevel@tonic-gate or %o0, %lo(current_thread_timestamp_zero), %o0 13067c478bd9Sstevel@tonic-gate9: 13077c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 13087c478bd9Sstevel@tonic-gate stx %g0, [%o3 + %o4] 13097c478bd9Sstevel@tonic-gate sub %o5, %o0, %o5 ! interval in o5 13107c478bd9Sstevel@tonic-gate 13117c478bd9Sstevel@tonic-gate ! Check for Energy Star mode 13127c478bd9Sstevel@tonic-gate lduh [%o3 + CPU_DIVISOR], %o4 ! %o4 = clock divisor 13137c478bd9Sstevel@tonic-gate cmp %o4, 1 13147c478bd9Sstevel@tonic-gate bg,a,pn %xcc, 2f 13157c478bd9Sstevel@tonic-gate mulx %o5, %o4, %o5 ! multiply interval by clock divisor iff > 1 13167c478bd9Sstevel@tonic-gate2: 13177c478bd9Sstevel@tonic-gate sllx %o2, 4, %o4 ! PIL index to byte offset 13187c478bd9Sstevel@tonic-gate add %o4, CPU_MCPU, %o4 ! CPU_INTRSTAT too large 13197c478bd9Sstevel@tonic-gate add %o4, MCPU_INTRSTAT, %o4 ! add parts separately 13207c478bd9Sstevel@tonic-gate ldx [%o3 + %o4], %o0 ! old counter in o0 13217c478bd9Sstevel@tonic-gate add %o0, %o5, %o0 ! new counter in o0 13227c478bd9Sstevel@tonic-gate stx %o0, [%o3 + %o4] ! store new counter 13237c478bd9Sstevel@tonic-gate 1324eda89462Sesolom ! Also update intracct[] 1325eda89462Sesolom lduh [%o3 + CPU_MSTATE], %o4 1326eda89462Sesolom sllx %o4, 3, %o4 1327eda89462Sesolom add %o4, CPU_INTRACCT, %o4 1328eda89462Sesolom ldx [%o3 + %o4], %o0 1329eda89462Sesolom add %o0, %o5, %o0 1330eda89462Sesolom stx %o0, [%o3 + %o4] 1331eda89462Sesolom 13327c478bd9Sstevel@tonic-gate ! 13337c478bd9Sstevel@tonic-gate ! get back on current thread's stack 13347c478bd9Sstevel@tonic-gate ! 13357c478bd9Sstevel@tonic-gate srl %l2, LOCK_LEVEL + 1, %l2 13367c478bd9Sstevel@tonic-gate tst %l2 ! any more high-level ints? 13377c478bd9Sstevel@tonic-gate movz %xcc, %l1, %sp 13387c478bd9Sstevel@tonic-gate ! 13397c478bd9Sstevel@tonic-gate ! Current register usage: 13407c478bd9Sstevel@tonic-gate ! o2 = PIL 13417c478bd9Sstevel@tonic-gate ! o3 = CPU pointer 13427c478bd9Sstevel@tonic-gate ! l0 = return address 13437c478bd9Sstevel@tonic-gate ! l2 = intr_actv shifted right 13447c478bd9Sstevel@tonic-gate ! 13457c478bd9Sstevel@tonic-gate bz,pt %xcc, 3f ! if l2 was zero, no more ints 13467c478bd9Sstevel@tonic-gate nop 13477c478bd9Sstevel@tonic-gate ! 13487c478bd9Sstevel@tonic-gate ! We found another high-level interrupt active below the one that just 13497c478bd9Sstevel@tonic-gate ! returned. Store a starting timestamp for it in the CPU structure. 13507c478bd9Sstevel@tonic-gate ! 13517c478bd9Sstevel@tonic-gate ! Use cpu_intr_actv to find the cpu_pil_high_start[] offset for the 13527c478bd9Sstevel@tonic-gate ! interrupted high-level interrupt. 13537c478bd9Sstevel@tonic-gate ! Create mask for cpu_intr_actv. Begin by looking for bits set 13547c478bd9Sstevel@tonic-gate ! at one level below the current PIL. Since %l2 contains the active 13557c478bd9Sstevel@tonic-gate ! mask already shifted right by (LOCK_LEVEL + 1), we start by looking 13567c478bd9Sstevel@tonic-gate ! at bit (current_pil - (LOCK_LEVEL + 2)). 13577c478bd9Sstevel@tonic-gate ! %l1 = mask, %o5 = index of bit set in mask 13587c478bd9Sstevel@tonic-gate ! 13597c478bd9Sstevel@tonic-gate mov 1, %l1 13607c478bd9Sstevel@tonic-gate sub %o2, LOCK_LEVEL + 2, %o5 13617c478bd9Sstevel@tonic-gate sll %l1, %o5, %l1 ! l1 = mask for level 13627c478bd9Sstevel@tonic-gate1: 13637c478bd9Sstevel@tonic-gate#ifdef DEBUG 13647c478bd9Sstevel@tonic-gate ! ASSERT(%l1 != 0) (we didn't shift the bit off the right edge) 13657c478bd9Sstevel@tonic-gate brnz,pt %l1, 9f 13667c478bd9Sstevel@tonic-gate nop 13677c478bd9Sstevel@tonic-gate sethi %hi(current_thread_nested_PIL_not_found), %o0 13687c478bd9Sstevel@tonic-gate call panic 13697c478bd9Sstevel@tonic-gate or %o0, %lo(current_thread_nested_PIL_not_found), %o0 13707c478bd9Sstevel@tonic-gate9: 13717c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 13727c478bd9Sstevel@tonic-gate andcc %l1, %l2, %g0 ! test mask against high-level bits of 13737c478bd9Sstevel@tonic-gate bnz %xcc, 2f ! cpu_intr_actv 13747c478bd9Sstevel@tonic-gate nop 13757c478bd9Sstevel@tonic-gate srl %l1, 1, %l1 ! No match. Try next lower PIL. 13767c478bd9Sstevel@tonic-gate ba,pt %xcc, 1b 13777c478bd9Sstevel@tonic-gate sub %o5, 1, %o5 ! delay - decrement PIL 13787c478bd9Sstevel@tonic-gate2: 13797c478bd9Sstevel@tonic-gate sll %o5, 3, %o5 ! convert array index to byte offset 13807c478bd9Sstevel@tonic-gate add %o5, CPU_MCPU, %o5 ! CPU_PIL_HIGH_START is too large 13817c478bd9Sstevel@tonic-gate add %o5, MCPU_PIL_HIGH_START, %o5 13827c478bd9Sstevel@tonic-gate rdpr %tick, %o4 13837c478bd9Sstevel@tonic-gate sllx %o4, 1, %o4 13847c478bd9Sstevel@tonic-gate srlx %o4, 1, %o4 13857c478bd9Sstevel@tonic-gate ! Another high-level interrupt is active below this one, so 13867c478bd9Sstevel@tonic-gate ! there is no need to check for an interrupt thread. That will be 13877c478bd9Sstevel@tonic-gate ! done by the lowest priority high-level interrupt active. 13887c478bd9Sstevel@tonic-gate ba,pt %xcc, 1f 13897c478bd9Sstevel@tonic-gate stx %o4, [%o3 + %o5] ! delay - store timestamp 13907c478bd9Sstevel@tonic-gate3: 13917c478bd9Sstevel@tonic-gate ! If we haven't interrupted another high-level interrupt, we may have 13927c478bd9Sstevel@tonic-gate ! interrupted a low level interrupt thread. If so, store a starting 13937c478bd9Sstevel@tonic-gate ! timestamp in its thread structure. 13947c478bd9Sstevel@tonic-gate lduh [THREAD_REG + T_FLAGS], %o4 13957c478bd9Sstevel@tonic-gate andcc %o4, T_INTR_THREAD, %g0 13967c478bd9Sstevel@tonic-gate bz,pt %xcc, 1f 13977c478bd9Sstevel@tonic-gate nop 13987c478bd9Sstevel@tonic-gate 13997c478bd9Sstevel@tonic-gate rdpr %tick, %o4 14007c478bd9Sstevel@tonic-gate sllx %o4, 1, %o4 14017c478bd9Sstevel@tonic-gate srlx %o4, 1, %o4 ! Shake off NPT bit 14027c478bd9Sstevel@tonic-gate stx %o4, [THREAD_REG + T_INTR_START] 14037c478bd9Sstevel@tonic-gate1: 14047c478bd9Sstevel@tonic-gate ! Enable interrupts and return 14057c478bd9Sstevel@tonic-gate jmp %l0 + 8 14067c478bd9Sstevel@tonic-gate wrpr %g0, %o2, %pil ! enable interrupts 14077c478bd9Sstevel@tonic-gate SET_SIZE(current_thread) 14087c478bd9Sstevel@tonic-gate 14097c478bd9Sstevel@tonic-gate 14107c478bd9Sstevel@tonic-gate#ifdef DEBUG 14117c478bd9Sstevel@tonic-gatecurrent_thread_wrong_pil: 14127c478bd9Sstevel@tonic-gate .asciz "current_thread: unexpected pil level: %d" 14137c478bd9Sstevel@tonic-gatecurrent_thread_actv_bit_set: 14147c478bd9Sstevel@tonic-gate .asciz "current_thread(): cpu_intr_actv bit already set for PIL" 14157c478bd9Sstevel@tonic-gatecurrent_thread_actv_bit_not_set: 14167c478bd9Sstevel@tonic-gate .asciz "current_thread(): cpu_intr_actv bit not set for PIL" 14177c478bd9Sstevel@tonic-gatecurrent_thread_nested_pil_zero: 14187c478bd9Sstevel@tonic-gate .asciz "current_thread(): timestamp zero for nested PIL %d" 14197c478bd9Sstevel@tonic-gatecurrent_thread_timestamp_zero: 14207c478bd9Sstevel@tonic-gate .asciz "current_thread(): timestamp zero upon handler return" 14217c478bd9Sstevel@tonic-gatecurrent_thread_nested_PIL_not_found: 14227c478bd9Sstevel@tonic-gate .asciz "current_thread: couldn't find nested high-level PIL" 14237c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 14247c478bd9Sstevel@tonic-gate#endif /* lint */ 14257c478bd9Sstevel@tonic-gate 14267c478bd9Sstevel@tonic-gate/* 14277c478bd9Sstevel@tonic-gate * Return a thread's interrupt level. 14287c478bd9Sstevel@tonic-gate * Since this isn't saved anywhere but in %l4 on interrupt entry, we 14297c478bd9Sstevel@tonic-gate * must dig it out of the save area. 14307c478bd9Sstevel@tonic-gate * 14317c478bd9Sstevel@tonic-gate * Caller 'swears' that this really is an interrupt thread. 14327c478bd9Sstevel@tonic-gate * 14337c478bd9Sstevel@tonic-gate * int 14347c478bd9Sstevel@tonic-gate * intr_level(t) 14357c478bd9Sstevel@tonic-gate * kthread_id_t t; 14367c478bd9Sstevel@tonic-gate */ 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate#if defined(lint) 14397c478bd9Sstevel@tonic-gate 14407c478bd9Sstevel@tonic-gate/* ARGSUSED */ 14417c478bd9Sstevel@tonic-gateint 14427c478bd9Sstevel@tonic-gateintr_level(kthread_id_t t) 14437c478bd9Sstevel@tonic-gate{ return (0); } 14447c478bd9Sstevel@tonic-gate 14457c478bd9Sstevel@tonic-gate#else /* lint */ 14467c478bd9Sstevel@tonic-gate 14477c478bd9Sstevel@tonic-gate ENTRY_NP(intr_level) 14487c478bd9Sstevel@tonic-gate retl 14497c478bd9Sstevel@tonic-gate ldub [%o0 + T_PIL], %o0 ! return saved pil 14507c478bd9Sstevel@tonic-gate SET_SIZE(intr_level) 14517c478bd9Sstevel@tonic-gate 14527c478bd9Sstevel@tonic-gate#endif /* lint */ 14537c478bd9Sstevel@tonic-gate 14547c478bd9Sstevel@tonic-gate#if defined(lint) 14557c478bd9Sstevel@tonic-gate 14567c478bd9Sstevel@tonic-gate/* ARGSUSED */ 14577c478bd9Sstevel@tonic-gateint 14587c478bd9Sstevel@tonic-gatedisable_pil_intr() 14597c478bd9Sstevel@tonic-gate{ return (0); } 14607c478bd9Sstevel@tonic-gate 14617c478bd9Sstevel@tonic-gate#else /* lint */ 14627c478bd9Sstevel@tonic-gate 14637c478bd9Sstevel@tonic-gate ENTRY_NP(disable_pil_intr) 14647c478bd9Sstevel@tonic-gate rdpr %pil, %o0 14657c478bd9Sstevel@tonic-gate retl 14667c478bd9Sstevel@tonic-gate wrpr %g0, PIL_MAX, %pil ! disable interrupts (1-15) 14677c478bd9Sstevel@tonic-gate SET_SIZE(disable_pil_intr) 14687c478bd9Sstevel@tonic-gate 14697c478bd9Sstevel@tonic-gate#endif /* lint */ 14707c478bd9Sstevel@tonic-gate 14717c478bd9Sstevel@tonic-gate#if defined(lint) 14727c478bd9Sstevel@tonic-gate 14737c478bd9Sstevel@tonic-gate/* ARGSUSED */ 14747c478bd9Sstevel@tonic-gatevoid 14757c478bd9Sstevel@tonic-gateenable_pil_intr(int pil_save) 14767c478bd9Sstevel@tonic-gate{} 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate#else /* lint */ 14797c478bd9Sstevel@tonic-gate 14807c478bd9Sstevel@tonic-gate ENTRY_NP(enable_pil_intr) 14817c478bd9Sstevel@tonic-gate retl 14827c478bd9Sstevel@tonic-gate wrpr %o0, %pil 14837c478bd9Sstevel@tonic-gate SET_SIZE(enable_pil_intr) 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate#endif /* lint */ 14867c478bd9Sstevel@tonic-gate 14877c478bd9Sstevel@tonic-gate#if defined(lint) 14887c478bd9Sstevel@tonic-gate 14897c478bd9Sstevel@tonic-gate/* ARGSUSED */ 14907c478bd9Sstevel@tonic-gateuint_t 14917c478bd9Sstevel@tonic-gatedisable_vec_intr(void) 14927c478bd9Sstevel@tonic-gate{ return (0); } 14937c478bd9Sstevel@tonic-gate 14947c478bd9Sstevel@tonic-gate#else /* lint */ 14957c478bd9Sstevel@tonic-gate 14967c478bd9Sstevel@tonic-gate ENTRY_NP(disable_vec_intr) 14977c478bd9Sstevel@tonic-gate rdpr %pstate, %o0 14987c478bd9Sstevel@tonic-gate andn %o0, PSTATE_IE, %g1 14997c478bd9Sstevel@tonic-gate retl 15007c478bd9Sstevel@tonic-gate wrpr %g0, %g1, %pstate ! disable interrupt 15017c478bd9Sstevel@tonic-gate SET_SIZE(disable_vec_intr) 15027c478bd9Sstevel@tonic-gate 15037c478bd9Sstevel@tonic-gate#endif /* lint */ 15047c478bd9Sstevel@tonic-gate 15057c478bd9Sstevel@tonic-gate#if defined(lint) 15067c478bd9Sstevel@tonic-gate 15077c478bd9Sstevel@tonic-gate/* ARGSUSED */ 15087c478bd9Sstevel@tonic-gatevoid 15097c478bd9Sstevel@tonic-gateenable_vec_intr(uint_t pstate_save) 15107c478bd9Sstevel@tonic-gate{} 15117c478bd9Sstevel@tonic-gate 15127c478bd9Sstevel@tonic-gate#else /* lint */ 15137c478bd9Sstevel@tonic-gate 15147c478bd9Sstevel@tonic-gate ENTRY_NP(enable_vec_intr) 15157c478bd9Sstevel@tonic-gate retl 15167c478bd9Sstevel@tonic-gate wrpr %g0, %o0, %pstate 15177c478bd9Sstevel@tonic-gate SET_SIZE(enable_vec_intr) 15187c478bd9Sstevel@tonic-gate 15197c478bd9Sstevel@tonic-gate#endif /* lint */ 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate#if defined(lint) 15227c478bd9Sstevel@tonic-gate 15237c478bd9Sstevel@tonic-gatevoid 15247c478bd9Sstevel@tonic-gatecbe_level14(void) 15257c478bd9Sstevel@tonic-gate{} 15267c478bd9Sstevel@tonic-gate 15277c478bd9Sstevel@tonic-gate#else /* lint */ 15287c478bd9Sstevel@tonic-gate 15297c478bd9Sstevel@tonic-gate ENTRY_NP(cbe_level14) 15307c478bd9Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp ! get a new window 15317c478bd9Sstevel@tonic-gate ! 15327c478bd9Sstevel@tonic-gate ! Make sure that this is from TICK_COMPARE; if not just return 15337c478bd9Sstevel@tonic-gate ! 15347c478bd9Sstevel@tonic-gate rd SOFTINT, %l1 15357c478bd9Sstevel@tonic-gate set (TICK_INT_MASK | STICK_INT_MASK), %o2 15367c478bd9Sstevel@tonic-gate andcc %l1, %o2, %g0 15377c478bd9Sstevel@tonic-gate bz,pn %icc, 2f 15387c478bd9Sstevel@tonic-gate nop 15397c478bd9Sstevel@tonic-gate 15407c478bd9Sstevel@tonic-gate CPU_ADDR(%o1, %o2) 15417c478bd9Sstevel@tonic-gate call cyclic_fire 15427c478bd9Sstevel@tonic-gate mov %o1, %o0 15437c478bd9Sstevel@tonic-gate2: 15447c478bd9Sstevel@tonic-gate ret 15457c478bd9Sstevel@tonic-gate restore %g0, 1, %o0 15467c478bd9Sstevel@tonic-gate SET_SIZE(cbe_level14) 15477c478bd9Sstevel@tonic-gate 15487c478bd9Sstevel@tonic-gate#endif /* lint */ 15497c478bd9Sstevel@tonic-gate 15507c478bd9Sstevel@tonic-gate 15517c478bd9Sstevel@tonic-gate#if defined(lint) 15527c478bd9Sstevel@tonic-gate 15537c478bd9Sstevel@tonic-gate/* ARGSUSED */ 15547c478bd9Sstevel@tonic-gatevoid 15557c478bd9Sstevel@tonic-gatesetsoftint(uint_t inum) 15567c478bd9Sstevel@tonic-gate{} 15577c478bd9Sstevel@tonic-gate 15587c478bd9Sstevel@tonic-gate#else /* lint */ 15597c478bd9Sstevel@tonic-gate 15607c478bd9Sstevel@tonic-gate ENTRY_NP(setsoftint) 15617c478bd9Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp ! get a new window 15627c478bd9Sstevel@tonic-gate rdpr %pstate, %l5 15637c478bd9Sstevel@tonic-gate andn %l5, PSTATE_IE, %l1 15647c478bd9Sstevel@tonic-gate wrpr %l1, %pstate ! disable interrupt 15657c478bd9Sstevel@tonic-gate ! 15667c478bd9Sstevel@tonic-gate ! Fetch data from intr_vector[] table according to the inum. 15677c478bd9Sstevel@tonic-gate ! 15687c478bd9Sstevel@tonic-gate ! We have an interrupt number. 15697c478bd9Sstevel@tonic-gate ! Put the request on the cpu's softint list, 15707c478bd9Sstevel@tonic-gate ! and set %set_softint. 15717c478bd9Sstevel@tonic-gate ! 15727c478bd9Sstevel@tonic-gate ! Register usage 15737c478bd9Sstevel@tonic-gate ! %i0 - inumber 15747c478bd9Sstevel@tonic-gate ! %l2 - requested pil 15757c478bd9Sstevel@tonic-gate ! %l3 - intr_req 15767c478bd9Sstevel@tonic-gate ! %l4 - *cpu 15777c478bd9Sstevel@tonic-gate ! %l1, %l6 - temps 15787c478bd9Sstevel@tonic-gate ! 15797c478bd9Sstevel@tonic-gate ! check if a softint is pending for this inum already 15807c478bd9Sstevel@tonic-gate ! if one is pending, don't bother queuing another 15817c478bd9Sstevel@tonic-gate ! 15827c478bd9Sstevel@tonic-gate set intr_vector, %l1 15837c478bd9Sstevel@tonic-gate sll %i0, INTR_VECTOR_SHIFT, %l6 15847c478bd9Sstevel@tonic-gate add %l1, %l6, %l1 ! %l1 = &intr_vector[inum] 15857c478bd9Sstevel@tonic-gate lduh [%l1 + IV_PENDING], %l6 15867c478bd9Sstevel@tonic-gate brnz,pn %l6, 4f ! branch, if pending 15877c478bd9Sstevel@tonic-gate or %g0, 1, %l2 15887c478bd9Sstevel@tonic-gate sth %l2, [%l1 + IV_PENDING] ! intr_vector[inum].pend = 1 15897c478bd9Sstevel@tonic-gate ! 15907c478bd9Sstevel@tonic-gate ! allocate an intr_req from the free list 15917c478bd9Sstevel@tonic-gate ! 15927c478bd9Sstevel@tonic-gate CPU_ADDR(%l4, %l2) 15937c478bd9Sstevel@tonic-gate ldn [%l4 + INTR_HEAD], %l3 15947c478bd9Sstevel@tonic-gate lduh [%l1 + IV_PIL], %l2 15957c478bd9Sstevel@tonic-gate ! 15967c478bd9Sstevel@tonic-gate ! fixup free list 15977c478bd9Sstevel@tonic-gate ! 15987c478bd9Sstevel@tonic-gate ldn [%l3 + INTR_NEXT], %l6 15997c478bd9Sstevel@tonic-gate stn %l6, [%l4 + INTR_HEAD] 16007c478bd9Sstevel@tonic-gate ! 16017c478bd9Sstevel@tonic-gate ! fill up intr_req 16027c478bd9Sstevel@tonic-gate ! 16037c478bd9Sstevel@tonic-gate st %i0, [%l3 + INTR_NUMBER] 16047c478bd9Sstevel@tonic-gate stn %g0, [%l3 + INTR_NEXT] 16057c478bd9Sstevel@tonic-gate ! 16067c478bd9Sstevel@tonic-gate ! move intr_req to appropriate list 16077c478bd9Sstevel@tonic-gate ! 16087c478bd9Sstevel@tonic-gate sll %l2, CPTRSHIFT, %l0 16097c478bd9Sstevel@tonic-gate add %l4, INTR_TAIL, %l6 16107c478bd9Sstevel@tonic-gate ldn [%l6 + %l0], %l1 ! current tail 16117c478bd9Sstevel@tonic-gate brz,pt %l1, 2f ! branch if list empty 16127c478bd9Sstevel@tonic-gate stn %l3, [%l6 + %l0] ! make intr_req new tail 16137c478bd9Sstevel@tonic-gate ! 16147c478bd9Sstevel@tonic-gate ! there's pending intr_req already 16157c478bd9Sstevel@tonic-gate ! 16167c478bd9Sstevel@tonic-gate ba,pt %xcc, 3f 16177c478bd9Sstevel@tonic-gate stn %l3, [%l1 + INTR_NEXT] ! update old tail 16187c478bd9Sstevel@tonic-gate2: 16197c478bd9Sstevel@tonic-gate ! 16207c478bd9Sstevel@tonic-gate ! no pending intr_req; make intr_req new head 16217c478bd9Sstevel@tonic-gate ! 16227c478bd9Sstevel@tonic-gate add %l4, INTR_HEAD, %l6 16237c478bd9Sstevel@tonic-gate stn %l3, [%l6 + %l0] 16247c478bd9Sstevel@tonic-gate3: 16257c478bd9Sstevel@tonic-gate ! 16267c478bd9Sstevel@tonic-gate ! Write %set_softint with (1<<pil) to cause a "pil" level trap 16277c478bd9Sstevel@tonic-gate ! 16287c478bd9Sstevel@tonic-gate mov 1, %l1 16297c478bd9Sstevel@tonic-gate sll %l1, %l2, %l1 16307c478bd9Sstevel@tonic-gate wr %l1, SET_SOFTINT 16317c478bd9Sstevel@tonic-gate4: 16327c478bd9Sstevel@tonic-gate wrpr %g0, %l5, %pstate 16337c478bd9Sstevel@tonic-gate ret 16347c478bd9Sstevel@tonic-gate restore 16357c478bd9Sstevel@tonic-gate SET_SIZE(setsoftint) 16367c478bd9Sstevel@tonic-gate 16377c478bd9Sstevel@tonic-gate#endif /* lint */ 16387c478bd9Sstevel@tonic-gate 16397c478bd9Sstevel@tonic-gate#if defined(lint) 16407c478bd9Sstevel@tonic-gate 16417c478bd9Sstevel@tonic-gate/*ARGSUSED*/ 16427c478bd9Sstevel@tonic-gatevoid 16437c478bd9Sstevel@tonic-gatesetsoftint_tl1(uint64_t inum, uint64_t dummy) 16447c478bd9Sstevel@tonic-gate{} 16457c478bd9Sstevel@tonic-gate 16467c478bd9Sstevel@tonic-gate#else /* lint */ 16477c478bd9Sstevel@tonic-gate 16487c478bd9Sstevel@tonic-gate ! 16497c478bd9Sstevel@tonic-gate ! Register usage 16507c478bd9Sstevel@tonic-gate ! 16517c478bd9Sstevel@tonic-gate ! Arguments: 16527c478bd9Sstevel@tonic-gate ! %g1 - inumber 16537c478bd9Sstevel@tonic-gate ! 16547c478bd9Sstevel@tonic-gate ! Internal: 16557c478bd9Sstevel@tonic-gate ! %g2 - requested pil 16567c478bd9Sstevel@tonic-gate ! %g3 - intr_req 16577c478bd9Sstevel@tonic-gate ! %g4 - cpu pointer 16587c478bd9Sstevel@tonic-gate ! %g5,%g6,%g7 - temps 16597c478bd9Sstevel@tonic-gate ! 16607c478bd9Sstevel@tonic-gate ENTRY_NP(setsoftint_tl1) 16617c478bd9Sstevel@tonic-gate ! 16627c478bd9Sstevel@tonic-gate ! Verify the inumber received (should be inum < MAXIVNUM). 16637c478bd9Sstevel@tonic-gate ! 16647c478bd9Sstevel@tonic-gate set MAXIVNUM, %g2 16657c478bd9Sstevel@tonic-gate cmp %g1, %g2 16667c478bd9Sstevel@tonic-gate bgeu,pn %xcc, .no_ivintr 16677c478bd9Sstevel@tonic-gate clr %g2 ! expected in .no_ivintr 16687c478bd9Sstevel@tonic-gate ! 16697c478bd9Sstevel@tonic-gate ! Fetch data from intr_vector[] table according to the inum. 16707c478bd9Sstevel@tonic-gate ! 16717c478bd9Sstevel@tonic-gate ! We have an interrupt number. Put the request on the cpu's softint 16727c478bd9Sstevel@tonic-gate ! list, and set %set_softint. 16737c478bd9Sstevel@tonic-gate ! 16747c478bd9Sstevel@tonic-gate set intr_vector, %g5 16757c478bd9Sstevel@tonic-gate sll %g1, INTR_VECTOR_SHIFT, %g6 16767c478bd9Sstevel@tonic-gate add %g5, %g6, %g5 ! %g5 = &intr_vector[inum] 16777c478bd9Sstevel@tonic-gate 16787c478bd9Sstevel@tonic-gate ! 16797c478bd9Sstevel@tonic-gate ! allocate an intr_req from the free list 16807c478bd9Sstevel@tonic-gate ! 16817c478bd9Sstevel@tonic-gate CPU_ADDR(%g4, %g2) 16827c478bd9Sstevel@tonic-gate ldn [%g4 + INTR_HEAD], %g3 16837c478bd9Sstevel@tonic-gate 16847c478bd9Sstevel@tonic-gate ! load the pil so it can be used by .no_intr_pool/.no_ivintr 16857c478bd9Sstevel@tonic-gate lduh [%g5 + IV_PIL], %g2 16867c478bd9Sstevel@tonic-gate 16877c478bd9Sstevel@tonic-gate ! Verify that the free list is not exhausted. 16887c478bd9Sstevel@tonic-gate brz,pn %g3, .no_intr_pool 16897c478bd9Sstevel@tonic-gate nop 16907c478bd9Sstevel@tonic-gate 16917c478bd9Sstevel@tonic-gate ! Verify the intr_vector[] entry according to the inumber. 16927c478bd9Sstevel@tonic-gate ! The iv_pil field should not be zero. This used to be 16937c478bd9Sstevel@tonic-gate ! guarded by DEBUG but broken drivers can cause spurious 16947c478bd9Sstevel@tonic-gate ! tick interrupts when the softint register is programmed 16957c478bd9Sstevel@tonic-gate ! with 1 << 0 at the end of this routine. Now we always 16967c478bd9Sstevel@tonic-gate ! check for an invalid pil. 16977c478bd9Sstevel@tonic-gate brz,pn %g2, .no_ivintr 16987c478bd9Sstevel@tonic-gate nop 16997c478bd9Sstevel@tonic-gate 17007c478bd9Sstevel@tonic-gate ! 17017c478bd9Sstevel@tonic-gate ! fixup free list 17027c478bd9Sstevel@tonic-gate ! 17037c478bd9Sstevel@tonic-gate ldn [%g3 + INTR_NEXT], %g6 17047c478bd9Sstevel@tonic-gate stn %g6, [%g4 + INTR_HEAD] 17057c478bd9Sstevel@tonic-gate 17067c478bd9Sstevel@tonic-gate ! 17077c478bd9Sstevel@tonic-gate ! fill in intr_req 17087c478bd9Sstevel@tonic-gate ! 17097c478bd9Sstevel@tonic-gate st %g1, [%g3 + INTR_NUMBER] 17107c478bd9Sstevel@tonic-gate stn %g0, [%g3 + INTR_NEXT] 17117c478bd9Sstevel@tonic-gate ! 17127c478bd9Sstevel@tonic-gate ! move intr_req to appropriate list 17137c478bd9Sstevel@tonic-gate ! 17147c478bd9Sstevel@tonic-gate sll %g2, CPTRSHIFT, %g7 17157c478bd9Sstevel@tonic-gate add %g4, INTR_TAIL, %g6 17167c478bd9Sstevel@tonic-gate ldn [%g6 + %g7], %g5 ! current tail 17177c478bd9Sstevel@tonic-gate brz,pt %g5, 2f ! branch if list empty 17187c478bd9Sstevel@tonic-gate stn %g3, [%g6 + %g7] ! make intr_req new tail 17197c478bd9Sstevel@tonic-gate ! 17207c478bd9Sstevel@tonic-gate ! there's pending intr_req already 17217c478bd9Sstevel@tonic-gate ! 17227c478bd9Sstevel@tonic-gate ba,pt %xcc, 3f 17237c478bd9Sstevel@tonic-gate stn %g3, [%g5 + INTR_NEXT] ! update old tail 17247c478bd9Sstevel@tonic-gate2: 17257c478bd9Sstevel@tonic-gate ! 17267c478bd9Sstevel@tonic-gate ! no pending intr_req; make intr_req new head 17277c478bd9Sstevel@tonic-gate ! 17287c478bd9Sstevel@tonic-gate add %g4, INTR_HEAD, %g6 17297c478bd9Sstevel@tonic-gate stn %g3, [%g6 + %g7] 17307c478bd9Sstevel@tonic-gate3: 17317c478bd9Sstevel@tonic-gate#ifdef TRAPTRACE 17327c478bd9Sstevel@tonic-gate TRACE_PTR(%g1, %g6) 17337c478bd9Sstevel@tonic-gate GET_TRACE_TICK(%g6) 17347c478bd9Sstevel@tonic-gate stxa %g6, [%g1 + TRAP_ENT_TICK]%asi 17357c478bd9Sstevel@tonic-gate TRACE_SAVE_TL_GL_REGS(%g1, %g6) 17367c478bd9Sstevel@tonic-gate rdpr %tt, %g6 17377c478bd9Sstevel@tonic-gate stha %g6, [%g1 + TRAP_ENT_TT]%asi 17387c478bd9Sstevel@tonic-gate rdpr %tpc, %g6 17397c478bd9Sstevel@tonic-gate stna %g6, [%g1 + TRAP_ENT_TPC]%asi 17407c478bd9Sstevel@tonic-gate rdpr %tstate, %g6 17417c478bd9Sstevel@tonic-gate stxa %g6, [%g1 + TRAP_ENT_TSTATE]%asi 17427c478bd9Sstevel@tonic-gate stna %sp, [%g1 + TRAP_ENT_SP]%asi 17437c478bd9Sstevel@tonic-gate ld [%g3 + INTR_NUMBER], %g6 17447c478bd9Sstevel@tonic-gate stna %g6, [%g1 + TRAP_ENT_TR]%asi 17457c478bd9Sstevel@tonic-gate add %g4, INTR_HEAD, %g6 17467c478bd9Sstevel@tonic-gate ldn [%g6 + %g7], %g6 ! intr_head[pil] 17477c478bd9Sstevel@tonic-gate stna %g6, [%g1 + TRAP_ENT_F1]%asi 17487c478bd9Sstevel@tonic-gate add %g4, INTR_TAIL, %g6 17497c478bd9Sstevel@tonic-gate ldn [%g6 + %g7], %g6 ! intr_tail[pil] 17507c478bd9Sstevel@tonic-gate stna %g6, [%g1 + TRAP_ENT_F2]%asi 17517c478bd9Sstevel@tonic-gate stna %g2, [%g1 + TRAP_ENT_F3]%asi ! pil 17527c478bd9Sstevel@tonic-gate stna %g3, [%g1 + TRAP_ENT_F4]%asi ! intr_req 17537c478bd9Sstevel@tonic-gate TRACE_NEXT(%g1, %g6, %g5) 17547c478bd9Sstevel@tonic-gate#endif /* TRAPTRACE */ 17557c478bd9Sstevel@tonic-gate ! 17567c478bd9Sstevel@tonic-gate ! Write %set_softint with (1<<pil) to cause a "pil" level trap 17577c478bd9Sstevel@tonic-gate ! 17587c478bd9Sstevel@tonic-gate mov 1, %g5 17597c478bd9Sstevel@tonic-gate sll %g5, %g2, %g5 17607c478bd9Sstevel@tonic-gate wr %g5, SET_SOFTINT 17617c478bd9Sstevel@tonic-gate4: 17627c478bd9Sstevel@tonic-gate retry 17637c478bd9Sstevel@tonic-gate 17647c478bd9Sstevel@tonic-gate.no_intr_pool: 17657c478bd9Sstevel@tonic-gate ! no_intr_pool: rp, inum (%g1), pil (%g2) 17667c478bd9Sstevel@tonic-gate mov %g2, %g3 17677c478bd9Sstevel@tonic-gate mov %g1, %g2 17687c478bd9Sstevel@tonic-gate set no_intr_pool, %g1 17697c478bd9Sstevel@tonic-gate ba,pt %xcc, sys_trap 17707c478bd9Sstevel@tonic-gate mov PIL_15, %g4 17717c478bd9Sstevel@tonic-gate 17727c478bd9Sstevel@tonic-gate.no_ivintr: 17737c478bd9Sstevel@tonic-gate ! no_ivintr: arguments: rp, inum (%g1), pil (%g2 == 0) 17747c478bd9Sstevel@tonic-gate mov %g2, %g3 17757c478bd9Sstevel@tonic-gate mov %g1, %g2 17767c478bd9Sstevel@tonic-gate set no_ivintr, %g1 17777c478bd9Sstevel@tonic-gate ba,pt %xcc, sys_trap 17787c478bd9Sstevel@tonic-gate mov PIL_15, %g4 17797c478bd9Sstevel@tonic-gate SET_SIZE(setsoftint_tl1) 17807c478bd9Sstevel@tonic-gate 17817c478bd9Sstevel@tonic-gate#endif /* lint */ 17827c478bd9Sstevel@tonic-gate 17837c478bd9Sstevel@tonic-gate#if defined(lint) 17847c478bd9Sstevel@tonic-gate 17857c478bd9Sstevel@tonic-gate/*ARGSUSED*/ 17867c478bd9Sstevel@tonic-gatevoid 17877c478bd9Sstevel@tonic-gatewr_clr_softint(uint_t value) 17887c478bd9Sstevel@tonic-gate{} 17897c478bd9Sstevel@tonic-gate 17907c478bd9Sstevel@tonic-gate#else 17917c478bd9Sstevel@tonic-gate 17927c478bd9Sstevel@tonic-gate ENTRY_NP(wr_clr_softint) 17937c478bd9Sstevel@tonic-gate retl 17947c478bd9Sstevel@tonic-gate wr %o0, CLEAR_SOFTINT 17957c478bd9Sstevel@tonic-gate SET_SIZE(wr_clr_softint) 17967c478bd9Sstevel@tonic-gate 17977c478bd9Sstevel@tonic-gate#endif /* lint */ 17987c478bd9Sstevel@tonic-gate 17997c478bd9Sstevel@tonic-gate#if defined(lint) 18007c478bd9Sstevel@tonic-gate 18017c478bd9Sstevel@tonic-gate/*ARGSUSED*/ 18027c478bd9Sstevel@tonic-gatevoid 18037c478bd9Sstevel@tonic-gateintr_enqueue_req(uint_t pil, uint32_t inum) 18047c478bd9Sstevel@tonic-gate{} 18057c478bd9Sstevel@tonic-gate 18067c478bd9Sstevel@tonic-gate#else /* lint */ 18077c478bd9Sstevel@tonic-gate 18087c478bd9Sstevel@tonic-gate/* 18097c478bd9Sstevel@tonic-gate * intr_enqueue_req 18107c478bd9Sstevel@tonic-gate * 18117c478bd9Sstevel@tonic-gate * %o0 - pil 18127c478bd9Sstevel@tonic-gate * %o1 - inum 18137c478bd9Sstevel@tonic-gate * %o5 - preserved 18147c478bd9Sstevel@tonic-gate * %g5 - preserved 18157c478bd9Sstevel@tonic-gate */ 18167c478bd9Sstevel@tonic-gate ENTRY_NP(intr_enqueue_req) 18177c478bd9Sstevel@tonic-gate ! get intr_req free list 18187c478bd9Sstevel@tonic-gate CPU_ADDR(%g4, %g1) 18197c478bd9Sstevel@tonic-gate ldn [%g4 + INTR_HEAD], %g3 18207c478bd9Sstevel@tonic-gate 18217c478bd9Sstevel@tonic-gate ! take intr_req from free list 18227c478bd9Sstevel@tonic-gate ldn [%g3 + INTR_NEXT], %g6 18237c478bd9Sstevel@tonic-gate stn %g6, [%g4 + INTR_HEAD] 18247c478bd9Sstevel@tonic-gate 18257c478bd9Sstevel@tonic-gate ! fill up intr_req 18267c478bd9Sstevel@tonic-gate st %o1, [%g3 + INTR_NUMBER] 18277c478bd9Sstevel@tonic-gate stn %g0, [%g3 + INTR_NEXT] 18287c478bd9Sstevel@tonic-gate 18297c478bd9Sstevel@tonic-gate ! add intr_req to proper pil list 18307c478bd9Sstevel@tonic-gate sll %o0, CPTRSHIFT, %o0 18317c478bd9Sstevel@tonic-gate add %g4, INTR_TAIL, %g6 18327c478bd9Sstevel@tonic-gate ldn [%o0 + %g6], %g1 ! current tail 18337c478bd9Sstevel@tonic-gate brz,pt %g1, 2f ! branch if list is empty 18347c478bd9Sstevel@tonic-gate stn %g3, [%g6 + %o0] ! make intr_req the new tail 18357c478bd9Sstevel@tonic-gate 18367c478bd9Sstevel@tonic-gate ! an intr_req was already queued so update old tail 18377c478bd9Sstevel@tonic-gate ba,pt %xcc, 3f 18387c478bd9Sstevel@tonic-gate stn %g3, [%g1 + INTR_NEXT] 18397c478bd9Sstevel@tonic-gate2: 18407c478bd9Sstevel@tonic-gate ! no intr_req's queued so make intr_req the new head 18417c478bd9Sstevel@tonic-gate add %g4, INTR_HEAD, %g6 18427c478bd9Sstevel@tonic-gate stn %g3, [%g6 + %o0] 18437c478bd9Sstevel@tonic-gate3: 18447c478bd9Sstevel@tonic-gate retl 18457c478bd9Sstevel@tonic-gate nop 18467c478bd9Sstevel@tonic-gate SET_SIZE(intr_enqueue_req) 18477c478bd9Sstevel@tonic-gate 18487c478bd9Sstevel@tonic-gate#endif /* lint */ 18497c478bd9Sstevel@tonic-gate 18507c478bd9Sstevel@tonic-gate/* 18517c478bd9Sstevel@tonic-gate * Set CPU's base SPL level, based on which interrupt levels are active. 18527c478bd9Sstevel@tonic-gate * Called at spl7 or above. 18537c478bd9Sstevel@tonic-gate */ 18547c478bd9Sstevel@tonic-gate 18557c478bd9Sstevel@tonic-gate#if defined(lint) 18567c478bd9Sstevel@tonic-gate 18577c478bd9Sstevel@tonic-gatevoid 18587c478bd9Sstevel@tonic-gateset_base_spl(void) 18597c478bd9Sstevel@tonic-gate{} 18607c478bd9Sstevel@tonic-gate 18617c478bd9Sstevel@tonic-gate#else /* lint */ 18627c478bd9Sstevel@tonic-gate 18637c478bd9Sstevel@tonic-gate ENTRY_NP(set_base_spl) 18647c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CPU], %o2 ! load CPU pointer 18657c478bd9Sstevel@tonic-gate ld [%o2 + CPU_INTR_ACTV], %o5 ! load active interrupts mask 18667c478bd9Sstevel@tonic-gate 18677c478bd9Sstevel@tonic-gate/* 18687c478bd9Sstevel@tonic-gate * WARNING: non-standard callinq sequence; do not call from C 18697c478bd9Sstevel@tonic-gate * %o2 = pointer to CPU 18707c478bd9Sstevel@tonic-gate * %o5 = updated CPU_INTR_ACTV 18717c478bd9Sstevel@tonic-gate */ 18727c478bd9Sstevel@tonic-gate_intr_set_spl: ! intr_thread_exit enters here 18737c478bd9Sstevel@tonic-gate ! 18747c478bd9Sstevel@tonic-gate ! Determine highest interrupt level active. Several could be blocked 18757c478bd9Sstevel@tonic-gate ! at higher levels than this one, so must convert flags to a PIL 18767c478bd9Sstevel@tonic-gate ! Normally nothing will be blocked, so test this first. 18777c478bd9Sstevel@tonic-gate ! 18787c478bd9Sstevel@tonic-gate brz,pt %o5, 1f ! nothing active 18797c478bd9Sstevel@tonic-gate sra %o5, 11, %o3 ! delay - set %o3 to bits 15-11 18807c478bd9Sstevel@tonic-gate set _intr_flag_table, %o1 18817c478bd9Sstevel@tonic-gate tst %o3 ! see if any of the bits set 18827c478bd9Sstevel@tonic-gate ldub [%o1 + %o3], %o3 ! load bit number 18837c478bd9Sstevel@tonic-gate bnz,a,pn %xcc, 1f ! yes, add 10 and we're done 18847c478bd9Sstevel@tonic-gate add %o3, 11-1, %o3 ! delay - add bit number - 1 18857c478bd9Sstevel@tonic-gate 18867c478bd9Sstevel@tonic-gate sra %o5, 6, %o3 ! test bits 10-6 18877c478bd9Sstevel@tonic-gate tst %o3 18887c478bd9Sstevel@tonic-gate ldub [%o1 + %o3], %o3 18897c478bd9Sstevel@tonic-gate bnz,a,pn %xcc, 1f 18907c478bd9Sstevel@tonic-gate add %o3, 6-1, %o3 18917c478bd9Sstevel@tonic-gate 18927c478bd9Sstevel@tonic-gate sra %o5, 1, %o3 ! test bits 5-1 18937c478bd9Sstevel@tonic-gate ldub [%o1 + %o3], %o3 18947c478bd9Sstevel@tonic-gate 18957c478bd9Sstevel@tonic-gate ! 18967c478bd9Sstevel@tonic-gate ! highest interrupt level number active is in %l6 18977c478bd9Sstevel@tonic-gate ! 18987c478bd9Sstevel@tonic-gate1: 18997c478bd9Sstevel@tonic-gate retl 19007c478bd9Sstevel@tonic-gate st %o3, [%o2 + CPU_BASE_SPL] ! delay - store base priority 19017c478bd9Sstevel@tonic-gate SET_SIZE(set_base_spl) 19027c478bd9Sstevel@tonic-gate 19037c478bd9Sstevel@tonic-gate/* 19047c478bd9Sstevel@tonic-gate * Table that finds the most significant bit set in a five bit field. 19057c478bd9Sstevel@tonic-gate * Each entry is the high-order bit number + 1 of it's index in the table. 19067c478bd9Sstevel@tonic-gate * This read-only data is in the text segment. 19077c478bd9Sstevel@tonic-gate */ 19087c478bd9Sstevel@tonic-gate_intr_flag_table: 19097c478bd9Sstevel@tonic-gate .byte 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4 19107c478bd9Sstevel@tonic-gate .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 19117c478bd9Sstevel@tonic-gate .align 4 19127c478bd9Sstevel@tonic-gate 19137c478bd9Sstevel@tonic-gate#endif /* lint */ 19147c478bd9Sstevel@tonic-gate 19157c478bd9Sstevel@tonic-gate/* 19167c478bd9Sstevel@tonic-gate * int 19177c478bd9Sstevel@tonic-gate * intr_passivate(from, to) 19187c478bd9Sstevel@tonic-gate * kthread_id_t from; interrupt thread 19197c478bd9Sstevel@tonic-gate * kthread_id_t to; interrupted thread 19207c478bd9Sstevel@tonic-gate */ 19217c478bd9Sstevel@tonic-gate 19227c478bd9Sstevel@tonic-gate#if defined(lint) 19237c478bd9Sstevel@tonic-gate 19247c478bd9Sstevel@tonic-gate/* ARGSUSED */ 19257c478bd9Sstevel@tonic-gateint 19267c478bd9Sstevel@tonic-gateintr_passivate(kthread_id_t from, kthread_id_t to) 19277c478bd9Sstevel@tonic-gate{ return (0); } 19287c478bd9Sstevel@tonic-gate 19297c478bd9Sstevel@tonic-gate#else /* lint */ 19307c478bd9Sstevel@tonic-gate 19317c478bd9Sstevel@tonic-gate ENTRY_NP(intr_passivate) 19327c478bd9Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp ! get a new window 19337c478bd9Sstevel@tonic-gate 19347c478bd9Sstevel@tonic-gate flushw ! force register windows to stack 19357c478bd9Sstevel@tonic-gate ! 19367c478bd9Sstevel@tonic-gate ! restore registers from the base of the stack of the interrupt thread. 19377c478bd9Sstevel@tonic-gate ! 19387c478bd9Sstevel@tonic-gate ldn [%i0 + T_STACK], %i2 ! get stack save area pointer 19397c478bd9Sstevel@tonic-gate ldn [%i2 + (0*GREGSIZE)], %l0 ! load locals 19407c478bd9Sstevel@tonic-gate ldn [%i2 + (1*GREGSIZE)], %l1 19417c478bd9Sstevel@tonic-gate ldn [%i2 + (2*GREGSIZE)], %l2 19427c478bd9Sstevel@tonic-gate ldn [%i2 + (3*GREGSIZE)], %l3 19437c478bd9Sstevel@tonic-gate ldn [%i2 + (4*GREGSIZE)], %l4 19447c478bd9Sstevel@tonic-gate ldn [%i2 + (5*GREGSIZE)], %l5 19457c478bd9Sstevel@tonic-gate ldn [%i2 + (6*GREGSIZE)], %l6 19467c478bd9Sstevel@tonic-gate ldn [%i2 + (7*GREGSIZE)], %l7 19477c478bd9Sstevel@tonic-gate ldn [%i2 + (8*GREGSIZE)], %o0 ! put ins from stack in outs 19487c478bd9Sstevel@tonic-gate ldn [%i2 + (9*GREGSIZE)], %o1 19497c478bd9Sstevel@tonic-gate ldn [%i2 + (10*GREGSIZE)], %o2 19507c478bd9Sstevel@tonic-gate ldn [%i2 + (11*GREGSIZE)], %o3 19517c478bd9Sstevel@tonic-gate ldn [%i2 + (12*GREGSIZE)], %o4 19527c478bd9Sstevel@tonic-gate ldn [%i2 + (13*GREGSIZE)], %o5 19537c478bd9Sstevel@tonic-gate ldn [%i2 + (14*GREGSIZE)], %i4 19547c478bd9Sstevel@tonic-gate ! copy stack/pointer without using %sp 19557c478bd9Sstevel@tonic-gate ldn [%i2 + (15*GREGSIZE)], %i5 19567c478bd9Sstevel@tonic-gate ! 19577c478bd9Sstevel@tonic-gate ! put registers into the save area at the top of the interrupted 19587c478bd9Sstevel@tonic-gate ! thread's stack, pointed to by %l7 in the save area just loaded. 19597c478bd9Sstevel@tonic-gate ! 19607c478bd9Sstevel@tonic-gate ldn [%i1 + T_SP], %i3 ! get stack save area pointer 19617c478bd9Sstevel@tonic-gate stn %l0, [%i3 + STACK_BIAS + (0*GREGSIZE)] ! save locals 19627c478bd9Sstevel@tonic-gate stn %l1, [%i3 + STACK_BIAS + (1*GREGSIZE)] 19637c478bd9Sstevel@tonic-gate stn %l2, [%i3 + STACK_BIAS + (2*GREGSIZE)] 19647c478bd9Sstevel@tonic-gate stn %l3, [%i3 + STACK_BIAS + (3*GREGSIZE)] 19657c478bd9Sstevel@tonic-gate stn %l4, [%i3 + STACK_BIAS + (4*GREGSIZE)] 19667c478bd9Sstevel@tonic-gate stn %l5, [%i3 + STACK_BIAS + (5*GREGSIZE)] 19677c478bd9Sstevel@tonic-gate stn %l6, [%i3 + STACK_BIAS + (6*GREGSIZE)] 19687c478bd9Sstevel@tonic-gate stn %l7, [%i3 + STACK_BIAS + (7*GREGSIZE)] 19697c478bd9Sstevel@tonic-gate stn %o0, [%i3 + STACK_BIAS + (8*GREGSIZE)] ! save ins using outs 19707c478bd9Sstevel@tonic-gate stn %o1, [%i3 + STACK_BIAS + (9*GREGSIZE)] 19717c478bd9Sstevel@tonic-gate stn %o2, [%i3 + STACK_BIAS + (10*GREGSIZE)] 19727c478bd9Sstevel@tonic-gate stn %o3, [%i3 + STACK_BIAS + (11*GREGSIZE)] 19737c478bd9Sstevel@tonic-gate stn %o4, [%i3 + STACK_BIAS + (12*GREGSIZE)] 19747c478bd9Sstevel@tonic-gate stn %o5, [%i3 + STACK_BIAS + (13*GREGSIZE)] 19757c478bd9Sstevel@tonic-gate stn %i4, [%i3 + STACK_BIAS + (14*GREGSIZE)] 19767c478bd9Sstevel@tonic-gate ! fp, %i7 copied using %i4 19777c478bd9Sstevel@tonic-gate stn %i5, [%i3 + STACK_BIAS + (15*GREGSIZE)] 19787c478bd9Sstevel@tonic-gate stn %g0, [%i2 + ((8+6)*GREGSIZE)] 19797c478bd9Sstevel@tonic-gate ! clear fp in save area 19807c478bd9Sstevel@tonic-gate 19817c478bd9Sstevel@tonic-gate ! load saved pil for return 19827c478bd9Sstevel@tonic-gate ldub [%i0 + T_PIL], %i0 19837c478bd9Sstevel@tonic-gate ret 19847c478bd9Sstevel@tonic-gate restore 19857c478bd9Sstevel@tonic-gate SET_SIZE(intr_passivate) 19867c478bd9Sstevel@tonic-gate 19877c478bd9Sstevel@tonic-gate#endif /* lint */ 19887c478bd9Sstevel@tonic-gate 19897c478bd9Sstevel@tonic-gate#if defined(lint) 19907c478bd9Sstevel@tonic-gate 19917c478bd9Sstevel@tonic-gate/* 19927c478bd9Sstevel@tonic-gate * intr_get_time() is a resource for interrupt handlers to determine how 19937c478bd9Sstevel@tonic-gate * much time has been spent handling the current interrupt. Such a function 19947c478bd9Sstevel@tonic-gate * is needed because higher level interrupts can arrive during the 19957c478bd9Sstevel@tonic-gate * processing of an interrupt, thus making direct comparisons of %tick by 19967c478bd9Sstevel@tonic-gate * the handler inaccurate. intr_get_time() only returns time spent in the 19977c478bd9Sstevel@tonic-gate * current interrupt handler. 19987c478bd9Sstevel@tonic-gate * 19997c478bd9Sstevel@tonic-gate * The caller must be calling from an interrupt handler running at a pil 20007c478bd9Sstevel@tonic-gate * below or at lock level. Timings are not provided for high-level 20017c478bd9Sstevel@tonic-gate * interrupts. 20027c478bd9Sstevel@tonic-gate * 20037c478bd9Sstevel@tonic-gate * The first time intr_get_time() is called while handling an interrupt, 20047c478bd9Sstevel@tonic-gate * it returns the time since the interrupt handler was invoked. Subsequent 20057c478bd9Sstevel@tonic-gate * calls will return the time since the prior call to intr_get_time(). Time 20067c478bd9Sstevel@tonic-gate * is returned as ticks, adjusted for any clock divisor due to power 20077c478bd9Sstevel@tonic-gate * management. Use tick2ns() to convert ticks to nsec. Warning: ticks may 20087c478bd9Sstevel@tonic-gate * not be the same across CPUs. 20097c478bd9Sstevel@tonic-gate * 20107c478bd9Sstevel@tonic-gate * Theory Of Intrstat[][]: 20117c478bd9Sstevel@tonic-gate * 20127c478bd9Sstevel@tonic-gate * uint64_t intrstat[pil][0..1] is an array indexed by pil level, with two 20137c478bd9Sstevel@tonic-gate * uint64_ts per pil. 20147c478bd9Sstevel@tonic-gate * 20157c478bd9Sstevel@tonic-gate * intrstat[pil][0] is a cumulative count of the number of ticks spent 20167c478bd9Sstevel@tonic-gate * handling all interrupts at the specified pil on this CPU. It is 20177c478bd9Sstevel@tonic-gate * exported via kstats to the user. 20187c478bd9Sstevel@tonic-gate * 20197c478bd9Sstevel@tonic-gate * intrstat[pil][1] is always a count of ticks less than or equal to the 20207c478bd9Sstevel@tonic-gate * value in [0]. The difference between [1] and [0] is the value returned 20217c478bd9Sstevel@tonic-gate * by a call to intr_get_time(). At the start of interrupt processing, 20227c478bd9Sstevel@tonic-gate * [0] and [1] will be equal (or nearly so). As the interrupt consumes 20237c478bd9Sstevel@tonic-gate * time, [0] will increase, but [1] will remain the same. A call to 20247c478bd9Sstevel@tonic-gate * intr_get_time() will return the difference, then update [1] to be the 20257c478bd9Sstevel@tonic-gate * same as [0]. Future calls will return the time since the last call. 20267c478bd9Sstevel@tonic-gate * Finally, when the interrupt completes, [1] is updated to the same as [0]. 20277c478bd9Sstevel@tonic-gate * 20287c478bd9Sstevel@tonic-gate * Implementation: 20297c478bd9Sstevel@tonic-gate * 20307c478bd9Sstevel@tonic-gate * intr_get_time() works much like a higher level interrupt arriving. It 20317c478bd9Sstevel@tonic-gate * "checkpoints" the timing information by incrementing intrstat[pil][0] 20327c478bd9Sstevel@tonic-gate * to include elapsed running time, and by setting t_intr_start to %tick. 20337c478bd9Sstevel@tonic-gate * It then sets the return value to intrstat[pil][0] - intrstat[pil][1], 20347c478bd9Sstevel@tonic-gate * and updates intrstat[pil][1] to be the same as the new value of 20357c478bd9Sstevel@tonic-gate * intrstat[pil][0]. 20367c478bd9Sstevel@tonic-gate * 20377c478bd9Sstevel@tonic-gate * In the normal handling of interrupts, after an interrupt handler returns 20387c478bd9Sstevel@tonic-gate * and the code in intr_thread() updates intrstat[pil][0], it then sets 20397c478bd9Sstevel@tonic-gate * intrstat[pil][1] to the new value of intrstat[pil][0]. When [0] == [1], 20407c478bd9Sstevel@tonic-gate * the timings are reset, i.e. intr_get_time() will return [0] - [1] which 20417c478bd9Sstevel@tonic-gate * is 0. 20427c478bd9Sstevel@tonic-gate * 20437c478bd9Sstevel@tonic-gate * Whenever interrupts arrive on a CPU which is handling a lower pil 20447c478bd9Sstevel@tonic-gate * interrupt, they update the lower pil's [0] to show time spent in the 20457c478bd9Sstevel@tonic-gate * handler that they've interrupted. This results in a growing discrepancy 20467c478bd9Sstevel@tonic-gate * between [0] and [1], which is returned the next time intr_get_time() is 20477c478bd9Sstevel@tonic-gate * called. Time spent in the higher-pil interrupt will not be returned in 20487c478bd9Sstevel@tonic-gate * the next intr_get_time() call from the original interrupt, because 20497c478bd9Sstevel@tonic-gate * the higher-pil interrupt's time is accumulated in intrstat[higherpil][]. 20507c478bd9Sstevel@tonic-gate */ 20517c478bd9Sstevel@tonic-gate 20527c478bd9Sstevel@tonic-gate/*ARGSUSED*/ 20537c478bd9Sstevel@tonic-gateuint64_t 20547c478bd9Sstevel@tonic-gateintr_get_time(void) 20557c478bd9Sstevel@tonic-gate{ return 0; } 20567c478bd9Sstevel@tonic-gate#else /* lint */ 20577c478bd9Sstevel@tonic-gate 20587c478bd9Sstevel@tonic-gate ENTRY_NP(intr_get_time) 20597c478bd9Sstevel@tonic-gate#ifdef DEBUG 20607c478bd9Sstevel@tonic-gate ! 20617c478bd9Sstevel@tonic-gate ! Lots of asserts, but just check panic_quiesce first. 20627c478bd9Sstevel@tonic-gate ! Don't bother with lots of tests if we're just ignoring them. 20637c478bd9Sstevel@tonic-gate ! 20647c478bd9Sstevel@tonic-gate sethi %hi(panic_quiesce), %o0 20657c478bd9Sstevel@tonic-gate ld [%o0 + %lo(panic_quiesce)], %o0 20667c478bd9Sstevel@tonic-gate brnz,pn %o0, 2f 20677c478bd9Sstevel@tonic-gate nop 20687c478bd9Sstevel@tonic-gate ! 20697c478bd9Sstevel@tonic-gate ! ASSERT(%pil <= LOCK_LEVEL) 20707c478bd9Sstevel@tonic-gate ! 20717c478bd9Sstevel@tonic-gate rdpr %pil, %o1 20727c478bd9Sstevel@tonic-gate cmp %o1, LOCK_LEVEL 20737c478bd9Sstevel@tonic-gate ble,pt %xcc, 0f 20747c478bd9Sstevel@tonic-gate sethi %hi(intr_get_time_high_pil), %o0 ! delay 20757c478bd9Sstevel@tonic-gate call panic 20767c478bd9Sstevel@tonic-gate or %o0, %lo(intr_get_time_high_pil), %o0 20777c478bd9Sstevel@tonic-gate0: 20787c478bd9Sstevel@tonic-gate ! 20797c478bd9Sstevel@tonic-gate ! ASSERT((t_flags & T_INTR_THREAD) != 0 && t_pil > 0) 20807c478bd9Sstevel@tonic-gate ! 20817c478bd9Sstevel@tonic-gate lduh [THREAD_REG + T_FLAGS], %o2 20827c478bd9Sstevel@tonic-gate andcc %o2, T_INTR_THREAD, %g0 20837c478bd9Sstevel@tonic-gate bz,pn %xcc, 1f 20847c478bd9Sstevel@tonic-gate ldub [THREAD_REG + T_PIL], %o1 ! delay 20857c478bd9Sstevel@tonic-gate brnz,pt %o1, 0f 20867c478bd9Sstevel@tonic-gate1: 20877c478bd9Sstevel@tonic-gate sethi %hi(intr_get_time_not_intr), %o0 20887c478bd9Sstevel@tonic-gate call panic 20897c478bd9Sstevel@tonic-gate or %o0, %lo(intr_get_time_not_intr), %o0 20907c478bd9Sstevel@tonic-gate0: 20917c478bd9Sstevel@tonic-gate ! 20927c478bd9Sstevel@tonic-gate ! ASSERT(t_intr_start != 0) 20937c478bd9Sstevel@tonic-gate ! 20947c478bd9Sstevel@tonic-gate ldx [THREAD_REG + T_INTR_START], %o1 20957c478bd9Sstevel@tonic-gate brnz,pt %o1, 2f 20967c478bd9Sstevel@tonic-gate sethi %hi(intr_get_time_no_start_time), %o0 ! delay 20977c478bd9Sstevel@tonic-gate call panic 20987c478bd9Sstevel@tonic-gate or %o0, %lo(intr_get_time_no_start_time), %o0 20997c478bd9Sstevel@tonic-gate2: 21007c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 21017c478bd9Sstevel@tonic-gate ! 21027c478bd9Sstevel@tonic-gate ! %o0 = elapsed time and return value 21037c478bd9Sstevel@tonic-gate ! %o1 = pil 21047c478bd9Sstevel@tonic-gate ! %o2 = scratch 21057c478bd9Sstevel@tonic-gate ! %o3 = scratch 21067c478bd9Sstevel@tonic-gate ! %o4 = scratch 21077c478bd9Sstevel@tonic-gate ! %o5 = cpu 21087c478bd9Sstevel@tonic-gate ! 21097c478bd9Sstevel@tonic-gate wrpr %g0, PIL_MAX, %pil ! make this easy -- block normal intrs 21107c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CPU], %o5 21117c478bd9Sstevel@tonic-gate ldub [THREAD_REG + T_PIL], %o1 21127c478bd9Sstevel@tonic-gate ldx [THREAD_REG + T_INTR_START], %o3 ! %o3 = t_intr_start 21137c478bd9Sstevel@tonic-gate ! 21147c478bd9Sstevel@tonic-gate ! Calculate elapsed time since t_intr_start. Update t_intr_start, 21157c478bd9Sstevel@tonic-gate ! get delta, and multiply by cpu_divisor if necessary. 21167c478bd9Sstevel@tonic-gate ! 21177c478bd9Sstevel@tonic-gate rdpr %tick, %o2 21187c478bd9Sstevel@tonic-gate sllx %o2, 1, %o2 21197c478bd9Sstevel@tonic-gate srlx %o2, 1, %o2 21207c478bd9Sstevel@tonic-gate stx %o2, [THREAD_REG + T_INTR_START] 21217c478bd9Sstevel@tonic-gate sub %o2, %o3, %o0 21227c478bd9Sstevel@tonic-gate 21237c478bd9Sstevel@tonic-gate lduh [%o5 + CPU_DIVISOR], %o4 21247c478bd9Sstevel@tonic-gate cmp %o4, 1 21257c478bd9Sstevel@tonic-gate bg,a,pn %xcc, 1f 21267c478bd9Sstevel@tonic-gate mulx %o0, %o4, %o0 ! multiply interval by clock divisor iff > 1 21277c478bd9Sstevel@tonic-gate1: 2128eda89462Sesolom ! Update intracct[] 2129eda89462Sesolom lduh [%o5 + CPU_MSTATE], %o4 2130eda89462Sesolom sllx %o4, 3, %o4 2131eda89462Sesolom add %o4, CPU_INTRACCT, %o4 2132eda89462Sesolom ldx [%o5 + %o4], %o2 2133eda89462Sesolom add %o2, %o0, %o2 2134eda89462Sesolom stx %o2, [%o5 + %o4] 2135eda89462Sesolom 21367c478bd9Sstevel@tonic-gate ! 21377c478bd9Sstevel@tonic-gate ! Increment cpu_m.intrstat[pil][0]. Calculate elapsed time since 21387c478bd9Sstevel@tonic-gate ! cpu_m.intrstat[pil][1], which is either when the interrupt was 21397c478bd9Sstevel@tonic-gate ! first entered, or the last time intr_get_time() was invoked. Then 21407c478bd9Sstevel@tonic-gate ! update cpu_m.intrstat[pil][1] to match [0]. 21417c478bd9Sstevel@tonic-gate ! 21427c478bd9Sstevel@tonic-gate sllx %o1, 4, %o3 21437c478bd9Sstevel@tonic-gate add %o3, CPU_MCPU, %o3 21447c478bd9Sstevel@tonic-gate add %o3, MCPU_INTRSTAT, %o3 21457c478bd9Sstevel@tonic-gate add %o3, %o5, %o3 ! %o3 = cpu_m.intrstat[pil][0] 21467c478bd9Sstevel@tonic-gate ldx [%o3], %o2 21477c478bd9Sstevel@tonic-gate add %o2, %o0, %o2 ! %o2 = new value for intrstat 21487c478bd9Sstevel@tonic-gate stx %o2, [%o3] 21497c478bd9Sstevel@tonic-gate ldx [%o3 + 8], %o4 ! %o4 = cpu_m.intrstat[pil][1] 21507c478bd9Sstevel@tonic-gate sub %o2, %o4, %o0 ! %o0 is elapsed time since %o4 21517c478bd9Sstevel@tonic-gate stx %o2, [%o3 + 8] ! make [1] match [0], resetting time 21527c478bd9Sstevel@tonic-gate 21537c478bd9Sstevel@tonic-gate ld [%o5 + CPU_BASE_SPL], %o2 ! restore %pil to the greater 21547c478bd9Sstevel@tonic-gate cmp %o2, %o1 ! of either our pil %o1 or 21557c478bd9Sstevel@tonic-gate movl %xcc, %o1, %o2 ! cpu_base_spl. 21567c478bd9Sstevel@tonic-gate retl 21577c478bd9Sstevel@tonic-gate wrpr %g0, %o2, %pil 21587c478bd9Sstevel@tonic-gate SET_SIZE(intr_get_time) 21597c478bd9Sstevel@tonic-gate 21607c478bd9Sstevel@tonic-gate#ifdef DEBUG 21617c478bd9Sstevel@tonic-gateintr_get_time_high_pil: 21627c478bd9Sstevel@tonic-gate .asciz "intr_get_time(): %pil > LOCK_LEVEL" 21637c478bd9Sstevel@tonic-gateintr_get_time_not_intr: 21647c478bd9Sstevel@tonic-gate .asciz "intr_get_time(): not called from an interrupt thread" 21657c478bd9Sstevel@tonic-gateintr_get_time_no_start_time: 21667c478bd9Sstevel@tonic-gate .asciz "intr_get_time(): t_intr_start == 0" 21677c478bd9Sstevel@tonic-gate#endif /* DEBUG */ 21687c478bd9Sstevel@tonic-gate#endif /* lint */ 21697c478bd9Sstevel@tonic-gate 21707c478bd9Sstevel@tonic-gate 21717c478bd9Sstevel@tonic-gate#if !defined(lint) 21727c478bd9Sstevel@tonic-gate 21737c478bd9Sstevel@tonic-gate/* 21747c478bd9Sstevel@tonic-gate * Check shift value used for computing array offsets 21757c478bd9Sstevel@tonic-gate */ 21767c478bd9Sstevel@tonic-gate#if INTR_VECTOR_SIZE != (1 << INTR_VECTOR_SHIFT) 21777c478bd9Sstevel@tonic-gate#error "INTR_VECTOR_SIZE has changed" 21787c478bd9Sstevel@tonic-gate#endif 21797c478bd9Sstevel@tonic-gate 21807c478bd9Sstevel@tonic-gate#endif /* lint */ 2181