1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 3446 mrj * Common Development and Distribution License (the "License"). 6 3446 mrj * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 9489 Joe * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel /* 27 0 stevel * Autovectored Interrupt Configuration and Deconfiguration 28 0 stevel */ 29 0 stevel 30 0 stevel #include <sys/param.h> 31 0 stevel #include <sys/cmn_err.h> 32 0 stevel #include <sys/trap.h> 33 0 stevel #include <sys/t_lock.h> 34 0 stevel #include <sys/avintr.h> 35 0 stevel #include <sys/kmem.h> 36 0 stevel #include <sys/machlock.h> 37 0 stevel #include <sys/systm.h> 38 0 stevel #include <sys/machsystm.h> 39 0 stevel #include <sys/sunddi.h> 40 0 stevel #include <sys/x_call.h> 41 0 stevel #include <sys/cpuvar.h> 42 0 stevel #include <sys/atomic.h> 43 0 stevel #include <sys/smp_impldefs.h> 44 0 stevel #include <sys/sdt.h> 45 0 stevel #include <sys/stack.h> 46 0 stevel #include <sys/ddi_impldefs.h> 47 5084 johnlev #ifdef __xpv 48 5084 johnlev #include <sys/evtchn_impl.h> 49 5084 johnlev #endif 50 0 stevel 51 999 lq150181 typedef struct av_softinfo { 52 999 lq150181 cpuset_t av_pending; /* pending bitmasks */ 53 999 lq150181 } av_softinfo_t; 54 999 lq150181 55 999 lq150181 static void insert_av(void *intr_id, struct av_head *vectp, avfunc f, 56 916 schwartz caddr_t arg1, caddr_t arg2, uint64_t *ticksp, int pri_level, 57 916 schwartz dev_info_t *dip); 58 0 stevel static void remove_av(void *intr_id, struct av_head *vectp, avfunc f, 59 0 stevel int pri_level, int vect); 60 0 stevel 61 0 stevel /* 62 0 stevel * Arrange for a driver to be called when a particular 63 0 stevel * auto-vectored interrupt occurs. 64 0 stevel * NOTE: if a device can generate interrupts on more than 65 0 stevel * one level, or if a driver services devices that interrupt 66 0 stevel * on more than one level, then the driver should install 67 0 stevel * itself on each of those levels. 68 0 stevel */ 69 0 stevel static char badsoft[] = 70 0 stevel "add_avintr: bad soft interrupt level %d for driver '%s'\n"; 71 0 stevel static char multilevel[] = 72 0 stevel "!IRQ%d is being shared by drivers with different interrupt levels.\n" 73 0 stevel "This may result in reduced system performance."; 74 0 stevel static char multilevel2[] = 75 0 stevel "Cannot register interrupt for '%s' device at IPL %d because it\n" 76 0 stevel "conflicts with another device using the same vector %d with an IPL\n" 77 0 stevel "of %d. Reconfigure the conflicting devices to use different vectors."; 78 0 stevel 79 5084 johnlev #ifdef __xpv 80 5084 johnlev #define MAX_VECT NR_IRQS 81 5084 johnlev #else 82 0 stevel #define MAX_VECT 256 83 5084 johnlev #endif 84 5084 johnlev 85 0 stevel struct autovec *nmivect = NULL; 86 0 stevel struct av_head autovect[MAX_VECT]; 87 0 stevel struct av_head softvect[LOCK_LEVEL + 1]; 88 0 stevel kmutex_t av_lock; 89 5107 eota /* 90 5107 eota * These are software interrupt handlers dedicated to ddi timer. 91 5107 eota * The interrupt levels up to 10 are supported, but high interrupts 92 5107 eota * must not be used there. 93 5107 eota */ 94 5107 eota ddi_softint_hdl_impl_t softlevel_hdl[DDI_IPL_10] = { 95 5107 eota {0, NULL, NULL, NULL, 0, NULL, NULL, NULL}, /* level 1 */ 96 5107 eota {0, NULL, NULL, NULL, 0, NULL, NULL, NULL}, /* level 2 */ 97 5107 eota {0, NULL, NULL, NULL, 0, NULL, NULL, NULL}, /* level 3 */ 98 5107 eota {0, NULL, NULL, NULL, 0, NULL, NULL, NULL}, /* level 4 */ 99 5107 eota {0, NULL, NULL, NULL, 0, NULL, NULL, NULL}, /* level 5 */ 100 5107 eota {0, NULL, NULL, NULL, 0, NULL, NULL, NULL}, /* level 6 */ 101 5107 eota {0, NULL, NULL, NULL, 0, NULL, NULL, NULL}, /* level 7 */ 102 5107 eota {0, NULL, NULL, NULL, 0, NULL, NULL, NULL}, /* level 8 */ 103 5107 eota {0, NULL, NULL, NULL, 0, NULL, NULL, NULL}, /* level 9 */ 104 5107 eota {0, NULL, NULL, NULL, 0, NULL, NULL, NULL}, /* level 10 */ 105 5107 eota }; 106 0 stevel ddi_softint_hdl_impl_t softlevel1_hdl = 107 999 lq150181 {0, NULL, NULL, NULL, 0, NULL, NULL, NULL}; 108 999 lq150181 109 999 lq150181 /* 110 999 lq150181 * clear/check softint pending flag corresponding for 111 999 lq150181 * the current CPU 112 999 lq150181 */ 113 0 stevel void 114 999 lq150181 av_clear_softint_pending(av_softinfo_t *infop) 115 0 stevel { 116 999 lq150181 CPUSET_ATOMIC_DEL(infop->av_pending, CPU->cpu_seqid); 117 999 lq150181 } 118 999 lq150181 119 999 lq150181 boolean_t 120 999 lq150181 av_check_softint_pending(av_softinfo_t *infop, boolean_t check_all) 121 999 lq150181 { 122 999 lq150181 if (check_all) 123 999 lq150181 return (!CPUSET_ISNULL(infop->av_pending)); 124 999 lq150181 else 125 999 lq150181 return (CPU_IN_SET(infop->av_pending, CPU->cpu_seqid) != 0); 126 999 lq150181 } 127 999 lq150181 128 999 lq150181 /* 129 4652 cwb * This is the wrapper function which is generally used to set a softint 130 4652 cwb * pending 131 4652 cwb */ 132 4652 cwb void 133 4652 cwb av_set_softint_pending(int pri, av_softinfo_t *infop) 134 4652 cwb { 135 4652 cwb kdi_av_set_softint_pending(pri, infop); 136 4652 cwb } 137 4652 cwb 138 4652 cwb /* 139 4652 cwb * This is kmdb's private entry point to setsoftint called from kdi_siron 140 999 lq150181 * It first sets our av softint pending bit for the current CPU, 141 999 lq150181 * then it sets the CPU softint pending bit for pri. 142 999 lq150181 */ 143 999 lq150181 void 144 4652 cwb kdi_av_set_softint_pending(int pri, av_softinfo_t *infop) 145 999 lq150181 { 146 999 lq150181 CPUSET_ATOMIC_ADD(infop->av_pending, CPU->cpu_seqid); 147 999 lq150181 148 0 stevel atomic_or_32((uint32_t *)&CPU->cpu_softinfo.st_pending, 1 << pri); 149 0 stevel } 150 0 stevel 151 0 stevel /* 152 0 stevel * register nmi interrupt routine. The first arg is used only to order 153 0 stevel * various nmi interrupt service routines in the chain. Higher lvls will 154 0 stevel * be called first 155 0 stevel */ 156 0 stevel int 157 0 stevel add_nmintr(int lvl, avfunc nmintr, char *name, caddr_t arg) 158 0 stevel { 159 0 stevel struct autovec *mem; 160 0 stevel struct autovec *p, *prev = NULL; 161 0 stevel 162 0 stevel if (nmintr == NULL) { 163 0 stevel printf("Attempt to add null vect for %s on nmi\n", name); 164 0 stevel return (0); 165 0 stevel 166 0 stevel } 167 0 stevel 168 0 stevel mem = kmem_zalloc(sizeof (struct autovec), KM_SLEEP); 169 0 stevel mem->av_vector = nmintr; 170 0 stevel mem->av_intarg1 = arg; 171 0 stevel mem->av_intarg2 = NULL; 172 0 stevel mem->av_intr_id = NULL; 173 0 stevel mem->av_prilevel = lvl; 174 191 ahl mem->av_dip = NULL; 175 0 stevel mem->av_link = NULL; 176 0 stevel 177 0 stevel mutex_enter(&av_lock); 178 0 stevel 179 0 stevel if (!nmivect) { 180 0 stevel nmivect = mem; 181 0 stevel mutex_exit(&av_lock); 182 0 stevel return (1); 183 0 stevel } 184 0 stevel /* find where it goes in list */ 185 0 stevel for (p = nmivect; p != NULL; p = p->av_link) { 186 0 stevel if (p->av_vector == nmintr && p->av_intarg1 == arg) { 187 0 stevel /* 188 0 stevel * already in list 189 0 stevel * So? Somebody added the same interrupt twice. 190 0 stevel */ 191 0 stevel cmn_err(CE_WARN, "Driver already registered '%s'", 192 0 stevel name); 193 0 stevel kmem_free(mem, sizeof (struct autovec)); 194 0 stevel mutex_exit(&av_lock); 195 0 stevel return (0); 196 0 stevel } 197 0 stevel if (p->av_prilevel < lvl) { 198 0 stevel if (p == nmivect) { /* it's at head of list */ 199 0 stevel mem->av_link = p; 200 0 stevel nmivect = mem; 201 0 stevel } else { 202 0 stevel mem->av_link = p; 203 0 stevel prev->av_link = mem; 204 0 stevel } 205 0 stevel mutex_exit(&av_lock); 206 0 stevel return (1); 207 0 stevel } 208 0 stevel prev = p; 209 0 stevel 210 0 stevel } 211 0 stevel /* didn't find it, add it to the end */ 212 0 stevel prev->av_link = mem; 213 0 stevel mutex_exit(&av_lock); 214 0 stevel return (1); 215 0 stevel 216 0 stevel } 217 0 stevel 218 0 stevel /* 219 0 stevel * register a hardware interrupt handler. 220 0 stevel */ 221 0 stevel int 222 0 stevel add_avintr(void *intr_id, int lvl, avfunc xxintr, char *name, int vect, 223 916 schwartz caddr_t arg1, caddr_t arg2, uint64_t *ticksp, dev_info_t *dip) 224 0 stevel { 225 0 stevel struct av_head *vecp = (struct av_head *)0; 226 0 stevel avfunc f; 227 0 stevel int s, vectindex; /* save old spl value */ 228 0 stevel ushort_t hi_pri; 229 0 stevel 230 0 stevel if ((f = xxintr) == NULL) { 231 0 stevel printf("Attempt to add null vect for %s on vector %d\n", 232 4652 cwb name, vect); 233 0 stevel return (0); 234 0 stevel 235 0 stevel } 236 0 stevel vectindex = vect % MAX_VECT; 237 0 stevel 238 0 stevel vecp = &autovect[vectindex]; 239 0 stevel 240 0 stevel /* 241 0 stevel * "hi_pri == 0" implies all entries on list are "unused", 242 0 stevel * which means that it's OK to just insert this one. 243 0 stevel */ 244 0 stevel hi_pri = vecp->avh_hi_pri; 245 0 stevel if (vecp->avh_link && (hi_pri != 0)) { 246 0 stevel if (((hi_pri > LOCK_LEVEL) && (lvl < LOCK_LEVEL)) || 247 0 stevel ((hi_pri < LOCK_LEVEL) && (lvl > LOCK_LEVEL))) { 248 0 stevel cmn_err(CE_WARN, multilevel2, name, lvl, vect, 249 4652 cwb hi_pri); 250 0 stevel return (0); 251 0 stevel } 252 0 stevel if ((vecp->avh_lo_pri != lvl) || (hi_pri != lvl)) 253 0 stevel cmn_err(CE_NOTE, multilevel, vect); 254 0 stevel } 255 0 stevel 256 999 lq150181 insert_av(intr_id, vecp, f, arg1, arg2, ticksp, lvl, dip); 257 0 stevel s = splhi(); 258 0 stevel /* 259 0 stevel * do what ever machine specific things are necessary 260 0 stevel * to set priority level (e.g. set picmasks) 261 0 stevel */ 262 0 stevel mutex_enter(&av_lock); 263 0 stevel (*addspl)(vect, lvl, vecp->avh_lo_pri, vecp->avh_hi_pri); 264 0 stevel mutex_exit(&av_lock); 265 0 stevel splx(s); 266 0 stevel return (1); 267 0 stevel 268 0 stevel } 269 0 stevel 270 0 stevel void 271 0 stevel update_avsoftintr_args(void *intr_id, int lvl, caddr_t arg2) 272 0 stevel { 273 0 stevel struct autovec *p; 274 0 stevel struct autovec *target = NULL; 275 0 stevel struct av_head *vectp = (struct av_head *)&softvect[lvl]; 276 0 stevel 277 0 stevel for (p = vectp->avh_link; p && p->av_vector; p = p->av_link) { 278 0 stevel if (p->av_intr_id == intr_id) { 279 0 stevel target = p; 280 0 stevel break; 281 0 stevel } 282 0 stevel } 283 0 stevel 284 0 stevel if (target == NULL) 285 0 stevel return; 286 0 stevel target->av_intarg2 = arg2; 287 0 stevel } 288 0 stevel 289 0 stevel /* 290 0 stevel * Register a software interrupt handler 291 0 stevel */ 292 0 stevel int 293 0 stevel add_avsoftintr(void *intr_id, int lvl, avfunc xxintr, char *name, 294 0 stevel caddr_t arg1, caddr_t arg2) 295 0 stevel { 296 0 stevel int slvl; 297 999 lq150181 ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)intr_id; 298 0 stevel 299 0 stevel if ((slvl = slvltovect(lvl)) != -1) 300 0 stevel return (add_avintr(intr_id, lvl, xxintr, 301 916 schwartz name, slvl, arg1, arg2, NULL, NULL)); 302 0 stevel 303 0 stevel if (intr_id == NULL) { 304 0 stevel printf("Attempt to add null intr_id for %s on level %d\n", 305 0 stevel name, lvl); 306 0 stevel return (0); 307 0 stevel } 308 0 stevel 309 0 stevel if (xxintr == NULL) { 310 0 stevel printf("Attempt to add null handler for %s on level %d\n", 311 0 stevel name, lvl); 312 0 stevel return (0); 313 0 stevel } 314 0 stevel 315 0 stevel if (lvl <= 0 || lvl > LOCK_LEVEL) { 316 0 stevel printf(badsoft, lvl, name); 317 0 stevel return (0); 318 0 stevel } 319 999 lq150181 320 999 lq150181 if (hdlp->ih_pending == NULL) { 321 999 lq150181 hdlp->ih_pending = 322 4652 cwb kmem_zalloc(sizeof (av_softinfo_t), KM_SLEEP); 323 0 stevel } 324 999 lq150181 325 999 lq150181 insert_av(intr_id, &softvect[lvl], xxintr, arg1, arg2, NULL, lvl, NULL); 326 999 lq150181 327 0 stevel return (1); 328 0 stevel } 329 0 stevel 330 0 stevel /* insert an interrupt vector into chain */ 331 999 lq150181 static void 332 0 stevel insert_av(void *intr_id, struct av_head *vectp, avfunc f, caddr_t arg1, 333 916 schwartz caddr_t arg2, uint64_t *ticksp, int pri_level, dev_info_t *dip) 334 0 stevel { 335 0 stevel /* 336 0 stevel * Protect rewrites of the list 337 0 stevel */ 338 0 stevel struct autovec *p, *mem; 339 0 stevel 340 0 stevel mem = kmem_zalloc(sizeof (struct autovec), KM_SLEEP); 341 0 stevel mem->av_vector = f; 342 0 stevel mem->av_intarg1 = arg1; 343 0 stevel mem->av_intarg2 = arg2; 344 916 schwartz mem->av_ticksp = ticksp; 345 0 stevel mem->av_intr_id = intr_id; 346 0 stevel mem->av_prilevel = pri_level; 347 0 stevel mem->av_dip = dip; 348 0 stevel mem->av_link = NULL; 349 0 stevel 350 0 stevel mutex_enter(&av_lock); 351 0 stevel 352 0 stevel if (vectp->avh_link == NULL) { /* Nothing on list - put it at head */ 353 0 stevel vectp->avh_link = mem; 354 0 stevel vectp->avh_hi_pri = vectp->avh_lo_pri = (ushort_t)pri_level; 355 0 stevel 356 0 stevel mutex_exit(&av_lock); 357 999 lq150181 return; 358 0 stevel } 359 0 stevel 360 0 stevel /* find where it goes in list */ 361 0 stevel for (p = vectp->avh_link; p != NULL; p = p->av_link) { 362 0 stevel if (p->av_vector == NULL) { /* freed struct available */ 363 0 stevel p->av_intarg1 = arg1; 364 0 stevel p->av_intarg2 = arg2; 365 916 schwartz p->av_ticksp = ticksp; 366 0 stevel p->av_intr_id = intr_id; 367 0 stevel p->av_prilevel = pri_level; 368 191 ahl p->av_dip = dip; 369 0 stevel if (pri_level > (int)vectp->avh_hi_pri) { 370 0 stevel vectp->avh_hi_pri = (ushort_t)pri_level; 371 0 stevel } 372 0 stevel if (pri_level < (int)vectp->avh_lo_pri) { 373 0 stevel vectp->avh_lo_pri = (ushort_t)pri_level; 374 0 stevel } 375 5084 johnlev /* 376 5084 johnlev * To prevent calling service routine before args 377 5084 johnlev * and ticksp are ready fill in vector last. 378 5084 johnlev */ 379 0 stevel p->av_vector = f; 380 0 stevel mutex_exit(&av_lock); 381 5084 johnlev kmem_free(mem, sizeof (struct autovec)); 382 999 lq150181 return; 383 0 stevel } 384 0 stevel } 385 0 stevel /* insert new intpt at beginning of chain */ 386 0 stevel mem->av_link = vectp->avh_link; 387 0 stevel vectp->avh_link = mem; 388 0 stevel if (pri_level > (int)vectp->avh_hi_pri) { 389 0 stevel vectp->avh_hi_pri = (ushort_t)pri_level; 390 0 stevel } 391 0 stevel if (pri_level < (int)vectp->avh_lo_pri) { 392 0 stevel vectp->avh_lo_pri = (ushort_t)pri_level; 393 0 stevel } 394 0 stevel mutex_exit(&av_lock); 395 0 stevel } 396 0 stevel 397 999 lq150181 static int 398 999 lq150181 av_rem_softintr(void *intr_id, int lvl, avfunc xxintr, boolean_t rem_softinfo) 399 0 stevel { 400 0 stevel struct av_head *vecp = (struct av_head *)0; 401 0 stevel int slvl; 402 999 lq150181 ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)intr_id; 403 999 lq150181 av_softinfo_t *infop = (av_softinfo_t *)hdlp->ih_pending; 404 0 stevel 405 0 stevel if (xxintr == NULL) 406 0 stevel return (0); 407 0 stevel 408 0 stevel if ((slvl = slvltovect(lvl)) != -1) { 409 0 stevel rem_avintr(intr_id, lvl, xxintr, slvl); 410 0 stevel return (1); 411 0 stevel } 412 0 stevel 413 0 stevel if (lvl <= 0 && lvl >= LOCK_LEVEL) { 414 0 stevel return (0); 415 0 stevel } 416 0 stevel vecp = &softvect[lvl]; 417 0 stevel remove_av(intr_id, vecp, xxintr, lvl, 0); 418 0 stevel 419 999 lq150181 if (rem_softinfo) { 420 999 lq150181 kmem_free(infop, sizeof (av_softinfo_t)); 421 999 lq150181 hdlp->ih_pending = NULL; 422 999 lq150181 } 423 999 lq150181 424 0 stevel return (1); 425 999 lq150181 } 426 999 lq150181 427 999 lq150181 int 428 999 lq150181 av_softint_movepri(void *intr_id, int old_lvl) 429 999 lq150181 { 430 999 lq150181 int ret; 431 999 lq150181 ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)intr_id; 432 999 lq150181 433 999 lq150181 ret = add_avsoftintr(intr_id, hdlp->ih_pri, hdlp->ih_cb_func, 434 999 lq150181 DEVI(hdlp->ih_dip)->devi_name, hdlp->ih_cb_arg1, hdlp->ih_cb_arg2); 435 999 lq150181 436 999 lq150181 if (ret) { 437 999 lq150181 (void) av_rem_softintr(intr_id, old_lvl, hdlp->ih_cb_func, 438 999 lq150181 B_FALSE); 439 999 lq150181 } 440 999 lq150181 441 999 lq150181 return (ret); 442 999 lq150181 } 443 999 lq150181 444 999 lq150181 /* 445 999 lq150181 * Remove a driver from the autovector list. 446 999 lq150181 */ 447 999 lq150181 int 448 999 lq150181 rem_avsoftintr(void *intr_id, int lvl, avfunc xxintr) 449 999 lq150181 { 450 999 lq150181 return (av_rem_softintr(intr_id, lvl, xxintr, B_TRUE)); 451 0 stevel } 452 0 stevel 453 0 stevel void 454 0 stevel rem_avintr(void *intr_id, int lvl, avfunc xxintr, int vect) 455 0 stevel { 456 0 stevel struct av_head *vecp = (struct av_head *)0; 457 0 stevel avfunc f; 458 0 stevel int s, vectindex; /* save old spl value */ 459 0 stevel 460 0 stevel if ((f = xxintr) == NULL) 461 0 stevel return; 462 0 stevel 463 0 stevel vectindex = vect % MAX_VECT; 464 0 stevel vecp = &autovect[vectindex]; 465 0 stevel remove_av(intr_id, vecp, f, lvl, vect); 466 0 stevel s = splhi(); 467 0 stevel mutex_enter(&av_lock); 468 0 stevel (*delspl)(vect, lvl, vecp->avh_lo_pri, vecp->avh_hi_pri); 469 0 stevel mutex_exit(&av_lock); 470 0 stevel splx(s); 471 0 stevel } 472 0 stevel 473 0 stevel 474 0 stevel /* 475 0 stevel * After having made a change to an autovector list, wait until we have 476 0 stevel * seen each cpu not executing an interrupt at that level--so we know our 477 0 stevel * change has taken effect completely (no old state in registers, etc). 478 0 stevel */ 479 9717 Colin static void 480 0 stevel wait_till_seen(int ipl) 481 0 stevel { 482 0 stevel int cpu_in_chain, cix; 483 0 stevel struct cpu *cpup; 484 0 stevel cpuset_t cpus_to_check; 485 0 stevel 486 0 stevel CPUSET_ALL(cpus_to_check); 487 0 stevel do { 488 0 stevel cpu_in_chain = 0; 489 0 stevel for (cix = 0; cix < NCPU; cix++) { 490 0 stevel cpup = cpu[cix]; 491 0 stevel if (cpup != NULL && CPU_IN_SET(cpus_to_check, cix)) { 492 9717 Colin if (INTR_ACTIVE(cpup, ipl)) { 493 0 stevel cpu_in_chain = 1; 494 0 stevel } else { 495 0 stevel CPUSET_DEL(cpus_to_check, cix); 496 0 stevel } 497 0 stevel } 498 0 stevel } 499 0 stevel } while (cpu_in_chain); 500 0 stevel } 501 0 stevel 502 5084 johnlev static uint64_t dummy_tick; 503 5084 johnlev 504 0 stevel /* remove an interrupt vector from the chain */ 505 0 stevel static void 506 0 stevel remove_av(void *intr_id, struct av_head *vectp, avfunc f, int pri_level, 507 0 stevel int vect) 508 0 stevel { 509 5084 johnlev struct autovec *p, *target; 510 0 stevel int lo_pri, hi_pri; 511 0 stevel int ipl; 512 0 stevel /* 513 0 stevel * Protect rewrites of the list 514 0 stevel */ 515 0 stevel target = NULL; 516 0 stevel 517 0 stevel mutex_enter(&av_lock); 518 0 stevel ipl = pri_level; 519 0 stevel lo_pri = MAXIPL; 520 0 stevel hi_pri = 0; 521 5084 johnlev for (p = vectp->avh_link; p; p = p->av_link) { 522 0 stevel if ((p->av_vector == f) && (p->av_intr_id == intr_id)) { 523 0 stevel /* found the handler */ 524 0 stevel target = p; 525 0 stevel continue; 526 0 stevel } 527 5084 johnlev if (p->av_vector != NULL) { 528 5084 johnlev if (p->av_prilevel > hi_pri) 529 5084 johnlev hi_pri = p->av_prilevel; 530 5084 johnlev if (p->av_prilevel < lo_pri) 531 5084 johnlev lo_pri = p->av_prilevel; 532 5084 johnlev } 533 0 stevel } 534 0 stevel if (ipl < hi_pri) 535 0 stevel ipl = hi_pri; 536 0 stevel if (target == NULL) { /* not found */ 537 0 stevel printf("Couldn't remove function %p at %d, %d\n", 538 4652 cwb (void *)f, vect, pri_level); 539 0 stevel mutex_exit(&av_lock); 540 0 stevel return; 541 0 stevel } 542 0 stevel 543 5084 johnlev /* 544 5084 johnlev * This drops the handler from the chain, it can no longer be called. 545 5084 johnlev * However, there is no guarantee that the handler is not currently 546 5084 johnlev * still executing. 547 5084 johnlev */ 548 0 stevel target->av_vector = NULL; 549 5084 johnlev /* 550 5084 johnlev * There is a race where we could be just about to pick up the ticksp 551 5084 johnlev * pointer to increment it after returning from the service routine 552 5084 johnlev * in av_dispatch_autovect. Rather than NULL it out let's just point 553 5084 johnlev * it off to something safe so that any final tick update attempt 554 5084 johnlev * won't fault. 555 5084 johnlev */ 556 5084 johnlev target->av_ticksp = &dummy_tick; 557 0 stevel wait_till_seen(ipl); 558 0 stevel 559 0 stevel if (lo_pri > hi_pri) { /* the chain is now empty */ 560 0 stevel /* Leave the unused entries here for probable future use */ 561 0 stevel vectp->avh_lo_pri = MAXIPL; 562 0 stevel vectp->avh_hi_pri = 0; 563 0 stevel } else { 564 0 stevel if ((int)vectp->avh_lo_pri < lo_pri) 565 0 stevel vectp->avh_lo_pri = (ushort_t)lo_pri; 566 0 stevel if ((int)vectp->avh_hi_pri > hi_pri) 567 0 stevel vectp->avh_hi_pri = (ushort_t)hi_pri; 568 0 stevel } 569 0 stevel mutex_exit(&av_lock); 570 0 stevel wait_till_seen(ipl); 571 4652 cwb } 572 4652 cwb 573 4652 cwb /* 574 4652 cwb * kmdb uses siron (and thus setsoftint) while the world is stopped in order to 575 4652 cwb * inform its driver component that there's work to be done. We need to keep 576 4652 cwb * DTrace from instrumenting kmdb's siron and setsoftint. We duplicate siron, 577 4652 cwb * giving kmdb's version a kdi prefix to keep DTrace at bay. We also 578 4652 cwb * provide a version of the various setsoftint functions available for kmdb to 579 4652 cwb * use using a kdi_ prefix while the main *setsoftint() functionality is 580 4652 cwb * implemented as a wrapper. This allows tracing, while still providing a 581 4652 cwb * way for kmdb to sneak in unmolested. 582 4652 cwb */ 583 4652 cwb void 584 4652 cwb kdi_siron(void) 585 4652 cwb { 586 4652 cwb (*kdisetsoftint)(1, softlevel1_hdl.ih_pending); 587 0 stevel } 588 0 stevel 589 0 stevel /* 590 0 stevel * Trigger a soft interrupt. 591 0 stevel */ 592 0 stevel void 593 0 stevel siron(void) 594 0 stevel { 595 5107 eota /* Level 1 software interrupt */ 596 999 lq150181 (*setsoftint)(1, softlevel1_hdl.ih_pending); 597 5107 eota } 598 5107 eota 599 5107 eota /* 600 5107 eota * Trigger software interrupts dedicated to ddi timer. 601 5107 eota */ 602 5107 eota void 603 5107 eota sir_on(int level) 604 5107 eota { 605 5107 eota ASSERT(level >= DDI_IPL_1 && level <= DDI_IPL_10); 606 5107 eota (*setsoftint)(level, softlevel_hdl[level-1].ih_pending); 607 0 stevel } 608 0 stevel 609 0 stevel /* 610 5076 mishra * The handler which is executed on the target CPU. 611 5076 mishra */ 612 5076 mishra /*ARGSUSED*/ 613 5076 mishra static int 614 5076 mishra siron_poke_intr(xc_arg_t a1, xc_arg_t a2, xc_arg_t a3) 615 5076 mishra { 616 5076 mishra siron(); 617 5076 mishra return (0); 618 5076 mishra } 619 5076 mishra 620 5076 mishra /* 621 5076 mishra * May get called from softcall to poke CPUs. 622 5076 mishra */ 623 5076 mishra void 624 5076 mishra siron_poke_cpu(cpuset_t poke) 625 5076 mishra { 626 5076 mishra int cpuid = CPU->cpu_id; 627 5076 mishra 628 5076 mishra /* 629 5076 mishra * If we are poking to ourself then we can simply 630 5076 mishra * generate level1 using siron() 631 5076 mishra */ 632 5076 mishra if (CPU_IN_SET(poke, cpuid)) { 633 5076 mishra siron(); 634 5076 mishra CPUSET_DEL(poke, cpuid); 635 5076 mishra if (CPUSET_ISNULL(poke)) 636 5076 mishra return; 637 5076 mishra } 638 5076 mishra 639 9489 Joe xc_call(0, 0, 0, CPUSET2BV(poke), (xc_func_t)siron_poke_intr); 640 5076 mishra } 641 5076 mishra 642 5076 mishra /* 643 0 stevel * Walk the autovector table for this vector, invoking each 644 0 stevel * interrupt handler as we go. 645 0 stevel */ 646 916 schwartz 647 916 schwartz extern uint64_t intr_get_time(void); 648 916 schwartz 649 0 stevel void 650 0 stevel av_dispatch_autovect(uint_t vec) 651 0 stevel { 652 0 stevel struct autovec *av; 653 0 stevel 654 0 stevel ASSERT_STACK_ALIGNED(); 655 0 stevel 656 0 stevel while ((av = autovect[vec].avh_link) != NULL) { 657 0 stevel uint_t numcalled = 0; 658 0 stevel uint_t claimed = 0; 659 0 stevel 660 0 stevel for (; av; av = av->av_link) { 661 0 stevel uint_t r; 662 0 stevel uint_t (*intr)() = av->av_vector; 663 0 stevel caddr_t arg1 = av->av_intarg1; 664 0 stevel caddr_t arg2 = av->av_intarg2; 665 0 stevel dev_info_t *dip = av->av_dip; 666 0 stevel 667 5084 johnlev /* 668 5084 johnlev * We must walk the entire chain. Removed handlers 669 5084 johnlev * may be anywhere in the chain. 670 5084 johnlev */ 671 0 stevel if (intr == NULL) 672 5084 johnlev continue; 673 0 stevel 674 0 stevel DTRACE_PROBE4(interrupt__start, dev_info_t *, dip, 675 0 stevel void *, intr, caddr_t, arg1, caddr_t, arg2); 676 0 stevel r = (*intr)(arg1, arg2); 677 0 stevel DTRACE_PROBE4(interrupt__complete, dev_info_t *, dip, 678 0 stevel void *, intr, caddr_t, arg1, uint_t, r); 679 3446 mrj numcalled++; 680 0 stevel claimed |= r; 681 916 schwartz if (av->av_ticksp && av->av_prilevel <= LOCK_LEVEL) 682 916 schwartz atomic_add_64(av->av_ticksp, intr_get_time()); 683 0 stevel } 684 0 stevel 685 0 stevel /* 686 0 stevel * If there's only one interrupt handler in the chain, 687 0 stevel * or if no-one claimed the interrupt at all give up now. 688 0 stevel */ 689 0 stevel if (numcalled == 1 || claimed == 0) 690 0 stevel break; 691 0 stevel } 692 0 stevel } 693 0 stevel 694 0 stevel /* 695 0 stevel * Call every soft interrupt handler we can find at this level once. 696 0 stevel */ 697 0 stevel void 698 0 stevel av_dispatch_softvect(uint_t pil) 699 0 stevel { 700 0 stevel struct autovec *av; 701 0 stevel ddi_softint_hdl_impl_t *hdlp; 702 0 stevel uint_t (*intr)(); 703 0 stevel caddr_t arg1; 704 0 stevel caddr_t arg2; 705 0 stevel 706 0 stevel ASSERT_STACK_ALIGNED(); 707 0 stevel ASSERT(pil >= 0 && pil <= PIL_MAX); 708 0 stevel 709 0 stevel for (av = softvect[pil].avh_link; av; av = av->av_link) { 710 5084 johnlev /* 711 5084 johnlev * We must walk the entire chain. Removed handlers 712 5084 johnlev * may be anywhere in the chain. 713 5084 johnlev */ 714 0 stevel if ((intr = av->av_vector) == NULL) 715 5084 johnlev continue; 716 0 stevel arg1 = av->av_intarg1; 717 0 stevel arg2 = av->av_intarg2; 718 0 stevel 719 0 stevel hdlp = (ddi_softint_hdl_impl_t *)av->av_intr_id; 720 0 stevel ASSERT(hdlp); 721 0 stevel 722 999 lq150181 /* 723 999 lq150181 * Each cpu has its own pending bit in hdlp->ih_pending, 724 999 lq150181 * here av_check/clear_softint_pending is just checking 725 999 lq150181 * and clearing the pending bit for the current cpu, who 726 999 lq150181 * has just triggered a softint. 727 999 lq150181 */ 728 999 lq150181 if (av_check_softint_pending(hdlp->ih_pending, B_FALSE)) { 729 999 lq150181 av_clear_softint_pending(hdlp->ih_pending); 730 0 stevel (void) (*intr)(arg1, arg2); 731 0 stevel } 732 0 stevel } 733 0 stevel } 734 0 stevel 735 0 stevel struct regs; 736 0 stevel 737 0 stevel /* 738 0 stevel * Call every NMI handler we know of once. 739 0 stevel */ 740 0 stevel void 741 0 stevel av_dispatch_nmivect(struct regs *rp) 742 0 stevel { 743 0 stevel struct autovec *av; 744 0 stevel 745 0 stevel ASSERT_STACK_ALIGNED(); 746 0 stevel 747 0 stevel for (av = nmivect; av; av = av->av_link) 748 0 stevel (void) (av->av_vector)(av->av_intarg1, rp); 749 0 stevel } 750