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