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