Home | History | Annotate | Download | only in io
      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