xref: /onnv-gate/usr/src/uts/i86pc/io/xsvc/xsvc.c (revision 8648:766bb1698e05)
13446Smrj /*
23446Smrj  * CDDL HEADER START
33446Smrj  *
43446Smrj  * The contents of this file are subject to the terms of the
53446Smrj  * Common Development and Distribution License (the "License").
63446Smrj  * You may not use this file except in compliance with the License.
73446Smrj  *
83446Smrj  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93446Smrj  * or http://www.opensolaris.org/os/licensing.
103446Smrj  * See the License for the specific language governing permissions
113446Smrj  * and limitations under the License.
123446Smrj  *
133446Smrj  * When distributing Covered Code, include this CDDL HEADER in each
143446Smrj  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153446Smrj  * If applicable, add the following below this CDDL HEADER, with the
163446Smrj  * fields enclosed by brackets "[]" replaced with your own identifying
173446Smrj  * information: Portions Copyright [yyyy] [name of copyright owner]
183446Smrj  *
193446Smrj  * CDDL HEADER END
203446Smrj  */
213446Smrj 
223446Smrj /*
23*8648SMark.Johnson@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
243446Smrj  * Use is subject to license terms.
253446Smrj  */
263446Smrj 
273446Smrj #include <sys/errno.h>
283446Smrj #include <sys/types.h>
293446Smrj #include <sys/conf.h>
303446Smrj #include <sys/kmem.h>
313446Smrj #include <sys/ddi.h>
323446Smrj #include <sys/stat.h>
333446Smrj #include <sys/sunddi.h>
343446Smrj #include <sys/file.h>
353446Smrj #include <sys/open.h>
363446Smrj #include <sys/modctl.h>
373446Smrj #include <sys/ddi_impldefs.h>
383446Smrj #include <vm/seg_kmem.h>
393446Smrj #include <sys/vmsystm.h>
403446Smrj #include <sys/sysmacros.h>
413446Smrj #include <sys/ddidevmap.h>
423446Smrj #include <sys/avl.h>
435084Sjohnlev #ifdef __xpv
445084Sjohnlev #include <sys/hypervisor.h>
455084Sjohnlev #endif
463446Smrj 
473446Smrj #include <sys/xsvc.h>
483446Smrj 
493446Smrj /* total max memory which can be alloced with ioctl interface */
503446Smrj uint64_t xsvc_max_memory = 10 * 1024 * 1024;
513446Smrj 
523446Smrj extern void i86_va_map(caddr_t vaddr, struct as *asp, caddr_t kaddr);
533446Smrj 
543446Smrj 
553446Smrj static int xsvc_open(dev_t *devp, int flag, int otyp, cred_t *cred);
563446Smrj static int xsvc_close(dev_t devp, int flag, int otyp, cred_t *cred);
573446Smrj static int xsvc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred,
583446Smrj     int *rval);
593446Smrj static int xsvc_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len,
603446Smrj     size_t *maplen, uint_t model);
613446Smrj static int xsvc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
623446Smrj static int xsvc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
633446Smrj static int xsvc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
643446Smrj     void **result);
653446Smrj 
663446Smrj static 	struct cb_ops xsvc_cb_ops = {
673446Smrj 	xsvc_open,		/* cb_open */
683446Smrj 	xsvc_close,		/* cb_close */
693446Smrj 	nodev,			/* cb_strategy */
703446Smrj 	nodev,			/* cb_print */
713446Smrj 	nodev,			/* cb_dump */
723446Smrj 	nodev,			/* cb_read */
733446Smrj 	nodev,			/* cb_write */
743446Smrj 	xsvc_ioctl,		/* cb_ioctl */
753446Smrj 	xsvc_devmap,		/* cb_devmap */
763446Smrj 	NULL,			/* cb_mmap */
773446Smrj 	NULL,			/* cb_segmap */
783446Smrj 	nochpoll,		/* cb_chpoll */
793446Smrj 	ddi_prop_op,		/* cb_prop_op */
803446Smrj 	NULL,			/* cb_stream */
813446Smrj 	D_NEW | D_MP | D_64BIT | D_DEVMAP,	/* cb_flag */
823446Smrj 	CB_REV
833446Smrj };
843446Smrj 
853446Smrj static struct dev_ops xsvc_dev_ops = {
863446Smrj 	DEVO_REV,		/* devo_rev */
873446Smrj 	0,			/* devo_refcnt */
883446Smrj 	xsvc_getinfo,		/* devo_getinfo */
893446Smrj 	nulldev,		/* devo_identify */
903446Smrj 	nulldev,		/* devo_probe */
913446Smrj 	xsvc_attach,		/* devo_attach */
923446Smrj 	xsvc_detach,		/* devo_detach */
933446Smrj 	nodev,			/* devo_reset */
943446Smrj 	&xsvc_cb_ops,		/* devo_cb_ops */
953446Smrj 	NULL,			/* devo_bus_ops */
967656SSherry.Moore@Sun.COM 	NULL,			/* power */
977656SSherry.Moore@Sun.COM 	ddi_quiesce_not_needed,		/* quiesce */
983446Smrj };
993446Smrj 
1003446Smrj static struct modldrv xsvc_modldrv = {
1013446Smrj 	&mod_driverops,		/* Type of module.  This one is a driver */
1027542SRichard.Bean@Sun.COM 	"xsvc driver",		/* Name of the module. */
1033446Smrj 	&xsvc_dev_ops,		/* driver ops */
1043446Smrj };
1053446Smrj 
1063446Smrj static struct modlinkage xsvc_modlinkage = {
1073446Smrj 	MODREV_1,
1083446Smrj 	(void *) &xsvc_modldrv,
1093446Smrj 	NULL
1103446Smrj };
1113446Smrj 
1123446Smrj 
1133446Smrj static int xsvc_ioctl_alloc_memory(xsvc_state_t *state, void *arg, int mode);
1143446Smrj static int xsvc_ioctl_flush_memory(xsvc_state_t *state, void *arg, int mode);
1153446Smrj static int xsvc_ioctl_free_memory(xsvc_state_t *state, void *arg, int mode);
1163446Smrj static int xsvc_mem_alloc(xsvc_state_t *state, uint64_t key,
1173446Smrj     xsvc_mem_t **mp);
1183446Smrj static void xsvc_mem_free(xsvc_state_t *state, xsvc_mem_t *mp);
1193446Smrj static xsvc_mem_t *xsvc_mem_lookup(xsvc_state_t *state,
1203446Smrj     uint64_t key);
1213446Smrj static int xsvc_mnode_key_compare(const void *q, const void *e);
1223446Smrj static int xsvc_umem_cookie_alloc(caddr_t kva, size_t size, int flags,
1233446Smrj     ddi_umem_cookie_t *cookiep);
1243446Smrj static void xsvc_umem_cookie_free(ddi_umem_cookie_t *cookiep);
1253446Smrj 
1263446Smrj 
1273446Smrj void *xsvc_statep;
1283446Smrj 
1293446Smrj static ddi_device_acc_attr_t xsvc_device_attr = {
1303446Smrj 	DDI_DEVICE_ATTR_V0,
1313446Smrj 	DDI_NEVERSWAP_ACC,
1323446Smrj 	DDI_STRICTORDER_ACC
1333446Smrj };
1343446Smrj 
135*8648SMark.Johnson@Sun.COM static int xsvc_devmap_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
136*8648SMark.Johnson@Sun.COM     offset_t off, size_t len, void **pvtp);
137*8648SMark.Johnson@Sun.COM static int xsvc_devmap_dup(devmap_cookie_t dhp, void *pvtp,
138*8648SMark.Johnson@Sun.COM     devmap_cookie_t new_dhp, void **new_pvtp);
139*8648SMark.Johnson@Sun.COM static void xsvc_devmap_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off,
140*8648SMark.Johnson@Sun.COM     size_t len, devmap_cookie_t new_dhp1, void **new_pvtp1,
141*8648SMark.Johnson@Sun.COM     devmap_cookie_t new_dhp2, void **new_pvtp2);
142*8648SMark.Johnson@Sun.COM 
143*8648SMark.Johnson@Sun.COM 
1443446Smrj static struct devmap_callback_ctl xsvc_callbk = {
1453446Smrj 	DEVMAP_OPS_REV,
146*8648SMark.Johnson@Sun.COM 	xsvc_devmap_map,
1473446Smrj 	NULL,
148*8648SMark.Johnson@Sun.COM 	xsvc_devmap_dup,
1493446Smrj 	xsvc_devmap_unmap
1503446Smrj };
1513446Smrj 
1523446Smrj 
1533446Smrj /*
1543446Smrj  * _init()
1553446Smrj  *
1563446Smrj  */
1573446Smrj int
_init(void)1583446Smrj _init(void)
1593446Smrj {
1603446Smrj 	int err;
1613446Smrj 
1623446Smrj 	err = ddi_soft_state_init(&xsvc_statep, sizeof (xsvc_state_t), 1);
1633446Smrj 	if (err != 0) {
1643446Smrj 		return (err);
1653446Smrj 	}
1663446Smrj 
1673446Smrj 	err = mod_install(&xsvc_modlinkage);
1683446Smrj 	if (err != 0) {
1693446Smrj 		ddi_soft_state_fini(&xsvc_statep);
1703446Smrj 		return (err);
1713446Smrj 	}
1723446Smrj 
1733446Smrj 	return (0);
1743446Smrj }
1753446Smrj 
1763446Smrj /*
1773446Smrj  * _info()
1783446Smrj  *
1793446Smrj  */
1803446Smrj int
_info(struct modinfo * modinfop)1813446Smrj _info(struct modinfo *modinfop)
1823446Smrj {
1833446Smrj 	return (mod_info(&xsvc_modlinkage, modinfop));
1843446Smrj }
1853446Smrj 
1863446Smrj /*
1873446Smrj  * _fini()
1883446Smrj  *
1893446Smrj  */
1903446Smrj int
_fini(void)1913446Smrj _fini(void)
1923446Smrj {
1933446Smrj 	int err;
1943446Smrj 
1953446Smrj 	err = mod_remove(&xsvc_modlinkage);
1963446Smrj 	if (err != 0) {
1973446Smrj 		return (err);
1983446Smrj 	}
1993446Smrj 
2003446Smrj 	ddi_soft_state_fini(&xsvc_statep);
2013446Smrj 
2023446Smrj 	return (0);
2033446Smrj }
2043446Smrj 
2053446Smrj /*
2063446Smrj  * xsvc_attach()
2073446Smrj  *
2083446Smrj  */
2093446Smrj static int
xsvc_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2103446Smrj xsvc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2113446Smrj {
2123446Smrj 	xsvc_state_t *state;
2133446Smrj 	int maxallocmem;
2143446Smrj 	int instance;
2153446Smrj 	int err;
2163446Smrj 
2173446Smrj 
2183446Smrj 	switch (cmd) {
2193446Smrj 	case DDI_ATTACH:
2203446Smrj 		break;
2213446Smrj 
2223446Smrj 	case DDI_RESUME:
2233446Smrj 		return (DDI_SUCCESS);
2243446Smrj 
2253446Smrj 	default:
2263446Smrj 		return (DDI_FAILURE);
2273446Smrj 	}
2283446Smrj 
2293446Smrj 	instance = ddi_get_instance(dip);
2303446Smrj 	err = ddi_soft_state_zalloc(xsvc_statep, instance);
2313446Smrj 	if (err != DDI_SUCCESS) {
2323446Smrj 		return (DDI_FAILURE);
2333446Smrj 	}
2343446Smrj 	state = ddi_get_soft_state(xsvc_statep, instance);
2353446Smrj 	if (state == NULL) {
2363446Smrj 		goto attachfail_get_soft_state;
2373446Smrj 	}
2383446Smrj 
2393446Smrj 	state->xs_dip = dip;
2403446Smrj 	state->xs_instance = instance;
2413446Smrj 
2423446Smrj 	/* Initialize allocation count */
2433446Smrj 	mutex_init(&state->xs_mutex, NULL, MUTEX_DRIVER, NULL);
2443446Smrj 	state->xs_currently_alloced = 0;
2453446Smrj 
246*8648SMark.Johnson@Sun.COM 	mutex_init(&state->xs_cookie_mutex, NULL, MUTEX_DRIVER, NULL);
247*8648SMark.Johnson@Sun.COM 
2483446Smrj 	/* create the minor node (for the ioctl) */
2493446Smrj 	err = ddi_create_minor_node(dip, "xsvc", S_IFCHR, instance, DDI_PSEUDO,
2503446Smrj 	    0);
2513446Smrj 	if (err != DDI_SUCCESS) {
2523446Smrj 		goto attachfail_minor_node;
2533446Smrj 	}
2543446Smrj 
2553446Smrj 	/*
2563446Smrj 	 * the maxallocmem property will override the default (xsvc_max_memory).
2573446Smrj 	 * This is the maximum total memory the ioctl will allow to be alloced.
2583446Smrj 	 */
2593446Smrj 	maxallocmem = ddi_prop_get_int(DDI_DEV_T_ANY, state->xs_dip,
2603446Smrj 	    DDI_PROP_DONTPASS, "maxallocmem", -1);
2613446Smrj 	if (maxallocmem >= 0) {
2623446Smrj 		xsvc_max_memory = maxallocmem * 1024;
2633446Smrj 	}
2643446Smrj 
2653446Smrj 	/* Initialize list of memory allocs */
2663446Smrj 	mutex_init(&state->xs_mlist.ml_mutex, NULL, MUTEX_DRIVER, NULL);
2673446Smrj 	avl_create(&state->xs_mlist.ml_avl, xsvc_mnode_key_compare,
2683446Smrj 	    sizeof (xsvc_mnode_t), offsetof(xsvc_mnode_t, mn_link));
2693446Smrj 
2703446Smrj 	/* Report that driver was loaded */
2713446Smrj 	ddi_report_dev(dip);
2723446Smrj 
2733446Smrj 	return (DDI_SUCCESS);
2743446Smrj 
2753446Smrj attachfail_minor_node:
276*8648SMark.Johnson@Sun.COM 	mutex_destroy(&state->xs_cookie_mutex);
2773446Smrj 	mutex_destroy(&state->xs_mutex);
2783446Smrj attachfail_get_soft_state:
2793446Smrj 	(void) ddi_soft_state_free(xsvc_statep, instance);
2803446Smrj 
2813446Smrj 	return (err);
2823446Smrj }
2833446Smrj 
2843446Smrj /*
2853446Smrj  * xsvc_detach()
2863446Smrj  *
2873446Smrj  */
2883446Smrj static int
xsvc_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)2893446Smrj xsvc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2903446Smrj {
2913446Smrj 	xsvc_state_t *state;
2923446Smrj 	xsvc_mnode_t *mnode;
2933446Smrj 	xsvc_mem_t *mp;
2943446Smrj 	int instance;
2953446Smrj 
2963446Smrj 
2973446Smrj 	instance = ddi_get_instance(dip);
2983446Smrj 	state = ddi_get_soft_state(xsvc_statep, instance);
2993446Smrj 	if (state == NULL) {
3003446Smrj 		return (DDI_FAILURE);
3013446Smrj 	}
3023446Smrj 
3033446Smrj 	switch (cmd) {
3043446Smrj 	case DDI_DETACH:
3053446Smrj 		break;
3063446Smrj 
3073446Smrj 	case DDI_SUSPEND:
3083446Smrj 		return (DDI_SUCCESS);
3093446Smrj 
3103446Smrj 	default:
3113446Smrj 		return (DDI_FAILURE);
3123446Smrj 	}
3133446Smrj 
3143446Smrj 	ddi_remove_minor_node(dip, NULL);
3153446Smrj 
3163446Smrj 	/* Free any memory on list */
3173446Smrj 	while ((mnode = avl_first(&state->xs_mlist.ml_avl)) != NULL) {
3183446Smrj 		mp = mnode->mn_home;
3193446Smrj 		xsvc_mem_free(state, mp);
3203446Smrj 	}
3213446Smrj 
3223446Smrj 	/* remove list */
3233446Smrj 	avl_destroy(&state->xs_mlist.ml_avl);
3243446Smrj 	mutex_destroy(&state->xs_mlist.ml_mutex);
3253446Smrj 
326*8648SMark.Johnson@Sun.COM 	mutex_destroy(&state->xs_cookie_mutex);
3273446Smrj 	mutex_destroy(&state->xs_mutex);
3283446Smrj 	(void) ddi_soft_state_free(xsvc_statep, state->xs_instance);
3293446Smrj 	return (DDI_SUCCESS);
3303446Smrj }
3313446Smrj 
3323446Smrj /*
3333446Smrj  * xsvc_getinfo()
3343446Smrj  *
3353446Smrj  */
3363446Smrj /*ARGSUSED*/
3373446Smrj static int
xsvc_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)3383446Smrj xsvc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
3393446Smrj {
3403446Smrj 	xsvc_state_t *state;
3413446Smrj 	int instance;
3423446Smrj 	dev_t dev;
3433446Smrj 	int err;
3443446Smrj 
3453446Smrj 
3463446Smrj 	dev = (dev_t)arg;
3473446Smrj 	instance = getminor(dev);
3483446Smrj 
3493446Smrj 	switch (cmd) {
3503446Smrj 	case DDI_INFO_DEVT2DEVINFO:
3513446Smrj 		state = ddi_get_soft_state(xsvc_statep, instance);
3523446Smrj 		if (state == NULL) {
3533446Smrj 			return (DDI_FAILURE);
3543446Smrj 		}
3553446Smrj 		*result = (void *)state->xs_dip;
3563446Smrj 		err = DDI_SUCCESS;
3573446Smrj 		break;
3583446Smrj 
3593446Smrj 	case DDI_INFO_DEVT2INSTANCE:
3603446Smrj 		*result = (void *)(uintptr_t)instance;
3613446Smrj 		err = DDI_SUCCESS;
3623446Smrj 		break;
3633446Smrj 
3643446Smrj 	default:
3653446Smrj 		err = DDI_FAILURE;
3663446Smrj 		break;
3673446Smrj 	}
3683446Smrj 
3693446Smrj 	return (err);
3703446Smrj }
3713446Smrj 
3723446Smrj 
3733446Smrj /*
3743446Smrj  * xsvc_open()
3753446Smrj  *
3763446Smrj  */
3773446Smrj /*ARGSUSED*/
3783446Smrj static int
xsvc_open(dev_t * devp,int flag,int otyp,cred_t * cred)3793446Smrj xsvc_open(dev_t *devp, int flag, int otyp, cred_t *cred)
3803446Smrj {
3813446Smrj 	xsvc_state_t *state;
3823446Smrj 	int instance;
3833446Smrj 
3843446Smrj 	instance = getminor(*devp);
3853446Smrj 	state = ddi_get_soft_state(xsvc_statep, instance);
3863446Smrj 	if (state == NULL) {
3873446Smrj 		return (ENXIO);
3883446Smrj 	}
3893446Smrj 
3903446Smrj 	return (0);
3913446Smrj }
3923446Smrj 
3933446Smrj /*
3943446Smrj  * xsvc_close()
3953446Smrj  *
3963446Smrj  */
3973446Smrj /*ARGSUSED*/
3983446Smrj static int
xsvc_close(dev_t devp,int flag,int otyp,cred_t * cred)3993446Smrj xsvc_close(dev_t devp, int flag, int otyp, cred_t *cred)
4003446Smrj {
4013446Smrj 	return (0);
4023446Smrj }
4033446Smrj 
4043446Smrj /*
4053446Smrj  * xsvc_ioctl()
4063446Smrj  *
4073446Smrj  */
4083446Smrj /*ARGSUSED*/
4093446Smrj static int
xsvc_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred,int * rval)4103446Smrj xsvc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, int *rval)
4113446Smrj {
4123446Smrj 	xsvc_state_t *state;
4133446Smrj 	int instance;
4143446Smrj 	int err;
4153446Smrj 
4163446Smrj 
4173446Smrj 	err = drv_priv(cred);
4183446Smrj 	if (err != 0) {
4193446Smrj 		return (EPERM);
4203446Smrj 	}
4213446Smrj 	instance = getminor(dev);
4223446Smrj 	if (instance == -1) {
4233446Smrj 		return (EBADF);
4243446Smrj 	}
4253446Smrj 	state = ddi_get_soft_state(xsvc_statep, instance);
4263446Smrj 	if (state == NULL) {
4273446Smrj 		return (EBADF);
4283446Smrj 	}
4293446Smrj 
4303446Smrj 	switch (cmd) {
4313446Smrj 	case XSVC_ALLOC_MEM:
4323446Smrj 		err = xsvc_ioctl_alloc_memory(state, (void *)arg, mode);
4333446Smrj 		break;
4343446Smrj 
4353446Smrj 	case XSVC_FREE_MEM:
4363446Smrj 		err = xsvc_ioctl_free_memory(state, (void *)arg, mode);
4373446Smrj 		break;
4383446Smrj 
4393446Smrj 	case XSVC_FLUSH_MEM:
4403446Smrj 		err = xsvc_ioctl_flush_memory(state, (void *)arg, mode);
4413446Smrj 		break;
4423446Smrj 
4433446Smrj 	default:
4443446Smrj 		err = ENXIO;
4453446Smrj 	}
4463446Smrj 
4473446Smrj 	return (err);
4483446Smrj }
4493446Smrj 
4503446Smrj /*
4513446Smrj  * xsvc_ioctl_alloc_memory()
4523446Smrj  *
4533446Smrj  */
4543446Smrj static int
xsvc_ioctl_alloc_memory(xsvc_state_t * state,void * arg,int mode)4553446Smrj xsvc_ioctl_alloc_memory(xsvc_state_t *state, void *arg, int mode)
4563446Smrj {
4573446Smrj 	xsvc_mem_req_32 params32;
4583446Smrj 	xsvc_mloc_32 *usgl32;
4593446Smrj 	xsvc_mem_req params;
4603446Smrj 	xsvc_mloc_32 sgl32;
4613446Smrj 	xsvc_mloc *usgl;
4623446Smrj 	xsvc_mem_t *mp;
4633446Smrj 	xsvc_mloc sgl;
4643446Smrj 	uint64_t key;
4653446Smrj 	size_t size;
4663446Smrj 	int err;
4673446Smrj 	int i;
4683446Smrj 
4693446Smrj 
4703446Smrj 	/* Copy in the params, then get the size and key */
4713446Smrj 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
4723446Smrj 		err = ddi_copyin(arg, &params32, sizeof (xsvc_mem_req_32),
4733446Smrj 		    mode);
4743446Smrj 		if (err != 0) {
4753446Smrj 			return (EFAULT);
4763446Smrj 		}
4773446Smrj 
4783446Smrj 		key = (uint64_t)params32.xsvc_mem_reqid;
4793446Smrj 		size = P2ROUNDUP((size_t)params32.xsvc_mem_size, PAGESIZE);
4803446Smrj 	} else {
4813446Smrj 		err = ddi_copyin(arg, &params, sizeof (xsvc_mem_req), mode);
4823446Smrj 		if (err != 0) {
4833446Smrj 			return (EFAULT);
4843446Smrj 		}
4853446Smrj 		key = (uint64_t)params.xsvc_mem_reqid;
4863446Smrj 		size = P2ROUNDUP(params.xsvc_mem_size, PAGESIZE);
4873446Smrj 	}
4883446Smrj 
4893446Smrj 	/*
4903446Smrj 	 * make sure this doesn't put us over the maximum allowed to be
4913446Smrj 	 * allocated
4923446Smrj 	 */
4933446Smrj 	mutex_enter(&state->xs_mutex);
4943446Smrj 	if ((state->xs_currently_alloced + size) > xsvc_max_memory) {
4953446Smrj 		mutex_exit(&state->xs_mutex);
4963446Smrj 		return (EAGAIN);
4973446Smrj 	}
4983446Smrj 	state->xs_currently_alloced += size;
4993446Smrj 	mutex_exit(&state->xs_mutex);
5003446Smrj 
5013446Smrj 	/* get state to track this memory */
5023446Smrj 	err = xsvc_mem_alloc(state, key, &mp);
5033446Smrj 	if (err != 0) {
5043446Smrj 		return (err);
5053446Smrj 	}
5063446Smrj 	mp->xm_size = size;
5073446Smrj 
5083446Smrj 	/* allocate and bind the memory */
5093446Smrj 	mp->xm_dma_attr.dma_attr_version = DMA_ATTR_V0;
5103446Smrj 	mp->xm_dma_attr.dma_attr_count_max = (uint64_t)0xFFFFFFFF;
5113446Smrj 	mp->xm_dma_attr.dma_attr_burstsizes = 1;
5123446Smrj 	mp->xm_dma_attr.dma_attr_minxfer = 1;
5133446Smrj 	mp->xm_dma_attr.dma_attr_maxxfer = (uint64_t)0xFFFFFFFF;
5143446Smrj 	mp->xm_dma_attr.dma_attr_seg = (uint64_t)0xFFFFFFFF;
5153446Smrj 	mp->xm_dma_attr.dma_attr_granular = 1;
5163446Smrj 	mp->xm_dma_attr.dma_attr_flags = 0;
5173446Smrj 
5183446Smrj 	/* Finish converting params */
5193446Smrj 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
5203446Smrj 		mp->xm_dma_attr.dma_attr_addr_lo = params32.xsvc_mem_addr_lo;
5213446Smrj 		mp->xm_dma_attr.dma_attr_addr_hi = params32.xsvc_mem_addr_hi;
5223446Smrj 		mp->xm_dma_attr.dma_attr_sgllen = params32.xsvc_mem_sgllen;
5233446Smrj 		usgl32 = (xsvc_mloc_32 *)(uintptr_t)params32.xsvc_sg_list;
5243446Smrj 		mp->xm_dma_attr.dma_attr_align = P2ROUNDUP(
5253446Smrj 		    params32.xsvc_mem_align, PAGESIZE);
5263446Smrj 	} else {
5273446Smrj 		mp->xm_dma_attr.dma_attr_addr_lo = params.xsvc_mem_addr_lo;
5283446Smrj 		mp->xm_dma_attr.dma_attr_addr_hi = params.xsvc_mem_addr_hi;
5293446Smrj 		mp->xm_dma_attr.dma_attr_sgllen = params.xsvc_mem_sgllen;
5303446Smrj 		usgl = (xsvc_mloc *)(uintptr_t)params.xsvc_sg_list;
5313446Smrj 		mp->xm_dma_attr.dma_attr_align = P2ROUNDUP(
5323446Smrj 		    params.xsvc_mem_align, PAGESIZE);
5333446Smrj 	}
5343446Smrj 
5353446Smrj 	mp->xm_device_attr = xsvc_device_attr;
5363446Smrj 
5373446Smrj 	err = ddi_dma_alloc_handle(state->xs_dip, &mp->xm_dma_attr,
5383446Smrj 	    DDI_DMA_SLEEP, NULL, &mp->xm_dma_handle);
5393446Smrj 	if (err != DDI_SUCCESS) {
5403446Smrj 		err = EINVAL;
5413446Smrj 		goto allocfail_alloc_handle;
5423446Smrj 	}
5433446Smrj 
5443446Smrj 	/* don't sleep here so we don't get stuck in contig alloc */
5453446Smrj 	err = ddi_dma_mem_alloc(mp->xm_dma_handle, mp->xm_size,
5463446Smrj 	    &mp->xm_device_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
5473446Smrj 	    &mp->xm_addr, &mp->xm_real_length, &mp->xm_mem_handle);
5483446Smrj 	if (err != DDI_SUCCESS) {
5493446Smrj 		err = EINVAL;
5503446Smrj 		goto allocfail_alloc_mem;
5513446Smrj 	}
5523446Smrj 
5533446Smrj 	err = ddi_dma_addr_bind_handle(mp->xm_dma_handle, NULL, mp->xm_addr,
5543446Smrj 	    mp->xm_size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
5553446Smrj 	    NULL, &mp->xm_cookie, &mp->xm_cookie_count);
5563446Smrj 	if (err != DDI_DMA_MAPPED) {
5573446Smrj 		err = EFAULT;
5583446Smrj 		goto allocfail_bind;
5593446Smrj 	}
5603446Smrj 
5613446Smrj 	/* return sgl */
5623446Smrj 	for (i = 0; i < mp->xm_cookie_count; i++) {
5633446Smrj 		if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
5643446Smrj 			sgl32.mloc_addr = mp->xm_cookie.dmac_laddress;
5653446Smrj 			sgl32.mloc_size = mp->xm_cookie.dmac_size;
5663446Smrj 			err = ddi_copyout(&sgl32, &usgl32[i],
5673446Smrj 			    sizeof (xsvc_mloc_32), mode);
5683446Smrj 			if (err != 0) {
5693446Smrj 				err = EFAULT;
5703446Smrj 				goto allocfail_copyout;
5713446Smrj 			}
5723446Smrj 		} else {
5733446Smrj 			sgl.mloc_addr = mp->xm_cookie.dmac_laddress;
5743446Smrj 			sgl.mloc_size = mp->xm_cookie.dmac_size;
5753446Smrj 			err = ddi_copyout(&sgl, &usgl[i], sizeof (xsvc_mloc),
5763446Smrj 			    mode);
5773446Smrj 			if (err != 0) {
5783446Smrj 				err = EFAULT;
5793446Smrj 				goto allocfail_copyout;
5803446Smrj 			}
5813446Smrj 		}
5823446Smrj 		ddi_dma_nextcookie(mp->xm_dma_handle, &mp->xm_cookie);
5833446Smrj 	}
5843446Smrj 
5853446Smrj 	/* set the last sgl entry to 0 to indicate cookie count */
5863446Smrj 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
5873446Smrj 		sgl32.mloc_addr = 0;
5883446Smrj 		sgl32.mloc_size = 0;
5893446Smrj 		err = ddi_copyout(&sgl32, &usgl32[i], sizeof (xsvc_mloc_32),
5903446Smrj 		    mode);
5913446Smrj 		if (err != 0) {
5923446Smrj 			err = EFAULT;
5933446Smrj 			goto allocfail_copyout;
5943446Smrj 		}
5953446Smrj 	} else {
5963446Smrj 		sgl.mloc_addr = 0;
5973446Smrj 		sgl.mloc_size = 0;
5983446Smrj 		err = ddi_copyout(&sgl, &usgl[i], sizeof (xsvc_mloc), mode);
5993446Smrj 		if (err != 0) {
6003446Smrj 			err = EFAULT;
6013446Smrj 			goto allocfail_copyout;
6023446Smrj 		}
6033446Smrj 	}
6043446Smrj 
6053446Smrj 	return (0);
6063446Smrj 
6073446Smrj allocfail_copyout:
6083446Smrj 	(void) ddi_dma_unbind_handle(mp->xm_dma_handle);
6093446Smrj allocfail_bind:
6103446Smrj 	ddi_dma_mem_free(&mp->xm_mem_handle);
6113446Smrj allocfail_alloc_mem:
6123446Smrj 	ddi_dma_free_handle(&mp->xm_dma_handle);
6133446Smrj allocfail_alloc_handle:
6143446Smrj 	mp->xm_dma_handle = NULL;
6153446Smrj 	xsvc_mem_free(state, mp);
6163446Smrj 
6173446Smrj 	mutex_enter(&state->xs_mutex);
6183446Smrj 	state->xs_currently_alloced = state->xs_currently_alloced - size;
6193446Smrj 	mutex_exit(&state->xs_mutex);
6203446Smrj 
6213446Smrj 	return (err);
6223446Smrj }
6233446Smrj 
6243446Smrj /*
6253446Smrj  * xsvc_ioctl_flush_memory()
6263446Smrj  *
6273446Smrj  */
6283446Smrj static int
xsvc_ioctl_flush_memory(xsvc_state_t * state,void * arg,int mode)6293446Smrj xsvc_ioctl_flush_memory(xsvc_state_t *state, void *arg, int mode)
6303446Smrj {
6313446Smrj 	xsvc_mem_req_32 params32;
6323446Smrj 	xsvc_mem_req params;
6333446Smrj 	xsvc_mem_t *mp;
6343446Smrj 	uint64_t key;
6353446Smrj 	int err;
6363446Smrj 
6373446Smrj 
6383446Smrj 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
6393446Smrj 		err = ddi_copyin(arg, &params32, sizeof (xsvc_mem_req_32),
6403446Smrj 		    mode);
6413446Smrj 		if (err != 0) {
6423446Smrj 			return (EFAULT);
6433446Smrj 		}
6443446Smrj 		key = (uint64_t)params32.xsvc_mem_reqid;
6453446Smrj 	} else {
6463446Smrj 		err = ddi_copyin(arg, &params, sizeof (xsvc_mem_req), mode);
6473446Smrj 		if (err != 0) {
6483446Smrj 			return (EFAULT);
6493446Smrj 		}
6503446Smrj 		key = (uint64_t)params.xsvc_mem_reqid;
6513446Smrj 	}
6523446Smrj 
6533446Smrj 	/* find the memory */
6543446Smrj 	mp = xsvc_mem_lookup(state, key);
6553446Smrj 	if (mp == NULL) {
6563446Smrj 		return (EINVAL);
6573446Smrj 	}
6583446Smrj 
6593446Smrj 	(void) ddi_dma_sync(mp->xm_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
6603446Smrj 
6613446Smrj 	return (0);
6623446Smrj }
6633446Smrj 
6643446Smrj 
6653446Smrj /*
6663446Smrj  * xsvc_ioctl_free_memory()
6673446Smrj  *
6683446Smrj  */
6693446Smrj static int
xsvc_ioctl_free_memory(xsvc_state_t * state,void * arg,int mode)6703446Smrj xsvc_ioctl_free_memory(xsvc_state_t *state, void *arg, int mode)
6713446Smrj {
6723446Smrj 	xsvc_mem_req_32 params32;
6733446Smrj 	xsvc_mem_req params;
6743446Smrj 	xsvc_mem_t *mp;
6753446Smrj 	uint64_t key;
6763446Smrj 	int err;
6773446Smrj 
6783446Smrj 
6793446Smrj 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
6803446Smrj 		err = ddi_copyin(arg, &params32, sizeof (xsvc_mem_req_32),
6813446Smrj 		    mode);
6823446Smrj 		if (err != 0) {
6833446Smrj 			return (EFAULT);
6843446Smrj 		}
6853446Smrj 		key = (uint64_t)params32.xsvc_mem_reqid;
6863446Smrj 	} else {
6873446Smrj 		err = ddi_copyin(arg, &params, sizeof (xsvc_mem_req), mode);
6883446Smrj 		if (err != 0) {
6893446Smrj 			return (EFAULT);
6903446Smrj 		}
6913446Smrj 		key = (uint64_t)params.xsvc_mem_reqid;
6923446Smrj 	}
6933446Smrj 
6943446Smrj 	/* find the memory */
6953446Smrj 	mp = xsvc_mem_lookup(state, key);
6963446Smrj 	if (mp == NULL) {
6973446Smrj 		return (EINVAL);
6983446Smrj 	}
6993446Smrj 
7003446Smrj 	xsvc_mem_free(state, mp);
7013446Smrj 
7023446Smrj 	return (0);
7033446Smrj }
7043446Smrj 
7053446Smrj /*
7063446Smrj  * xsvc_mem_alloc()
7073446Smrj  *
7083446Smrj  */
7093446Smrj static int
xsvc_mem_alloc(xsvc_state_t * state,uint64_t key,xsvc_mem_t ** mp)7103446Smrj xsvc_mem_alloc(xsvc_state_t *state, uint64_t key, xsvc_mem_t **mp)
7113446Smrj {
7123446Smrj 	xsvc_mem_t *mem;
7133446Smrj 
7143446Smrj 	mem = xsvc_mem_lookup(state, key);
7153446Smrj 	if (mem != NULL) {
7163446Smrj 		xsvc_mem_free(state, mem);
7173446Smrj 	}
7183446Smrj 
7193446Smrj 	*mp = kmem_alloc(sizeof (xsvc_mem_t), KM_SLEEP);
7203446Smrj 	(*mp)->xm_mnode.mn_home = *mp;
7213446Smrj 	(*mp)->xm_mnode.mn_key = key;
7223446Smrj 
7233446Smrj 	mutex_enter(&state->xs_mlist.ml_mutex);
7243446Smrj 	avl_add(&state->xs_mlist.ml_avl, &(*mp)->xm_mnode);
7253446Smrj 	mutex_exit(&state->xs_mlist.ml_mutex);
7263446Smrj 
7273446Smrj 	return (0);
7283446Smrj }
7293446Smrj 
7303446Smrj /*
7313446Smrj  * xsvc_mem_free()
7323446Smrj  *
7333446Smrj  */
7343446Smrj static void
xsvc_mem_free(xsvc_state_t * state,xsvc_mem_t * mp)7353446Smrj xsvc_mem_free(xsvc_state_t *state, xsvc_mem_t *mp)
7363446Smrj {
7373446Smrj 	if (mp->xm_dma_handle != NULL) {
7383446Smrj 		(void) ddi_dma_unbind_handle(mp->xm_dma_handle);
7393446Smrj 		ddi_dma_mem_free(&mp->xm_mem_handle);
7403446Smrj 		ddi_dma_free_handle(&mp->xm_dma_handle);
7413446Smrj 
7423446Smrj 		mutex_enter(&state->xs_mutex);
7433446Smrj 		state->xs_currently_alloced = state->xs_currently_alloced -
7443446Smrj 		    mp->xm_size;
7453446Smrj 		mutex_exit(&state->xs_mutex);
7463446Smrj 	}
7473446Smrj 
7483446Smrj 	mutex_enter(&state->xs_mlist.ml_mutex);
7493446Smrj 	avl_remove(&state->xs_mlist.ml_avl, &mp->xm_mnode);
7503446Smrj 	mutex_exit(&state->xs_mlist.ml_mutex);
7513446Smrj 
7523446Smrj 	kmem_free(mp, sizeof (*mp));
7533446Smrj }
7543446Smrj 
7553446Smrj /*
7563446Smrj  * xsvc_mem_lookup()
7573446Smrj  *
7583446Smrj  */
7593446Smrj static xsvc_mem_t *
xsvc_mem_lookup(xsvc_state_t * state,uint64_t key)7603446Smrj xsvc_mem_lookup(xsvc_state_t *state, uint64_t key)
7613446Smrj {
7623446Smrj 	xsvc_mnode_t mnode;
7633446Smrj 	xsvc_mnode_t *mnp;
7643446Smrj 	avl_index_t where;
7653446Smrj 	xsvc_mem_t *mp;
7663446Smrj 
7673446Smrj 	mnode.mn_key = key;
7683446Smrj 	mutex_enter(&state->xs_mlist.ml_mutex);
7693446Smrj 	mnp = avl_find(&state->xs_mlist.ml_avl, &mnode, &where);
7703446Smrj 	mutex_exit(&state->xs_mlist.ml_mutex);
7713446Smrj 
7723446Smrj 	if (mnp != NULL) {
7733446Smrj 		mp = mnp->mn_home;
7743446Smrj 	} else {
7753446Smrj 		mp = NULL;
7763446Smrj 	}
7773446Smrj 
7783446Smrj 	return (mp);
7793446Smrj }
7803446Smrj 
7813446Smrj /*
7823446Smrj  * xsvc_mnode_key_compare()
7833446Smrj  *
7843446Smrj  */
7853446Smrj static int
xsvc_mnode_key_compare(const void * q,const void * e)7863446Smrj xsvc_mnode_key_compare(const void *q, const void *e)
7873446Smrj {
7883446Smrj 	xsvc_mnode_t *n1;
7893446Smrj 	xsvc_mnode_t *n2;
7903446Smrj 
7913446Smrj 	n1 = (xsvc_mnode_t *)q;
7923446Smrj 	n2 = (xsvc_mnode_t *)e;
7933446Smrj 
7943446Smrj 	if (n1->mn_key < n2->mn_key) {
7953446Smrj 		return (-1);
7963446Smrj 	} else if (n1->mn_key > n2->mn_key) {
7973446Smrj 		return (1);
7983446Smrj 	} else {
7993446Smrj 		return (0);
8003446Smrj 	}
8013446Smrj }
8023446Smrj 
8033446Smrj /*
8043446Smrj  * xsvc_devmap()
8053446Smrj  *
8063446Smrj  */
8073446Smrj /*ARGSUSED*/
8083446Smrj static int
xsvc_devmap(dev_t dev,devmap_cookie_t dhp,offset_t off,size_t len,size_t * maplen,uint_t model)8093446Smrj xsvc_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len,
8103446Smrj 		size_t *maplen, uint_t model)
8113446Smrj {
8123446Smrj 	ddi_umem_cookie_t cookie;
8133446Smrj 	xsvc_state_t *state;
8143446Smrj 	offset_t off_align;
8153446Smrj 	size_t npages;
8163446Smrj 	caddr_t kvai;
8173446Smrj 	size_t psize;
8183446Smrj 	int instance;
8193446Smrj 	caddr_t kva;
8203446Smrj 	pfn_t pfn;
8213446Smrj 	int err;
8223446Smrj 	int i;
8233446Smrj 
8243446Smrj 
8253446Smrj 	instance = getminor(dev);
8263446Smrj 	state = ddi_get_soft_state(xsvc_statep, instance);
8273446Smrj 	if (state == NULL) {
8283446Smrj 		return (ENXIO);
8293446Smrj 	}
8303446Smrj 
8313446Smrj 	/*
8323446Smrj 	 * On 64-bit kernels, if we have a 32-bit application doing a mmap(),
8333446Smrj 	 * smmap32 will sign extend the offset. We need to undo that since
8343446Smrj 	 * we are passed a physical address in off, not a offset.
8353446Smrj 	 */
8363446Smrj #if defined(__amd64)
8373446Smrj 	if (((model & DDI_MODEL_MASK) == DDI_MODEL_ILP32) &&
8383446Smrj 	    ((off & ~0xFFFFFFFFll) == ~0xFFFFFFFFll)) {
8393446Smrj 		off = off & 0xFFFFFFFF;
8403446Smrj 	}
8413446Smrj #endif
8423446Smrj 
8435084Sjohnlev #ifdef __xpv
8445084Sjohnlev 	/*
8455084Sjohnlev 	 * we won't allow guest OSes to devmap mfn/pfns. Maybe we'll relax
8465084Sjohnlev 	 * this some later when there is a good reason.
8475084Sjohnlev 	 */
8485084Sjohnlev 	if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
8495084Sjohnlev 		return (-1);
8505084Sjohnlev 	}
8513446Smrj 
8525084Sjohnlev 	/* we will always treat this as a foreign MFN */
8535084Sjohnlev 	pfn = xen_assign_pfn(btop(off));
8545084Sjohnlev #else
8555084Sjohnlev 	pfn = btop(off);
8565084Sjohnlev #endif
8573446Smrj 	/* always work with whole pages */
8585084Sjohnlev 
8593446Smrj 	off_align = P2ALIGN(off, PAGESIZE);
8603446Smrj 	psize = P2ROUNDUP(off + len, PAGESIZE) - off_align;
8613446Smrj 
8623446Smrj 	/*
8633446Smrj 	 * if this is memory we're trying to map into user space, we first
8643446Smrj 	 * need to map the PFNs into KVA, then build up a umem cookie, and
8653446Smrj 	 * finally do a umem_setup to map it in.
8663446Smrj 	 */
8673446Smrj 	if (pf_is_memory(pfn)) {
8683446Smrj 		npages = btop(psize);
8693446Smrj 
8703446Smrj 		kva = vmem_alloc(heap_arena, psize, VM_SLEEP);
8713446Smrj 		if (kva == NULL) {
8723446Smrj 			return (-1);
8733446Smrj 		}
8743446Smrj 
8753446Smrj 		kvai = kva;
8763446Smrj 		for (i = 0; i < npages; i++) {
8773446Smrj 			hat_devload(kas.a_hat, kvai, PAGESIZE, pfn,
8783446Smrj 			    PROT_READ | PROT_WRITE, HAT_LOAD_LOCK);
8793446Smrj 			pfn++;
8803446Smrj 			kvai = (caddr_t)((uintptr_t)kvai + PAGESIZE);
8813446Smrj 		}
8823446Smrj 
8833446Smrj 		err = xsvc_umem_cookie_alloc(kva, psize, KM_SLEEP, &cookie);
8843446Smrj 		if (err != 0) {
8853446Smrj 			goto devmapfail_cookie_alloc;
8863446Smrj 		}
8873446Smrj 
8883446Smrj 		if ((err = devmap_umem_setup(dhp, state->xs_dip, &xsvc_callbk,
8893446Smrj 		    cookie, 0, psize, PROT_ALL, 0, &xsvc_device_attr)) < 0) {
8903446Smrj 			goto devmapfail_umem_setup;
8913446Smrj 		}
8923446Smrj 		*maplen = psize;
8933446Smrj 
8945084Sjohnlev 	/*
8955084Sjohnlev 	 * If this is not memory (or a foreign MFN in i86xpv), go through
8965084Sjohnlev 	 * devmem_setup.
8975084Sjohnlev 	 */
8983446Smrj 	} else {
8993446Smrj 		if ((err = devmap_devmem_setup(dhp, state->xs_dip, NULL, 0,
9003446Smrj 		    off_align, psize, PROT_ALL, 0, &xsvc_device_attr)) < 0) {
9013446Smrj 			return (err);
9023446Smrj 		}
9033446Smrj 		*maplen = psize;
9043446Smrj 	}
9053446Smrj 
9063446Smrj 	return (0);
9073446Smrj 
9083446Smrj devmapfail_umem_setup:
9093446Smrj 	xsvc_umem_cookie_free(&cookie);
9103446Smrj 
9113446Smrj devmapfail_cookie_alloc:
9123446Smrj 	kvai = kva;
9133446Smrj 	for (i = 0; i < npages; i++) {
9143446Smrj 		hat_unload(kas.a_hat, kvai, PAGESIZE,
9153446Smrj 		    HAT_UNLOAD_UNLOCK);
9163446Smrj 		kvai = (caddr_t)((uintptr_t)kvai + PAGESIZE);
9173446Smrj 	}
9183446Smrj 	vmem_free(heap_arena, kva, psize);
9193446Smrj 
9203446Smrj 	return (err);
9213446Smrj }
9223446Smrj 
9233446Smrj /*
9243446Smrj  * xsvc_umem_cookie_alloc()
9253446Smrj  *
9263446Smrj  *   allocate a umem cookie to be used in devmap_umem_setup using KVA already
9273446Smrj  *   allocated.
9283446Smrj  */
9293446Smrj int
xsvc_umem_cookie_alloc(caddr_t kva,size_t size,int flags,ddi_umem_cookie_t * cookiep)9303446Smrj xsvc_umem_cookie_alloc(caddr_t kva, size_t size, int flags,
9313446Smrj     ddi_umem_cookie_t *cookiep)
9323446Smrj {
9333446Smrj 	struct ddi_umem_cookie *umem_cookiep;
9343446Smrj 
9353446Smrj 	umem_cookiep = kmem_zalloc(sizeof (struct ddi_umem_cookie), flags);
9363446Smrj 	if (umem_cookiep == NULL) {
9373446Smrj 		*cookiep = NULL;
9383446Smrj 		return (-1);
9393446Smrj 	}
9403446Smrj 
9413446Smrj 	umem_cookiep->cvaddr = kva;
9423446Smrj 	umem_cookiep->type = KMEM_NON_PAGEABLE;
9433446Smrj 	umem_cookiep->size = size;
9443446Smrj 	*cookiep = (ddi_umem_cookie_t *)umem_cookiep;
9453446Smrj 
9463446Smrj 	return (0);
9473446Smrj }
9483446Smrj 
9493446Smrj /*
9503446Smrj  * xsvc_umem_cookie_free()
9513446Smrj  *
9523446Smrj  */
9533446Smrj static void
xsvc_umem_cookie_free(ddi_umem_cookie_t * cookiep)9543446Smrj xsvc_umem_cookie_free(ddi_umem_cookie_t *cookiep)
9553446Smrj {
9563446Smrj 	kmem_free(*cookiep, sizeof (struct ddi_umem_cookie));
9573446Smrj 	*cookiep = NULL;
9583446Smrj }
9593446Smrj 
960*8648SMark.Johnson@Sun.COM 
961*8648SMark.Johnson@Sun.COM /*
962*8648SMark.Johnson@Sun.COM  * xsvc_devmap_map()
963*8648SMark.Johnson@Sun.COM  *
964*8648SMark.Johnson@Sun.COM  */
965*8648SMark.Johnson@Sun.COM /*ARGSUSED*/
966*8648SMark.Johnson@Sun.COM static int
xsvc_devmap_map(devmap_cookie_t dhc,dev_t dev,uint_t flags,offset_t off,size_t len,void ** pvtp)967*8648SMark.Johnson@Sun.COM xsvc_devmap_map(devmap_cookie_t dhc, dev_t dev, uint_t flags, offset_t off,
968*8648SMark.Johnson@Sun.COM     size_t len, void **pvtp)
969*8648SMark.Johnson@Sun.COM {
970*8648SMark.Johnson@Sun.COM 	struct ddi_umem_cookie *cp;
971*8648SMark.Johnson@Sun.COM 	devmap_handle_t *dhp;
972*8648SMark.Johnson@Sun.COM 	xsvc_state_t *state;
973*8648SMark.Johnson@Sun.COM 	int instance;
974*8648SMark.Johnson@Sun.COM 
975*8648SMark.Johnson@Sun.COM 
976*8648SMark.Johnson@Sun.COM 	instance = getminor(dev);
977*8648SMark.Johnson@Sun.COM 	state = ddi_get_soft_state(xsvc_statep, instance);
978*8648SMark.Johnson@Sun.COM 	if (state == NULL) {
979*8648SMark.Johnson@Sun.COM 		return (ENXIO);
980*8648SMark.Johnson@Sun.COM 	}
981*8648SMark.Johnson@Sun.COM 
982*8648SMark.Johnson@Sun.COM 	dhp = (devmap_handle_t *)dhc;
983*8648SMark.Johnson@Sun.COM 	/* This driver only supports MAP_SHARED, not MAP_PRIVATE */
984*8648SMark.Johnson@Sun.COM 	if (flags & MAP_PRIVATE) {
985*8648SMark.Johnson@Sun.COM 		cmn_err(CE_WARN, "!xsvc driver doesn't support MAP_PRIVATE");
986*8648SMark.Johnson@Sun.COM 		return (EINVAL);
987*8648SMark.Johnson@Sun.COM 	}
988*8648SMark.Johnson@Sun.COM 
989*8648SMark.Johnson@Sun.COM 	cp = (struct ddi_umem_cookie *)dhp->dh_cookie;
990*8648SMark.Johnson@Sun.COM 	cp->cook_refcnt = 1;
991*8648SMark.Johnson@Sun.COM 
992*8648SMark.Johnson@Sun.COM 	*pvtp = state;
993*8648SMark.Johnson@Sun.COM 	return (0);
994*8648SMark.Johnson@Sun.COM }
995*8648SMark.Johnson@Sun.COM 
996*8648SMark.Johnson@Sun.COM 
997*8648SMark.Johnson@Sun.COM /*
998*8648SMark.Johnson@Sun.COM  * xsvc_devmap_dup()
999*8648SMark.Johnson@Sun.COM  *
1000*8648SMark.Johnson@Sun.COM  *   keep a reference count for forks so we don't unmap if we have multiple
1001*8648SMark.Johnson@Sun.COM  *   mappings.
1002*8648SMark.Johnson@Sun.COM  */
1003*8648SMark.Johnson@Sun.COM /*ARGSUSED*/
1004*8648SMark.Johnson@Sun.COM static int
xsvc_devmap_dup(devmap_cookie_t dhc,void * pvtp,devmap_cookie_t new_dhp,void ** new_pvtp)1005*8648SMark.Johnson@Sun.COM xsvc_devmap_dup(devmap_cookie_t dhc, void *pvtp, devmap_cookie_t new_dhp,
1006*8648SMark.Johnson@Sun.COM     void **new_pvtp)
1007*8648SMark.Johnson@Sun.COM {
1008*8648SMark.Johnson@Sun.COM 	struct ddi_umem_cookie *cp;
1009*8648SMark.Johnson@Sun.COM 	devmap_handle_t *dhp;
1010*8648SMark.Johnson@Sun.COM 	xsvc_state_t *state;
1011*8648SMark.Johnson@Sun.COM 
1012*8648SMark.Johnson@Sun.COM 
1013*8648SMark.Johnson@Sun.COM 	state = (xsvc_state_t *)pvtp;
1014*8648SMark.Johnson@Sun.COM 	dhp = (devmap_handle_t *)dhc;
1015*8648SMark.Johnson@Sun.COM 
1016*8648SMark.Johnson@Sun.COM 	mutex_enter(&state->xs_cookie_mutex);
1017*8648SMark.Johnson@Sun.COM 	cp = (struct ddi_umem_cookie *)dhp->dh_cookie;
1018*8648SMark.Johnson@Sun.COM 	if (cp == NULL) {
1019*8648SMark.Johnson@Sun.COM 		mutex_exit(&state->xs_cookie_mutex);
1020*8648SMark.Johnson@Sun.COM 		return (ENOMEM);
1021*8648SMark.Johnson@Sun.COM 	}
1022*8648SMark.Johnson@Sun.COM 
1023*8648SMark.Johnson@Sun.COM 	cp->cook_refcnt++;
1024*8648SMark.Johnson@Sun.COM 	mutex_exit(&state->xs_cookie_mutex);
1025*8648SMark.Johnson@Sun.COM 
1026*8648SMark.Johnson@Sun.COM 	*new_pvtp = state;
1027*8648SMark.Johnson@Sun.COM 	return (0);
1028*8648SMark.Johnson@Sun.COM }
1029*8648SMark.Johnson@Sun.COM 
1030*8648SMark.Johnson@Sun.COM 
10313446Smrj /*
10323446Smrj  * xsvc_devmap_unmap()
10333446Smrj  *
10343446Smrj  *   This routine is only call if we were mapping in memory in xsvc_devmap().
10353446Smrj  *   i.e. we only pass in xsvc_callbk to devmap_umem_setup if pf_is_memory()
10363446Smrj  *   was true. It would have been nice if devmap_callback_ctl had an args param.
10373446Smrj  *   We wouldn't have had to look into the devmap_handle and into the umem
10383446Smrj  *   cookie.
10393446Smrj  */
10403446Smrj /*ARGSUSED*/
10413446Smrj static void
xsvc_devmap_unmap(devmap_cookie_t dhc,void * pvtp,offset_t off,size_t len,devmap_cookie_t new_dhp1,void ** new_pvtp1,devmap_cookie_t new_dhp2,void ** new_pvtp2)10423446Smrj xsvc_devmap_unmap(devmap_cookie_t dhc, void *pvtp, offset_t off, size_t len,
10433446Smrj     devmap_cookie_t new_dhp1, void **new_pvtp1, devmap_cookie_t new_dhp2,
10443446Smrj     void **new_pvtp2)
10453446Smrj {
1046*8648SMark.Johnson@Sun.COM 	struct ddi_umem_cookie *ncp;
10473446Smrj 	struct ddi_umem_cookie *cp;
1048*8648SMark.Johnson@Sun.COM 	devmap_handle_t *ndhp;
10493446Smrj 	devmap_handle_t *dhp;
1050*8648SMark.Johnson@Sun.COM 	xsvc_state_t *state;
10513446Smrj 	size_t npages;
10523446Smrj 	caddr_t kvai;
10533446Smrj 	caddr_t kva;
10543446Smrj 	size_t size;
10553446Smrj 	int i;
10563446Smrj 
10573446Smrj 
1058*8648SMark.Johnson@Sun.COM 	state = (xsvc_state_t *)pvtp;
1059*8648SMark.Johnson@Sun.COM 	mutex_enter(&state->xs_cookie_mutex);
1060*8648SMark.Johnson@Sun.COM 
10613446Smrj 	/* peek into the umem cookie to figure out what we need to free up */
10623446Smrj 	dhp = (devmap_handle_t *)dhc;
10633446Smrj 	cp = (struct ddi_umem_cookie *)dhp->dh_cookie;
1064*8648SMark.Johnson@Sun.COM 	ASSERT(cp != NULL);
1065*8648SMark.Johnson@Sun.COM 
1066*8648SMark.Johnson@Sun.COM 	if (new_dhp1 != NULL) {
1067*8648SMark.Johnson@Sun.COM 		ndhp = (devmap_handle_t *)new_dhp1;
1068*8648SMark.Johnson@Sun.COM 		ncp = (struct ddi_umem_cookie *)ndhp->dh_cookie;
1069*8648SMark.Johnson@Sun.COM 		ncp->cook_refcnt++;
1070*8648SMark.Johnson@Sun.COM 		*new_pvtp1 = state;
1071*8648SMark.Johnson@Sun.COM 	}
1072*8648SMark.Johnson@Sun.COM 	if (new_dhp2 != NULL) {
1073*8648SMark.Johnson@Sun.COM 		ndhp = (devmap_handle_t *)new_dhp2;
1074*8648SMark.Johnson@Sun.COM 		ncp = (struct ddi_umem_cookie *)ndhp->dh_cookie;
1075*8648SMark.Johnson@Sun.COM 		ncp->cook_refcnt++;
1076*8648SMark.Johnson@Sun.COM 		*new_pvtp2 = state;
1077*8648SMark.Johnson@Sun.COM 	}
10783446Smrj 
1079*8648SMark.Johnson@Sun.COM 	cp->cook_refcnt--;
1080*8648SMark.Johnson@Sun.COM 	if (cp->cook_refcnt == 0) {
1081*8648SMark.Johnson@Sun.COM 		kva = cp->cvaddr;
1082*8648SMark.Johnson@Sun.COM 		size = cp->size;
1083*8648SMark.Johnson@Sun.COM 
1084*8648SMark.Johnson@Sun.COM 		/*
1085*8648SMark.Johnson@Sun.COM 		 * free up the umem cookie, then unmap all the pages what we
1086*8648SMark.Johnson@Sun.COM 		 * mapped in during devmap, then free up the kva space.
1087*8648SMark.Johnson@Sun.COM 		 */
1088*8648SMark.Johnson@Sun.COM 		npages = btop(size);
1089*8648SMark.Johnson@Sun.COM 		xsvc_umem_cookie_free(&dhp->dh_cookie);
1090*8648SMark.Johnson@Sun.COM 		kvai = kva;
1091*8648SMark.Johnson@Sun.COM 		for (i = 0; i < npages; i++) {
1092*8648SMark.Johnson@Sun.COM 			hat_unload(kas.a_hat, kvai, PAGESIZE,
1093*8648SMark.Johnson@Sun.COM 			    HAT_UNLOAD_UNLOCK);
1094*8648SMark.Johnson@Sun.COM 			kvai = (caddr_t)((uintptr_t)kvai + PAGESIZE);
1095*8648SMark.Johnson@Sun.COM 		}
1096*8648SMark.Johnson@Sun.COM 		vmem_free(heap_arena, kva, size);
10973446Smrj 	}
1098*8648SMark.Johnson@Sun.COM 
1099*8648SMark.Johnson@Sun.COM 	mutex_exit(&state->xs_cookie_mutex);
11003446Smrj }
1101