xref: /onnv-gate/usr/src/uts/sun4v/io/vnex.c (revision 444:9d33e7d4c98b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4 5.0 */
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/cmn_err.h>
310Sstevel@tonic-gate #include <sys/conf.h>
320Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
330Sstevel@tonic-gate #include <sys/autoconf.h>
340Sstevel@tonic-gate #include <sys/systm.h>
350Sstevel@tonic-gate #include <sys/modctl.h>
360Sstevel@tonic-gate #include <sys/ddi.h>
370Sstevel@tonic-gate #include <sys/sunddi.h>
380Sstevel@tonic-gate #include <sys/ddi_subrdefs.h>
390Sstevel@tonic-gate #include <sys/nexusintr_impl.h>
400Sstevel@tonic-gate #include <sys/promif.h>
410Sstevel@tonic-gate #include <sys/machsystm.h>
420Sstevel@tonic-gate #include <sys/ddi_intr_impl.h>
430Sstevel@tonic-gate #include <sys/hypervisor_api.h>
440Sstevel@tonic-gate #include <sys/intr.h>
450Sstevel@tonic-gate 
460Sstevel@tonic-gate #define	SUN4V_REG_SPEC2CFG_HDL(x)	((x >> 32) & ~(0xfull << 28))
470Sstevel@tonic-gate 
480Sstevel@tonic-gate static kmutex_t vnex_id_lock;
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate  * Vnex name  to pil map
510Sstevel@tonic-gate  */
520Sstevel@tonic-gate typedef struct vnex_regspec {
530Sstevel@tonic-gate 	uint64_t physaddr;
540Sstevel@tonic-gate 	uint64_t size;
550Sstevel@tonic-gate } vnex_regspec_t;
560Sstevel@tonic-gate 
570Sstevel@tonic-gate struct vnex_pil_map {
580Sstevel@tonic-gate 	caddr_t	name;
590Sstevel@tonic-gate 	uint32_t pil;
600Sstevel@tonic-gate };
610Sstevel@tonic-gate 
620Sstevel@tonic-gate /* vnex interrupt descriptor */
630Sstevel@tonic-gate typedef struct vnex_id {
640Sstevel@tonic-gate 	dev_info_t *vid_dip;
650Sstevel@tonic-gate 	uint32_t vid_ino;
660Sstevel@tonic-gate 	uint64_t vid_ihdl;
670Sstevel@tonic-gate 	uint_t	(*vid_handler)();
680Sstevel@tonic-gate 	caddr_t	vid_arg1;
690Sstevel@tonic-gate 	caddr_t	vid_arg2;
700Sstevel@tonic-gate 	ddi_intr_handle_impl_t *vid_ddi_hdlp;
710Sstevel@tonic-gate 	uint64_t vid_cfg_hdl;
720Sstevel@tonic-gate 	struct vnex_id *vid_next;
730Sstevel@tonic-gate 	struct vnex_id *vid_prev;
740Sstevel@tonic-gate } vnex_id_t;
750Sstevel@tonic-gate 
760Sstevel@tonic-gate /* vnex interrupt descriptor list */
770Sstevel@tonic-gate static vnex_id_t *vnex_id_list;
780Sstevel@tonic-gate 
79*444Sarao hrtime_t vnex_pending_timeout = 2ull * NANOSEC; /* 2 seconds in nanoseconds */
80*444Sarao 
810Sstevel@tonic-gate /*
820Sstevel@tonic-gate  * vnex interrupt descriptor list manipulation functions
830Sstevel@tonic-gate  */
840Sstevel@tonic-gate 
850Sstevel@tonic-gate static vnex_id_t *vnex_locate_id(dev_info_t *dip, uint32_t ino);
860Sstevel@tonic-gate static vnex_id_t *vnex_alloc_id(dev_info_t *dip, uint32_t ino,
870Sstevel@tonic-gate 	uint64_t dhdl);
880Sstevel@tonic-gate static void vnex_add_id(vnex_id_t *vid_p);
890Sstevel@tonic-gate static void vnex_rem_id(vnex_id_t *vid_p);
900Sstevel@tonic-gate static void vnex_free_id(vnex_id_t *vid_p);
910Sstevel@tonic-gate 
920Sstevel@tonic-gate uint_t vnex_intr_wrapper(caddr_t arg);
930Sstevel@tonic-gate 
940Sstevel@tonic-gate static struct vnex_pil_map vnex_name_to_pil[] = {
950Sstevel@tonic-gate 	{"console", 	PIL_12},
960Sstevel@tonic-gate 	{"fma",		PIL_5},
970Sstevel@tonic-gate 	{"echo", 	PIL_3},
980Sstevel@tonic-gate 	{"loop", 	PIL_3},
990Sstevel@tonic-gate 	{"sunmc", 	PIL_3},
1000Sstevel@tonic-gate 	{"sunvts", 	PIL_3},
1010Sstevel@tonic-gate 	{"explorer", 	PIL_3}
1020Sstevel@tonic-gate };
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate #define	VNEX_MAX_DEVS	(sizeof (vnex_name_to_pil) /	\
1050Sstevel@tonic-gate 			    sizeof (struct vnex_pil_map))
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate /*
1080Sstevel@tonic-gate  * Config information
1090Sstevel@tonic-gate  */
1100Sstevel@tonic-gate static int vnex_intr_ops(dev_info_t *dip, dev_info_t *rdip,
1110Sstevel@tonic-gate     ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result);
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate static int
1140Sstevel@tonic-gate vnex_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *);
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate static struct bus_ops vnex_bus_ops = {
1170Sstevel@tonic-gate 	BUSO_REV,
1180Sstevel@tonic-gate 	nullbusmap,
1190Sstevel@tonic-gate 	NULL,	/* NO OP */
1200Sstevel@tonic-gate 	NULL,	/* NO OP */
1210Sstevel@tonic-gate 	NULL,	/* NO OP */
1220Sstevel@tonic-gate 	i_ddi_map_fault,
1230Sstevel@tonic-gate 	ddi_no_dma_map,
1240Sstevel@tonic-gate 	ddi_no_dma_allochdl,
1250Sstevel@tonic-gate 	NULL,
1260Sstevel@tonic-gate 	NULL,
1270Sstevel@tonic-gate 	NULL,
1280Sstevel@tonic-gate 	NULL,
1290Sstevel@tonic-gate 	NULL,
1300Sstevel@tonic-gate 	NULL,
1310Sstevel@tonic-gate 	vnex_ctl,
1320Sstevel@tonic-gate 	ddi_bus_prop_op,
1330Sstevel@tonic-gate 	NULL,	/* (*bus_get_eventcookie)();    */
1340Sstevel@tonic-gate 	NULL,	/* (*bus_add_eventcall)();	*/
1350Sstevel@tonic-gate 	NULL,	/* (*bus_remove_eventcall)();   */
1360Sstevel@tonic-gate 	NULL,	/* (*bus_post_event)();		*/
1370Sstevel@tonic-gate 	NULL,	/* (*bus_intr_ctl)();		*/
1380Sstevel@tonic-gate 	NULL,	/* (*bus_config)();		*/
1390Sstevel@tonic-gate 	NULL,	/* (*bus_unconfig)();		*/
1400Sstevel@tonic-gate 	NULL,	/* (*bus_fm_init)();		*/
1410Sstevel@tonic-gate 	NULL,	/* (*bus_fm_fini)();		*/
1420Sstevel@tonic-gate 	NULL,	/* (*bus_fm_access_enter)();	*/
1430Sstevel@tonic-gate 	NULL,	/* (*bus_fm_access_fini)();	*/
1440Sstevel@tonic-gate 	NULL,	/* (*bus_power)();		*/
1450Sstevel@tonic-gate 	vnex_intr_ops	/* (*bus_intr_op)();	*/
1460Sstevel@tonic-gate };
1470Sstevel@tonic-gate 
148*444Sarao static int vnex_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
149*444Sarao static int vnex_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate static struct dev_ops pseudo_ops = {
1520Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev, */
1530Sstevel@tonic-gate 	0,			/* refcnt  */
1540Sstevel@tonic-gate 	ddi_no_info,		/* info */
1550Sstevel@tonic-gate 	nulldev,		/* identify */
1560Sstevel@tonic-gate 	nulldev,		/* probe */
1570Sstevel@tonic-gate 	vnex_attach,		/* attach */
1580Sstevel@tonic-gate 	vnex_detach,		/* detach */
1590Sstevel@tonic-gate 	nodev,			/* reset */
1600Sstevel@tonic-gate 	(struct cb_ops *)0,	/* driver operations */
1610Sstevel@tonic-gate 	&vnex_bus_ops,	/* bus operations */
1620Sstevel@tonic-gate 	nulldev			/* power */
1630Sstevel@tonic-gate };
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate /*
1660Sstevel@tonic-gate  * Module linkage information for the kernel.
1670Sstevel@tonic-gate  */
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate static struct modldrv modldrv = {
1700Sstevel@tonic-gate 	&mod_driverops, /* Type of module.  This one is a pseudo driver */
1710Sstevel@tonic-gate 	"sun4v virtual-devices nexus driver v%I%",
1720Sstevel@tonic-gate 	&pseudo_ops,	/* driver ops */
1730Sstevel@tonic-gate };
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate static struct modlinkage modlinkage = {
1760Sstevel@tonic-gate 	MODREV_1, (void *)&modldrv, NULL
1770Sstevel@tonic-gate };
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate int
1800Sstevel@tonic-gate _init(void)
1810Sstevel@tonic-gate {
1820Sstevel@tonic-gate 	return (mod_install(&modlinkage));
1830Sstevel@tonic-gate }
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate int
1860Sstevel@tonic-gate _fini(void)
1870Sstevel@tonic-gate {
1880Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
1890Sstevel@tonic-gate }
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate int
1920Sstevel@tonic-gate _info(struct modinfo *modinfop)
1930Sstevel@tonic-gate {
1940Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1950Sstevel@tonic-gate }
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate /*ARGSUSED*/
198*444Sarao void
199*444Sarao vnex_intr_dist(void *arg)
200*444Sarao {
201*444Sarao 	vnex_id_t *vid_p;
202*444Sarao 	uint32_t cpuid;
203*444Sarao 	int	intr_state;
204*444Sarao 	hrtime_t start;
205*444Sarao 
206*444Sarao 	mutex_enter(&vnex_id_lock);
207*444Sarao 
208*444Sarao 	for (vid_p = vnex_id_list; vid_p != NULL;
209*444Sarao 	    vid_p = vid_p->vid_next) {
210*444Sarao 		/*
211*444Sarao 		 * Don't do anything for disabled interrupts.
212*444Sarao 		 * vnex_enable_intr takes care of redistributing interrupts.
213*444Sarao 		 */
214*444Sarao 		if ((hvio_intr_getvalid(vid_p->vid_ihdl,
215*444Sarao 		    &intr_state) == H_EOK) && (intr_state == HV_INTR_NOTVALID))
216*444Sarao 				continue;
217*444Sarao 
218*444Sarao 		cpuid = intr_dist_cpuid();
219*444Sarao 
220*444Sarao 		(void) hvio_intr_setvalid(vid_p->vid_ihdl, HV_INTR_NOTVALID);
221*444Sarao 		/*
222*444Sarao 		 * Make a best effort to wait for pending interrupts to finish.
223*444Sarao 		 * There is not much we can do if we timeout.
224*444Sarao 		 */
225*444Sarao 		start = gethrtime();
226*444Sarao 		while (!panicstr &&
227*444Sarao 		    (hvio_intr_getstate(vid_p->vid_ihdl, &intr_state) ==
228*444Sarao 		    H_EOK) && (intr_state == HV_INTR_DELIVERED_STATE)) {
229*444Sarao 			if (gethrtime() - start > vnex_pending_timeout) {
230*444Sarao 				cmn_err(CE_WARN, "vnex_intr_dist: %s%d "
231*444Sarao 				    "ino 0x%x pending: timedout\n",
232*444Sarao 				    ddi_driver_name(vid_p->vid_dip),
233*444Sarao 				    ddi_get_instance(vid_p->vid_dip),
234*444Sarao 				    vid_p->vid_ino);
235*444Sarao 				break;
236*444Sarao 			}
237*444Sarao 		}
238*444Sarao 		(void) hvio_intr_settarget(vid_p->vid_ihdl, cpuid);
239*444Sarao 		(void) hvio_intr_setvalid(vid_p->vid_ihdl, HV_INTR_VALID);
240*444Sarao 	}
241*444Sarao 	mutex_exit(&vnex_id_lock);
242*444Sarao }
243*444Sarao 
2440Sstevel@tonic-gate static int
245*444Sarao vnex_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2460Sstevel@tonic-gate {
2470Sstevel@tonic-gate 	switch (cmd) {
2480Sstevel@tonic-gate 	case DDI_ATTACH:
2490Sstevel@tonic-gate 		/*
2500Sstevel@tonic-gate 		 * Intitialize interrupt descriptor list
2510Sstevel@tonic-gate 		 * and mutex.
2520Sstevel@tonic-gate 		 */
2530Sstevel@tonic-gate 		vnex_id_list = NULL;
2540Sstevel@tonic-gate 		mutex_init(&vnex_id_lock, NULL, MUTEX_DRIVER, NULL);
255*444Sarao 		/*
256*444Sarao 		 * Add interrupt redistribution callback.
257*444Sarao 		 */
258*444Sarao 		intr_dist_add(vnex_intr_dist, dip);
2590Sstevel@tonic-gate 		return (DDI_SUCCESS);
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	case DDI_RESUME:
2620Sstevel@tonic-gate 		return (DDI_SUCCESS);
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 	default:
2650Sstevel@tonic-gate 		return (DDI_FAILURE);
2660Sstevel@tonic-gate 	}
2670Sstevel@tonic-gate }
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate /*ARGSUSED*/
2700Sstevel@tonic-gate static int
271*444Sarao vnex_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2720Sstevel@tonic-gate {
2730Sstevel@tonic-gate 	switch (cmd) {
2740Sstevel@tonic-gate 	case DDI_DETACH:
2750Sstevel@tonic-gate 		return (DDI_FAILURE);
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	case DDI_SUSPEND:
2780Sstevel@tonic-gate 		return (DDI_SUCCESS);
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	default:
2810Sstevel@tonic-gate 		return (DDI_FAILURE);
2820Sstevel@tonic-gate 	}
2830Sstevel@tonic-gate }
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate static int
2860Sstevel@tonic-gate vnex_ctl(dev_info_t *dip, dev_info_t *rdip,
2870Sstevel@tonic-gate 	ddi_ctl_enum_t ctlop, void *arg, void *result)
2880Sstevel@tonic-gate {
2890Sstevel@tonic-gate 	char	name[12];	/* enough for a decimal integer */
2900Sstevel@tonic-gate 	int		reglen;
2910Sstevel@tonic-gate 	uint32_t	*vnex_regspec;
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	switch (ctlop) {
2940Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTDEV:
2950Sstevel@tonic-gate 		if (rdip == NULL)
2960Sstevel@tonic-gate 			return (DDI_FAILURE);
2970Sstevel@tonic-gate 		cmn_err(CE_CONT, "?virtual-device: %s%d\n",
2980Sstevel@tonic-gate 		    ddi_driver_name(rdip), ddi_get_instance(rdip));
2990Sstevel@tonic-gate 		return (DDI_SUCCESS);
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD:
3020Sstevel@tonic-gate 	{
3030Sstevel@tonic-gate 		dev_info_t *child = (dev_info_t *)arg;
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 		if (ddi_getlongprop(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS,
3060Sstevel@tonic-gate 		    "reg", (caddr_t)&vnex_regspec, &reglen) != DDI_SUCCESS)
3070Sstevel@tonic-gate 			return (DDI_FAILURE);
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 		(void) sprintf(name, "%x", *vnex_regspec);
3100Sstevel@tonic-gate 		ddi_set_name_addr(child, name);
3110Sstevel@tonic-gate 		ddi_set_parent_data(child, NULL);
3120Sstevel@tonic-gate 		kmem_free((caddr_t)vnex_regspec, reglen);
3130Sstevel@tonic-gate 		return (DDI_SUCCESS);
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	}
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD:
3180Sstevel@tonic-gate 	{
3190Sstevel@tonic-gate 		dev_info_t *child = (dev_info_t *)arg;
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 		ddi_set_name_addr(child, NULL);
3220Sstevel@tonic-gate 		ddi_remove_minor_node(arg, NULL);
3230Sstevel@tonic-gate 		return (DDI_SUCCESS);
3240Sstevel@tonic-gate 	}
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	/*
3270Sstevel@tonic-gate 	 * These ops correspond to functions that "shouldn't" be called
3280Sstevel@tonic-gate 	 * by a pseudo driver.  So we whinge when we're called.
3290Sstevel@tonic-gate 	 */
3300Sstevel@tonic-gate 	case DDI_CTLOPS_DMAPMAPC:
3310Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTINT:
3320Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
3330Sstevel@tonic-gate 	{
3340Sstevel@tonic-gate 		*((off_t *)result) = 0;
3350Sstevel@tonic-gate 		return (DDI_SUCCESS);
3360Sstevel@tonic-gate 	}
3370Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
3380Sstevel@tonic-gate 	{
3390Sstevel@tonic-gate 		dev_info_t *child = (dev_info_t *)arg;
3400Sstevel@tonic-gate 		if (ddi_getlongprop(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS,
3410Sstevel@tonic-gate 		    "reg", (caddr_t)&vnex_regspec, &reglen) != DDI_SUCCESS)
3420Sstevel@tonic-gate 			return (DDI_FAILURE);
3430Sstevel@tonic-gate 		*((uint_t *)result) = reglen / sizeof (uint32_t);
3440Sstevel@tonic-gate 		kmem_free((caddr_t)vnex_regspec, reglen);
3450Sstevel@tonic-gate 		return (DDI_SUCCESS);
3460Sstevel@tonic-gate 	}
3470Sstevel@tonic-gate 	case DDI_CTLOPS_NINTRS:
3480Sstevel@tonic-gate 	case DDI_CTLOPS_SIDDEV:
3490Sstevel@tonic-gate 	case DDI_CTLOPS_SLAVEONLY:
3500Sstevel@tonic-gate 	case DDI_CTLOPS_AFFINITY:
3510Sstevel@tonic-gate 	case DDI_CTLOPS_IOMIN:
3520Sstevel@tonic-gate 	case DDI_CTLOPS_POKE:
3530Sstevel@tonic-gate 	case DDI_CTLOPS_PEEK:
3540Sstevel@tonic-gate 	case DDI_CTLOPS_INTR_HILEVEL:
3550Sstevel@tonic-gate 	case DDI_CTLOPS_XLATE_INTRS:
3560Sstevel@tonic-gate 		cmn_err(CE_CONT, "%s%d: invalid op (%d) from %s%d\n",
3570Sstevel@tonic-gate 			ddi_get_name(dip), ddi_get_instance(dip),
3580Sstevel@tonic-gate 			ctlop, ddi_get_name(rdip), ddi_get_instance(rdip));
3590Sstevel@tonic-gate 		return (DDI_FAILURE);
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 	/*
3620Sstevel@tonic-gate 	 * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up
3630Sstevel@tonic-gate 	 */
3640Sstevel@tonic-gate 	default:
3650Sstevel@tonic-gate 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
3660Sstevel@tonic-gate 	}
3670Sstevel@tonic-gate }
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate static int
3700Sstevel@tonic-gate vnex_get_pil(dev_info_t *rdip)
3710Sstevel@tonic-gate {
3720Sstevel@tonic-gate 	int i;
3730Sstevel@tonic-gate 	caddr_t	name;
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 	name = ddi_node_name(rdip);
3760Sstevel@tonic-gate 	for (i = 0; i < VNEX_MAX_DEVS; i++) {
3770Sstevel@tonic-gate 		if (strcmp(vnex_name_to_pil[i].name,
3780Sstevel@tonic-gate 		    name) == 0) {
3790Sstevel@tonic-gate 			return (vnex_name_to_pil[i].pil);
3800Sstevel@tonic-gate 		}
3810Sstevel@tonic-gate 	}
3820Sstevel@tonic-gate 	/*
3830Sstevel@tonic-gate 	 * if not found pil is 0
3840Sstevel@tonic-gate 	 */
3850Sstevel@tonic-gate 	return (0);
3860Sstevel@tonic-gate }
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate static int
3890Sstevel@tonic-gate vnex_enable_intr(dev_info_t *rdip, ddi_intr_handle_impl_t *hdlp)
3900Sstevel@tonic-gate {
3910Sstevel@tonic-gate 	vnex_id_t *vid_p;
3920Sstevel@tonic-gate 	uint32_t cpuid;
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	vid_p = vnex_locate_id(rdip, hdlp->ih_vector);
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	ASSERT(vid_p != NULL);
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 	cpuid = intr_dist_cpuid();
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	if ((hvio_intr_settarget(vid_p->vid_ihdl, cpuid)) != H_EOK) {
4010Sstevel@tonic-gate 		return (DDI_FAILURE);
4020Sstevel@tonic-gate 	}
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 	if (hvio_intr_setstate(vid_p->vid_ihdl, HV_INTR_IDLE_STATE) != H_EOK) {
4050Sstevel@tonic-gate 		return (DDI_FAILURE);
4060Sstevel@tonic-gate 	}
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	if ((hvio_intr_setvalid(vid_p->vid_ihdl, HV_INTR_VALID)) != H_EOK) {
4090Sstevel@tonic-gate 		return (DDI_FAILURE);
4100Sstevel@tonic-gate 	}
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	return (DDI_SUCCESS);
4130Sstevel@tonic-gate }
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate static int
4160Sstevel@tonic-gate vnex_disable_intr(dev_info_t *rdip, ddi_intr_handle_impl_t *hdlp)
4170Sstevel@tonic-gate {
4180Sstevel@tonic-gate 	vnex_id_t *vid_p;
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	vid_p = vnex_locate_id(rdip, hdlp->ih_vector);
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	ASSERT(vid_p != NULL);
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate 	if (hvio_intr_setvalid(vid_p->vid_ihdl, HV_INTR_NOTVALID) != H_EOK) {
4250Sstevel@tonic-gate 		return (DDI_FAILURE);
4260Sstevel@tonic-gate 	}
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 	return (DDI_SUCCESS);
4290Sstevel@tonic-gate }
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate static int
4320Sstevel@tonic-gate vnex_add_intr(dev_info_t *dip, dev_info_t *rdip,
4330Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp)
4340Sstevel@tonic-gate {
4350Sstevel@tonic-gate 	int reglen, ret = DDI_SUCCESS;
4360Sstevel@tonic-gate 	vnex_id_t	*vid_p;
4370Sstevel@tonic-gate 	uint64_t cfg;
4380Sstevel@tonic-gate 	uint32_t ino;
4390Sstevel@tonic-gate 	uint64_t ihdl;
4400Sstevel@tonic-gate 	vnex_regspec_t *reg_p;
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_NONE, dip,
4430Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "reg", (caddr_t)&reg_p,
4440Sstevel@tonic-gate 	    &reglen) != DDI_SUCCESS) {
4450Sstevel@tonic-gate 		return (DDI_FAILURE);
4460Sstevel@tonic-gate 	}
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	/*
4490Sstevel@tonic-gate 	 * get the sun4v config handle for this device
4500Sstevel@tonic-gate 	 */
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	cfg = SUN4V_REG_SPEC2CFG_HDL(reg_p->physaddr);
453288Sarao 	kmem_free(reg_p, reglen);
4540Sstevel@tonic-gate 	ino = hdlp->ih_vector;
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	/*
4570Sstevel@tonic-gate 	 * call hv to get vihdl
4580Sstevel@tonic-gate 	 */
4590Sstevel@tonic-gate 	if (hvio_intr_devino_to_sysino(cfg, ino, &ihdl) != H_EOK)
4600Sstevel@tonic-gate 		return (DDI_FAILURE);
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 	hdlp->ih_vector = ihdl;
4630Sstevel@tonic-gate 	/*
4640Sstevel@tonic-gate 	 * Allocate a interrupt descriptor (id) with the
4650Sstevel@tonic-gate 	 * the interrupt handler and append it to
4660Sstevel@tonic-gate 	 * the id list.
4670Sstevel@tonic-gate 	 */
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	vid_p = vnex_alloc_id(rdip, ino, cfg);
4700Sstevel@tonic-gate 	vid_p->vid_ihdl = ihdl;
4710Sstevel@tonic-gate 	vid_p->vid_handler =  hdlp->ih_cb_func;
4720Sstevel@tonic-gate 	vid_p->vid_arg1 =  hdlp->ih_cb_arg1;
4730Sstevel@tonic-gate 	vid_p->vid_arg2 =  hdlp->ih_cb_arg2;
4740Sstevel@tonic-gate 	vid_p->vid_ddi_hdlp =  hdlp;
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 	DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp,
4770Sstevel@tonic-gate 	    (ddi_intr_handler_t *)vnex_intr_wrapper, (caddr_t)vid_p, NULL);
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 	if (hdlp->ih_pri == 0) {
4800Sstevel@tonic-gate 		hdlp->ih_pri = vnex_get_pil(rdip);
4810Sstevel@tonic-gate 	}
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 	ret = i_ddi_add_ivintr(hdlp);
4840Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
4850Sstevel@tonic-gate 		return (ret);
4860Sstevel@tonic-gate 	}
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, vid_p->vid_handler,
4890Sstevel@tonic-gate 	    vid_p->vid_arg1, vid_p->vid_arg2);
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	return (ret);
4920Sstevel@tonic-gate }
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate static int
4950Sstevel@tonic-gate vnex_remove_intr(dev_info_t *rdip,
4960Sstevel@tonic-gate 	ddi_intr_handle_impl_t *hdlp)
4970Sstevel@tonic-gate {
4980Sstevel@tonic-gate 	vnex_id_t *vid_p;
4990Sstevel@tonic-gate 	uint32_t ino;
5000Sstevel@tonic-gate 	int ret = DDI_SUCCESS;
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	ino = hdlp->ih_vector;
5030Sstevel@tonic-gate 	vid_p = vnex_locate_id(rdip, ino);
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	hdlp->ih_vector = vid_p->vid_ihdl;
5060Sstevel@tonic-gate 	i_ddi_rem_ivintr(hdlp);
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	vnex_free_id(vid_p);
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 	return (ret);
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate static int
5140Sstevel@tonic-gate vnex_intr_ops(dev_info_t *dip, dev_info_t *rdip,
5150Sstevel@tonic-gate     ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result)
5160Sstevel@tonic-gate {
5170Sstevel@tonic-gate 	ddi_ispec_t *ispecp = (ddi_ispec_t *)hdlp->ih_private;
5180Sstevel@tonic-gate 	int ret = DDI_SUCCESS;
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	switch (intr_op) {
5210Sstevel@tonic-gate 		case DDI_INTROP_GETCAP:
5220Sstevel@tonic-gate 			*(int *)result = 0;
5230Sstevel@tonic-gate 			break;
5240Sstevel@tonic-gate 		case DDI_INTROP_ALLOC:
5250Sstevel@tonic-gate 			*(int *)result = hdlp->ih_scratch1;
5260Sstevel@tonic-gate 			break;
5270Sstevel@tonic-gate 		case DDI_INTROP_GETPRI:
5280Sstevel@tonic-gate 			*(int *)result = ispecp->is_pil ?
5290Sstevel@tonic-gate 			    ispecp->is_pil : vnex_get_pil(rdip);
5300Sstevel@tonic-gate 			break;
5310Sstevel@tonic-gate 		case DDI_INTROP_FREE:
5320Sstevel@tonic-gate 			break;
5330Sstevel@tonic-gate 		case DDI_INTROP_SETPRI:
5340Sstevel@tonic-gate 			ispecp->is_pil = (*(int *)result);
5350Sstevel@tonic-gate 			break;
5360Sstevel@tonic-gate 		case DDI_INTROP_ADDISR:
5370Sstevel@tonic-gate 			hdlp->ih_vector = *ispecp->is_intr;
5380Sstevel@tonic-gate 			ret = vnex_add_intr(dip, rdip, hdlp);
5390Sstevel@tonic-gate 			break;
5400Sstevel@tonic-gate 		case DDI_INTROP_REMISR:
5410Sstevel@tonic-gate 			hdlp->ih_vector = *ispecp->is_intr;
5420Sstevel@tonic-gate 			ret = vnex_remove_intr(rdip, hdlp);
5430Sstevel@tonic-gate 			break;
5440Sstevel@tonic-gate 		case DDI_INTROP_ENABLE:
5450Sstevel@tonic-gate 			hdlp->ih_vector = *ispecp->is_intr;
5460Sstevel@tonic-gate 			ret = vnex_enable_intr(rdip, hdlp);
5470Sstevel@tonic-gate 			break;
5480Sstevel@tonic-gate 		case DDI_INTROP_DISABLE:
5490Sstevel@tonic-gate 			hdlp->ih_vector = *ispecp->is_intr;
5500Sstevel@tonic-gate 			ret = vnex_disable_intr(rdip, hdlp);
5510Sstevel@tonic-gate 			break;
5520Sstevel@tonic-gate 		case DDI_INTROP_NINTRS:
5530Sstevel@tonic-gate 		case DDI_INTROP_NAVAIL:
5540Sstevel@tonic-gate 			*(int *)result = i_ddi_get_nintrs(rdip);
5550Sstevel@tonic-gate 			break;
5560Sstevel@tonic-gate 		case DDI_INTROP_SUPPORTED_TYPES:
5570Sstevel@tonic-gate 			*(int *)result = i_ddi_get_nintrs(rdip) ?
5580Sstevel@tonic-gate 			    DDI_INTR_TYPE_FIXED : 0;
5590Sstevel@tonic-gate 			break;
5600Sstevel@tonic-gate 		default:
5610Sstevel@tonic-gate 			ret = DDI_ENOTSUP;
5620Sstevel@tonic-gate 			break;
5630Sstevel@tonic-gate 	}
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 	return (ret);
5660Sstevel@tonic-gate }
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate vnex_id_t *
5690Sstevel@tonic-gate vnex_alloc_id(dev_info_t *dip, uint32_t ino, uint64_t dhdl)
5700Sstevel@tonic-gate {
5710Sstevel@tonic-gate 	vnex_id_t *vid_p = kmem_alloc(sizeof (vnex_id_t), KM_SLEEP);
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	vid_p->vid_dip = dip;
5740Sstevel@tonic-gate 	vid_p->vid_ino = ino;
5750Sstevel@tonic-gate 	vid_p->vid_cfg_hdl = dhdl;
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	mutex_enter(&vnex_id_lock);
5780Sstevel@tonic-gate 	vnex_add_id(vid_p);
5790Sstevel@tonic-gate 	mutex_exit(&vnex_id_lock);
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 	return (vid_p);
5820Sstevel@tonic-gate }
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate vnex_id_t *
5850Sstevel@tonic-gate vnex_locate_id(dev_info_t *dip, uint32_t ino)
5860Sstevel@tonic-gate {
5870Sstevel@tonic-gate 	vnex_id_t *vid_p;
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	mutex_enter(&vnex_id_lock);
5900Sstevel@tonic-gate 	vid_p = vnex_id_list;
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 	while (vid_p != NULL) {
5930Sstevel@tonic-gate 		if (vid_p->vid_dip == dip && vid_p->vid_ino == ino) {
5940Sstevel@tonic-gate 			mutex_exit(&vnex_id_lock);
5950Sstevel@tonic-gate 			return (vid_p);
5960Sstevel@tonic-gate 		}
5970Sstevel@tonic-gate 		vid_p = vid_p->vid_next;
5980Sstevel@tonic-gate 	}
5990Sstevel@tonic-gate 	mutex_exit(&vnex_id_lock);
6000Sstevel@tonic-gate 	return (NULL);
6010Sstevel@tonic-gate }
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate static void
6040Sstevel@tonic-gate vnex_free_id(vnex_id_t *vid_p)
6050Sstevel@tonic-gate {
6060Sstevel@tonic-gate 	mutex_enter(&vnex_id_lock);
6070Sstevel@tonic-gate 	vnex_rem_id(vid_p);
6080Sstevel@tonic-gate 	mutex_exit(&vnex_id_lock);
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	kmem_free(vid_p, sizeof (*vid_p));
6110Sstevel@tonic-gate }
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate static void
6140Sstevel@tonic-gate vnex_rem_id(vnex_id_t *vid_p)
6150Sstevel@tonic-gate {
6160Sstevel@tonic-gate 	if (vid_p->vid_prev == NULL) {
6170Sstevel@tonic-gate 		vnex_id_list = vid_p->vid_next;
6180Sstevel@tonic-gate 		vid_p->vid_prev = NULL;
6190Sstevel@tonic-gate 	} else if (vid_p->vid_next == NULL) {
6200Sstevel@tonic-gate 		vid_p->vid_prev->vid_next = NULL;
6210Sstevel@tonic-gate 	} else {
6220Sstevel@tonic-gate 		vid_p->vid_prev->vid_next = vid_p->vid_next;
6230Sstevel@tonic-gate 		vid_p->vid_next->vid_prev = vid_p->vid_prev;
6240Sstevel@tonic-gate 	}
6250Sstevel@tonic-gate }
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate static void
6280Sstevel@tonic-gate vnex_add_id(vnex_id_t *vid_p)
6290Sstevel@tonic-gate {
6300Sstevel@tonic-gate 	if (vnex_id_list == NULL) {
6310Sstevel@tonic-gate 		vnex_id_list = vid_p;
6320Sstevel@tonic-gate 		vid_p->vid_next = NULL;
6330Sstevel@tonic-gate 		vid_p->vid_prev = NULL;
6340Sstevel@tonic-gate 		return;
6350Sstevel@tonic-gate 	}
6360Sstevel@tonic-gate 	/*
6370Sstevel@tonic-gate 	 * We always just add to the front of the list
6380Sstevel@tonic-gate 	 */
6390Sstevel@tonic-gate 	vnex_id_list->vid_prev = vid_p;
6400Sstevel@tonic-gate 	vid_p->vid_next = vnex_id_list;
6410Sstevel@tonic-gate 	vid_p->vid_prev = NULL;
6420Sstevel@tonic-gate 	vnex_id_list = vid_p;
6430Sstevel@tonic-gate }
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate uint_t
6460Sstevel@tonic-gate vnex_intr_wrapper(caddr_t arg)
6470Sstevel@tonic-gate {
6480Sstevel@tonic-gate 	vnex_id_t *vid_p = (vnex_id_t *)arg;
6490Sstevel@tonic-gate 	int res;
6500Sstevel@tonic-gate 	uint_t (*handler)();
6510Sstevel@tonic-gate 	caddr_t handler_arg1;
6520Sstevel@tonic-gate 	caddr_t handler_arg2;
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	handler = vid_p->vid_handler;
6550Sstevel@tonic-gate 	handler_arg1 = vid_p->vid_arg1;
6560Sstevel@tonic-gate 	handler_arg2 = vid_p->vid_arg2;
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 	res = (*handler)(handler_arg1, handler_arg2);
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 	(void) hvio_intr_setstate(vid_p->vid_ihdl, HV_INTR_IDLE_STATE);
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 	return (res);
6630Sstevel@tonic-gate }
664