1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/cpuvar.h> 30*0Sstevel@tonic-gate #include <sys/regset.h> 31*0Sstevel@tonic-gate #include <sys/psw.h> 32*0Sstevel@tonic-gate #include <sys/types.h> 33*0Sstevel@tonic-gate #include <sys/thread.h> 34*0Sstevel@tonic-gate #include <sys/systm.h> 35*0Sstevel@tonic-gate #include <sys/segments.h> 36*0Sstevel@tonic-gate #include <sys/pcb.h> 37*0Sstevel@tonic-gate #include <sys/trap.h> 38*0Sstevel@tonic-gate #include <sys/ftrace.h> 39*0Sstevel@tonic-gate #include <sys/traptrace.h> 40*0Sstevel@tonic-gate #include <sys/clock.h> 41*0Sstevel@tonic-gate #include <sys/panic.h> 42*0Sstevel@tonic-gate #include <sys/disp.h> 43*0Sstevel@tonic-gate #include <vm/seg_kp.h> 44*0Sstevel@tonic-gate #include <sys/stack.h> 45*0Sstevel@tonic-gate #include <sys/sysmacros.h> 46*0Sstevel@tonic-gate #include <sys/cmn_err.h> 47*0Sstevel@tonic-gate #include <sys/kstat.h> 48*0Sstevel@tonic-gate #include <sys/smp_impldefs.h> 49*0Sstevel@tonic-gate #include <sys/pool_pset.h> 50*0Sstevel@tonic-gate #include <sys/zone.h> 51*0Sstevel@tonic-gate #include <sys/bitmap.h> 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate #if defined(__amd64) 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate #if defined(__lint) 56*0Sstevel@tonic-gate /* 57*0Sstevel@tonic-gate * atomic_btr32() is a gcc __inline__ function, defined in <asm/bitmap.h> 58*0Sstevel@tonic-gate * For lint purposes, define it here. 59*0Sstevel@tonic-gate */ 60*0Sstevel@tonic-gate uint_t 61*0Sstevel@tonic-gate atomic_btr32(uint32_t *pending, uint_t pil) 62*0Sstevel@tonic-gate { 63*0Sstevel@tonic-gate return (*pending &= ~(1 << pil)); 64*0Sstevel@tonic-gate } 65*0Sstevel@tonic-gate #else 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate extern uint_t atomic_btr32(uint32_t *pending, uint_t pil); 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate #endif 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate /* 72*0Sstevel@tonic-gate * This code is amd64-only for now, but as time permits, we should 73*0Sstevel@tonic-gate * use this on i386 too. 74*0Sstevel@tonic-gate */ 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate /* 77*0Sstevel@tonic-gate * Some questions to ponder: 78*0Sstevel@tonic-gate * - in several of these routines, we make multiple calls to tsc_read() 79*0Sstevel@tonic-gate * without invoking functions .. couldn't we just reuse the same 80*0Sstevel@tonic-gate * timestamp sometimes? 81*0Sstevel@tonic-gate * - if we have the inline, we can probably make set_base_spl be a 82*0Sstevel@tonic-gate * C routine too. 83*0Sstevel@tonic-gate */ 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate static uint_t 86*0Sstevel@tonic-gate bsrw_insn(uint16_t mask) 87*0Sstevel@tonic-gate { 88*0Sstevel@tonic-gate uint_t index = sizeof (mask) * NBBY - 1; 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate ASSERT(mask != 0); 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate while ((mask & (1 << index)) == 0) 93*0Sstevel@tonic-gate index--; 94*0Sstevel@tonic-gate return (index); 95*0Sstevel@tonic-gate } 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate /* 98*0Sstevel@tonic-gate * Do all the work necessary to set up the cpu and thread structures 99*0Sstevel@tonic-gate * to dispatch a high-level interrupt. 100*0Sstevel@tonic-gate * 101*0Sstevel@tonic-gate * Returns 0 if we're -not- already on the high-level interrupt stack, 102*0Sstevel@tonic-gate * (and *must* switch to it), non-zero if we are already on that stack. 103*0Sstevel@tonic-gate * 104*0Sstevel@tonic-gate * Called with interrupts masked. 105*0Sstevel@tonic-gate * The 'pil' is already set to the appropriate level for rp->r_trapno. 106*0Sstevel@tonic-gate */ 107*0Sstevel@tonic-gate int 108*0Sstevel@tonic-gate hilevel_intr_prolog(struct cpu *cpu, uint_t pil, uint_t oldpil, struct regs *rp) 109*0Sstevel@tonic-gate { 110*0Sstevel@tonic-gate struct machcpu *mcpu = &cpu->cpu_m; 111*0Sstevel@tonic-gate uint_t mask; 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate ASSERT(pil > LOCK_LEVEL); 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate if (pil == CBE_HIGH_PIL) { 116*0Sstevel@tonic-gate cpu->cpu_profile_pil = oldpil; 117*0Sstevel@tonic-gate if (USERMODE(rp->r_cs)) { 118*0Sstevel@tonic-gate cpu->cpu_profile_pc = 0; 119*0Sstevel@tonic-gate cpu->cpu_profile_upc = rp->r_pc; 120*0Sstevel@tonic-gate } else { 121*0Sstevel@tonic-gate cpu->cpu_profile_pc = rp->r_pc; 122*0Sstevel@tonic-gate cpu->cpu_profile_upc = 0; 123*0Sstevel@tonic-gate } 124*0Sstevel@tonic-gate } 125*0Sstevel@tonic-gate 126*0Sstevel@tonic-gate mask = cpu->cpu_intr_actv & CPU_INTR_ACTV_HIGH_LEVEL_MASK; 127*0Sstevel@tonic-gate if (mask != 0) { 128*0Sstevel@tonic-gate int nestpil; 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate /* 131*0Sstevel@tonic-gate * We have interrupted another high-level interrupt. 132*0Sstevel@tonic-gate * Load starting timestamp, compute interval, update 133*0Sstevel@tonic-gate * cumulative counter. 134*0Sstevel@tonic-gate */ 135*0Sstevel@tonic-gate nestpil = bsrw_insn((uint16_t)mask); 136*0Sstevel@tonic-gate ASSERT(nestpil < pil); 137*0Sstevel@tonic-gate mcpu->intrstat[nestpil] += tsc_read() - 138*0Sstevel@tonic-gate mcpu->pil_high_start[nestpil - (LOCK_LEVEL + 1)]; 139*0Sstevel@tonic-gate /* 140*0Sstevel@tonic-gate * Another high-level interrupt is active below this one, so 141*0Sstevel@tonic-gate * there is no need to check for an interrupt thread. That 142*0Sstevel@tonic-gate * will be done by the lowest priority high-level interrupt 143*0Sstevel@tonic-gate * active. 144*0Sstevel@tonic-gate */ 145*0Sstevel@tonic-gate } else { 146*0Sstevel@tonic-gate kthread_t *t = cpu->cpu_thread; 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate /* 149*0Sstevel@tonic-gate * See if we are interrupting a low-level interrupt thread. 150*0Sstevel@tonic-gate * If so, account for its time slice only if its time stamp 151*0Sstevel@tonic-gate * is non-zero. 152*0Sstevel@tonic-gate */ 153*0Sstevel@tonic-gate if ((t->t_flag & T_INTR_THREAD) != 0 && t->t_intr_start != 0) { 154*0Sstevel@tonic-gate mcpu->intrstat[t->t_pil] += 155*0Sstevel@tonic-gate tsc_read() - t->t_intr_start; 156*0Sstevel@tonic-gate t->t_intr_start = 0; 157*0Sstevel@tonic-gate } 158*0Sstevel@tonic-gate } 159*0Sstevel@tonic-gate 160*0Sstevel@tonic-gate /* 161*0Sstevel@tonic-gate * Store starting timestamp in CPU structure for this PIL. 162*0Sstevel@tonic-gate */ 163*0Sstevel@tonic-gate mcpu->pil_high_start[pil - (LOCK_LEVEL + 1)] = tsc_read(); 164*0Sstevel@tonic-gate 165*0Sstevel@tonic-gate ASSERT((cpu->cpu_intr_actv & (1 << pil)) == 0); 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gate if (pil == 15) { 168*0Sstevel@tonic-gate /* 169*0Sstevel@tonic-gate * To support reentrant level 15 interrupts, we maintain a 170*0Sstevel@tonic-gate * recursion count in the top half of cpu_intr_actv. Only 171*0Sstevel@tonic-gate * when this count hits zero do we clear the PIL 15 bit from 172*0Sstevel@tonic-gate * the lower half of cpu_intr_actv. 173*0Sstevel@tonic-gate */ 174*0Sstevel@tonic-gate uint16_t *refcntp = (uint16_t *)&cpu->cpu_intr_actv + 1; 175*0Sstevel@tonic-gate (*refcntp)++; 176*0Sstevel@tonic-gate } 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate mask = cpu->cpu_intr_actv; 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate cpu->cpu_intr_actv |= (1 << pil); 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gate return (mask & CPU_INTR_ACTV_HIGH_LEVEL_MASK); 183*0Sstevel@tonic-gate } 184*0Sstevel@tonic-gate 185*0Sstevel@tonic-gate /* 186*0Sstevel@tonic-gate * Does most of the work of returning from a high level interrupt. 187*0Sstevel@tonic-gate * 188*0Sstevel@tonic-gate * Returns 0 if there are no more high level interrupts (in which 189*0Sstevel@tonic-gate * case we must switch back to the interrupted thread stack) or 190*0Sstevel@tonic-gate * non-zero if there are more (in which case we should stay on it). 191*0Sstevel@tonic-gate * 192*0Sstevel@tonic-gate * Called with interrupts masked 193*0Sstevel@tonic-gate */ 194*0Sstevel@tonic-gate int 195*0Sstevel@tonic-gate hilevel_intr_epilog(struct cpu *cpu, uint_t pil, uint_t oldpil, uint_t vecnum) 196*0Sstevel@tonic-gate { 197*0Sstevel@tonic-gate struct machcpu *mcpu = &cpu->cpu_m; 198*0Sstevel@tonic-gate uint_t mask; 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate ASSERT(mcpu->mcpu_pri == pil); 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate cpu->cpu_stats.sys.intr[pil - 1]++; 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate ASSERT(cpu->cpu_intr_actv & (1 << pil)); 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate if (pil == 15) { 207*0Sstevel@tonic-gate /* 208*0Sstevel@tonic-gate * To support reentrant level 15 interrupts, we maintain a 209*0Sstevel@tonic-gate * recursion count in the top half of cpu_intr_actv. Only 210*0Sstevel@tonic-gate * when this count hits zero do we clear the PIL 15 bit from 211*0Sstevel@tonic-gate * the lower half of cpu_intr_actv. 212*0Sstevel@tonic-gate */ 213*0Sstevel@tonic-gate uint16_t *refcntp = (uint16_t *)&cpu->cpu_intr_actv + 1; 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate ASSERT(*refcntp > 0); 216*0Sstevel@tonic-gate 217*0Sstevel@tonic-gate if (--(*refcntp) == 0) 218*0Sstevel@tonic-gate cpu->cpu_intr_actv &= ~(1 << pil); 219*0Sstevel@tonic-gate } else { 220*0Sstevel@tonic-gate cpu->cpu_intr_actv &= ~(1 << pil); 221*0Sstevel@tonic-gate } 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate ASSERT(mcpu->pil_high_start[pil - (LOCK_LEVEL + 1)] != 0); 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate mcpu->intrstat[pil] += 226*0Sstevel@tonic-gate tsc_read() - mcpu->pil_high_start[pil - (LOCK_LEVEL + 1)]; 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate /* 229*0Sstevel@tonic-gate * Check for lower-pil nested high-level interrupt beneath 230*0Sstevel@tonic-gate * current one. If so, place a starting timestamp in its 231*0Sstevel@tonic-gate * pil_high_start entry. 232*0Sstevel@tonic-gate */ 233*0Sstevel@tonic-gate mask = cpu->cpu_intr_actv & CPU_INTR_ACTV_HIGH_LEVEL_MASK; 234*0Sstevel@tonic-gate if (mask != 0) { 235*0Sstevel@tonic-gate int nestpil; 236*0Sstevel@tonic-gate 237*0Sstevel@tonic-gate /* 238*0Sstevel@tonic-gate * find PIL of nested interrupt 239*0Sstevel@tonic-gate */ 240*0Sstevel@tonic-gate nestpil = bsrw_insn((uint16_t)mask); 241*0Sstevel@tonic-gate ASSERT(nestpil < pil); 242*0Sstevel@tonic-gate mcpu->pil_high_start[nestpil - (LOCK_LEVEL + 1)] = tsc_read(); 243*0Sstevel@tonic-gate /* 244*0Sstevel@tonic-gate * (Another high-level interrupt is active below this one, 245*0Sstevel@tonic-gate * so there is no need to check for an interrupt 246*0Sstevel@tonic-gate * thread. That will be done by the lowest priority 247*0Sstevel@tonic-gate * high-level interrupt active.) 248*0Sstevel@tonic-gate */ 249*0Sstevel@tonic-gate } else { 250*0Sstevel@tonic-gate /* 251*0Sstevel@tonic-gate * Check to see if there is a low-level interrupt active. 252*0Sstevel@tonic-gate * If so, place a starting timestamp in the thread 253*0Sstevel@tonic-gate * structure. 254*0Sstevel@tonic-gate */ 255*0Sstevel@tonic-gate kthread_t *t = cpu->cpu_thread; 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate if (t->t_flag & T_INTR_THREAD) 258*0Sstevel@tonic-gate t->t_intr_start = tsc_read(); 259*0Sstevel@tonic-gate } 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate mcpu->mcpu_pri = oldpil; 262*0Sstevel@tonic-gate (void) (*setlvlx)(oldpil, vecnum); 263*0Sstevel@tonic-gate 264*0Sstevel@tonic-gate return (cpu->cpu_intr_actv & CPU_INTR_ACTV_HIGH_LEVEL_MASK); 265*0Sstevel@tonic-gate } 266*0Sstevel@tonic-gate 267*0Sstevel@tonic-gate /* 268*0Sstevel@tonic-gate * Set up the cpu, thread and interrupt thread structures for 269*0Sstevel@tonic-gate * executing an interrupt thread. The new stack pointer of the 270*0Sstevel@tonic-gate * interrupt thread (which *must* be switched to) is returned. 271*0Sstevel@tonic-gate */ 272*0Sstevel@tonic-gate caddr_t 273*0Sstevel@tonic-gate intr_thread_prolog(struct cpu *cpu, caddr_t stackptr, uint_t pil) 274*0Sstevel@tonic-gate { 275*0Sstevel@tonic-gate struct machcpu *mcpu = &cpu->cpu_m; 276*0Sstevel@tonic-gate kthread_t *t, *volatile it; 277*0Sstevel@tonic-gate 278*0Sstevel@tonic-gate ASSERT(pil > 0); 279*0Sstevel@tonic-gate ASSERT((cpu->cpu_intr_actv & (1 << pil)) == 0); 280*0Sstevel@tonic-gate cpu->cpu_intr_actv |= (1 << pil); 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate /* 283*0Sstevel@tonic-gate * Get set to run an interrupt thread. 284*0Sstevel@tonic-gate * There should always be an interrupt thread, since we 285*0Sstevel@tonic-gate * allocate one for each level on each CPU. 286*0Sstevel@tonic-gate * 287*0Sstevel@tonic-gate * Note that the code in kcpc_overflow_intr -relies- on the 288*0Sstevel@tonic-gate * ordering of events here - in particular that t->t_lwp of 289*0Sstevel@tonic-gate * the interrupt thread is set to the pinned thread *before* 290*0Sstevel@tonic-gate * curthread is changed. 291*0Sstevel@tonic-gate */ 292*0Sstevel@tonic-gate t = cpu->cpu_thread; 293*0Sstevel@tonic-gate if (t->t_flag & T_INTR_THREAD) { 294*0Sstevel@tonic-gate mcpu->intrstat[t->t_pil] += t->t_intr_start - tsc_read(); 295*0Sstevel@tonic-gate t->t_intr_start = 0; 296*0Sstevel@tonic-gate } 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate ASSERT(SA((uintptr_t)stackptr) == (uintptr_t)stackptr); 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate t->t_sp = (uintptr_t)stackptr; /* mark stack in curthread for resume */ 301*0Sstevel@tonic-gate 302*0Sstevel@tonic-gate /* 303*0Sstevel@tonic-gate * unlink the interrupt thread off the cpu 304*0Sstevel@tonic-gate */ 305*0Sstevel@tonic-gate it = cpu->cpu_intr_thread; 306*0Sstevel@tonic-gate cpu->cpu_intr_thread = it->t_link; 307*0Sstevel@tonic-gate it->t_intr = t; 308*0Sstevel@tonic-gate it->t_lwp = t->t_lwp; 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate /* 311*0Sstevel@tonic-gate * (threads on the interrupt thread free list could have state 312*0Sstevel@tonic-gate * preset to TS_ONPROC, but it helps in debugging if 313*0Sstevel@tonic-gate * they're TS_FREE.) 314*0Sstevel@tonic-gate */ 315*0Sstevel@tonic-gate it->t_state = TS_ONPROC; 316*0Sstevel@tonic-gate 317*0Sstevel@tonic-gate cpu->cpu_thread = it; /* new curthread on this cpu */ 318*0Sstevel@tonic-gate it->t_pil = (uchar_t)pil; 319*0Sstevel@tonic-gate it->t_pri = intr_pri + (pri_t)pil; 320*0Sstevel@tonic-gate it->t_intr_start = tsc_read(); 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate return (it->t_stk); 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate #ifdef DEBUG 327*0Sstevel@tonic-gate int intr_thread_cnt; 328*0Sstevel@tonic-gate #endif 329*0Sstevel@tonic-gate 330*0Sstevel@tonic-gate /* 331*0Sstevel@tonic-gate * Called with interrupts disabled 332*0Sstevel@tonic-gate */ 333*0Sstevel@tonic-gate void 334*0Sstevel@tonic-gate intr_thread_epilog(struct cpu *cpu, uint_t vec, uint_t oldpil) 335*0Sstevel@tonic-gate { 336*0Sstevel@tonic-gate struct machcpu *mcpu = &cpu->cpu_m; 337*0Sstevel@tonic-gate kthread_t *t; 338*0Sstevel@tonic-gate kthread_t *it = cpu->cpu_thread; /* curthread */ 339*0Sstevel@tonic-gate uint_t pil, basespl; 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate pil = it->t_pil; 342*0Sstevel@tonic-gate cpu->cpu_stats.sys.intr[pil - 1]++; 343*0Sstevel@tonic-gate 344*0Sstevel@tonic-gate ASSERT(it->t_intr_start != 0); 345*0Sstevel@tonic-gate mcpu->intrstat[pil] += tsc_read() - it->t_intr_start; 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate ASSERT(cpu->cpu_intr_actv & (1 << pil)); 348*0Sstevel@tonic-gate cpu->cpu_intr_actv &= ~(1 << pil); 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate /* 351*0Sstevel@tonic-gate * If there is still an interrupted thread underneath this one 352*0Sstevel@tonic-gate * then the interrupt was never blocked and the return is 353*0Sstevel@tonic-gate * fairly simple. Otherwise it isn't. 354*0Sstevel@tonic-gate */ 355*0Sstevel@tonic-gate if ((t = it->t_intr) == NULL) { 356*0Sstevel@tonic-gate /* 357*0Sstevel@tonic-gate * The interrupted thread is no longer pinned underneath 358*0Sstevel@tonic-gate * the interrupt thread. This means the interrupt must 359*0Sstevel@tonic-gate * have blocked, and the interrupted thread has been 360*0Sstevel@tonic-gate * unpinned, and has probably been running around the 361*0Sstevel@tonic-gate * system for a while. 362*0Sstevel@tonic-gate * 363*0Sstevel@tonic-gate * Since there is no longer a thread under this one, put 364*0Sstevel@tonic-gate * this interrupt thread back on the CPU's free list and 365*0Sstevel@tonic-gate * resume the idle thread which will dispatch the next 366*0Sstevel@tonic-gate * thread to run. 367*0Sstevel@tonic-gate */ 368*0Sstevel@tonic-gate #ifdef DEBUG 369*0Sstevel@tonic-gate intr_thread_cnt++; 370*0Sstevel@tonic-gate #endif 371*0Sstevel@tonic-gate cpu->cpu_stats.sys.intrblk++; 372*0Sstevel@tonic-gate /* 373*0Sstevel@tonic-gate * Set CPU's base SPL based on active interrupts bitmask 374*0Sstevel@tonic-gate */ 375*0Sstevel@tonic-gate set_base_spl(); 376*0Sstevel@tonic-gate basespl = cpu->cpu_base_spl; 377*0Sstevel@tonic-gate mcpu->mcpu_pri = basespl; 378*0Sstevel@tonic-gate (*setlvlx)(basespl, vec); 379*0Sstevel@tonic-gate (void) splhigh(); 380*0Sstevel@tonic-gate it->t_state = TS_FREE; 381*0Sstevel@tonic-gate /* 382*0Sstevel@tonic-gate * Return interrupt thread to pool 383*0Sstevel@tonic-gate */ 384*0Sstevel@tonic-gate it->t_link = cpu->cpu_intr_thread; 385*0Sstevel@tonic-gate cpu->cpu_intr_thread = it; 386*0Sstevel@tonic-gate swtch(); 387*0Sstevel@tonic-gate /*NOTREACHED*/ 388*0Sstevel@tonic-gate } 389*0Sstevel@tonic-gate 390*0Sstevel@tonic-gate /* 391*0Sstevel@tonic-gate * Return interrupt thread to the pool 392*0Sstevel@tonic-gate */ 393*0Sstevel@tonic-gate it->t_link = cpu->cpu_intr_thread; 394*0Sstevel@tonic-gate cpu->cpu_intr_thread = it; 395*0Sstevel@tonic-gate it->t_state = TS_FREE; 396*0Sstevel@tonic-gate 397*0Sstevel@tonic-gate basespl = cpu->cpu_base_spl; 398*0Sstevel@tonic-gate pil = MAX(oldpil, basespl); 399*0Sstevel@tonic-gate mcpu->mcpu_pri = pil; 400*0Sstevel@tonic-gate (*setlvlx)(pil, vec); 401*0Sstevel@tonic-gate t->t_intr_start = tsc_read(); 402*0Sstevel@tonic-gate cpu->cpu_thread = t; 403*0Sstevel@tonic-gate } 404*0Sstevel@tonic-gate 405*0Sstevel@tonic-gate caddr_t 406*0Sstevel@tonic-gate dosoftint_prolog( 407*0Sstevel@tonic-gate struct cpu *cpu, 408*0Sstevel@tonic-gate caddr_t stackptr, 409*0Sstevel@tonic-gate uint32_t st_pending, 410*0Sstevel@tonic-gate uint_t oldpil) 411*0Sstevel@tonic-gate { 412*0Sstevel@tonic-gate kthread_t *t, *volatile it; 413*0Sstevel@tonic-gate struct machcpu *mcpu = &cpu->cpu_m; 414*0Sstevel@tonic-gate uint_t pil; 415*0Sstevel@tonic-gate 416*0Sstevel@tonic-gate top: 417*0Sstevel@tonic-gate ASSERT(st_pending == mcpu->mcpu_softinfo.st_pending); 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate pil = bsrw_insn((uint16_t)st_pending); 420*0Sstevel@tonic-gate if (pil <= oldpil || pil <= cpu->cpu_base_spl) 421*0Sstevel@tonic-gate return (0); 422*0Sstevel@tonic-gate 423*0Sstevel@tonic-gate /* 424*0Sstevel@tonic-gate * XX64 Sigh. 425*0Sstevel@tonic-gate * 426*0Sstevel@tonic-gate * This is a transliteration of the i386 assembler code for 427*0Sstevel@tonic-gate * soft interrupts. One question is "why does this need 428*0Sstevel@tonic-gate * to be atomic?" One possible race is -other- processors 429*0Sstevel@tonic-gate * posting soft interrupts to us in set_pending() i.e. the 430*0Sstevel@tonic-gate * CPU might get preempted just after the address computation, 431*0Sstevel@tonic-gate * but just before the atomic transaction, so another CPU would 432*0Sstevel@tonic-gate * actually set the original CPU's st_pending bit. However, 433*0Sstevel@tonic-gate * it looks like it would be simpler to disable preemption there. 434*0Sstevel@tonic-gate * Are there other races for which preemption control doesn't work? 435*0Sstevel@tonic-gate * 436*0Sstevel@tonic-gate * The i386 assembler version -also- checks to see if the bit 437*0Sstevel@tonic-gate * being cleared was actually set; if it wasn't, it rechecks 438*0Sstevel@tonic-gate * for more. This seems a bit strange, as the only code that 439*0Sstevel@tonic-gate * ever clears the bit is -this- code running with interrupts 440*0Sstevel@tonic-gate * disabled on -this- CPU. This code would probably be cheaper: 441*0Sstevel@tonic-gate * 442*0Sstevel@tonic-gate * atomic_and_32((uint32_t *)&mcpu->mcpu_softinfo.st_pending, 443*0Sstevel@tonic-gate * ~(1 << pil)); 444*0Sstevel@tonic-gate * 445*0Sstevel@tonic-gate * and t->t_preempt--/++ around set_pending() even cheaper, 446*0Sstevel@tonic-gate * but at this point, correctness is critical, so we slavishly 447*0Sstevel@tonic-gate * emulate the i386 port. 448*0Sstevel@tonic-gate */ 449*0Sstevel@tonic-gate if (atomic_btr32((uint32_t *)&mcpu->mcpu_softinfo.st_pending, pil) 450*0Sstevel@tonic-gate == 0) { 451*0Sstevel@tonic-gate st_pending = mcpu->mcpu_softinfo.st_pending; 452*0Sstevel@tonic-gate goto top; 453*0Sstevel@tonic-gate } 454*0Sstevel@tonic-gate 455*0Sstevel@tonic-gate mcpu->mcpu_pri = pil; 456*0Sstevel@tonic-gate (*setspl)(pil); 457*0Sstevel@tonic-gate 458*0Sstevel@tonic-gate /* 459*0Sstevel@tonic-gate * Get set to run interrupt thread. 460*0Sstevel@tonic-gate * There should always be an interrupt thread since we 461*0Sstevel@tonic-gate * allocate one for each level on the CPU. 462*0Sstevel@tonic-gate */ 463*0Sstevel@tonic-gate it = cpu->cpu_intr_thread; 464*0Sstevel@tonic-gate cpu->cpu_intr_thread = it->t_link; 465*0Sstevel@tonic-gate 466*0Sstevel@tonic-gate /* 467*0Sstevel@tonic-gate * Note that the code in kcpc_overflow_intr -relies- on the 468*0Sstevel@tonic-gate * ordering of events here - in particular that t->t_lwp of 469*0Sstevel@tonic-gate * the interrupt thread is set to the pinned thread *before* 470*0Sstevel@tonic-gate * curthread is changed 471*0Sstevel@tonic-gate */ 472*0Sstevel@tonic-gate t = cpu->cpu_thread; 473*0Sstevel@tonic-gate if (t->t_flag & T_INTR_THREAD) 474*0Sstevel@tonic-gate mcpu->intrstat[pil] += tsc_read() - t->t_intr_start; 475*0Sstevel@tonic-gate it->t_lwp = t->t_lwp; 476*0Sstevel@tonic-gate it->t_state = TS_ONPROC; 477*0Sstevel@tonic-gate 478*0Sstevel@tonic-gate /* 479*0Sstevel@tonic-gate * Push interrupted thread onto list from new thread. 480*0Sstevel@tonic-gate * Set the new thread as the current one. 481*0Sstevel@tonic-gate * Set interrupted thread's T_SP because if it is the idle thread, 482*0Sstevel@tonic-gate * resume() may use that stack between threads. 483*0Sstevel@tonic-gate */ 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate ASSERT(SA((uintptr_t)stackptr) == (uintptr_t)stackptr); 486*0Sstevel@tonic-gate t->t_sp = (uintptr_t)stackptr; 487*0Sstevel@tonic-gate 488*0Sstevel@tonic-gate it->t_intr = t; 489*0Sstevel@tonic-gate cpu->cpu_thread = it; 490*0Sstevel@tonic-gate 491*0Sstevel@tonic-gate /* 492*0Sstevel@tonic-gate * Set bit for this pil in CPU's interrupt active bitmask. 493*0Sstevel@tonic-gate */ 494*0Sstevel@tonic-gate ASSERT((cpu->cpu_intr_actv & (1 << pil)) == 0); 495*0Sstevel@tonic-gate cpu->cpu_intr_actv |= (1 << pil); 496*0Sstevel@tonic-gate 497*0Sstevel@tonic-gate /* 498*0Sstevel@tonic-gate * Initialize thread priority level from intr_pri 499*0Sstevel@tonic-gate */ 500*0Sstevel@tonic-gate it->t_pil = (uchar_t)pil; 501*0Sstevel@tonic-gate it->t_pri = (pri_t)pil + intr_pri; 502*0Sstevel@tonic-gate it->t_intr_start = tsc_read(); 503*0Sstevel@tonic-gate 504*0Sstevel@tonic-gate return (it->t_stk); 505*0Sstevel@tonic-gate } 506*0Sstevel@tonic-gate 507*0Sstevel@tonic-gate void 508*0Sstevel@tonic-gate dosoftint_epilog(struct cpu *cpu, uint_t oldpil) 509*0Sstevel@tonic-gate { 510*0Sstevel@tonic-gate struct machcpu *mcpu = &cpu->cpu_m; 511*0Sstevel@tonic-gate kthread_t *t, *it; 512*0Sstevel@tonic-gate uint_t pil, basespl; 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate it = cpu->cpu_thread; 515*0Sstevel@tonic-gate pil = it->t_pil; 516*0Sstevel@tonic-gate 517*0Sstevel@tonic-gate cpu->cpu_stats.sys.intr[pil - 1]++; 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gate ASSERT(cpu->cpu_intr_actv & (1 << pil)); 520*0Sstevel@tonic-gate cpu->cpu_intr_actv &= ~(1 << pil); 521*0Sstevel@tonic-gate mcpu->intrstat[pil] += tsc_read() - it->t_intr_start; 522*0Sstevel@tonic-gate 523*0Sstevel@tonic-gate /* 524*0Sstevel@tonic-gate * If there is still an interrupted thread underneath this one 525*0Sstevel@tonic-gate * then the interrupt was never blocked and the return is 526*0Sstevel@tonic-gate * fairly simple. Otherwise it isn't. 527*0Sstevel@tonic-gate */ 528*0Sstevel@tonic-gate if ((t = it->t_intr) == NULL) { 529*0Sstevel@tonic-gate /* 530*0Sstevel@tonic-gate * Put thread back on the interrupt thread list. 531*0Sstevel@tonic-gate * This was an interrupt thread, so set CPU's base SPL. 532*0Sstevel@tonic-gate */ 533*0Sstevel@tonic-gate set_base_spl(); 534*0Sstevel@tonic-gate it->t_state = TS_FREE; 535*0Sstevel@tonic-gate it->t_link = cpu->cpu_intr_thread; 536*0Sstevel@tonic-gate cpu->cpu_intr_thread = it; 537*0Sstevel@tonic-gate (void) splhigh(); 538*0Sstevel@tonic-gate swtch(); 539*0Sstevel@tonic-gate /*NOTREACHED*/ 540*0Sstevel@tonic-gate } 541*0Sstevel@tonic-gate it->t_link = cpu->cpu_intr_thread; 542*0Sstevel@tonic-gate cpu->cpu_intr_thread = it; 543*0Sstevel@tonic-gate it->t_state = TS_FREE; 544*0Sstevel@tonic-gate cpu->cpu_thread = t; 545*0Sstevel@tonic-gate if (t->t_flag & T_INTR_THREAD) 546*0Sstevel@tonic-gate t->t_intr_start = tsc_read(); 547*0Sstevel@tonic-gate basespl = cpu->cpu_base_spl; 548*0Sstevel@tonic-gate pil = MAX(oldpil, basespl); 549*0Sstevel@tonic-gate mcpu->mcpu_pri = pil; 550*0Sstevel@tonic-gate (*setspl)(pil); 551*0Sstevel@tonic-gate } 552*0Sstevel@tonic-gate 553*0Sstevel@tonic-gate /* 554*0Sstevel@tonic-gate * Make the interrupted thread 'to' be runnable. 555*0Sstevel@tonic-gate * 556*0Sstevel@tonic-gate * Since t->t_sp has already been saved, t->t_pc is all 557*0Sstevel@tonic-gate * that needs to be set in this function. 558*0Sstevel@tonic-gate * 559*0Sstevel@tonic-gate * Returns the interrupt level of the interrupt thread. 560*0Sstevel@tonic-gate */ 561*0Sstevel@tonic-gate int 562*0Sstevel@tonic-gate intr_passivate( 563*0Sstevel@tonic-gate kthread_t *it, /* interrupt thread */ 564*0Sstevel@tonic-gate kthread_t *t) /* interrupted thread */ 565*0Sstevel@tonic-gate { 566*0Sstevel@tonic-gate extern void _sys_rtt(); 567*0Sstevel@tonic-gate 568*0Sstevel@tonic-gate ASSERT(it->t_flag & T_INTR_THREAD); 569*0Sstevel@tonic-gate ASSERT(SA(t->t_sp) == t->t_sp); 570*0Sstevel@tonic-gate 571*0Sstevel@tonic-gate t->t_pc = (uintptr_t)_sys_rtt; 572*0Sstevel@tonic-gate return (it->t_pil); 573*0Sstevel@tonic-gate } 574*0Sstevel@tonic-gate 575*0Sstevel@tonic-gate #endif /* __amd64 */ 576*0Sstevel@tonic-gate 577*0Sstevel@tonic-gate /* 578*0Sstevel@tonic-gate * Allocate threads and stacks for interrupt handling. 579*0Sstevel@tonic-gate */ 580*0Sstevel@tonic-gate #define NINTR_THREADS (LOCK_LEVEL-1) /* number of interrupt threads */ 581*0Sstevel@tonic-gate 582*0Sstevel@tonic-gate void 583*0Sstevel@tonic-gate init_intr_threads(struct cpu *cp) 584*0Sstevel@tonic-gate { 585*0Sstevel@tonic-gate int i; 586*0Sstevel@tonic-gate 587*0Sstevel@tonic-gate for (i = 0; i < NINTR_THREADS; i++) 588*0Sstevel@tonic-gate thread_create_intr(cp); 589*0Sstevel@tonic-gate 590*0Sstevel@tonic-gate cp->cpu_intr_stack = (caddr_t)segkp_get(segkp, INTR_STACK_SIZE, 591*0Sstevel@tonic-gate KPD_HASREDZONE | KPD_NO_ANON | KPD_LOCKED) + 592*0Sstevel@tonic-gate INTR_STACK_SIZE - SA(MINFRAME); 593*0Sstevel@tonic-gate } 594*0Sstevel@tonic-gate 595*0Sstevel@tonic-gate /* 596*0Sstevel@tonic-gate * Create interrupt kstats for this CPU. 597*0Sstevel@tonic-gate */ 598*0Sstevel@tonic-gate void 599*0Sstevel@tonic-gate cpu_create_intrstat(cpu_t *cp) 600*0Sstevel@tonic-gate { 601*0Sstevel@tonic-gate int i; 602*0Sstevel@tonic-gate kstat_t *intr_ksp; 603*0Sstevel@tonic-gate kstat_named_t *knp; 604*0Sstevel@tonic-gate char name[KSTAT_STRLEN]; 605*0Sstevel@tonic-gate zoneid_t zoneid; 606*0Sstevel@tonic-gate 607*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 608*0Sstevel@tonic-gate 609*0Sstevel@tonic-gate if (pool_pset_enabled()) 610*0Sstevel@tonic-gate zoneid = GLOBAL_ZONEID; 611*0Sstevel@tonic-gate else 612*0Sstevel@tonic-gate zoneid = ALL_ZONES; 613*0Sstevel@tonic-gate 614*0Sstevel@tonic-gate intr_ksp = kstat_create_zone("cpu", cp->cpu_id, "intrstat", "misc", 615*0Sstevel@tonic-gate KSTAT_TYPE_NAMED, PIL_MAX * 2, NULL, zoneid); 616*0Sstevel@tonic-gate 617*0Sstevel@tonic-gate /* 618*0Sstevel@tonic-gate * Initialize each PIL's named kstat 619*0Sstevel@tonic-gate */ 620*0Sstevel@tonic-gate if (intr_ksp != NULL) { 621*0Sstevel@tonic-gate intr_ksp->ks_update = cpu_kstat_intrstat_update; 622*0Sstevel@tonic-gate knp = (kstat_named_t *)intr_ksp->ks_data; 623*0Sstevel@tonic-gate intr_ksp->ks_private = cp; 624*0Sstevel@tonic-gate for (i = 0; i < PIL_MAX; i++) { 625*0Sstevel@tonic-gate (void) snprintf(name, KSTAT_STRLEN, "level-%d-time", 626*0Sstevel@tonic-gate i + 1); 627*0Sstevel@tonic-gate kstat_named_init(&knp[i * 2], name, KSTAT_DATA_UINT64); 628*0Sstevel@tonic-gate (void) snprintf(name, KSTAT_STRLEN, "level-%d-count", 629*0Sstevel@tonic-gate i + 1); 630*0Sstevel@tonic-gate kstat_named_init(&knp[(i * 2) + 1], name, 631*0Sstevel@tonic-gate KSTAT_DATA_UINT64); 632*0Sstevel@tonic-gate } 633*0Sstevel@tonic-gate kstat_install(intr_ksp); 634*0Sstevel@tonic-gate } 635*0Sstevel@tonic-gate } 636*0Sstevel@tonic-gate 637*0Sstevel@tonic-gate /* 638*0Sstevel@tonic-gate * Delete interrupt kstats for this CPU. 639*0Sstevel@tonic-gate */ 640*0Sstevel@tonic-gate void 641*0Sstevel@tonic-gate cpu_delete_intrstat(cpu_t *cp) 642*0Sstevel@tonic-gate { 643*0Sstevel@tonic-gate kstat_delete_byname_zone("cpu", cp->cpu_id, "intrstat", ALL_ZONES); 644*0Sstevel@tonic-gate } 645*0Sstevel@tonic-gate 646*0Sstevel@tonic-gate /* 647*0Sstevel@tonic-gate * Convert interrupt statistics from CPU ticks to nanoseconds and 648*0Sstevel@tonic-gate * update kstat. 649*0Sstevel@tonic-gate */ 650*0Sstevel@tonic-gate int 651*0Sstevel@tonic-gate cpu_kstat_intrstat_update(kstat_t *ksp, int rw) 652*0Sstevel@tonic-gate { 653*0Sstevel@tonic-gate kstat_named_t *knp = ksp->ks_data; 654*0Sstevel@tonic-gate cpu_t *cpup = (cpu_t *)ksp->ks_private; 655*0Sstevel@tonic-gate int i; 656*0Sstevel@tonic-gate hrtime_t hrt; 657*0Sstevel@tonic-gate 658*0Sstevel@tonic-gate if (rw == KSTAT_WRITE) 659*0Sstevel@tonic-gate return (EACCES); 660*0Sstevel@tonic-gate 661*0Sstevel@tonic-gate for (i = 0; i < PIL_MAX; i++) { 662*0Sstevel@tonic-gate hrt = (hrtime_t)cpup->cpu_m.intrstat[i + 1]; 663*0Sstevel@tonic-gate tsc_scalehrtime(&hrt); 664*0Sstevel@tonic-gate knp[i * 2].value.ui64 = (uint64_t)hrt; 665*0Sstevel@tonic-gate knp[(i * 2) + 1].value.ui64 = cpup->cpu_stats.sys.intr[i]; 666*0Sstevel@tonic-gate } 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate return (0); 669*0Sstevel@tonic-gate } 670*0Sstevel@tonic-gate 671*0Sstevel@tonic-gate /* 672*0Sstevel@tonic-gate * An interrupt thread is ending a time slice, so compute the interval it 673*0Sstevel@tonic-gate * ran for and update the statistic for its PIL. 674*0Sstevel@tonic-gate */ 675*0Sstevel@tonic-gate void 676*0Sstevel@tonic-gate cpu_intr_swtch_enter(kthread_id_t t) 677*0Sstevel@tonic-gate { 678*0Sstevel@tonic-gate uint64_t interval; 679*0Sstevel@tonic-gate uint64_t start; 680*0Sstevel@tonic-gate 681*0Sstevel@tonic-gate ASSERT((t->t_flag & T_INTR_THREAD) != 0); 682*0Sstevel@tonic-gate ASSERT(t->t_pil > 0 && t->t_pil <= LOCK_LEVEL); 683*0Sstevel@tonic-gate 684*0Sstevel@tonic-gate /* 685*0Sstevel@tonic-gate * We could be here with a zero timestamp. This could happen if: 686*0Sstevel@tonic-gate * an interrupt thread which no longer has a pinned thread underneath 687*0Sstevel@tonic-gate * it (i.e. it blocked at some point in its past) has finished running 688*0Sstevel@tonic-gate * its handler. intr_thread() updated the interrupt statistic for its 689*0Sstevel@tonic-gate * PIL and zeroed its timestamp. Since there was no pinned thread to 690*0Sstevel@tonic-gate * return to, swtch() gets called and we end up here. 691*0Sstevel@tonic-gate */ 692*0Sstevel@tonic-gate if (t->t_intr_start) { 693*0Sstevel@tonic-gate do { 694*0Sstevel@tonic-gate start = t->t_intr_start; 695*0Sstevel@tonic-gate interval = tsc_read() - start; 696*0Sstevel@tonic-gate } while (cas64(&t->t_intr_start, start, 0) != start); 697*0Sstevel@tonic-gate CPU->cpu_m.intrstat[t->t_pil] += interval; 698*0Sstevel@tonic-gate } else 699*0Sstevel@tonic-gate ASSERT(t->t_intr == NULL); 700*0Sstevel@tonic-gate } 701*0Sstevel@tonic-gate 702*0Sstevel@tonic-gate /* 703*0Sstevel@tonic-gate * An interrupt thread is returning from swtch(). Place a starting timestamp 704*0Sstevel@tonic-gate * in its thread structure. 705*0Sstevel@tonic-gate */ 706*0Sstevel@tonic-gate void 707*0Sstevel@tonic-gate cpu_intr_swtch_exit(kthread_id_t t) 708*0Sstevel@tonic-gate { 709*0Sstevel@tonic-gate uint64_t ts; 710*0Sstevel@tonic-gate 711*0Sstevel@tonic-gate ASSERT((t->t_flag & T_INTR_THREAD) != 0); 712*0Sstevel@tonic-gate ASSERT(t->t_pil > 0 && t->t_pil <= LOCK_LEVEL); 713*0Sstevel@tonic-gate 714*0Sstevel@tonic-gate do { 715*0Sstevel@tonic-gate ts = t->t_intr_start; 716*0Sstevel@tonic-gate } while (cas64(&t->t_intr_start, ts, tsc_read()) != ts); 717*0Sstevel@tonic-gate } 718