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 /* 30*0Sstevel@tonic-gate * Autovectored Interrupt Configuration and Deconfiguration 31*0Sstevel@tonic-gate */ 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include <sys/param.h> 34*0Sstevel@tonic-gate #include <sys/cmn_err.h> 35*0Sstevel@tonic-gate #include <sys/trap.h> 36*0Sstevel@tonic-gate #include <sys/t_lock.h> 37*0Sstevel@tonic-gate #include <sys/avintr.h> 38*0Sstevel@tonic-gate #include <sys/kmem.h> 39*0Sstevel@tonic-gate #include <sys/machlock.h> 40*0Sstevel@tonic-gate #include <sys/systm.h> 41*0Sstevel@tonic-gate #include <sys/machsystm.h> 42*0Sstevel@tonic-gate #include <sys/sunddi.h> 43*0Sstevel@tonic-gate #include <sys/x_call.h> 44*0Sstevel@tonic-gate #include <sys/cpuvar.h> 45*0Sstevel@tonic-gate #include <sys/atomic.h> 46*0Sstevel@tonic-gate #include <sys/smp_impldefs.h> 47*0Sstevel@tonic-gate #include <sys/sdt.h> 48*0Sstevel@tonic-gate #include <sys/stack.h> 49*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 50*0Sstevel@tonic-gate 51*0Sstevel@tonic-gate static int insert_av(void *intr_id, struct av_head *vectp, avfunc f, 52*0Sstevel@tonic-gate caddr_t arg1, caddr_t arg2, int pri_level, dev_info_t *dip); 53*0Sstevel@tonic-gate static void remove_av(void *intr_id, struct av_head *vectp, avfunc f, 54*0Sstevel@tonic-gate int pri_level, int vect); 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate /* 57*0Sstevel@tonic-gate * Arrange for a driver to be called when a particular 58*0Sstevel@tonic-gate * auto-vectored interrupt occurs. 59*0Sstevel@tonic-gate * NOTE: if a device can generate interrupts on more than 60*0Sstevel@tonic-gate * one level, or if a driver services devices that interrupt 61*0Sstevel@tonic-gate * on more than one level, then the driver should install 62*0Sstevel@tonic-gate * itself on each of those levels. 63*0Sstevel@tonic-gate */ 64*0Sstevel@tonic-gate static char badsoft[] = 65*0Sstevel@tonic-gate "add_avintr: bad soft interrupt level %d for driver '%s'\n"; 66*0Sstevel@tonic-gate static char multilevel[] = 67*0Sstevel@tonic-gate "!IRQ%d is being shared by drivers with different interrupt levels.\n" 68*0Sstevel@tonic-gate "This may result in reduced system performance."; 69*0Sstevel@tonic-gate static char multilevel2[] = 70*0Sstevel@tonic-gate "Cannot register interrupt for '%s' device at IPL %d because it\n" 71*0Sstevel@tonic-gate "conflicts with another device using the same vector %d with an IPL\n" 72*0Sstevel@tonic-gate "of %d. Reconfigure the conflicting devices to use different vectors."; 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate #define MAX_VECT 256 75*0Sstevel@tonic-gate struct autovec *nmivect = NULL; 76*0Sstevel@tonic-gate struct av_head autovect[MAX_VECT]; 77*0Sstevel@tonic-gate struct av_head softvect[LOCK_LEVEL + 1]; 78*0Sstevel@tonic-gate kmutex_t av_lock; 79*0Sstevel@tonic-gate ddi_softint_hdl_impl_t softlevel1_hdl = 80*0Sstevel@tonic-gate {0, NULL, NULL, 0, 0, NULL, NULL, NULL}; 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate void 83*0Sstevel@tonic-gate set_pending(int pri) 84*0Sstevel@tonic-gate { 85*0Sstevel@tonic-gate atomic_or_32((uint32_t *)&CPU->cpu_softinfo.st_pending, 1 << pri); 86*0Sstevel@tonic-gate } 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate /* 89*0Sstevel@tonic-gate * register nmi interrupt routine. The first arg is used only to order 90*0Sstevel@tonic-gate * various nmi interrupt service routines in the chain. Higher lvls will 91*0Sstevel@tonic-gate * be called first 92*0Sstevel@tonic-gate */ 93*0Sstevel@tonic-gate int 94*0Sstevel@tonic-gate add_nmintr(int lvl, avfunc nmintr, char *name, caddr_t arg) 95*0Sstevel@tonic-gate { 96*0Sstevel@tonic-gate struct autovec *mem; 97*0Sstevel@tonic-gate struct autovec *p, *prev = NULL; 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate if (nmintr == NULL) { 100*0Sstevel@tonic-gate printf("Attempt to add null vect for %s on nmi\n", name); 101*0Sstevel@tonic-gate return (0); 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate } 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate mem = kmem_zalloc(sizeof (struct autovec), KM_SLEEP); 106*0Sstevel@tonic-gate mem->av_vector = nmintr; 107*0Sstevel@tonic-gate mem->av_intarg1 = arg; 108*0Sstevel@tonic-gate mem->av_intarg2 = NULL; 109*0Sstevel@tonic-gate mem->av_intr_id = NULL; 110*0Sstevel@tonic-gate mem->av_prilevel = lvl; 111*0Sstevel@tonic-gate mem->av_link = NULL; 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate mutex_enter(&av_lock); 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate if (!nmivect) { 116*0Sstevel@tonic-gate nmivect = mem; 117*0Sstevel@tonic-gate mutex_exit(&av_lock); 118*0Sstevel@tonic-gate return (1); 119*0Sstevel@tonic-gate } 120*0Sstevel@tonic-gate /* find where it goes in list */ 121*0Sstevel@tonic-gate for (p = nmivect; p != NULL; p = p->av_link) { 122*0Sstevel@tonic-gate if (p->av_vector == nmintr && p->av_intarg1 == arg) { 123*0Sstevel@tonic-gate /* 124*0Sstevel@tonic-gate * already in list 125*0Sstevel@tonic-gate * So? Somebody added the same interrupt twice. 126*0Sstevel@tonic-gate */ 127*0Sstevel@tonic-gate cmn_err(CE_WARN, "Driver already registered '%s'", 128*0Sstevel@tonic-gate name); 129*0Sstevel@tonic-gate kmem_free(mem, sizeof (struct autovec)); 130*0Sstevel@tonic-gate mutex_exit(&av_lock); 131*0Sstevel@tonic-gate return (0); 132*0Sstevel@tonic-gate } 133*0Sstevel@tonic-gate if (p->av_prilevel < lvl) { 134*0Sstevel@tonic-gate if (p == nmivect) { /* it's at head of list */ 135*0Sstevel@tonic-gate mem->av_link = p; 136*0Sstevel@tonic-gate nmivect = mem; 137*0Sstevel@tonic-gate } else { 138*0Sstevel@tonic-gate mem->av_link = p; 139*0Sstevel@tonic-gate prev->av_link = mem; 140*0Sstevel@tonic-gate } 141*0Sstevel@tonic-gate mutex_exit(&av_lock); 142*0Sstevel@tonic-gate return (1); 143*0Sstevel@tonic-gate } 144*0Sstevel@tonic-gate prev = p; 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gate } 147*0Sstevel@tonic-gate /* didn't find it, add it to the end */ 148*0Sstevel@tonic-gate prev->av_link = mem; 149*0Sstevel@tonic-gate mutex_exit(&av_lock); 150*0Sstevel@tonic-gate return (1); 151*0Sstevel@tonic-gate 152*0Sstevel@tonic-gate } 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gate /* 155*0Sstevel@tonic-gate * register a hardware interrupt handler. 156*0Sstevel@tonic-gate */ 157*0Sstevel@tonic-gate int 158*0Sstevel@tonic-gate add_avintr(void *intr_id, int lvl, avfunc xxintr, char *name, int vect, 159*0Sstevel@tonic-gate caddr_t arg1, caddr_t arg2, dev_info_t *dip) 160*0Sstevel@tonic-gate { 161*0Sstevel@tonic-gate struct av_head *vecp = (struct av_head *)0; 162*0Sstevel@tonic-gate avfunc f; 163*0Sstevel@tonic-gate int s, vectindex; /* save old spl value */ 164*0Sstevel@tonic-gate ushort_t hi_pri; 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate if ((f = xxintr) == NULL) { 167*0Sstevel@tonic-gate printf("Attempt to add null vect for %s on vector %d\n", 168*0Sstevel@tonic-gate name, vect); 169*0Sstevel@tonic-gate return (0); 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate } 172*0Sstevel@tonic-gate vectindex = vect % MAX_VECT; 173*0Sstevel@tonic-gate 174*0Sstevel@tonic-gate vecp = &autovect[vectindex]; 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate /* 177*0Sstevel@tonic-gate * "hi_pri == 0" implies all entries on list are "unused", 178*0Sstevel@tonic-gate * which means that it's OK to just insert this one. 179*0Sstevel@tonic-gate */ 180*0Sstevel@tonic-gate hi_pri = vecp->avh_hi_pri; 181*0Sstevel@tonic-gate if (vecp->avh_link && (hi_pri != 0)) { 182*0Sstevel@tonic-gate if (((hi_pri > LOCK_LEVEL) && (lvl < LOCK_LEVEL)) || 183*0Sstevel@tonic-gate ((hi_pri < LOCK_LEVEL) && (lvl > LOCK_LEVEL))) { 184*0Sstevel@tonic-gate cmn_err(CE_WARN, multilevel2, name, lvl, vect, 185*0Sstevel@tonic-gate hi_pri); 186*0Sstevel@tonic-gate return (0); 187*0Sstevel@tonic-gate } 188*0Sstevel@tonic-gate if ((vecp->avh_lo_pri != lvl) || (hi_pri != lvl)) 189*0Sstevel@tonic-gate cmn_err(CE_NOTE, multilevel, vect); 190*0Sstevel@tonic-gate } 191*0Sstevel@tonic-gate 192*0Sstevel@tonic-gate if (!insert_av(intr_id, vecp, f, arg1, arg2, lvl, dip)) 193*0Sstevel@tonic-gate return (0); 194*0Sstevel@tonic-gate s = splhi(); 195*0Sstevel@tonic-gate /* 196*0Sstevel@tonic-gate * do what ever machine specific things are necessary 197*0Sstevel@tonic-gate * to set priority level (e.g. set picmasks) 198*0Sstevel@tonic-gate */ 199*0Sstevel@tonic-gate mutex_enter(&av_lock); 200*0Sstevel@tonic-gate (*addspl)(vect, lvl, vecp->avh_lo_pri, vecp->avh_hi_pri); 201*0Sstevel@tonic-gate mutex_exit(&av_lock); 202*0Sstevel@tonic-gate splx(s); 203*0Sstevel@tonic-gate return (1); 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate } 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate void 208*0Sstevel@tonic-gate update_avsoftintr_args(void *intr_id, int lvl, caddr_t arg2) 209*0Sstevel@tonic-gate { 210*0Sstevel@tonic-gate struct autovec *p; 211*0Sstevel@tonic-gate struct autovec *target = NULL; 212*0Sstevel@tonic-gate struct av_head *vectp = (struct av_head *)&softvect[lvl]; 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate for (p = vectp->avh_link; p && p->av_vector; p = p->av_link) { 215*0Sstevel@tonic-gate if (p->av_intr_id == intr_id) { 216*0Sstevel@tonic-gate target = p; 217*0Sstevel@tonic-gate break; 218*0Sstevel@tonic-gate } 219*0Sstevel@tonic-gate } 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate if (target == NULL) 222*0Sstevel@tonic-gate return; 223*0Sstevel@tonic-gate target->av_intarg2 = arg2; 224*0Sstevel@tonic-gate } 225*0Sstevel@tonic-gate 226*0Sstevel@tonic-gate /* 227*0Sstevel@tonic-gate * Register a software interrupt handler 228*0Sstevel@tonic-gate */ 229*0Sstevel@tonic-gate int 230*0Sstevel@tonic-gate add_avsoftintr(void *intr_id, int lvl, avfunc xxintr, char *name, 231*0Sstevel@tonic-gate caddr_t arg1, caddr_t arg2) 232*0Sstevel@tonic-gate { 233*0Sstevel@tonic-gate int slvl; 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate if ((slvl = slvltovect(lvl)) != -1) 236*0Sstevel@tonic-gate return (add_avintr(intr_id, lvl, xxintr, 237*0Sstevel@tonic-gate name, slvl, arg1, arg2, NULL)); 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gate if (intr_id == NULL) { 240*0Sstevel@tonic-gate printf("Attempt to add null intr_id for %s on level %d\n", 241*0Sstevel@tonic-gate name, lvl); 242*0Sstevel@tonic-gate return (0); 243*0Sstevel@tonic-gate } 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate if (xxintr == NULL) { 246*0Sstevel@tonic-gate printf("Attempt to add null handler for %s on level %d\n", 247*0Sstevel@tonic-gate name, lvl); 248*0Sstevel@tonic-gate return (0); 249*0Sstevel@tonic-gate } 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate if (lvl <= 0 || lvl > LOCK_LEVEL) { 252*0Sstevel@tonic-gate printf(badsoft, lvl, name); 253*0Sstevel@tonic-gate return (0); 254*0Sstevel@tonic-gate } 255*0Sstevel@tonic-gate if (!insert_av(intr_id, &softvect[lvl], xxintr, arg1, arg2, 256*0Sstevel@tonic-gate lvl, NULL)) { 257*0Sstevel@tonic-gate return (0); 258*0Sstevel@tonic-gate } 259*0Sstevel@tonic-gate return (1); 260*0Sstevel@tonic-gate } 261*0Sstevel@tonic-gate 262*0Sstevel@tonic-gate /* insert an interrupt vector into chain */ 263*0Sstevel@tonic-gate static int 264*0Sstevel@tonic-gate insert_av(void *intr_id, struct av_head *vectp, avfunc f, caddr_t arg1, 265*0Sstevel@tonic-gate caddr_t arg2, int pri_level, dev_info_t *dip) 266*0Sstevel@tonic-gate { 267*0Sstevel@tonic-gate /* 268*0Sstevel@tonic-gate * Protect rewrites of the list 269*0Sstevel@tonic-gate */ 270*0Sstevel@tonic-gate struct autovec *p, *mem; 271*0Sstevel@tonic-gate 272*0Sstevel@tonic-gate mem = kmem_zalloc(sizeof (struct autovec), KM_SLEEP); 273*0Sstevel@tonic-gate mem->av_vector = f; 274*0Sstevel@tonic-gate mem->av_intarg1 = arg1; 275*0Sstevel@tonic-gate mem->av_intarg2 = arg2; 276*0Sstevel@tonic-gate mem->av_intr_id = intr_id; 277*0Sstevel@tonic-gate mem->av_prilevel = pri_level; 278*0Sstevel@tonic-gate mem->av_dip = dip; 279*0Sstevel@tonic-gate mem->av_link = NULL; 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate mutex_enter(&av_lock); 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate if (vectp->avh_link == NULL) { /* Nothing on list - put it at head */ 284*0Sstevel@tonic-gate vectp->avh_link = mem; 285*0Sstevel@tonic-gate vectp->avh_hi_pri = vectp->avh_lo_pri = (ushort_t)pri_level; 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate mutex_exit(&av_lock); 288*0Sstevel@tonic-gate return (1); 289*0Sstevel@tonic-gate } 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate /* find where it goes in list */ 292*0Sstevel@tonic-gate for (p = vectp->avh_link; p != NULL; p = p->av_link) { 293*0Sstevel@tonic-gate if (p->av_vector == NULL) { /* freed struct available */ 294*0Sstevel@tonic-gate kmem_free(mem, sizeof (struct autovec)); 295*0Sstevel@tonic-gate p->av_intarg1 = arg1; 296*0Sstevel@tonic-gate p->av_intarg2 = arg2; 297*0Sstevel@tonic-gate p->av_intr_id = intr_id; 298*0Sstevel@tonic-gate p->av_prilevel = pri_level; 299*0Sstevel@tonic-gate if (pri_level > (int)vectp->avh_hi_pri) { 300*0Sstevel@tonic-gate vectp->avh_hi_pri = (ushort_t)pri_level; 301*0Sstevel@tonic-gate } 302*0Sstevel@tonic-gate if (pri_level < (int)vectp->avh_lo_pri) { 303*0Sstevel@tonic-gate vectp->avh_lo_pri = (ushort_t)pri_level; 304*0Sstevel@tonic-gate } 305*0Sstevel@tonic-gate p->av_vector = f; 306*0Sstevel@tonic-gate mutex_exit(&av_lock); 307*0Sstevel@tonic-gate return (1); 308*0Sstevel@tonic-gate } 309*0Sstevel@tonic-gate } 310*0Sstevel@tonic-gate /* insert new intpt at beginning of chain */ 311*0Sstevel@tonic-gate mem->av_link = vectp->avh_link; 312*0Sstevel@tonic-gate vectp->avh_link = mem; 313*0Sstevel@tonic-gate if (pri_level > (int)vectp->avh_hi_pri) { 314*0Sstevel@tonic-gate vectp->avh_hi_pri = (ushort_t)pri_level; 315*0Sstevel@tonic-gate } 316*0Sstevel@tonic-gate if (pri_level < (int)vectp->avh_lo_pri) { 317*0Sstevel@tonic-gate vectp->avh_lo_pri = (ushort_t)pri_level; 318*0Sstevel@tonic-gate } 319*0Sstevel@tonic-gate mutex_exit(&av_lock); 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate return (1); 322*0Sstevel@tonic-gate } 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate /* 325*0Sstevel@tonic-gate * Remove a driver from the autovector list. 326*0Sstevel@tonic-gate */ 327*0Sstevel@tonic-gate int 328*0Sstevel@tonic-gate rem_avsoftintr(void *intr_id, int lvl, avfunc xxintr) 329*0Sstevel@tonic-gate { 330*0Sstevel@tonic-gate struct av_head *vecp = (struct av_head *)0; 331*0Sstevel@tonic-gate int slvl; 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate if (xxintr == NULL) 334*0Sstevel@tonic-gate return (0); 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate if ((slvl = slvltovect(lvl)) != -1) { 337*0Sstevel@tonic-gate rem_avintr(intr_id, lvl, xxintr, slvl); 338*0Sstevel@tonic-gate return (1); 339*0Sstevel@tonic-gate } 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate if (lvl <= 0 && lvl >= LOCK_LEVEL) { 342*0Sstevel@tonic-gate return (0); 343*0Sstevel@tonic-gate } 344*0Sstevel@tonic-gate vecp = &softvect[lvl]; 345*0Sstevel@tonic-gate remove_av(intr_id, vecp, xxintr, lvl, 0); 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate return (1); 348*0Sstevel@tonic-gate } 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate void 351*0Sstevel@tonic-gate rem_avintr(void *intr_id, int lvl, avfunc xxintr, int vect) 352*0Sstevel@tonic-gate { 353*0Sstevel@tonic-gate struct av_head *vecp = (struct av_head *)0; 354*0Sstevel@tonic-gate avfunc f; 355*0Sstevel@tonic-gate int s, vectindex; /* save old spl value */ 356*0Sstevel@tonic-gate 357*0Sstevel@tonic-gate if ((f = xxintr) == NULL) 358*0Sstevel@tonic-gate return; 359*0Sstevel@tonic-gate 360*0Sstevel@tonic-gate vectindex = vect % MAX_VECT; 361*0Sstevel@tonic-gate vecp = &autovect[vectindex]; 362*0Sstevel@tonic-gate remove_av(intr_id, vecp, f, lvl, vect); 363*0Sstevel@tonic-gate s = splhi(); 364*0Sstevel@tonic-gate mutex_enter(&av_lock); 365*0Sstevel@tonic-gate (*delspl)(vect, lvl, vecp->avh_lo_pri, vecp->avh_hi_pri); 366*0Sstevel@tonic-gate mutex_exit(&av_lock); 367*0Sstevel@tonic-gate splx(s); 368*0Sstevel@tonic-gate } 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate 371*0Sstevel@tonic-gate /* 372*0Sstevel@tonic-gate * After having made a change to an autovector list, wait until we have 373*0Sstevel@tonic-gate * seen each cpu not executing an interrupt at that level--so we know our 374*0Sstevel@tonic-gate * change has taken effect completely (no old state in registers, etc). 375*0Sstevel@tonic-gate */ 376*0Sstevel@tonic-gate void 377*0Sstevel@tonic-gate wait_till_seen(int ipl) 378*0Sstevel@tonic-gate { 379*0Sstevel@tonic-gate int cpu_in_chain, cix; 380*0Sstevel@tonic-gate struct cpu *cpup; 381*0Sstevel@tonic-gate cpuset_t cpus_to_check; 382*0Sstevel@tonic-gate 383*0Sstevel@tonic-gate CPUSET_ALL(cpus_to_check); 384*0Sstevel@tonic-gate do { 385*0Sstevel@tonic-gate cpu_in_chain = 0; 386*0Sstevel@tonic-gate for (cix = 0; cix < NCPU; cix++) { 387*0Sstevel@tonic-gate cpup = cpu[cix]; 388*0Sstevel@tonic-gate if (cpup != NULL && CPU_IN_SET(cpus_to_check, cix)) { 389*0Sstevel@tonic-gate if (intr_active(cpup, ipl)) { 390*0Sstevel@tonic-gate cpu_in_chain = 1; 391*0Sstevel@tonic-gate } else { 392*0Sstevel@tonic-gate CPUSET_DEL(cpus_to_check, cix); 393*0Sstevel@tonic-gate } 394*0Sstevel@tonic-gate } 395*0Sstevel@tonic-gate } 396*0Sstevel@tonic-gate } while (cpu_in_chain); 397*0Sstevel@tonic-gate } 398*0Sstevel@tonic-gate 399*0Sstevel@tonic-gate /* remove an interrupt vector from the chain */ 400*0Sstevel@tonic-gate static void 401*0Sstevel@tonic-gate remove_av(void *intr_id, struct av_head *vectp, avfunc f, int pri_level, 402*0Sstevel@tonic-gate int vect) 403*0Sstevel@tonic-gate { 404*0Sstevel@tonic-gate struct autovec *endp, *p, *target; 405*0Sstevel@tonic-gate int lo_pri, hi_pri; 406*0Sstevel@tonic-gate int ipl; 407*0Sstevel@tonic-gate /* 408*0Sstevel@tonic-gate * Protect rewrites of the list 409*0Sstevel@tonic-gate */ 410*0Sstevel@tonic-gate target = NULL; 411*0Sstevel@tonic-gate 412*0Sstevel@tonic-gate mutex_enter(&av_lock); 413*0Sstevel@tonic-gate ipl = pri_level; 414*0Sstevel@tonic-gate lo_pri = MAXIPL; 415*0Sstevel@tonic-gate hi_pri = 0; 416*0Sstevel@tonic-gate for (endp = p = vectp->avh_link; p && p->av_vector; p = p->av_link) { 417*0Sstevel@tonic-gate endp = p; 418*0Sstevel@tonic-gate if ((p->av_vector == f) && (p->av_intr_id == intr_id)) { 419*0Sstevel@tonic-gate /* found the handler */ 420*0Sstevel@tonic-gate target = p; 421*0Sstevel@tonic-gate continue; 422*0Sstevel@tonic-gate } 423*0Sstevel@tonic-gate if (p->av_prilevel > hi_pri) 424*0Sstevel@tonic-gate hi_pri = p->av_prilevel; 425*0Sstevel@tonic-gate if (p->av_prilevel < lo_pri) 426*0Sstevel@tonic-gate lo_pri = p->av_prilevel; 427*0Sstevel@tonic-gate } 428*0Sstevel@tonic-gate if (ipl < hi_pri) 429*0Sstevel@tonic-gate ipl = hi_pri; 430*0Sstevel@tonic-gate if (target == NULL) { /* not found */ 431*0Sstevel@tonic-gate printf("Couldn't remove function %p at %d, %d\n", 432*0Sstevel@tonic-gate (void *)f, vect, pri_level); 433*0Sstevel@tonic-gate mutex_exit(&av_lock); 434*0Sstevel@tonic-gate return; 435*0Sstevel@tonic-gate } 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gate target->av_vector = NULL; 438*0Sstevel@tonic-gate wait_till_seen(ipl); 439*0Sstevel@tonic-gate if (endp != target) { /* vector to be removed is not last in chain */ 440*0Sstevel@tonic-gate target->av_intarg1 = endp->av_intarg1; 441*0Sstevel@tonic-gate target->av_intarg2 = endp->av_intarg2; 442*0Sstevel@tonic-gate target->av_prilevel = endp->av_prilevel; 443*0Sstevel@tonic-gate target->av_intr_id = endp->av_intr_id; 444*0Sstevel@tonic-gate target->av_vector = endp->av_vector; 445*0Sstevel@tonic-gate /* 446*0Sstevel@tonic-gate * We have a hole here where the routine corresponding to 447*0Sstevel@tonic-gate * endp may not get called. Do a wait_till_seen to take care 448*0Sstevel@tonic-gate * of this. 449*0Sstevel@tonic-gate */ 450*0Sstevel@tonic-gate wait_till_seen(ipl); 451*0Sstevel@tonic-gate endp->av_vector = NULL; 452*0Sstevel@tonic-gate } 453*0Sstevel@tonic-gate 454*0Sstevel@tonic-gate if (lo_pri > hi_pri) { /* the chain is now empty */ 455*0Sstevel@tonic-gate /* Leave the unused entries here for probable future use */ 456*0Sstevel@tonic-gate vectp->avh_lo_pri = MAXIPL; 457*0Sstevel@tonic-gate vectp->avh_hi_pri = 0; 458*0Sstevel@tonic-gate } else { 459*0Sstevel@tonic-gate if ((int)vectp->avh_lo_pri < lo_pri) 460*0Sstevel@tonic-gate vectp->avh_lo_pri = (ushort_t)lo_pri; 461*0Sstevel@tonic-gate if ((int)vectp->avh_hi_pri > hi_pri) 462*0Sstevel@tonic-gate vectp->avh_hi_pri = (ushort_t)hi_pri; 463*0Sstevel@tonic-gate } 464*0Sstevel@tonic-gate mutex_exit(&av_lock); 465*0Sstevel@tonic-gate wait_till_seen(ipl); 466*0Sstevel@tonic-gate } 467*0Sstevel@tonic-gate 468*0Sstevel@tonic-gate /* 469*0Sstevel@tonic-gate * Trigger a soft interrupt. 470*0Sstevel@tonic-gate */ 471*0Sstevel@tonic-gate void 472*0Sstevel@tonic-gate siron(void) 473*0Sstevel@tonic-gate { 474*0Sstevel@tonic-gate softlevel1_hdl.ih_pending = 1; 475*0Sstevel@tonic-gate (*setsoftint)(1); 476*0Sstevel@tonic-gate } 477*0Sstevel@tonic-gate 478*0Sstevel@tonic-gate /* 479*0Sstevel@tonic-gate * Walk the autovector table for this vector, invoking each 480*0Sstevel@tonic-gate * interrupt handler as we go. 481*0Sstevel@tonic-gate */ 482*0Sstevel@tonic-gate void 483*0Sstevel@tonic-gate av_dispatch_autovect(uint_t vec) 484*0Sstevel@tonic-gate { 485*0Sstevel@tonic-gate struct autovec *av; 486*0Sstevel@tonic-gate 487*0Sstevel@tonic-gate ASSERT_STACK_ALIGNED(); 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gate while ((av = autovect[vec].avh_link) != NULL) { 490*0Sstevel@tonic-gate uint_t numcalled = 0; 491*0Sstevel@tonic-gate uint_t claimed = 0; 492*0Sstevel@tonic-gate 493*0Sstevel@tonic-gate for (; av; av = av->av_link) { 494*0Sstevel@tonic-gate uint_t r; 495*0Sstevel@tonic-gate uint_t (*intr)() = av->av_vector; 496*0Sstevel@tonic-gate caddr_t arg1 = av->av_intarg1; 497*0Sstevel@tonic-gate caddr_t arg2 = av->av_intarg2; 498*0Sstevel@tonic-gate dev_info_t *dip = av->av_dip; 499*0Sstevel@tonic-gate 500*0Sstevel@tonic-gate numcalled++; 501*0Sstevel@tonic-gate if (intr == NULL) 502*0Sstevel@tonic-gate break; 503*0Sstevel@tonic-gate 504*0Sstevel@tonic-gate DTRACE_PROBE4(interrupt__start, dev_info_t *, dip, 505*0Sstevel@tonic-gate void *, intr, caddr_t, arg1, caddr_t, arg2); 506*0Sstevel@tonic-gate r = (*intr)(arg1, arg2); 507*0Sstevel@tonic-gate DTRACE_PROBE4(interrupt__complete, dev_info_t *, dip, 508*0Sstevel@tonic-gate void *, intr, caddr_t, arg1, uint_t, r); 509*0Sstevel@tonic-gate claimed |= r; 510*0Sstevel@tonic-gate } 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate /* 513*0Sstevel@tonic-gate * If there's only one interrupt handler in the chain, 514*0Sstevel@tonic-gate * or if no-one claimed the interrupt at all give up now. 515*0Sstevel@tonic-gate */ 516*0Sstevel@tonic-gate if (numcalled == 1 || claimed == 0) 517*0Sstevel@tonic-gate break; 518*0Sstevel@tonic-gate } 519*0Sstevel@tonic-gate } 520*0Sstevel@tonic-gate 521*0Sstevel@tonic-gate /* 522*0Sstevel@tonic-gate * Call every soft interrupt handler we can find at this level once. 523*0Sstevel@tonic-gate */ 524*0Sstevel@tonic-gate void 525*0Sstevel@tonic-gate av_dispatch_softvect(uint_t pil) 526*0Sstevel@tonic-gate { 527*0Sstevel@tonic-gate struct autovec *av; 528*0Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp; 529*0Sstevel@tonic-gate uint_t (*intr)(); 530*0Sstevel@tonic-gate caddr_t arg1; 531*0Sstevel@tonic-gate caddr_t arg2; 532*0Sstevel@tonic-gate 533*0Sstevel@tonic-gate ASSERT_STACK_ALIGNED(); 534*0Sstevel@tonic-gate ASSERT(pil >= 0 && pil <= PIL_MAX); 535*0Sstevel@tonic-gate 536*0Sstevel@tonic-gate for (av = softvect[pil].avh_link; av; av = av->av_link) { 537*0Sstevel@tonic-gate if ((intr = av->av_vector) == NULL) 538*0Sstevel@tonic-gate break; 539*0Sstevel@tonic-gate arg1 = av->av_intarg1; 540*0Sstevel@tonic-gate arg2 = av->av_intarg2; 541*0Sstevel@tonic-gate 542*0Sstevel@tonic-gate hdlp = (ddi_softint_hdl_impl_t *)av->av_intr_id; 543*0Sstevel@tonic-gate ASSERT(hdlp); 544*0Sstevel@tonic-gate 545*0Sstevel@tonic-gate if (hdlp->ih_pending) { 546*0Sstevel@tonic-gate hdlp->ih_pending = 0; 547*0Sstevel@tonic-gate (void) (*intr)(arg1, arg2); 548*0Sstevel@tonic-gate } 549*0Sstevel@tonic-gate } 550*0Sstevel@tonic-gate } 551*0Sstevel@tonic-gate 552*0Sstevel@tonic-gate struct regs; 553*0Sstevel@tonic-gate 554*0Sstevel@tonic-gate /* 555*0Sstevel@tonic-gate * Call every NMI handler we know of once. 556*0Sstevel@tonic-gate */ 557*0Sstevel@tonic-gate void 558*0Sstevel@tonic-gate av_dispatch_nmivect(struct regs *rp) 559*0Sstevel@tonic-gate { 560*0Sstevel@tonic-gate struct autovec *av; 561*0Sstevel@tonic-gate 562*0Sstevel@tonic-gate ASSERT_STACK_ALIGNED(); 563*0Sstevel@tonic-gate 564*0Sstevel@tonic-gate for (av = nmivect; av; av = av->av_link) 565*0Sstevel@tonic-gate (void) (av->av_vector)(av->av_intarg1, rp); 566*0Sstevel@tonic-gate } 567