xref: /illumos-gate/usr/src/uts/sun4v/io/cnex.c (revision bbf21555)
11ae08745Sheppo /*
21ae08745Sheppo  * CDDL HEADER START
31ae08745Sheppo  *
41ae08745Sheppo  * The contents of this file are subject to the terms of the
51ae08745Sheppo  * Common Development and Distribution License (the "License").
61ae08745Sheppo  * You may not use this file except in compliance with the License.
71ae08745Sheppo  *
81ae08745Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91ae08745Sheppo  * or http://www.opensolaris.org/os/licensing.
101ae08745Sheppo  * See the License for the specific language governing permissions
111ae08745Sheppo  * and limitations under the License.
121ae08745Sheppo  *
131ae08745Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
141ae08745Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151ae08745Sheppo  * If applicable, add the following below this CDDL HEADER, with the
161ae08745Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
171ae08745Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
181ae08745Sheppo  *
191ae08745Sheppo  * CDDL HEADER END
201ae08745Sheppo  */
211ae08745Sheppo /*
2220ae46ebSha  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
231ae08745Sheppo  * Use is subject to license terms.
241ae08745Sheppo  */
251ae08745Sheppo 
261ae08745Sheppo 
271ae08745Sheppo /*
281ae08745Sheppo  * Logical domain channel devices are devices implemented entirely
291ae08745Sheppo  * in software; cnex is the nexus for channel-devices. They use
301ae08745Sheppo  * the HV channel interfaces via the LDC transport module to send
311ae08745Sheppo  * and receive data and to register callbacks.
321ae08745Sheppo  */
331ae08745Sheppo 
341ae08745Sheppo #include <sys/types.h>
351ae08745Sheppo #include <sys/cmn_err.h>
361ae08745Sheppo #include <sys/conf.h>
371ae08745Sheppo #include <sys/ddi.h>
381ae08745Sheppo #include <sys/ddi_impldefs.h>
391ae08745Sheppo #include <sys/devops.h>
401ae08745Sheppo #include <sys/instance.h>
411ae08745Sheppo #include <sys/modctl.h>
421ae08745Sheppo #include <sys/open.h>
431ae08745Sheppo #include <sys/stat.h>
441ae08745Sheppo #include <sys/sunddi.h>
451ae08745Sheppo #include <sys/sunndi.h>
461ae08745Sheppo #include <sys/systm.h>
471ae08745Sheppo #include <sys/mkdev.h>
481ae08745Sheppo #include <sys/machsystm.h>
49a10abbb4Slm #include <sys/intreg.h>
501ae08745Sheppo #include <sys/intr.h>
511ae08745Sheppo #include <sys/ddi_intr_impl.h>
521ae08745Sheppo #include <sys/ivintr.h>
531ae08745Sheppo #include <sys/hypervisor_api.h>
541ae08745Sheppo #include <sys/ldc.h>
551ae08745Sheppo #include <sys/cnex.h>
561ae08745Sheppo #include <sys/mach_descrip.h>
57d66f8315Sjb #include <sys/hsvc.h>
580705ae3aSraghuram #include <sys/sdt.h>
591ae08745Sheppo 
601ae08745Sheppo /*
611ae08745Sheppo  * Internal functions/information
621ae08745Sheppo  */
6320ae46ebSha static struct cnex_intr_map cnex_class_to_intr[] = {
6420ae46ebSha 	{LDC_DEV_GENERIC,	PIL_3,	 0},
6520ae46ebSha 	{LDC_DEV_BLK,		PIL_4,	10},
6620ae46ebSha 	{LDC_DEV_BLK_SVC,	PIL_3,	10},
6720ae46ebSha 	{LDC_DEV_NT,		PIL_6,	35},
6820ae46ebSha 	{LDC_DEV_NT_SVC,	PIL_4,	35},
6920ae46ebSha 	{LDC_DEV_SERIAL,	PIL_6,	 0}
701ae08745Sheppo };
7120ae46ebSha #define	CNEX_MAX_DEVS (sizeof (cnex_class_to_intr) / \
7220ae46ebSha 				sizeof (cnex_class_to_intr[0]))
7320ae46ebSha 
7420ae46ebSha #define	CNEX_TX_INTR_WEIGHT	0
751ae08745Sheppo 
761ae08745Sheppo #define	SUN4V_REG_SPEC2CFG_HDL(x)	((x >> 32) & ~(0xfull << 28))
771ae08745Sheppo 
78a8ea4edeSnarayan static clock_t cnex_wait_usecs = 1000; /* wait time in usecs */
790d0c8d4bSnarayan static int cnex_wait_retries = 3;
801ae08745Sheppo static void *cnex_state;
811ae08745Sheppo 
821ae08745Sheppo static uint_t cnex_intr_wrapper(caddr_t arg);
830705ae3aSraghuram static dev_info_t *cnex_find_chan_dip(dev_info_t *dip, uint64_t chan_id,
840705ae3aSraghuram     md_t *mdp, mde_cookie_t mde);
851ae08745Sheppo 
8620ae46ebSha /*
8720ae46ebSha  * Channel Interrupt Distribution
8820ae46ebSha  *
8920ae46ebSha  * In order to balance interrupts among available CPUs, we use
9020ae46ebSha  * the intr_dist_cpuid_{add,remove}_device_weight() interface to
9120ae46ebSha  * assign weights to channel interrupts. These weights, which are
9220ae46ebSha  * defined in the cnex_intr_map structure, influence which CPU
9320ae46ebSha  * is returned by intr_dist_cpuid() when called via the cnex
9420ae46ebSha  * interrupt redistribution callback cnex_intr_redist().
9520ae46ebSha  * Interrupts for VIO devclass channels are given more weight than
9620ae46ebSha  * other interrupts because they are expected to occur more
9720ae46ebSha  * frequently and have a larger impact on overall performance.
9820ae46ebSha  * Transmit interrupts are given a zero weight because they are
9920ae46ebSha  * not used.
10020ae46ebSha  *
10120ae46ebSha  * The interrupt weights influence the target CPU selection when
10220ae46ebSha  * interrupts are redistributed and when they are added. However,
10320ae46ebSha  * removal of interrupts can unbalance the distribution even if
10420ae46ebSha  * they are removed in converse order--compared to the order they
10520ae46ebSha  * are added. This can occur when interrupts are removed after
10620ae46ebSha  * redistribution occurs.
10720ae46ebSha  *
10820ae46ebSha  * Channel interrupt weights affect interrupt-CPU distribution
10920ae46ebSha  * relative to other weighted interrupts on the system. For VIO
11020ae46ebSha  * devclass channels, values are chosen to match those used by
11120ae46ebSha  * the PCI express nexus driver for net and storage devices.
11220ae46ebSha  */
11320ae46ebSha static void cnex_intr_redist(void *arg, int32_t weight_max, int32_t weight);
11420ae46ebSha static int cnex_intr_new_cpu(cnex_soft_state_t *ssp, cnex_intr_t *iinfo);
11520ae46ebSha static int cnex_intr_dis_wait(cnex_soft_state_t *ssp, cnex_intr_t *iinfo);
11620ae46ebSha static int32_t cnex_class_weight(ldc_dev_t devclass);
11720ae46ebSha 
1181ae08745Sheppo /*
1191ae08745Sheppo  * Debug info
1201ae08745Sheppo  */
1211ae08745Sheppo #ifdef DEBUG
1221ae08745Sheppo 
1231ae08745Sheppo /*
1241ae08745Sheppo  * Print debug messages
1251ae08745Sheppo  *
1261ae08745Sheppo  * set cnexdbg to 0xf for enabling all msgs
1271ae08745Sheppo  * 0x8 - Errors
1281ae08745Sheppo  * 0x4 - Warnings
1291ae08745Sheppo  * 0x2 - All debug messages
1301ae08745Sheppo  * 0x1 - Minimal debug messages
1311ae08745Sheppo  */
1321ae08745Sheppo 
1331ae08745Sheppo int cnexdbg = 0x8;
1341ae08745Sheppo 
1351ae08745Sheppo static void
cnexdebug(const char * fmt,...)1361ae08745Sheppo cnexdebug(const char *fmt, ...)
1371ae08745Sheppo {
1381ae08745Sheppo 	char buf[512];
1391ae08745Sheppo 	va_list ap;
1401ae08745Sheppo 
1411ae08745Sheppo 	va_start(ap, fmt);
1421ae08745Sheppo 	(void) vsprintf(buf, fmt, ap);
1431ae08745Sheppo 	va_end(ap);
1441ae08745Sheppo 
1451ae08745Sheppo 	cmn_err(CE_CONT, "%s\n", buf);
1461ae08745Sheppo }
1471ae08745Sheppo 
1481ae08745Sheppo #define	D1		\
1491ae08745Sheppo if (cnexdbg & 0x01)	\
1501ae08745Sheppo 	cnexdebug
1511ae08745Sheppo 
1521ae08745Sheppo #define	D2		\
1531ae08745Sheppo if (cnexdbg & 0x02)	\
1541ae08745Sheppo 	cnexdebug
1551ae08745Sheppo 
1561ae08745Sheppo #define	DWARN		\
1571ae08745Sheppo if (cnexdbg & 0x04)	\
1581ae08745Sheppo 	cnexdebug
1591ae08745Sheppo 
1601ae08745Sheppo #define	DERR		\
1611ae08745Sheppo if (cnexdbg & 0x08)	\
1621ae08745Sheppo 	cnexdebug
1631ae08745Sheppo 
1641ae08745Sheppo #else
1651ae08745Sheppo 
1661ae08745Sheppo #define	D1
1671ae08745Sheppo #define	D2
1681ae08745Sheppo #define	DWARN
1691ae08745Sheppo #define	DERR
1701ae08745Sheppo 
1711ae08745Sheppo #endif
1721ae08745Sheppo 
1731ae08745Sheppo /*
1741ae08745Sheppo  * Config information
1751ae08745Sheppo  */
1761ae08745Sheppo static int cnex_attach(dev_info_t *, ddi_attach_cmd_t);
1771ae08745Sheppo static int cnex_detach(dev_info_t *, ddi_detach_cmd_t);
1781ae08745Sheppo static int cnex_open(dev_t *, int, int, cred_t *);
1791ae08745Sheppo static int cnex_close(dev_t, int, int, cred_t *);
1801ae08745Sheppo static int cnex_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
1811ae08745Sheppo static int cnex_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *,
1821ae08745Sheppo     void *);
1831ae08745Sheppo 
1841ae08745Sheppo static struct bus_ops cnex_bus_ops = {
1851ae08745Sheppo 	BUSO_REV,
1861ae08745Sheppo 	nullbusmap,		/* bus_map */
1871ae08745Sheppo 	NULL,			/* bus_get_intrspec */
1881ae08745Sheppo 	NULL,			/* bus_add_intrspec */
1891ae08745Sheppo 	NULL,			/* bus_remove_intrspec */
1901ae08745Sheppo 	i_ddi_map_fault,	/* bus_map_fault */
1911ae08745Sheppo 	ddi_no_dma_map,		/* bus_dma_map */
1921ae08745Sheppo 	ddi_no_dma_allochdl,	/* bus_dma_allochdl */
1931ae08745Sheppo 	NULL,			/* bus_dma_freehdl */
1941ae08745Sheppo 	NULL,			/* bus_dma_bindhdl */
1951ae08745Sheppo 	NULL,			/* bus_dma_unbindhdl */
1961ae08745Sheppo 	NULL,			/* bus_dma_flush */
1971ae08745Sheppo 	NULL,			/* bus_dma_win */
1981ae08745Sheppo 	NULL,			/* bus_dma_ctl */
1991ae08745Sheppo 	cnex_ctl,		/* bus_ctl */
2001ae08745Sheppo 	ddi_bus_prop_op,	/* bus_prop_op */
2011ae08745Sheppo 	0,			/* bus_get_eventcookie */
2021ae08745Sheppo 	0,			/* bus_add_eventcall */
2031ae08745Sheppo 	0,			/* bus_remove_eventcall	*/
2041ae08745Sheppo 	0,			/* bus_post_event */
2051ae08745Sheppo 	NULL,			/* bus_intr_ctl */
2061ae08745Sheppo 	NULL,			/* bus_config */
2071ae08745Sheppo 	NULL,			/* bus_unconfig */
2081ae08745Sheppo 	NULL,			/* bus_fm_init */
2091ae08745Sheppo 	NULL,			/* bus_fm_fini */
2101ae08745Sheppo 	NULL,			/* bus_fm_access_enter */
2111ae08745Sheppo 	NULL,			/* bus_fm_access_exit */
2121ae08745Sheppo 	NULL,			/* bus_power */
2131ae08745Sheppo 	NULL			/* bus_intr_op */
2141ae08745Sheppo };
2151ae08745Sheppo 
2161ae08745Sheppo static struct cb_ops cnex_cb_ops = {
2171ae08745Sheppo 	cnex_open,			/* open */
2181ae08745Sheppo 	cnex_close,			/* close */
2191ae08745Sheppo 	nodev,				/* strategy */
2201ae08745Sheppo 	nodev,				/* print */
2211ae08745Sheppo 	nodev,				/* dump */
2221ae08745Sheppo 	nodev,				/* read */
2231ae08745Sheppo 	nodev,				/* write */
2241ae08745Sheppo 	cnex_ioctl,			/* ioctl */
2251ae08745Sheppo 	nodev,				/* devmap */
2261ae08745Sheppo 	nodev,				/* mmap */
2271ae08745Sheppo 	nodev,				/* segmap */
2281ae08745Sheppo 	nochpoll,			/* poll */
2291ae08745Sheppo 	ddi_prop_op,			/* cb_prop_op */
2301ae08745Sheppo 	0,				/* streamtab  */
2311ae08745Sheppo 	D_MP | D_NEW | D_HOTPLUG	/* Driver compatibility flag */
2321ae08745Sheppo };
2331ae08745Sheppo 
2341ae08745Sheppo static struct dev_ops cnex_ops = {
2351ae08745Sheppo 	DEVO_REV,		/* devo_rev, */
2361ae08745Sheppo 	0,			/* refcnt  */
2371ae08745Sheppo 	ddi_getinfo_1to1,	/* info */
2381ae08745Sheppo 	nulldev,		/* identify */
2391ae08745Sheppo 	nulldev,		/* probe */
2401ae08745Sheppo 	cnex_attach,		/* attach */
2411ae08745Sheppo 	cnex_detach,		/* detach */
2421ae08745Sheppo 	nodev,			/* reset */
2431ae08745Sheppo 	&cnex_cb_ops,		/* driver operations */
2441ae08745Sheppo 	&cnex_bus_ops,		/* bus operations */
24519397407SSherry Moore 	nulldev,		/* power */
24619397407SSherry Moore 	ddi_quiesce_not_needed,		/* quiesce */
2471ae08745Sheppo };
2481ae08745Sheppo 
2491ae08745Sheppo /*
2501ae08745Sheppo  * Module linkage information for the kernel.
2511ae08745Sheppo  */
2521ae08745Sheppo static struct modldrv modldrv = {
2531ae08745Sheppo 	&mod_driverops,
25419397407SSherry Moore 	"sun4v channel-devices nexus",
2551ae08745Sheppo 	&cnex_ops,
2561ae08745Sheppo };
2571ae08745Sheppo 
2581ae08745Sheppo static struct modlinkage modlinkage = {
2591ae08745Sheppo 	MODREV_1, (void *)&modldrv, NULL
2601ae08745Sheppo };
2611ae08745Sheppo 
2621ae08745Sheppo int
_init(void)2631ae08745Sheppo _init(void)
2641ae08745Sheppo {
2651ae08745Sheppo 	int err;
266d66f8315Sjb 	uint64_t majornum;
267d66f8315Sjb 	uint64_t minornum;
268d66f8315Sjb 
269d66f8315Sjb 	/*
270d66f8315Sjb 	 * Check HV intr group api versioning.
271d66f8315Sjb 	 * Note that cnex assumes interrupt cookies is
272d66f8315Sjb 	 * in version 1.0 of the intr group api.
273d66f8315Sjb 	 */
274d66f8315Sjb 	if ((err = hsvc_version(HSVC_GROUP_INTR, &majornum, &minornum)) != 0) {
275d66f8315Sjb 		cmn_err(CE_WARN, "cnex: failed to get intr api "
276d66f8315Sjb 		    "group versioning errno=%d", err);
277d66f8315Sjb 		return (err);
278d66f8315Sjb 	} else if ((majornum != 1) && (majornum != 2)) {
279d66f8315Sjb 		cmn_err(CE_WARN, "cnex: unsupported intr api group: "
280d66f8315Sjb 		    "maj:0x%lx, min:0x%lx", majornum, minornum);
281d66f8315Sjb 		return (ENOTSUP);
282d66f8315Sjb 	}
2831ae08745Sheppo 
2841ae08745Sheppo 	if ((err = ddi_soft_state_init(&cnex_state,
2850705ae3aSraghuram 	    sizeof (cnex_soft_state_t), 0)) != 0) {
2861ae08745Sheppo 		return (err);
2871ae08745Sheppo 	}
2881ae08745Sheppo 	if ((err = mod_install(&modlinkage)) != 0) {
2891ae08745Sheppo 		ddi_soft_state_fini(&cnex_state);
2901ae08745Sheppo 		return (err);
2911ae08745Sheppo 	}
2921ae08745Sheppo 	return (0);
2931ae08745Sheppo }
2941ae08745Sheppo 
2951ae08745Sheppo int
_fini(void)2961ae08745Sheppo _fini(void)
2971ae08745Sheppo {
2981ae08745Sheppo 	int err;
2991ae08745Sheppo 
3001ae08745Sheppo 	if ((err = mod_remove(&modlinkage)) != 0)
3011ae08745Sheppo 		return (err);
3021ae08745Sheppo 	ddi_soft_state_fini(&cnex_state);
3031ae08745Sheppo 	return (0);
3041ae08745Sheppo }
3051ae08745Sheppo 
3061ae08745Sheppo int
_info(struct modinfo * modinfop)3071ae08745Sheppo _info(struct modinfo *modinfop)
3081ae08745Sheppo {
3091ae08745Sheppo 	return (mod_info(&modlinkage, modinfop));
3101ae08745Sheppo }
3111ae08745Sheppo 
3121ae08745Sheppo /*
3131ae08745Sheppo  * Callback function invoked by the interrupt redistribution
3141ae08745Sheppo  * framework. This will redirect interrupts at CPUs that are
3151ae08745Sheppo  * currently available in the system.
31620ae46ebSha  *
31720ae46ebSha  * Note: any interrupts with weight greater than or equal to
31820ae46ebSha  * weight_max must be redistributed when this callback is
31920ae46ebSha  * invoked with (weight == weight_max) which will be once per
32020ae46ebSha  * redistribution.
3211ae08745Sheppo  */
32220ae46ebSha /*ARGSUSED*/
3231ae08745Sheppo static void
cnex_intr_redist(void * arg,int32_t weight_max,int32_t weight)32420ae46ebSha cnex_intr_redist(void *arg, int32_t weight_max, int32_t weight)
3251ae08745Sheppo {
3261ae08745Sheppo 	cnex_ldc_t		*cldcp;
3271ae08745Sheppo 	cnex_soft_state_t	*cnex_ssp = arg;
3281ae08745Sheppo 
3291ae08745Sheppo 	ASSERT(cnex_ssp != NULL);
3301ae08745Sheppo 	mutex_enter(&cnex_ssp->clist_lock);
3311ae08745Sheppo 
3321ae08745Sheppo 	cldcp = cnex_ssp->clist;
3331ae08745Sheppo 	while (cldcp != NULL) {
3341ae08745Sheppo 
3351ae08745Sheppo 		mutex_enter(&cldcp->lock);
3361ae08745Sheppo 
33720ae46ebSha 		if (cldcp->tx.hdlr && (cldcp->tx.weight == weight ||
33820ae46ebSha 		    (weight_max == weight && cldcp->tx.weight > weight))) {
33920ae46ebSha 			(void) cnex_intr_new_cpu(cnex_ssp, &cldcp->tx);
3401ae08745Sheppo 		}
3411ae08745Sheppo 
34220ae46ebSha 		if (cldcp->rx.hdlr && (cldcp->rx.weight == weight ||
34320ae46ebSha 		    (weight_max == weight && cldcp->rx.weight > weight))) {
34420ae46ebSha 			(void) cnex_intr_new_cpu(cnex_ssp, &cldcp->rx);
3451ae08745Sheppo 		}
3461ae08745Sheppo 
3471ae08745Sheppo 		mutex_exit(&cldcp->lock);
3481ae08745Sheppo 
3491ae08745Sheppo 		/* next channel */
3501ae08745Sheppo 		cldcp = cldcp->next;
3511ae08745Sheppo 	}
3521ae08745Sheppo 
3531ae08745Sheppo 	mutex_exit(&cnex_ssp->clist_lock);
3541ae08745Sheppo }
3551ae08745Sheppo 
35620ae46ebSha /*
35720ae46ebSha  * Internal function to replace the CPU used by an interrupt
35820ae46ebSha  * during interrupt redistribution.
35920ae46ebSha  */
36020ae46ebSha static int
cnex_intr_new_cpu(cnex_soft_state_t * ssp,cnex_intr_t * iinfo)36120ae46ebSha cnex_intr_new_cpu(cnex_soft_state_t *ssp, cnex_intr_t *iinfo)
36220ae46ebSha {
36320ae46ebSha 	int	intr_state;
36420ae46ebSha 	int 	rv;
36520ae46ebSha 
36620ae46ebSha 	/* Determine if the interrupt is enabled */
36720ae46ebSha 	rv = hvldc_intr_getvalid(ssp->cfghdl, iinfo->ino, &intr_state);
36820ae46ebSha 	if (rv) {
36920ae46ebSha 		DWARN("cnex_intr_new_cpu: rx ino=0x%llx, can't get valid\n",
37020ae46ebSha 		    iinfo->ino);
37120ae46ebSha 		return (rv);
37220ae46ebSha 	}
37320ae46ebSha 
37420ae46ebSha 	/* If it is enabled, disable it */
37520ae46ebSha 	if (intr_state == HV_INTR_VALID) {
37620ae46ebSha 		rv = cnex_intr_dis_wait(ssp, iinfo);
37720ae46ebSha 		if (rv) {
37820ae46ebSha 			return (rv);
37920ae46ebSha 		}
38020ae46ebSha 	}
38120ae46ebSha 
38220ae46ebSha 	/* Target the interrupt at a new CPU. */
38320ae46ebSha 	iinfo->cpuid = intr_dist_cpuid();
38420ae46ebSha 	(void) hvldc_intr_settarget(ssp->cfghdl, iinfo->ino, iinfo->cpuid);
38520ae46ebSha 	intr_dist_cpuid_add_device_weight(iinfo->cpuid, iinfo->dip,
38620ae46ebSha 	    iinfo->weight);
38720ae46ebSha 
38820ae46ebSha 	/* Re-enable the interrupt if it was enabled */
38920ae46ebSha 	if (intr_state == HV_INTR_VALID) {
39020ae46ebSha 		(void) hvldc_intr_setvalid(ssp->cfghdl, iinfo->ino,
39120ae46ebSha 		    HV_INTR_VALID);
39220ae46ebSha 	}
39320ae46ebSha 
39420ae46ebSha 	return (0);
39520ae46ebSha }
39620ae46ebSha 
39720ae46ebSha /*
39820ae46ebSha  * Internal function to disable an interrupt and wait
39920ae46ebSha  * for any pending interrupts to finish.
40020ae46ebSha  */
40120ae46ebSha static int
cnex_intr_dis_wait(cnex_soft_state_t * ssp,cnex_intr_t * iinfo)40220ae46ebSha cnex_intr_dis_wait(cnex_soft_state_t *ssp, cnex_intr_t *iinfo)
40320ae46ebSha {
40420ae46ebSha 	int rv, intr_state, retries;
40520ae46ebSha 
40620ae46ebSha 	/* disable interrupts */
40720ae46ebSha 	rv = hvldc_intr_setvalid(ssp->cfghdl, iinfo->ino, HV_INTR_NOTVALID);
40820ae46ebSha 	if (rv) {
40920ae46ebSha 		DWARN("cnex_intr_dis_wait: ino=0x%llx, can't set valid\n",
41020ae46ebSha 		    iinfo->ino);
41120ae46ebSha 		return (ENXIO);
41220ae46ebSha 	}
41320ae46ebSha 
41420ae46ebSha 	/*
41520ae46ebSha 	 * Make a best effort to wait for pending interrupts
41620ae46ebSha 	 * to finish. There is not much we can do if we timeout.
41720ae46ebSha 	 */
41820ae46ebSha 	retries = 0;
41920ae46ebSha 
42020ae46ebSha 	do {
42120ae46ebSha 		rv = hvldc_intr_getstate(ssp->cfghdl, iinfo->ino, &intr_state);
42220ae46ebSha 		if (rv) {
42320ae46ebSha 			DWARN("cnex_intr_dis_wait: ino=0x%llx, can't get "
42420ae46ebSha 			    "state\n", iinfo->ino);
42520ae46ebSha 			return (ENXIO);
42620ae46ebSha 		}
42720ae46ebSha 
42820ae46ebSha 		if (intr_state != HV_INTR_DELIVERED_STATE)
42920ae46ebSha 			break;
43020ae46ebSha 
43120ae46ebSha 		drv_usecwait(cnex_wait_usecs);
43220ae46ebSha 
43320ae46ebSha 	} while (!panicstr && ++retries <= cnex_wait_retries);
43420ae46ebSha 
43520ae46ebSha 	return (0);
43620ae46ebSha }
43720ae46ebSha 
43820ae46ebSha /*
43920ae46ebSha  * Returns the interrupt weight to use for the specified devclass.
44020ae46ebSha  */
44120ae46ebSha static int32_t
cnex_class_weight(ldc_dev_t devclass)44220ae46ebSha cnex_class_weight(ldc_dev_t devclass)
44320ae46ebSha {
44420ae46ebSha 	int idx;
445