xref: /titanic_52/usr/src/uts/sun4v/io/ldc_shm.c (revision 34f94fbc7a730740933e4776ade5f74009afe4ce)
120ae46ebSha137994 /*
220ae46ebSha137994  * CDDL HEADER START
320ae46ebSha137994  *
420ae46ebSha137994  * The contents of this file are subject to the terms of the
520ae46ebSha137994  * Common Development and Distribution License (the "License").
620ae46ebSha137994  * You may not use this file except in compliance with the License.
720ae46ebSha137994  *
820ae46ebSha137994  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
920ae46ebSha137994  * or http://www.opensolaris.org/os/licensing.
1020ae46ebSha137994  * See the License for the specific language governing permissions
1120ae46ebSha137994  * and limitations under the License.
1220ae46ebSha137994  *
1320ae46ebSha137994  * When distributing Covered Code, include this CDDL HEADER in each
1420ae46ebSha137994  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1520ae46ebSha137994  * If applicable, add the following below this CDDL HEADER, with the
1620ae46ebSha137994  * fields enclosed by brackets "[]" replaced with your own identifying
1720ae46ebSha137994  * information: Portions Copyright [yyyy] [name of copyright owner]
1820ae46ebSha137994  *
1920ae46ebSha137994  * CDDL HEADER END
2020ae46ebSha137994  */
2120ae46ebSha137994 
2220ae46ebSha137994 /*
23*34f94fbcSWENTAO YANG  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
2420ae46ebSha137994  */
2520ae46ebSha137994 
2620ae46ebSha137994 /*
2720ae46ebSha137994  * sun4v LDC Link Layer Shared Memory Routines
2820ae46ebSha137994  */
2920ae46ebSha137994 #include <sys/types.h>
3020ae46ebSha137994 #include <sys/kmem.h>
3120ae46ebSha137994 #include <sys/cmn_err.h>
3220ae46ebSha137994 #include <sys/ksynch.h>
3320ae46ebSha137994 #include <sys/debug.h>
3420ae46ebSha137994 #include <sys/cyclic.h>
3520ae46ebSha137994 #include <sys/machsystm.h>
3620ae46ebSha137994 #include <sys/vm.h>
3720ae46ebSha137994 #include <sys/machcpuvar.h>
3820ae46ebSha137994 #include <sys/mmu.h>
3920ae46ebSha137994 #include <sys/pte.h>
4020ae46ebSha137994 #include <vm/hat.h>
4120ae46ebSha137994 #include <vm/as.h>
4220ae46ebSha137994 #include <vm/hat_sfmmu.h>
4320ae46ebSha137994 #include <sys/vm_machparam.h>
4420ae46ebSha137994 #include <vm/seg_kmem.h>
4520ae46ebSha137994 #include <vm/seg_kpm.h>
4620ae46ebSha137994 #include <sys/hypervisor_api.h>
4720ae46ebSha137994 #include <sys/ldc.h>
4820ae46ebSha137994 #include <sys/ldc_impl.h>
4920ae46ebSha137994 
5020ae46ebSha137994 /* LDC variables used by shared memory routines */
5120ae46ebSha137994 extern ldc_soft_state_t *ldcssp;
5220ae46ebSha137994 extern int ldc_max_retries;
5320ae46ebSha137994 extern clock_t ldc_delay;
5420ae46ebSha137994 
5520ae46ebSha137994 #ifdef DEBUG
5620ae46ebSha137994 extern int ldcdbg;
5720ae46ebSha137994 #endif
5820ae46ebSha137994 
5920ae46ebSha137994 /* LDC internal functions used by shared memory routines */
6020ae46ebSha137994 extern void i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset);
6120ae46ebSha137994 extern int i_ldc_h2v_error(int h_error);
6220ae46ebSha137994 
6320ae46ebSha137994 #ifdef DEBUG
6420ae46ebSha137994 extern void ldcdebug(int64_t id, const char *fmt, ...);
6520ae46ebSha137994 #endif
6620ae46ebSha137994 
6720ae46ebSha137994 /* Memory synchronization internal functions */
6820ae46ebSha137994 static int i_ldc_mem_acquire_release(ldc_mem_handle_t mhandle,
6920ae46ebSha137994     uint8_t direction, uint64_t offset, size_t size);
7020ae46ebSha137994 static int i_ldc_dring_acquire_release(ldc_dring_handle_t dhandle,
7120ae46ebSha137994     uint8_t direction, uint64_t start, uint64_t end);
72bbfa0259Sha137994 static int i_ldc_mem_map(ldc_mem_handle_t mhandle, ldc_mem_cookie_t *cookie,
73bbfa0259Sha137994     uint32_t ccount, uint8_t mtype, uint8_t perm, caddr_t *vaddr,
74bbfa0259Sha137994     caddr_t *raddr);
75bbfa0259Sha137994 static int i_ldc_mem_bind_handle(ldc_mem_handle_t mhandle, caddr_t vaddr,
76bbfa0259Sha137994     size_t len, uint8_t mtype, uint8_t perm, ldc_mem_cookie_t *cookie,
77bbfa0259Sha137994     uint32_t *ccount);
7820ae46ebSha137994 
7920ae46ebSha137994 /*
8020ae46ebSha137994  * LDC framework supports mapping remote domain's memory
8120ae46ebSha137994  * either directly or via shadow memory pages. Default
8220ae46ebSha137994  * support is currently implemented via shadow copy.
8320ae46ebSha137994  * Direct map can be enabled by setting 'ldc_shmem_enabled'
8420ae46ebSha137994  */
85*34f94fbcSWENTAO YANG int ldc_shmem_enabled = 1;
8620ae46ebSha137994 
8720ae46ebSha137994 /*
88bbfa0259Sha137994  * Use of directly mapped shared memory for LDC descriptor
89bbfa0259Sha137994  * rings is permitted if this variable is non-zero.
90bbfa0259Sha137994  */
91bbfa0259Sha137994 int ldc_dring_shmem_enabled = 1;
92bbfa0259Sha137994 
93bbfa0259Sha137994 /*
94bbfa0259Sha137994  * The major and minor versions required to use directly
95bbfa0259Sha137994  * mapped shared memory for LDC descriptor rings. The
96bbfa0259Sha137994  * ldc_dring_shmem_hv_force variable, if set to a non-zero
97bbfa0259Sha137994  * value, overrides the hypervisor API version check.
98bbfa0259Sha137994  */
99bbfa0259Sha137994 static int ldc_dring_shmem_hv_major = 1;
100bbfa0259Sha137994 static int ldc_dring_shmem_hv_minor = 1;
101bbfa0259Sha137994 static int ldc_dring_shmem_hv_force = 0;
102bbfa0259Sha137994 
103bbfa0259Sha137994 /*
104bbfa0259Sha137994  * The results of the hypervisor service group API check.
105bbfa0259Sha137994  * A non-zero value indicates the HV includes support for
106bbfa0259Sha137994  * descriptor ring shared memory.
107bbfa0259Sha137994  */
108bbfa0259Sha137994 static int ldc_dring_shmem_hv_ok = 0;
109bbfa0259Sha137994 
110bbfa0259Sha137994 /*
11120ae46ebSha137994  * Pages exported for remote access over each channel is
11220ae46ebSha137994  * maintained in a table registered with the Hypervisor.
11320ae46ebSha137994  * The default number of entries in the table is set to
11420ae46ebSha137994  * 'ldc_mtbl_entries'.
11520ae46ebSha137994  */
11620ae46ebSha137994 uint64_t ldc_maptable_entries = LDC_MTBL_ENTRIES;
11720ae46ebSha137994 
11820ae46ebSha137994 #define	IDX2COOKIE(idx, pg_szc, pg_shift)				\
11920ae46ebSha137994 	(((pg_szc) << LDC_COOKIE_PGSZC_SHIFT) | ((idx) << (pg_shift)))
12020ae46ebSha137994 
12120ae46ebSha137994 /*
122*34f94fbcSWENTAO YANG  * Pages imported over each channel are maintained in a global (per-guest)
123*34f94fbcSWENTAO YANG  * mapin table. Starting with HV LDC API version 1.2, HV supports APIs to
124*34f94fbcSWENTAO YANG  * obtain information about the total size of the memory that can be direct
125*34f94fbcSWENTAO YANG  * mapped through this mapin table. The minimum size of the mapin area that we
126*34f94fbcSWENTAO YANG  * expect is defined below.
127*34f94fbcSWENTAO YANG  */
128*34f94fbcSWENTAO YANG #define	GIGABYTE		((uint64_t)(1 << 30))
129*34f94fbcSWENTAO YANG uint64_t ldc_mapin_size_min = GIGABYTE;
130*34f94fbcSWENTAO YANG 
131*34f94fbcSWENTAO YANG /* HV LDC API version that supports mapin size info */
132*34f94fbcSWENTAO YANG #define	LDC_MAPIN_VER_MAJOR	1
133*34f94fbcSWENTAO YANG #define	LDC_MAPIN_VER_MINOR	2
134*34f94fbcSWENTAO YANG 
135*34f94fbcSWENTAO YANG /*
136bbfa0259Sha137994  * Sets ldc_dring_shmem_hv_ok to a non-zero value if the HV LDC
137bbfa0259Sha137994  * API version supports directly mapped shared memory or if it has
138bbfa0259Sha137994  * been explicitly enabled via ldc_dring_shmem_hv_force.
139bbfa0259Sha137994  */
140bbfa0259Sha137994 void
141bbfa0259Sha137994 i_ldc_mem_set_hsvc_vers(uint64_t major, uint64_t minor)
142bbfa0259Sha137994 {
143bbfa0259Sha137994 	if ((major == ldc_dring_shmem_hv_major &&
144bbfa0259Sha137994 	    minor >= ldc_dring_shmem_hv_minor) ||
145bbfa0259Sha137994 	    (major > ldc_dring_shmem_hv_major) ||
146bbfa0259Sha137994 	    (ldc_dring_shmem_hv_force != 0)) {
147bbfa0259Sha137994 		ldc_dring_shmem_hv_ok = 1;
148bbfa0259Sha137994 	}
149bbfa0259Sha137994 }
150bbfa0259Sha137994 
151bbfa0259Sha137994 /*
152*34f94fbcSWENTAO YANG  * initialize mapin table.
153*34f94fbcSWENTAO YANG  */
154*34f94fbcSWENTAO YANG void
155*34f94fbcSWENTAO YANG i_ldc_init_mapin(ldc_soft_state_t *ldcssp, uint64_t major, uint64_t minor)
156*34f94fbcSWENTAO YANG {
157*34f94fbcSWENTAO YANG 	int		rv;
158*34f94fbcSWENTAO YANG 	uint64_t	sz;
159*34f94fbcSWENTAO YANG 	uint64_t	table_type = LDC_MAPIN_TYPE_REGULAR;
160*34f94fbcSWENTAO YANG 
161*34f94fbcSWENTAO YANG 	/* set mapin size to default. */
162*34f94fbcSWENTAO YANG 	ldcssp->mapin_size = LDC_DIRECT_MAP_SIZE_DEFAULT;
163*34f94fbcSWENTAO YANG 
164*34f94fbcSWENTAO YANG 	/* Check if the HV supports mapin size API. */
165*34f94fbcSWENTAO YANG 	if ((major == LDC_MAPIN_VER_MAJOR &&
166*34f94fbcSWENTAO YANG 	    minor < LDC_MAPIN_VER_MINOR) ||
167*34f94fbcSWENTAO YANG 	    (major < LDC_MAPIN_VER_MAJOR)) {
168*34f94fbcSWENTAO YANG 		/* Older version of HV. */
169*34f94fbcSWENTAO YANG 		return;
170*34f94fbcSWENTAO YANG 	}
171*34f94fbcSWENTAO YANG 
172*34f94fbcSWENTAO YANG 	/* Get info about the mapin size supported by HV */
173*34f94fbcSWENTAO YANG 	rv = hv_ldc_mapin_size_max(table_type, &sz);
174*34f94fbcSWENTAO YANG 	if (rv != 0) {
175*34f94fbcSWENTAO YANG 		cmn_err(CE_NOTE, "Failed to get mapin information\n");
176*34f94fbcSWENTAO YANG 		return;
177*34f94fbcSWENTAO YANG 	}
178*34f94fbcSWENTAO YANG 
179*34f94fbcSWENTAO YANG 	/* Save the table size */
180*34f94fbcSWENTAO YANG 	ldcssp->mapin_size = sz;
181*34f94fbcSWENTAO YANG 
182*34f94fbcSWENTAO YANG 	D1(DBG_ALL_LDCS, "%s: mapin_size read from HV is (0x%llx)\n",
183*34f94fbcSWENTAO YANG 	    __func__, sz);
184*34f94fbcSWENTAO YANG }
185*34f94fbcSWENTAO YANG 
186*34f94fbcSWENTAO YANG /*
18720ae46ebSha137994  * Allocate a memory handle for the channel and link it into the list
18820ae46ebSha137994  * Also choose which memory table to use if this is the first handle
18920ae46ebSha137994  * being assigned to this channel
19020ae46ebSha137994  */
19120ae46ebSha137994 int
19220ae46ebSha137994 ldc_mem_alloc_handle(ldc_handle_t handle, ldc_mem_handle_t *mhandle)
19320ae46ebSha137994 {
19420ae46ebSha137994 	ldc_chan_t 	*ldcp;
19520ae46ebSha137994 	ldc_mhdl_t	*mhdl;
19620ae46ebSha137994 
19720ae46ebSha137994 	if (handle == NULL) {
19820ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
19920ae46ebSha137994 		    "ldc_mem_alloc_handle: invalid channel handle\n");
20020ae46ebSha137994 		return (EINVAL);
20120ae46ebSha137994 	}
20220ae46ebSha137994 	ldcp = (ldc_chan_t *)handle;
20320ae46ebSha137994 
20420ae46ebSha137994 	mutex_enter(&ldcp->lock);
20520ae46ebSha137994 
20620ae46ebSha137994 	/* check to see if channel is initalized */
20720ae46ebSha137994 	if ((ldcp->tstate & ~TS_IN_RESET) < TS_INIT) {
20820ae46ebSha137994 		DWARN(ldcp->id,
20920ae46ebSha137994 		    "ldc_mem_alloc_handle: (0x%llx) channel not initialized\n",
21020ae46ebSha137994 		    ldcp->id);
21120ae46ebSha137994 		mutex_exit(&ldcp->lock);
21220ae46ebSha137994 		return (EINVAL);
21320ae46ebSha137994 	}
21420ae46ebSha137994 
21520ae46ebSha137994 	/* allocate handle for channel */
21620ae46ebSha137994 	mhdl = kmem_cache_alloc(ldcssp->memhdl_cache, KM_SLEEP);
21720ae46ebSha137994 
21820ae46ebSha137994 	/* initialize the lock */
21920ae46ebSha137994 	mutex_init(&mhdl->lock, NULL, MUTEX_DRIVER, NULL);
22020ae46ebSha137994 
22120ae46ebSha137994 	mhdl->myshadow = B_FALSE;
22220ae46ebSha137994 	mhdl->memseg = NULL;
22320ae46ebSha137994 	mhdl->ldcp = ldcp;
22420ae46ebSha137994 	mhdl->status = LDC_UNBOUND;
22520ae46ebSha137994 
22620ae46ebSha137994 	/* insert memory handle (@ head) into list */
22720ae46ebSha137994 	if (ldcp->mhdl_list == NULL) {
22820ae46ebSha137994 		ldcp->mhdl_list = mhdl;
22920ae46ebSha137994 		mhdl->next = NULL;
23020ae46ebSha137994 	} else {
23120ae46ebSha137994 		/* insert @ head */
23220ae46ebSha137994 		mhdl->next = ldcp->mhdl_list;
23320ae46ebSha137994 		ldcp->mhdl_list = mhdl;
23420ae46ebSha137994 	}
23520ae46ebSha137994 
23620ae46ebSha137994 	/* return the handle */
23720ae46ebSha137994 	*mhandle = (ldc_mem_handle_t)mhdl;
23820ae46ebSha137994 
23920ae46ebSha137994 	mutex_exit(&ldcp->lock);
24020ae46ebSha137994 
24120ae46ebSha137994 	D1(ldcp->id, "ldc_mem_alloc_handle: (0x%llx) allocated handle 0x%llx\n",
24220ae46ebSha137994 	    ldcp->id, mhdl);
24320ae46ebSha137994 
24420ae46ebSha137994 	return (0);
24520ae46ebSha137994 }
24620ae46ebSha137994 
24720ae46ebSha137994 /*
24820ae46ebSha137994  * Free memory handle for the channel and unlink it from the list
24920ae46ebSha137994  */
25020ae46ebSha137994 int
25120ae46ebSha137994 ldc_mem_free_handle(ldc_mem_handle_t mhandle)
25220ae46ebSha137994 {
25320ae46ebSha137994 	ldc_mhdl_t 	*mhdl, *phdl;
25420ae46ebSha137994 	ldc_chan_t 	*ldcp;
25520ae46ebSha137994 
25620ae46ebSha137994 	if (mhandle == NULL) {
25720ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
25820ae46ebSha137994 		    "ldc_mem_free_handle: invalid memory handle\n");
25920ae46ebSha137994 		return (EINVAL);
26020ae46ebSha137994 	}
26120ae46ebSha137994 	mhdl = (ldc_mhdl_t *)mhandle;
26220ae46ebSha137994 
26320ae46ebSha137994 	mutex_enter(&mhdl->lock);
26420ae46ebSha137994 
26520ae46ebSha137994 	ldcp = mhdl->ldcp;
26620ae46ebSha137994 
26720ae46ebSha137994 	if (mhdl->status == LDC_BOUND || mhdl->status == LDC_MAPPED) {
26820ae46ebSha137994 		DWARN(ldcp->id,
26920ae46ebSha137994 		    "ldc_mem_free_handle: cannot free, 0x%llx hdl bound\n",
27020ae46ebSha137994 		    mhdl);
27120ae46ebSha137994 		mutex_exit(&mhdl->lock);
27220ae46ebSha137994 		return (EINVAL);
27320ae46ebSha137994 	}
27420ae46ebSha137994 	mutex_exit(&mhdl->lock);
27520ae46ebSha137994 
27620ae46ebSha137994 	mutex_enter(&ldcp->mlist_lock);
27720ae46ebSha137994 
27820ae46ebSha137994 	phdl = ldcp->mhdl_list;
27920ae46ebSha137994 
28020ae46ebSha137994 	/* first handle */
28120ae46ebSha137994 	if (phdl == mhdl) {
28220ae46ebSha137994 		ldcp->mhdl_list = mhdl->next;
28320ae46ebSha137994 		mutex_destroy(&mhdl->lock);
28420ae46ebSha137994 		kmem_cache_free(ldcssp->memhdl_cache, mhdl);
28520ae46ebSha137994 
28620ae46ebSha137994 		D1(ldcp->id,
28720ae46ebSha137994 		    "ldc_mem_free_handle: (0x%llx) freed handle 0x%llx\n",
28820ae46ebSha137994 		    ldcp->id, mhdl);
28920ae46ebSha137994 	} else {
29020ae46ebSha137994 		/* walk the list - unlink and free */
29120ae46ebSha137994 		while (phdl != NULL) {
29220ae46ebSha137994 			if (phdl->next == mhdl) {
29320ae46ebSha137994 				phdl->next = mhdl->next;
29420ae46ebSha137994 				mutex_destroy(&mhdl->lock);
29520ae46ebSha137994 				kmem_cache_free(ldcssp->memhdl_cache, mhdl);
29620ae46ebSha137994 				D1(ldcp->id,
29720ae46ebSha137994 				    "ldc_mem_free_handle: (0x%llx) freed "
29820ae46ebSha137994 				    "handle 0x%llx\n", ldcp->id, mhdl);
29920ae46ebSha137994 				break;
30020ae46ebSha137994 			}
30120ae46ebSha137994 			phdl = phdl->next;
30220ae46ebSha137994 		}
30320ae46ebSha137994 	}
30420ae46ebSha137994 
30520ae46ebSha137994 	if (phdl == NULL) {
30620ae46ebSha137994 		DWARN(ldcp->id,
30720ae46ebSha137994 		    "ldc_mem_free_handle: invalid handle 0x%llx\n", mhdl);
30820ae46ebSha137994 		mutex_exit(&ldcp->mlist_lock);
30920ae46ebSha137994 		return (EINVAL);
31020ae46ebSha137994 	}
31120ae46ebSha137994 
31220ae46ebSha137994 	mutex_exit(&ldcp->mlist_lock);
31320ae46ebSha137994 
31420ae46ebSha137994 	return (0);
31520ae46ebSha137994 }
31620ae46ebSha137994 
31720ae46ebSha137994 /*
31820ae46ebSha137994  * Bind a memory handle to a virtual address.
31920ae46ebSha137994  * The virtual address is converted to the corresponding real addresses.
32020ae46ebSha137994  * Returns pointer to the first ldc_mem_cookie and the total number
32120ae46ebSha137994  * of cookies for this virtual address. Other cookies can be obtained
32220ae46ebSha137994  * using the ldc_mem_nextcookie() call. If the pages are stored in
32320ae46ebSha137994  * consecutive locations in the table, a single cookie corresponding to
32420ae46ebSha137994  * the first location is returned. The cookie size spans all the entries.
32520ae46ebSha137994  *
32620ae46ebSha137994  * If the VA corresponds to a page that is already being exported, reuse
32720ae46ebSha137994  * the page and do not export it again. Bump the page's use count.
32820ae46ebSha137994  */
32920ae46ebSha137994 int
33020ae46ebSha137994 ldc_mem_bind_handle(ldc_mem_handle_t mhandle, caddr_t vaddr, size_t len,
33120ae46ebSha137994     uint8_t mtype, uint8_t perm, ldc_mem_cookie_t *cookie, uint32_t *ccount)
33220ae46ebSha137994 {
333bbfa0259Sha137994 	/*
334bbfa0259Sha137994 	 * Check if direct shared memory map is enabled, if not change
335bbfa0259Sha137994 	 * the mapping type to SHADOW_MAP.
336bbfa0259Sha137994 	 */
337bbfa0259Sha137994 	if (ldc_shmem_enabled == 0)
338bbfa0259Sha137994 		mtype = LDC_SHADOW_MAP;
339bbfa0259Sha137994 
340bbfa0259Sha137994 	return (i_ldc_mem_bind_handle(mhandle, vaddr, len, mtype, perm,
341bbfa0259Sha137994 	    cookie, ccount));
342bbfa0259Sha137994 }
343bbfa0259Sha137994 
344bbfa0259Sha137994 static int
345bbfa0259Sha137994 i_ldc_mem_bind_handle(ldc_mem_handle_t mhandle, caddr_t vaddr, size_t len,
346bbfa0259Sha137994     uint8_t mtype, uint8_t perm, ldc_mem_cookie_t *cookie, uint32_t *ccount)
347bbfa0259Sha137994 {
34820ae46ebSha137994 	ldc_mhdl_t	*mhdl;
34920ae46ebSha137994 	ldc_chan_t 	*ldcp;
35020ae46ebSha137994 	ldc_mtbl_t	*mtbl;
35120ae46ebSha137994 	ldc_memseg_t	*memseg;
35220ae46ebSha137994 	ldc_mte_t	tmp_mte;
35320ae46ebSha137994 	uint64_t	index, prev_index = 0;
35420ae46ebSha137994 	int64_t		cookie_idx;
35520ae46ebSha137994 	uintptr_t	raddr, ra_aligned;
35620ae46ebSha137994 	uint64_t	psize, poffset, v_offset;
35720ae46ebSha137994 	uint64_t	pg_shift, pg_size, pg_size_code, pg_mask;
35820ae46ebSha137994 	pgcnt_t		npages;
35920ae46ebSha137994 	caddr_t		v_align, addr;
36020ae46ebSha137994 	int 		i, rv;
36120ae46ebSha137994 
36220ae46ebSha137994 	if (mhandle == NULL) {
36320ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
36420ae46ebSha137994 		    "ldc_mem_bind_handle: invalid memory handle\n");
36520ae46ebSha137994 		return (EINVAL);
36620ae46ebSha137994 	}
36720ae46ebSha137994 	mhdl = (ldc_mhdl_t *)mhandle;
36820ae46ebSha137994 	ldcp = mhdl->ldcp;
36920ae46ebSha137994 
37020ae46ebSha137994 	/* clear count */
37120ae46ebSha137994 	*ccount = 0;
37220ae46ebSha137994 
37320ae46ebSha137994 	mutex_enter(&mhdl->lock);
37420ae46ebSha137994 
37520ae46ebSha137994 	if (mhdl->status == LDC_BOUND || mhdl->memseg != NULL) {
37620ae46ebSha137994 		DWARN(ldcp->id,
37720ae46ebSha137994 		    "ldc_mem_bind_handle: (0x%x) handle already bound\n",
37820ae46ebSha137994 		    mhandle);
37920ae46ebSha137994 		mutex_exit(&mhdl->lock);
38020ae46ebSha137994 		return (EINVAL);
38120ae46ebSha137994 	}
38220ae46ebSha137994 
38320ae46ebSha137994 	/* Force address and size to be 8-byte aligned */
38420ae46ebSha137994 	if ((((uintptr_t)vaddr | len) & 0x7) != 0) {
38520ae46ebSha137994 		DWARN(ldcp->id,
38620ae46ebSha137994 		    "ldc_mem_bind_handle: addr/size is not 8-byte aligned\n");
38720ae46ebSha137994 		mutex_exit(&mhdl->lock);
38820ae46ebSha137994 		return (EINVAL);
38920ae46ebSha137994 	}
39020ae46ebSha137994 
391bbfa0259Sha137994 	mutex_enter(&ldcp->lock);
392bbfa0259Sha137994 
39320ae46ebSha137994 	/*
39420ae46ebSha137994 	 * If this channel is binding a memory handle for the
39520ae46ebSha137994 	 * first time allocate it a memory map table and initialize it
39620ae46ebSha137994 	 */
39720ae46ebSha137994 	if ((mtbl = ldcp->mtbl) == NULL) {
39820ae46ebSha137994 
39920ae46ebSha137994 		/* Allocate and initialize the map table structure */
40020ae46ebSha137994 		mtbl = kmem_zalloc(sizeof (ldc_mtbl_t), KM_SLEEP);
40120ae46ebSha137994 		mtbl->num_entries = mtbl->num_avail = ldc_maptable_entries;
40220ae46ebSha137994 		mtbl->size = ldc_maptable_entries * sizeof (ldc_mte_slot_t);
40320ae46ebSha137994 		mtbl->next_entry = NULL;
40420ae46ebSha137994 		mtbl->contigmem = B_TRUE;
40520ae46ebSha137994 
40620ae46ebSha137994 		/* Allocate the table itself */
40720ae46ebSha137994 		mtbl->table = (ldc_mte_slot_t *)
40820ae46ebSha137994 		    contig_mem_alloc_align(mtbl->size, MMU_PAGESIZE);
40920ae46ebSha137994 		if (mtbl->table == NULL) {
41020ae46ebSha137994 
41120ae46ebSha137994 			/* allocate a page of memory using kmem_alloc */
41220ae46ebSha137994 			mtbl->table = kmem_alloc(MMU_PAGESIZE, KM_SLEEP);
41320ae46ebSha137994 			mtbl->size = MMU_PAGESIZE;
41420ae46ebSha137994 			mtbl->contigmem = B_FALSE;
41520ae46ebSha137994 			mtbl->num_entries = mtbl->num_avail =
41620ae46ebSha137994 			    mtbl->size / sizeof (ldc_mte_slot_t);
41720ae46ebSha137994 			DWARN(ldcp->id,
41820ae46ebSha137994 			    "ldc_mem_bind_handle: (0x%llx) reduced tbl size "
41920ae46ebSha137994 			    "to %lx entries\n", ldcp->id, mtbl->num_entries);
42020ae46ebSha137994 		}
42120ae46ebSha137994 
42220ae46ebSha137994 		/* zero out the memory */
42320ae46ebSha137994 		bzero(mtbl->table, mtbl->size);
42420ae46ebSha137994 
42520ae46ebSha137994 		/* initialize the lock */
42620ae46ebSha137994 		mutex_init(&mtbl->lock, NULL, MUTEX_DRIVER, NULL);
42720ae46ebSha137994 
42820ae46ebSha137994 		/* register table for this channel */
42920ae46ebSha137994 		rv = hv_ldc_set_map_table(ldcp->id,
43020ae46ebSha137994 		    va_to_pa(mtbl->table), mtbl->num_entries);
43120ae46ebSha137994 		if (rv != 0) {
432bbfa0259Sha137994 			DWARN(DBG_ALL_LDCS,
43320ae46ebSha137994 			    "ldc_mem_bind_handle: (0x%lx) err %d mapping tbl",
43420ae46ebSha137994 			    ldcp->id, rv);
43520ae46ebSha137994 			if (mtbl->contigmem)
43620ae46ebSha137994 				contig_mem_free(mtbl->table, mtbl->size);
43720ae46ebSha137994 			else
43820ae46ebSha137994 				kmem_free(mtbl->table, mtbl->size);
43920ae46ebSha137994 			mutex_destroy(&mtbl->lock);
44020ae46ebSha137994 			kmem_free(mtbl, sizeof (ldc_mtbl_t));
44120ae46ebSha137994 			mutex_exit(&ldcp->lock);
44220ae46ebSha137994 			mutex_exit(&mhdl->lock);
44320ae46ebSha137994 			return (EIO);
44420ae46ebSha137994 		}
44520ae46ebSha137994 
44620ae46ebSha137994 		ldcp->mtbl = mtbl;
44720ae46ebSha137994 
44820ae46ebSha137994 		D1(ldcp->id,
44920ae46ebSha137994 		    "ldc_mem_bind_handle: (0x%llx) alloc'd map table 0x%llx\n",
45020ae46ebSha137994 		    ldcp->id, ldcp->mtbl->table);
45120ae46ebSha137994 	}
45220ae46ebSha137994 
453bbfa0259Sha137994 	mutex_exit(&ldcp->lock);
454bbfa0259Sha137994 
45520ae46ebSha137994 	/* FUTURE: get the page size, pgsz code, and shift */
45620ae46ebSha137994 	pg_size = MMU_PAGESIZE;
45720ae46ebSha137994 	pg_size_code = page_szc(pg_size);
45820ae46ebSha137994 	pg_shift = page_get_shift(pg_size_code);
45920ae46ebSha137994 	pg_mask = ~(pg_size - 1);
46020ae46ebSha137994 
46120ae46ebSha137994 	D1(ldcp->id, "ldc_mem_bind_handle: (0x%llx) binding "
46220ae46ebSha137994 	    "va 0x%llx pgsz=0x%llx, pgszc=0x%llx, pg_shift=0x%llx\n",
46320ae46ebSha137994 	    ldcp->id, vaddr, pg_size, pg_size_code, pg_shift);
46420ae46ebSha137994 
46520ae46ebSha137994 	/* aligned VA and its offset */
46620ae46ebSha137994 	v_align = (caddr_t)(((uintptr_t)vaddr) & ~(pg_size - 1));
46720ae46ebSha137994 	v_offset = ((uintptr_t)vaddr) & (pg_size - 1);
46820ae46ebSha137994 
46920ae46ebSha137994 	npages = (len+v_offset)/pg_size;
47020ae46ebSha137994 	npages = ((len+v_offset)%pg_size == 0) ? npages : npages+1;
47120ae46ebSha137994 
47220ae46ebSha137994 	D1(ldcp->id, "ldc_mem_bind_handle: binding "
47320ae46ebSha137994 	    "(0x%llx) v=0x%llx,val=0x%llx,off=0x%x,pgs=0x%x\n",
47420ae46ebSha137994 	    ldcp->id, vaddr, v_align, v_offset, npages);
47520ae46ebSha137994 
47620ae46ebSha137994 	/* lock the memory table - exclusive access to channel */
47720ae46ebSha137994 	mutex_enter(&mtbl->lock);
47820ae46ebSha137994 
47920ae46ebSha137994 	if (npages > mtbl->num_avail) {
48020ae46ebSha137994 		D1(ldcp->id, "ldc_mem_bind_handle: (0x%llx) no table entries\n",
48120ae46ebSha137994 		    ldcp->id);
48220ae46ebSha137994 		mutex_exit(&mtbl->lock);
48320ae46ebSha137994 		mutex_exit(&mhdl->lock);
48420ae46ebSha137994 		return (ENOMEM);
48520ae46ebSha137994 	}
48620ae46ebSha137994 
48720ae46ebSha137994 	/* Allocate a memseg structure */
48820ae46ebSha137994 	memseg = mhdl->memseg =
48920ae46ebSha137994 	    kmem_cache_alloc(ldcssp->memseg_cache, KM_SLEEP);
49020ae46ebSha137994 
49120ae46ebSha137994 	/* Allocate memory to store all pages and cookies */
49220ae46ebSha137994 	memseg->pages = kmem_zalloc((sizeof (ldc_page_t) * npages), KM_SLEEP);
49320ae46ebSha137994 	memseg->cookies =
49420ae46ebSha137994 	    kmem_zalloc((sizeof (ldc_mem_cookie_t) * npages), KM_SLEEP);
49520ae46ebSha137994 
49620ae46ebSha137994 	D2(ldcp->id, "ldc_mem_bind_handle: (0x%llx) processing 0x%llx pages\n",
49720ae46ebSha137994 	    ldcp->id, npages);
49820ae46ebSha137994 
49920ae46ebSha137994 	addr = v_align;
50020ae46ebSha137994 
50120ae46ebSha137994 	/*
50220ae46ebSha137994 	 * Table slots are used in a round-robin manner. The algorithm permits
50320ae46ebSha137994 	 * inserting duplicate entries. Slots allocated earlier will typically
50420ae46ebSha137994 	 * get freed before we get back to reusing the slot.Inserting duplicate
50520ae46ebSha137994 	 * entries should be OK as we only lookup entries using the cookie addr
50620ae46ebSha137994 	 * i.e. tbl index, during export, unexport and copy operation.
50720ae46ebSha137994 	 *
50820ae46ebSha137994 	 * One implementation what was tried was to search for a duplicate
50920ae46ebSha137994 	 * page entry first and reuse it. The search overhead is very high and
51020ae46ebSha137994 	 * in the vnet case dropped the perf by almost half, 50 to 24 mbps.
51120ae46ebSha137994 	 * So it does make sense to avoid searching for duplicates.
51220ae46ebSha137994 	 *
51320ae46ebSha137994 	 * But during the process of searching for a free slot, if we find a
51420ae46ebSha137994 	 * duplicate entry we will go ahead and use it, and bump its use count.
51520ae46ebSha137994 	 */
51620ae46ebSha137994 
51720ae46ebSha137994 	/* index to start searching from */
51820ae46ebSha137994 	index = mtbl->next_entry;
51920ae46ebSha137994 	cookie_idx = -1;
52020ae46ebSha137994 
52120ae46ebSha137994 	tmp_mte.ll = 0;	/* initialise fields to 0 */
52220ae46ebSha137994 
52320ae46ebSha137994 	if (mtype & LDC_DIRECT_MAP) {
52420ae46ebSha137994 		tmp_mte.mte_r = (perm & LDC_MEM_R) ? 1 : 0;
52520ae46ebSha137994 		tmp_mte.mte_w = (perm & LDC_MEM_W) ? 1 : 0;
52620ae46ebSha137994 		tmp_mte.mte_x = (perm & LDC_MEM_X) ? 1 : 0;
52720ae46ebSha137994 	}
52820ae46ebSha137994 
52920ae46ebSha137994 	if (mtype & LDC_SHADOW_MAP) {
53020ae46ebSha137994 		tmp_mte.mte_cr = (perm & LDC_MEM_R) ? 1 : 0;
53120ae46ebSha137994 		tmp_mte.mte_cw = (perm & LDC_MEM_W) ? 1 : 0;
53220ae46ebSha137994 	}
53320ae46ebSha137994 
53420ae46ebSha137994 	if (mtype & LDC_IO_MAP) {
53520ae46ebSha137994 		tmp_mte.mte_ir = (perm & LDC_MEM_R) ? 1 : 0;
53620ae46ebSha137994 		tmp_mte.mte_iw = (perm & LDC_MEM_W) ? 1 : 0;
53720ae46ebSha137994 	}
53820ae46ebSha137994 
53920ae46ebSha137994 	D1(ldcp->id, "ldc_mem_bind_handle mte=0x%llx\n", tmp_mte.ll);
54020ae46ebSha137994 
54120ae46ebSha137994 	tmp_mte.mte_pgszc = pg_size_code;
54220ae46ebSha137994 
54320ae46ebSha137994 	/* initialize each mem table entry */
54420ae46ebSha137994 	for (i = 0; i < npages; i++) {
54520ae46ebSha137994 
54620ae46ebSha137994 		/* check if slot is available in the table */
54720ae46ebSha137994 		while (mtbl->table[index].entry.ll != 0) {
54820ae46ebSha137994 
54920ae46ebSha137994 			index = (index + 1) % mtbl->num_entries;
55020ae46ebSha137994 
55120ae46ebSha137994 			if (index == mtbl->next_entry) {
55220ae46ebSha137994 				/* we have looped around */
55320ae46ebSha137994 				DWARN(DBG_ALL_LDCS,
55420ae46ebSha137994 				    "ldc_mem_bind_handle: (0x%llx) cannot find "
55520ae46ebSha137994 				    "entry\n", ldcp->id);
55620ae46ebSha137994 				*ccount = 0;
55720ae46ebSha137994 
55820ae46ebSha137994 				/* NOTE: free memory, remove previous entries */
55920ae46ebSha137994 				/* this shouldnt happen as num_avail was ok */
56020ae46ebSha137994 
56120ae46ebSha137994 				mutex_exit(&mtbl->lock);
56220ae46ebSha137994 				mutex_exit(&mhdl->lock);
56320ae46ebSha137994 				return (ENOMEM);
56420ae46ebSha137994 			}
56520ae46ebSha137994 		}
56620ae46ebSha137994 
56720ae46ebSha137994 		/* get the real address */
56820ae46ebSha137994 		raddr = va_to_pa((void *)addr);
56920ae46ebSha137994 		ra_aligned = ((uintptr_t)raddr & pg_mask);
57020ae46ebSha137994 
57120ae46ebSha137994 		/* build the mte */
57220ae46ebSha137994 		tmp_mte.mte_rpfn = ra_aligned >> pg_shift;
57320ae46ebSha137994 
57420ae46ebSha137994 		D1(ldcp->id, "ldc_mem_bind_handle mte=0x%llx\n", tmp_mte.ll);
57520ae46ebSha137994 
57620ae46ebSha137994 		/* update entry in table */
57720ae46ebSha137994 		mtbl->table[index].entry = tmp_mte;
57820ae46ebSha137994 
57920ae46ebSha137994 		D2(ldcp->id, "ldc_mem_bind_handle: (0x%llx) stored MTE 0x%llx"
58020ae46ebSha137994 		    " into loc 0x%llx\n", ldcp->id, tmp_mte.ll, index);
58120ae46ebSha137994 
58220ae46ebSha137994 		/* calculate the size and offset for this export range */
58320ae46ebSha137994 		if (i == 0) {
58420ae46ebSha137994 			/* first page */
58520ae46ebSha137994 			psize = min((pg_size - v_offset), len);
58620ae46ebSha137994 			poffset = v_offset;
58720ae46ebSha137994 
58820ae46ebSha137994 		} else if (i == (npages - 1)) {
58920ae46ebSha137994 			/* last page */
59020ae46ebSha137994 			psize =	(((uintptr_t)(vaddr + len)) &
59120ae46ebSha137994 			    ((uint64_t)(pg_size-1)));
59220ae46ebSha137994 			if (psize == 0)
59320ae46ebSha137994 				psize = pg_size;
59420ae46ebSha137994 			poffset = 0;
59520ae46ebSha137994 
59620ae46ebSha137994 		} else {
59720ae46ebSha137994 			/* middle pages */
59820ae46ebSha137994 			psize = pg_size;
59920ae46ebSha137994 			poffset = 0;
60020ae46ebSha137994 		}
60120ae46ebSha137994 
60220ae46ebSha137994 		/* store entry for this page */
60320ae46ebSha137994 		memseg->pages[i].index = index;
60420ae46ebSha137994 		memseg->pages[i].raddr = raddr;
60520ae46ebSha137994 		memseg->pages[i].mte = &(mtbl->table[index]);
60620ae46ebSha137994 
60720ae46ebSha137994 		/* create the cookie */
60820ae46ebSha137994 		if (i == 0 || (index != prev_index + 1)) {
60920ae46ebSha137994 			cookie_idx++;
61020ae46ebSha137994 			memseg->cookies[cookie_idx].addr =
61120ae46ebSha137994 			    IDX2COOKIE(index, pg_size_code, pg_shift);
61220ae46ebSha137994 			memseg->cookies[cookie_idx].addr |= poffset;
61320ae46ebSha137994 			memseg->cookies[cookie_idx].size = psize;
61420ae46ebSha137994 
61520ae46ebSha137994 		} else {
61620ae46ebSha137994 			memseg->cookies[cookie_idx].size += psize;
61720ae46ebSha137994 		}
61820ae46ebSha137994 
61920ae46ebSha137994 		D1(ldcp->id, "ldc_mem_bind_handle: bound "
62020ae46ebSha137994 		    "(0x%llx) va=0x%llx, idx=0x%llx, "
62120ae46ebSha137994 		    "ra=0x%llx(sz=0x%x,off=0x%x)\n",
62220ae46ebSha137994 		    ldcp->id, addr, index, raddr, psize, poffset);
62320ae46ebSha137994 
62420ae46ebSha137994 		/* decrement number of available entries */
62520ae46ebSha137994 		mtbl->num_avail--;
62620ae46ebSha137994 
62720ae46ebSha137994 		/* increment va by page size */
62820ae46ebSha137994 		addr += pg_size;
62920ae46ebSha137994 
63020ae46ebSha137994 		/* increment index */
63120ae46ebSha137994 		prev_index = index;
63220ae46ebSha137994 		index = (index + 1) % mtbl->num_entries;
63320ae46ebSha137994 
63420ae46ebSha137994 		/* save the next slot */
63520ae46ebSha137994 		mtbl->next_entry = index;
63620ae46ebSha137994 	}
63720ae46ebSha137994 
63820ae46ebSha137994 	mutex_exit(&mtbl->lock);
63920ae46ebSha137994 
64020ae46ebSha137994 	/* memory handle = bound */
64120ae46ebSha137994 	mhdl->mtype = mtype;
64220ae46ebSha137994 	mhdl->perm = perm;
64320ae46ebSha137994 	mhdl->status = LDC_BOUND;
64420ae46ebSha137994 
64520ae46ebSha137994 	/* update memseg_t */
64620ae46ebSha137994 	memseg->vaddr = vaddr;
64720ae46ebSha137994 	memseg->raddr = memseg->pages[0].raddr;
64820ae46ebSha137994 	memseg->size = len;
64920ae46ebSha137994 	memseg->npages = npages;
65020ae46ebSha137994 	memseg->ncookies = cookie_idx + 1;
65120ae46ebSha137994 	memseg->next_cookie = (memseg->ncookies > 1) ? 1 : 0;
65220ae46ebSha137994 
65320ae46ebSha137994 	/* return count and first cookie */
65420ae46ebSha137994 	*ccount = memseg->ncookies;
65520ae46ebSha137994 	cookie->addr = memseg->cookies[0].addr;
65620ae46ebSha137994 	cookie->size = memseg->cookies[0].size;
65720ae46ebSha137994 
65820ae46ebSha137994 	D1(ldcp->id,
65920ae46ebSha137994 	    "ldc_mem_bind_handle: (0x%llx) bound 0x%llx, va=0x%llx, "
66020ae46ebSha137994 	    "pgs=0x%llx cookies=0x%llx\n",
66120ae46ebSha137994 	    ldcp->id, mhdl, vaddr, npages, memseg->ncookies);
66220ae46ebSha137994 
66320ae46ebSha137994 	mutex_exit(&mhdl->lock);
66420ae46ebSha137994 	return (0);
66520ae46ebSha137994 }
66620ae46ebSha137994 
66720ae46ebSha137994 /*
66820ae46ebSha137994  * Return the next cookie associated with the specified memory handle
66920ae46ebSha137994  */
67020ae46ebSha137994 int
67120ae46ebSha137994 ldc_mem_nextcookie(ldc_mem_handle_t mhandle, ldc_mem_cookie_t *cookie)
67220ae46ebSha137994 {
67320ae46ebSha137994 	ldc_mhdl_t	*mhdl;
67420ae46ebSha137994 	ldc_chan_t 	*ldcp;
67520ae46ebSha137994 	ldc_memseg_t	*memseg;
67620ae46ebSha137994 
67720ae46ebSha137994 	if (mhandle == NULL) {
67820ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
67920ae46ebSha137994 		    "ldc_mem_nextcookie: invalid memory handle\n");
68020ae46ebSha137994 		return (EINVAL);
68120ae46ebSha137994 	}
68220ae46ebSha137994 	mhdl = (ldc_mhdl_t *)mhandle;
68320ae46ebSha137994 
68420ae46ebSha137994 	mutex_enter(&mhdl->lock);
68520ae46ebSha137994 
68620ae46ebSha137994 	ldcp = mhdl->ldcp;
68720ae46ebSha137994 	memseg = mhdl->memseg;
68820ae46ebSha137994 
68920ae46ebSha137994 	if (cookie == 0) {
69020ae46ebSha137994 		DWARN(ldcp->id,
69120ae46ebSha137994 		    "ldc_mem_nextcookie:(0x%llx) invalid cookie arg\n",
69220ae46ebSha137994 		    ldcp->id);
69320ae46ebSha137994 		mutex_exit(&mhdl->lock);
69420ae46ebSha137994 		return (EINVAL);
69520ae46ebSha137994 	}
69620ae46ebSha137994 
69720ae46ebSha137994 	if (memseg->next_cookie != 0) {
69820ae46ebSha137994 		cookie->addr = memseg->cookies[memseg->next_cookie].addr;
69920ae46ebSha137994 		cookie->size = memseg->cookies[memseg->next_cookie].size;
70020ae46ebSha137994 		memseg->next_cookie++;
70120ae46ebSha137994 		if (memseg->next_cookie == memseg->ncookies)
70220ae46ebSha137994 			memseg->next_cookie = 0;
70320ae46ebSha137994 
70420ae46ebSha137994 	} else {
70520ae46ebSha137994 		DWARN(ldcp->id,
70620ae46ebSha137994 		    "ldc_mem_nextcookie:(0x%llx) no more cookies\n", ldcp->id);
70720ae46ebSha137994 		cookie->addr = 0;
70820ae46ebSha137994 		cookie->size = 0;
70920ae46ebSha137994 		mutex_exit(&mhdl->lock);
71020ae46ebSha137994 		return (EINVAL);
71120ae46ebSha137994 	}
71220ae46ebSha137994 
71320ae46ebSha137994 	D1(ldcp->id,
71420ae46ebSha137994 	    "ldc_mem_nextcookie: (0x%llx) cookie addr=0x%llx,sz=0x%llx\n",
71520ae46ebSha137994 	    ldcp->id, cookie->addr, cookie->size);
71620ae46ebSha137994 
71720ae46ebSha137994 	mutex_exit(&mhdl->lock);
71820ae46ebSha137994 	return (0);
71920ae46ebSha137994 }
72020ae46ebSha137994 
72120ae46ebSha137994 /*
72220ae46ebSha137994  * Unbind the virtual memory region associated with the specified
72320ae46ebSha137994  * memory handle. Allassociated cookies are freed and the corresponding
72420ae46ebSha137994  * RA space is no longer exported.
72520ae46ebSha137994  */
72620ae46ebSha137994 int
72720ae46ebSha137994 ldc_mem_unbind_handle(ldc_mem_handle_t mhandle)
72820ae46ebSha137994 {
72920ae46ebSha137994 	ldc_mhdl_t	*mhdl;
73020ae46ebSha137994 	ldc_chan_t 	*ldcp;
73120ae46ebSha137994 	ldc_mtbl_t	*mtbl;
73220ae46ebSha137994 	ldc_memseg_t	*memseg;
73320ae46ebSha137994 	uint64_t	cookie_addr;
73420ae46ebSha137994 	uint64_t	pg_shift, pg_size_code;
735bbfa0259Sha137994 	int		i, rv, retries;
73620ae46ebSha137994 
73720ae46ebSha137994 	if (mhandle == NULL) {
73820ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
73920ae46ebSha137994 		    "ldc_mem_unbind_handle: invalid memory handle\n");
74020ae46ebSha137994 		return (EINVAL);
74120ae46ebSha137994 	}
74220ae46ebSha137994 	mhdl = (ldc_mhdl_t *)mhandle;
74320ae46ebSha137994 
74420ae46ebSha137994 	mutex_enter(&mhdl->lock);
74520ae46ebSha137994 
74620ae46ebSha137994 	if (mhdl->status == LDC_UNBOUND) {
74720ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
74820ae46ebSha137994 		    "ldc_mem_unbind_handle: (0x%x) handle is not bound\n",
74920ae46ebSha137994 		    mhandle);
75020ae46ebSha137994 		mutex_exit(&mhdl->lock);
75120ae46ebSha137994 		return (EINVAL);
75220ae46ebSha137994 	}
75320ae46ebSha137994 
75420ae46ebSha137994 	ldcp = mhdl->ldcp;
75520ae46ebSha137994 	mtbl = ldcp->mtbl;
75620ae46ebSha137994 
75720ae46ebSha137994 	memseg = mhdl->memseg;
75820ae46ebSha137994 
75920ae46ebSha137994 	/* lock the memory table - exclusive access to channel */
76020ae46ebSha137994 	mutex_enter(&mtbl->lock);
76120ae46ebSha137994 
76220ae46ebSha137994 	/* undo the pages exported */
76320ae46ebSha137994 	for (i = 0; i < memseg->npages; i++) {
76420ae46ebSha137994 
765bbfa0259Sha137994 		/* clear the entry from the table */
766bbfa0259Sha137994 		memseg->pages[i].mte->entry.ll = 0;
767bbfa0259Sha137994 
76820ae46ebSha137994 		/* check for mapped pages, revocation cookie != 0 */
76920ae46ebSha137994 		if (memseg->pages[i].mte->cookie) {
77020ae46ebSha137994 
7715b7cb889Sha137994 			pg_size_code = page_szc(MMU_PAGESIZE);
772bbfa0259Sha137994 			pg_shift = page_get_shift(pg_size_code);
77320ae46ebSha137994 			cookie_addr = IDX2COOKIE(memseg->pages[i].index,
77420ae46ebSha137994 			    pg_size_code, pg_shift);
77520ae46ebSha137994 
77620ae46ebSha137994 			D1(ldcp->id, "ldc_mem_unbind_handle: (0x%llx) revoke "
77720ae46ebSha137994 			    "cookie 0x%llx, rcookie 0x%llx\n", ldcp->id,
77820ae46ebSha137994 			    cookie_addr, memseg->pages[i].mte->cookie);
779bbfa0259Sha137994 
780bbfa0259Sha137994 			retries = 0;
781bbfa0259Sha137994 			do {
78220ae46ebSha137994 				rv = hv_ldc_revoke(ldcp->id, cookie_addr,
78320ae46ebSha137994 				    memseg->pages[i].mte->cookie);
784bbfa0259Sha137994 
785bbfa0259Sha137994 				if (rv != H_EWOULDBLOCK)
786bbfa0259Sha137994 					break;
787bbfa0259Sha137994 
788bbfa0259Sha137994 				drv_usecwait(ldc_delay);
789bbfa0259Sha137994 
790bbfa0259Sha137994 			} while (retries++ < ldc_max_retries);
791bbfa0259Sha137994 
79220ae46ebSha137994 			if (rv) {
79320ae46ebSha137994 				DWARN(ldcp->id,
79420ae46ebSha137994 				    "ldc_mem_unbind_handle: (0x%llx) cannot "
79520ae46ebSha137994 				    "revoke mapping, cookie %llx\n", ldcp->id,
79620ae46ebSha137994 				    cookie_addr);
79720ae46ebSha137994 			}
79820ae46ebSha137994 		}
79920ae46ebSha137994 
80020ae46ebSha137994 		mtbl->num_avail++;
80120ae46ebSha137994 	}
80220ae46ebSha137994 	mutex_exit(&mtbl->lock);
80320ae46ebSha137994 
80420ae46ebSha137994 	/* free the allocated memseg and page structures */
80520ae46ebSha137994 	kmem_free(memseg->pages, (sizeof (ldc_page_t) * memseg->npages));
80620ae46ebSha137994 	kmem_free(memseg->cookies,
80720ae46ebSha137994 	    (sizeof (ldc_mem_cookie_t) * memseg->npages));
80820ae46ebSha137994 	kmem_cache_free(ldcssp->memseg_cache, memseg);
80920ae46ebSha137994 
81020ae46ebSha137994 	/* uninitialize the memory handle */
81120ae46ebSha137994 	mhdl->memseg = NULL;
81220ae46ebSha137994 	mhdl->status = LDC_UNBOUND;
81320ae46ebSha137994 
81420ae46ebSha137994 	D1(ldcp->id, "ldc_mem_unbind_handle: (0x%llx) unbound handle 0x%llx\n",
81520ae46ebSha137994 	    ldcp->id, mhdl);
81620ae46ebSha137994 
81720ae46ebSha137994 	mutex_exit(&mhdl->lock);
81820ae46ebSha137994 	return (0);
81920ae46ebSha137994 }
82020ae46ebSha137994 
82120ae46ebSha137994 /*
82220ae46ebSha137994  * Get information about the dring. The base address of the descriptor
82320ae46ebSha137994  * ring along with the type and permission are returned back.
82420ae46ebSha137994  */
82520ae46ebSha137994 int
82620ae46ebSha137994 ldc_mem_info(ldc_mem_handle_t mhandle, ldc_mem_info_t *minfo)
82720ae46ebSha137994 {
82820ae46ebSha137994 	ldc_mhdl_t	*mhdl;
82920ae46ebSha137994 
83020ae46ebSha137994 	if (mhandle == NULL) {
83120ae46ebSha137994 		DWARN(DBG_ALL_LDCS, "ldc_mem_info: invalid memory handle\n");
83220ae46ebSha137994 		return (EINVAL);
83320ae46ebSha137994 	}
83420ae46ebSha137994 	mhdl = (ldc_mhdl_t *)mhandle;
83520ae46ebSha137994 
83620ae46ebSha137994 	if (minfo == NULL) {
83720ae46ebSha137994 		DWARN(DBG_ALL_LDCS, "ldc_mem_info: invalid args\n");
83820ae46ebSha137994 		return (EINVAL);
83920ae46ebSha137994 	}
84020ae46ebSha137994 
84120ae46ebSha137994 	mutex_enter(&mhdl->lock);
84220ae46ebSha137994 
84320ae46ebSha137994 	minfo->status = mhdl->status;
84420ae46ebSha137994 	if (mhdl->status == LDC_BOUND || mhdl->status == LDC_MAPPED) {
84520ae46ebSha137994 		minfo->vaddr = mhdl->memseg->vaddr;
84620ae46ebSha137994 		minfo->raddr = mhdl->memseg->raddr;
84720ae46ebSha137994 		minfo->mtype = mhdl->mtype;
84820ae46ebSha137994 		minfo->perm = mhdl->perm;
84920ae46ebSha137994 	}
85020ae46ebSha137994 	mutex_exit(&mhdl->lock);
85120ae46ebSha137994 
85220ae46ebSha137994 	return (0);
85320ae46ebSha137994 }
85420ae46ebSha137994 
85520ae46ebSha137994 /*
85620ae46ebSha137994  * Copy data either from or to the client specified virtual address
85720ae46ebSha137994  * space to or from the exported memory associated with the cookies.
85820ae46ebSha137994  * The direction argument determines whether the data is read from or
85920ae46ebSha137994  * written to exported memory.
86020ae46ebSha137994  */
86120ae46ebSha137994 int
86220ae46ebSha137994 ldc_mem_copy(ldc_handle_t handle, caddr_t vaddr, uint64_t off, size_t *size,
86320ae46ebSha137994     ldc_mem_cookie_t *cookies, uint32_t ccount, uint8_t direction)
86420ae46ebSha137994 {
86520ae46ebSha137994 	ldc_chan_t 	*ldcp;
86620ae46ebSha137994 	uint64_t	local_voff, local_valign;
86720ae46ebSha137994 	uint64_t	cookie_addr, cookie_size;
86820ae46ebSha137994 	uint64_t	pg_shift, pg_size, pg_size_code;
86920ae46ebSha137994 	uint64_t 	export_caddr, export_poff, export_psize, export_size;
87020ae46ebSha137994 	uint64_t	local_ra, local_poff, local_psize;
87120ae46ebSha137994 	uint64_t	copy_size, copied_len = 0, total_bal = 0, idx = 0;
87220ae46ebSha137994 	pgcnt_t		npages;
87320ae46ebSha137994 	size_t		len = *size;
87420ae46ebSha137994 	int 		i, rv = 0;
87520ae46ebSha137994 
87620ae46ebSha137994 	uint64_t	chid;
87720ae46ebSha137994 
87820ae46ebSha137994 	if (handle == NULL) {
87920ae46ebSha137994 		DWARN(DBG_ALL_LDCS, "ldc_mem_copy: invalid channel handle\n");
88020ae46ebSha137994 		return (EINVAL);
88120ae46ebSha137994 	}
88220ae46ebSha137994 	ldcp = (ldc_chan_t *)handle;
88320ae46ebSha137994 	chid = ldcp->id;
88420ae46ebSha137994 
88520ae46ebSha137994 	/* check to see if channel is UP */
88620ae46ebSha137994 	if (ldcp->tstate != TS_UP) {
88720ae46ebSha137994 		DWARN(chid, "ldc_mem_copy: (0x%llx) channel is not UP\n",
88820ae46ebSha137994 		    chid);
88920ae46ebSha137994 		return (ECONNRESET);
89020ae46ebSha137994 	}
89120ae46ebSha137994 
89220ae46ebSha137994 	/* Force address and size to be 8-byte aligned */
89320ae46ebSha137994 	if ((((uintptr_t)vaddr | len) & 0x7) != 0) {
89420ae46ebSha137994 		DWARN(chid,
89520ae46ebSha137994 		    "ldc_mem_copy: addr/sz is not 8-byte aligned\n");
89620ae46ebSha137994 		return (EINVAL);
89720ae46ebSha137994 	}
89820ae46ebSha137994 
89920ae46ebSha137994 	/* Find the size of the exported memory */
90020ae46ebSha137994 	export_size = 0;
90120ae46ebSha137994 	for (i = 0; i < ccount; i++)
90220ae46ebSha137994 		export_size += cookies[i].size;
90320ae46ebSha137994 
90420ae46ebSha137994 	/* check to see if offset is valid */
90520ae46ebSha137994 	if (off > export_size) {
90620ae46ebSha137994 		DWARN(chid,
90720ae46ebSha137994 		    "ldc_mem_copy: (0x%llx) start offset > export mem size\n",
90820ae46ebSha137994 		    chid);
90920ae46ebSha137994 		return (EINVAL);
91020ae46ebSha137994 	}
91120ae46ebSha137994 
91220ae46ebSha137994 	/*
91320ae46ebSha137994 	 * Check to see if the export size is smaller than the size we
91420ae46ebSha137994 	 * are requesting to copy - if so flag an error
91520ae46ebSha137994 	 */
91620ae46ebSha137994 	if ((export_size - off) < *size) {
91720ae46ebSha137994 		DWARN(chid,
91820ae46ebSha137994 		    "ldc_mem_copy: (0x%llx) copy size > export mem size\n",
91920ae46ebSha137994 		    chid);
92020ae46ebSha137994 		return (EINVAL);
92120ae46ebSha137994 	}
92220ae46ebSha137994 
92320ae46ebSha137994 	total_bal = min(export_size, *size);
92420ae46ebSha137994 
92520ae46ebSha137994 	/* FUTURE: get the page size, pgsz code, and shift */
92620ae46ebSha137994 	pg_size = MMU_PAGESIZE;
92720ae46ebSha137994 	pg_size_code = page_szc(pg_size);
92820ae46ebSha137994 	pg_shift = page_get_shift(pg_size_code);
92920ae46ebSha137994 
93020ae46ebSha137994 	D1(chid, "ldc_mem_copy: copying data "
93120ae46ebSha137994 	    "(0x%llx) va 0x%llx pgsz=0x%llx, pgszc=0x%llx, pg_shift=0x%llx\n",
93220ae46ebSha137994 	    chid, vaddr, pg_size, pg_size_code, pg_shift);
93320ae46ebSha137994 
93420ae46ebSha137994 	/* aligned VA and its offset */
93520ae46ebSha137994 	local_valign = (((uintptr_t)vaddr) & ~(pg_size - 1));
93620ae46ebSha137994 	local_voff = ((uintptr_t)vaddr) & (pg_size - 1);
93720ae46ebSha137994 
93820ae46ebSha137994 	npages = (len+local_voff)/pg_size;
93920ae46ebSha137994 	npages = ((len+local_voff)%pg_size == 0) ? npages : npages+1;
94020ae46ebSha137994 
94120ae46ebSha137994 	D1(chid,
94220ae46ebSha137994 	    "ldc_mem_copy: (0x%llx) v=0x%llx,val=0x%llx,off=0x%x,pgs=0x%x\n",
94320ae46ebSha137994 	    chid, vaddr, local_valign, local_voff, npages);
94420ae46ebSha137994 
94520ae46ebSha137994 	local_ra = va_to_pa((void *)local_valign);
94620ae46ebSha137994 	local_poff = local_voff;
94720ae46ebSha137994 	local_psize = min(len, (pg_size - local_voff));
94820ae46ebSha137994 
94920ae46ebSha137994 	len -= local_psize;
95020ae46ebSha137994 
95120ae46ebSha137994 	/*
95220ae46ebSha137994 	 * find the first cookie in the list of cookies
95320ae46ebSha137994 	 * if the offset passed in is not zero
95420ae46ebSha137994 	 */
95520ae46ebSha137994 	for (idx = 0; idx < ccount; idx++) {
95620ae46ebSha137994 		cookie_size = cookies[idx].size;
95720ae46ebSha137994 		if (off < cookie_size)
95820ae46ebSha137994 			break;
95920ae46ebSha137994 		off -= cookie_size;
96020ae46ebSha137994 	}
96120ae46ebSha137994 
96220ae46ebSha137994 	cookie_addr = cookies[idx].addr + off;
96320ae46ebSha137994 	cookie_size = cookies[idx].size - off;
96420ae46ebSha137994 
96520ae46ebSha137994 	export_caddr = cookie_addr & ~(pg_size - 1);
96620ae46ebSha137994 	export_poff = cookie_addr & (pg_size - 1);
96720ae46ebSha137994 	export_psize = min(cookie_size, (pg_size - export_poff));
96820ae46ebSha137994 
96920ae46ebSha137994 	for (;;) {
97020ae46ebSha137994 
97120ae46ebSha137994 		copy_size = min(export_psize, local_psize);
97220ae46ebSha137994 
97320ae46ebSha137994 		D1(chid,
97420ae46ebSha137994 		    "ldc_mem_copy:(0x%llx) dir=0x%x, caddr=0x%llx,"
97520ae46ebSha137994 		    " loc_ra=0x%llx, exp_poff=0x%llx, loc_poff=0x%llx,"
97620ae46ebSha137994 		    " exp_psz=0x%llx, loc_psz=0x%llx, copy_sz=0x%llx,"
97720ae46ebSha137994 		    " total_bal=0x%llx\n",
97820ae46ebSha137994 		    chid, direction, export_caddr, local_ra, export_poff,
97920ae46ebSha137994 		    local_poff, export_psize, local_psize, copy_size,
98020ae46ebSha137994 		    total_bal);
98120ae46ebSha137994 
98220ae46ebSha137994 		rv = hv_ldc_copy(chid, direction,
98320ae46ebSha137994 		    (export_caddr + export_poff), (local_ra + local_poff),
98420ae46ebSha137994 		    copy_size, &copied_len);
98520ae46ebSha137994 
98620ae46ebSha137994 		if (rv != 0) {
98720ae46ebSha137994 			int 		error = EIO;
98820ae46ebSha137994 			uint64_t	rx_hd, rx_tl;
98920ae46ebSha137994 
99020ae46ebSha137994 			DWARN(chid,
99120ae46ebSha137994 			    "ldc_mem_copy: (0x%llx) err %d during copy\n",
99220ae46ebSha137994 			    (unsigned long long)chid, rv);
99320ae46ebSha137994 			DWARN(chid,
99420ae46ebSha137994 			    "ldc_mem_copy: (0x%llx) dir=0x%x, caddr=0x%lx, "
99520ae46ebSha137994 			    "loc_ra=0x%lx, exp_poff=0x%lx, loc_poff=0x%lx,"
99620ae46ebSha137994 			    " exp_psz=0x%lx, loc_psz=0x%lx, copy_sz=0x%lx,"
99720ae46ebSha137994 			    " copied_len=0x%lx, total_bal=0x%lx\n",
99820ae46ebSha137994 			    chid, direction, export_caddr, local_ra,
99920ae46ebSha137994 			    export_poff, local_poff, export_psize, local_psize,
100020ae46ebSha137994 			    copy_size, copied_len, total_bal);
100120ae46ebSha137994 
100220ae46ebSha137994 			*size = *size - total_bal;
100320ae46ebSha137994 
100420ae46ebSha137994 			/*
100520ae46ebSha137994 			 * check if reason for copy error was due to
100620ae46ebSha137994 			 * a channel reset. we need to grab the lock
100720ae46ebSha137994 			 * just in case we have to do a reset.
100820ae46ebSha137994 			 */
100920ae46ebSha137994 			mutex_enter(&ldcp->lock);
101020ae46ebSha137994 			mutex_enter(&ldcp->tx_lock);
101120ae46ebSha137994 
101220ae46ebSha137994 			rv = hv_ldc_rx_get_state(ldcp->id,
101320ae46ebSha137994 			    &rx_hd, &rx_tl, &(ldcp->link_state));
101420ae46ebSha137994 			if (ldcp->link_state == LDC_CHANNEL_DOWN ||
101520ae46ebSha137994 			    ldcp->link_state == LDC_CHANNEL_RESET) {
101620ae46ebSha137994 				i_ldc_reset(ldcp, B_FALSE);
101720ae46ebSha137994 				error = ECONNRESET;
101820ae46ebSha137994 			}
101920ae46ebSha137994 
102020ae46ebSha137994 			mutex_exit(&ldcp->tx_lock);
102120ae46ebSha137994 			mutex_exit(&ldcp->lock);
102220ae46ebSha137994 
102320ae46ebSha137994 			return (error);
102420ae46ebSha137994 		}
102520ae46ebSha137994 
102620ae46ebSha137994 		ASSERT(copied_len <= copy_size);
102720ae46ebSha137994 
102820ae46ebSha137994 		D2(chid, "ldc_mem_copy: copied=0x%llx\n", copied_len);
102920ae46ebSha137994 		export_poff += copied_len;
103020ae46ebSha137994 		local_poff += copied_len;
103120ae46ebSha137994 		export_psize -= copied_len;
103220ae46ebSha137994 		local_psize -= copied_len;
103320ae46ebSha137994 		cookie_size -= copied_len;
103420ae46ebSha137994 
103520ae46ebSha137994 		total_bal -= copied_len;
103620ae46ebSha137994 
103720ae46ebSha137994 		if (copy_size != copied_len)
103820ae46ebSha137994 			continue;
103920ae46ebSha137994 
104020ae46ebSha137994 		if (export_psize == 0 && total_bal != 0) {
104120ae46ebSha137994 
104220ae46ebSha137994 			if (cookie_size == 0) {
104320ae46ebSha137994 				idx++;
104420ae46ebSha137994 				cookie_addr = cookies[idx].addr;
104520ae46ebSha137994 				cookie_size = cookies[idx].size;
104620ae46ebSha137994 
104720ae46ebSha137994 				export_caddr = cookie_addr & ~(pg_size - 1);
104820ae46ebSha137994 				export_poff = cookie_addr & (pg_size - 1);
104920ae46ebSha137994 				export_psize =
105020ae46ebSha137994 				    min(cookie_size, (pg_size-export_poff));
105120ae46ebSha137994 			} else {
105220ae46ebSha137994 				export_caddr += pg_size;
105320ae46ebSha137994 				export_poff = 0;
105420ae46ebSha137994 				export_psize = min(cookie_size, pg_size);
105520ae46ebSha137994 			}
105620ae46ebSha137994 		}
105720ae46ebSha137994 
105820ae46ebSha137994 		if (local_psize == 0 && total_bal != 0) {
105920ae46ebSha137994 			local_valign += pg_size;
106020ae46ebSha137994 			local_ra = va_to_pa((void *)local_valign);
106120ae46ebSha137994 			local_poff = 0;
106220ae46ebSha137994 			local_psize = min(pg_size, len);
106320ae46ebSha137994 			len -= local_psize;
106420ae46ebSha137994 		}
106520ae46ebSha137994 
106620ae46ebSha137994 		/* check if we are all done */
106720ae46ebSha137994 		if (total_bal == 0)
106820ae46ebSha137994 			break;
106920ae46ebSha137994 	}
107020ae46ebSha137994 
107120ae46ebSha137994 
107220ae46ebSha137994 	D1(chid,
107320ae46ebSha137994 	    "ldc_mem_copy: (0x%llx) done copying sz=0x%llx\n",
107420ae46ebSha137994 	    chid, *size);
107520ae46ebSha137994 
107620ae46ebSha137994 	return (0);
107720ae46ebSha137994 }
107820ae46ebSha137994 
107920ae46ebSha137994 /*
108020ae46ebSha137994  * Copy data either from or to the client specified virtual address
108120ae46ebSha137994  * space to or from HV physical memory.
108220ae46ebSha137994  *
108320ae46ebSha137994  * The direction argument determines whether the data is read from or
108420ae46ebSha137994  * written to HV memory. direction values are LDC_COPY_IN/OUT similar
108520ae46ebSha137994  * to the ldc_mem_copy interface
108620ae46ebSha137994  */
108720ae46ebSha137994 int
108820ae46ebSha137994 ldc_mem_rdwr_cookie(ldc_handle_t handle, caddr_t vaddr, size_t *size,
108920ae46ebSha137994     caddr_t paddr, uint8_t direction)
109020ae46ebSha137994 {
109120ae46ebSha137994 	ldc_chan_t 	*ldcp;
109220ae46ebSha137994 	uint64_t	local_voff, local_valign;
109320ae46ebSha137994 	uint64_t	pg_shift, pg_size, pg_size_code;
109420ae46ebSha137994 	uint64_t 	target_pa, target_poff, target_psize, target_size;
109520ae46ebSha137994 	uint64_t	local_ra, local_poff, local_psize;
109620ae46ebSha137994 	uint64_t	copy_size, copied_len = 0;
109720ae46ebSha137994 	pgcnt_t		npages;
109820ae46ebSha137994 	size_t		len = *size;
109920ae46ebSha137994 	int 		rv = 0;
110020ae46ebSha137994 
110120ae46ebSha137994 	if (handle == NULL) {
110220ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
110320ae46ebSha137994 		    "ldc_mem_rdwr_cookie: invalid channel handle\n");
110420ae46ebSha137994 		return (EINVAL);
110520ae46ebSha137994 	}
110620ae46ebSha137994 	ldcp = (ldc_chan_t *)handle;
110720ae46ebSha137994 
110820ae46ebSha137994 	mutex_enter(&ldcp->lock);
110920ae46ebSha137994 
111020ae46ebSha137994 	/* check to see if channel is UP */
111120ae46ebSha137994 	if (ldcp->tstate != TS_UP) {
111220ae46ebSha137994 		DWARN(ldcp->id,
111320ae46ebSha137994 		    "ldc_mem_rdwr_cookie: (0x%llx) channel is not UP\n",
111420ae46ebSha137994 		    ldcp->id);
111520ae46ebSha137994 		mutex_exit(&ldcp->lock);
111620ae46ebSha137994 		return (ECONNRESET);
111720ae46ebSha137994 	}
111820ae46ebSha137994 
111920ae46ebSha137994 	/* Force address and size to be 8-byte aligned */
112020ae46ebSha137994 	if ((((uintptr_t)vaddr | len) & 0x7) != 0) {
112120ae46ebSha137994 		DWARN(ldcp->id,
112220ae46ebSha137994 		    "ldc_mem_rdwr_cookie: addr/size is not 8-byte aligned\n");
112320ae46ebSha137994 		mutex_exit(&ldcp->lock);
112420ae46ebSha137994 		return (EINVAL);
112520ae46ebSha137994 	}
112620ae46ebSha137994 
112720ae46ebSha137994 	target_size = *size;
112820ae46ebSha137994 
112920ae46ebSha137994 	/* FUTURE: get the page size, pgsz code, and shift */
113020ae46ebSha137994 	pg_size = MMU_PAGESIZE;
113120ae46ebSha137994 	pg_size_code = page_szc(pg_size);
113220ae46ebSha137994 	pg_shift = page_get_shift(pg_size_code);
113320ae46ebSha137994 
113420ae46ebSha137994 	D1(ldcp->id, "ldc_mem_rdwr_cookie: copying data "
113520ae46ebSha137994 	    "(0x%llx) va 0x%llx pgsz=0x%llx, pgszc=0x%llx, pg_shift=0x%llx\n",
113620ae46ebSha137994 	    ldcp->id, vaddr, pg_size, pg_size_code, pg_shift);
113720ae46ebSha137994 
113820ae46ebSha137994 	/* aligned VA and its offset */
113920ae46ebSha137994 	local_valign = ((uintptr_t)vaddr) & ~(pg_size - 1);
114020ae46ebSha137994 	local_voff = ((uintptr_t)vaddr) & (pg_size - 1);
114120ae46ebSha137994 
114220ae46ebSha137994 	npages = (len + local_voff) / pg_size;
114320ae46ebSha137994 	npages = ((len + local_voff) % pg_size == 0) ? npages : npages+1;
114420ae46ebSha137994 
114520ae46ebSha137994 	D1(ldcp->id, "ldc_mem_rdwr_cookie: (0x%llx) v=0x%llx, "
114620ae46ebSha137994 	    "val=0x%llx,off=0x%x,pgs=0x%x\n",
114720ae46ebSha137994 	    ldcp->id, vaddr, local_valign, local_voff, npages);
114820ae46ebSha137994 
114920ae46ebSha137994 	local_ra = va_to_pa((void *)local_valign);
115020ae46ebSha137994 	local_poff = local_voff;
115120ae46ebSha137994 	local_psize = min(len, (pg_size - local_voff));
115220ae46ebSha137994 
115320ae46ebSha137994 	len -= local_psize;
115420ae46ebSha137994 
115520ae46ebSha137994 	target_pa = ((uintptr_t)paddr) & ~(pg_size - 1);
115620ae46ebSha137994 	target_poff = ((uintptr_t)paddr) & (pg_size - 1);
115720ae46ebSha137994 	target_psize = pg_size - target_poff;
115820ae46ebSha137994 
115920ae46ebSha137994 	for (;;) {
116020ae46ebSha137994 
116120ae46ebSha137994 		copy_size = min(target_psize, local_psize);
116220ae46ebSha137994 
116320ae46ebSha137994 		D1(ldcp->id,
116420ae46ebSha137994 		    "ldc_mem_rdwr_cookie: (0x%llx) dir=0x%x, tar_pa=0x%llx,"
116520ae46ebSha137994 		    " loc_ra=0x%llx, tar_poff=0x%llx, loc_poff=0x%llx,"
116620ae46ebSha137994 		    " tar_psz=0x%llx, loc_psz=0x%llx, copy_sz=0x%llx,"
116720ae46ebSha137994 		    " total_bal=0x%llx\n",
116820ae46ebSha137994 		    ldcp->id, direction, target_pa, local_ra, target_poff,
116920ae46ebSha137994 		    local_poff, target_psize, local_psize, copy_size,
117020ae46ebSha137994 		    target_size);
117120ae46ebSha137994 
117220ae46ebSha137994 		rv = hv_ldc_copy(ldcp->id, direction,
117320ae46ebSha137994 		    (target_pa + target_poff), (local_ra + local_poff),
117420ae46ebSha137994 		    copy_size, &copied_len);
117520ae46ebSha137994 
117620ae46ebSha137994 		if (rv != 0) {
117720ae46ebSha137994 			DWARN(DBG_ALL_LDCS,
117820ae46ebSha137994 			    "ldc_mem_rdwr_cookie: (0x%lx) err %d during copy\n",
117920ae46ebSha137994 			    ldcp->id, rv);
118020ae46ebSha137994 			DWARN(DBG_ALL_LDCS,
118120ae46ebSha137994 			    "ldc_mem_rdwr_cookie: (0x%llx) dir=%lld, "
118220ae46ebSha137994 			    "tar_pa=0x%llx, loc_ra=0x%llx, tar_poff=0x%llx, "
118320ae46ebSha137994 			    "loc_poff=0x%llx, tar_psz=0x%llx, loc_psz=0x%llx, "
118420ae46ebSha137994 			    "copy_sz=0x%llx, total_bal=0x%llx\n",
118520ae46ebSha137994 			    ldcp->id, direction, target_pa, local_ra,
118620ae46ebSha137994 			    target_poff, local_poff, target_psize, local_psize,
118720ae46ebSha137994 			    copy_size, target_size);
118820ae46ebSha137994 
118920ae46ebSha137994 			*size = *size - target_size;
119020ae46ebSha137994 			mutex_exit(&ldcp->lock);
119120ae46ebSha137994 			return (i_ldc_h2v_error(rv));
119220ae46ebSha137994 		}
119320ae46ebSha137994 
119420ae46ebSha137994 		D2(ldcp->id, "ldc_mem_rdwr_cookie: copied=0x%llx\n",
119520ae46ebSha137994 		    copied_len);
119620ae46ebSha137994 		target_poff += copied_len;
119720ae46ebSha137994 		local_poff += copied_len;
119820ae46ebSha137994 		target_psize -= copied_len;
119920ae46ebSha137994 		local_psize -= copied_len;
120020ae46ebSha137994 
120120ae46ebSha137994 		target_size -= copied_len;
120220ae46ebSha137994 
120320ae46ebSha137994 		if (copy_size != copied_len)
120420ae46ebSha137994 			continue;
120520ae46ebSha137994 
120620ae46ebSha137994 		if (target_psize == 0 && target_size != 0) {
120720ae46ebSha137994 			target_pa += pg_size;
120820ae46ebSha137994 			target_poff = 0;
120920ae46ebSha137994 			target_psize = min(pg_size, target_size);
121020ae46ebSha137994 		}
121120ae46ebSha137994 
121220ae46ebSha137994 		if (local_psize == 0 && target_size != 0) {
121320ae46ebSha137994 			local_valign += pg_size;
121420ae46ebSha137994 			local_ra = va_to_pa((void *)local_valign);
121520ae46ebSha137994 			local_poff = 0;
121620ae46ebSha137994 			local_psize = min(pg_size, len);
121720ae46ebSha137994 			len -= local_psize;
121820ae46ebSha137994 		}
121920ae46ebSha137994 
122020ae46ebSha137994 		/* check if we are all done */
122120ae46ebSha137994 		if (target_size == 0)
122220ae46ebSha137994 			break;
122320ae46ebSha137994 	}
122420ae46ebSha137994 
122520ae46ebSha137994 	mutex_exit(&ldcp->lock);
122620ae46ebSha137994 
122720ae46ebSha137994 	D1(ldcp->id, "ldc_mem_rdwr_cookie: (0x%llx) done copying sz=0x%llx\n",
122820ae46ebSha137994 	    ldcp->id, *size);
122920ae46ebSha137994 
123020ae46ebSha137994 	return (0);
123120ae46ebSha137994 }
123220ae46ebSha137994 
123320ae46ebSha137994 /*
123420ae46ebSha137994  * Map an exported memory segment into the local address space. If the
123520ae46ebSha137994  * memory range was exported for direct map access, a HV call is made
123620ae46ebSha137994  * to allocate a RA range. If the map is done via a shadow copy, local
123720ae46ebSha137994  * shadow memory is allocated and the base VA is returned in 'vaddr'. If
123820ae46ebSha137994  * the mapping is a direct map then the RA is returned in 'raddr'.
123920ae46ebSha137994  */
124020ae46ebSha137994 int
124120ae46ebSha137994 ldc_mem_map(ldc_mem_handle_t mhandle, ldc_mem_cookie_t *cookie, uint32_t ccount,
124220ae46ebSha137994     uint8_t mtype, uint8_t perm, caddr_t *vaddr, caddr_t *raddr)
124320ae46ebSha137994 {
1244bbfa0259Sha137994 	/*
1245bbfa0259Sha137994 	 * Check if direct map over shared memory is enabled, if not change
1246bbfa0259Sha137994 	 * the mapping type to SHADOW_MAP.
1247bbfa0259Sha137994 	 */
1248bbfa0259Sha137994 	if (ldc_shmem_enabled == 0)
1249bbfa0259Sha137994 		mtype = LDC_SHADOW_MAP;
1250bbfa0259Sha137994 
1251bbfa0259Sha137994 	return (i_ldc_mem_map(mhandle, cookie, ccount, mtype, perm,
1252bbfa0259Sha137994 	    vaddr, raddr));
1253bbfa0259Sha137994 }
1254bbfa0259Sha137994 
1255bbfa0259Sha137994 static int
1256bbfa0259Sha137994 i_ldc_mem_map(ldc_mem_handle_t mhandle, ldc_mem_cookie_t *cookie,
1257bbfa0259Sha137994     uint32_t ccount, uint8_t mtype, uint8_t perm, caddr_t *vaddr,
1258bbfa0259Sha137994     caddr_t *raddr)
1259bbfa0259Sha137994 {
1260bbfa0259Sha137994 
126120ae46ebSha137994 	int		i, j, idx, rv, retries;
126220ae46ebSha137994 	ldc_chan_t 	*ldcp;
126320ae46ebSha137994 	ldc_mhdl_t	*mhdl;
126420ae46ebSha137994 	ldc_memseg_t	*memseg;
126520ae46ebSha137994 	caddr_t		tmpaddr;
126620ae46ebSha137994 	uint64_t	map_perm = perm;
126720ae46ebSha137994 	uint64_t	pg_size, pg_shift, pg_size_code, pg_mask;
126820ae46ebSha137994 	uint64_t	exp_size = 0, base_off, map_size, npages;
126920ae46ebSha137994 	uint64_t	cookie_addr, cookie_off, cookie_size;
127020ae46ebSha137994 	tte_t		ldc_tte;
127120ae46ebSha137994 
127220ae46ebSha137994 	if (mhandle == NULL) {
127320ae46ebSha137994 		DWARN(DBG_ALL_LDCS, "ldc_mem_map: invalid memory handle\n");
127420ae46ebSha137994 		return (EINVAL);
127520ae46ebSha137994 	}
127620ae46ebSha137994 	mhdl = (ldc_mhdl_t *)mhandle;
127720ae46ebSha137994 
127820ae46ebSha137994 	mutex_enter(&mhdl->lock);
127920ae46ebSha137994 
128020ae46ebSha137994 	if (mhdl->status == LDC_BOUND || mhdl->status == LDC_MAPPED ||
128120ae46ebSha137994 	    mhdl->memseg != NULL) {
128220ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
128320ae46ebSha137994 		    "ldc_mem_map: (0x%llx) handle bound/mapped\n", mhandle);
128420ae46ebSha137994 		mutex_exit(&mhdl->lock);
128520ae46ebSha137994 		return (EINVAL);
128620ae46ebSha137994 	}
128720ae46ebSha137994 
128820ae46ebSha137994 	ldcp = mhdl->ldcp;
128920ae46ebSha137994 
129020ae46ebSha137994 	mutex_enter(&ldcp->lock);
129120ae46ebSha137994 
129220ae46ebSha137994 	if (ldcp->tstate != TS_UP) {
129320ae46ebSha137994 		DWARN(ldcp->id,
129420ae46ebSha137994 		    "ldc_mem_dring_map: (0x%llx) channel is not UP\n",
129520ae46ebSha137994 		    ldcp->id);
129620ae46ebSha137994 		mutex_exit(&ldcp->lock);
129720ae46ebSha137994 		mutex_exit(&mhdl->lock);
129820ae46ebSha137994 		return (ECONNRESET);
129920ae46ebSha137994 	}
130020ae46ebSha137994 
130120ae46ebSha137994 	if ((mtype & (LDC_SHADOW_MAP|LDC_DIRECT_MAP|LDC_IO_MAP)) == 0) {
130220ae46ebSha137994 		DWARN(ldcp->id, "ldc_mem_map: invalid map type\n");
130320ae46ebSha137994 		mutex_exit(&ldcp->lock);
130420ae46ebSha137994 		mutex_exit(&mhdl->lock);
130520ae46ebSha137994 		return (EINVAL);
130620ae46ebSha137994 	}
130720ae46ebSha137994 
130820ae46ebSha137994 	D1(ldcp->id, "ldc_mem_map: (0x%llx) cookie = 0x%llx,0x%llx\n",
130920ae46ebSha137994 	    ldcp->id, cookie->addr, cookie->size);
131020ae46ebSha137994 
131120ae46ebSha137994 	/* FUTURE: get the page size, pgsz code, and shift */
131220ae46ebSha137994 	pg_size = MMU_PAGESIZE;
131320ae46ebSha137994 	pg_size_code = page_szc(pg_size);
131420ae46ebSha137994 	pg_shift = page_get_shift(pg_size_code);
131520ae46ebSha137994 	pg_mask = ~(pg_size - 1);
131620ae46ebSha137994 
131720ae46ebSha137994 	/* calculate the number of pages in the exported cookie */
131820ae46ebSha137994 	base_off = cookie[0].addr & (pg_size - 1);
131920ae46ebSha137994 	for (idx = 0; idx < ccount; idx++)
132020ae46ebSha137994 		exp_size += cookie[idx].size;
132120ae46ebSha137994 	map_size = P2ROUNDUP((exp_size + base_off), pg_size);
132220ae46ebSha137994 	npages = (map_size >> pg_shift);
132320ae46ebSha137994 
132420ae46ebSha137994 	/* Allocate memseg structure */
132520ae46ebSha137994 	memseg = mhdl->memseg =
132620ae46ebSha137994 	    kmem_cache_alloc(ldcssp->memseg_cache, KM_SLEEP);
132720ae46ebSha137994 
132820ae46ebSha137994 	/* Allocate memory to store all pages and cookies */
132920ae46ebSha137994 	memseg->pages =	kmem_zalloc((sizeof (ldc_page_t) * npages), KM_SLEEP);
133020ae46ebSha137994 	memseg->cookies =
133120ae46ebSha137994 	    kmem_zalloc((sizeof (ldc_mem_cookie_t) * ccount), KM_SLEEP);
133220ae46ebSha137994 
133320ae46ebSha137994 	D2(ldcp->id, "ldc_mem_map: (0x%llx) exp_size=0x%llx, map_size=0x%llx,"
133420ae46ebSha137994 	    "pages=0x%llx\n", ldcp->id, exp_size, map_size, npages);
133520ae46ebSha137994 
133620ae46ebSha137994 	/*
133720ae46ebSha137994 	 * Check to see if the client is requesting direct or shadow map
133820ae46ebSha137994 	 * If direct map is requested, try to map remote memory first,
133920ae46ebSha137994 	 * and if that fails, revert to shadow map
134020ae46ebSha137994 	 */
134120ae46ebSha137994 	if (mtype == LDC_DIRECT_MAP) {
134220ae46ebSha137994 
134320ae46ebSha137994 		/* Allocate kernel virtual space for mapping */
134420ae46ebSha137994 		memseg->vaddr = vmem_xalloc(heap_arena, map_size,
134520ae46ebSha137994 		    pg_size, 0, 0, NULL, NULL, VM_NOSLEEP);
134620ae46ebSha137994 		if (memseg->vaddr == NULL) {
1347bbfa0259Sha137994 			DWARN(DBG_ALL_LDCS,
134820ae46ebSha137994 			    "ldc_mem_map: (0x%lx) memory map failed\n",
134920ae46ebSha137994 			    ldcp->id);
135020ae46ebSha137994 			kmem_free(memseg->cookies,
135120ae46ebSha137994 			    (sizeof (ldc_mem_cookie_t) * ccount));
135220ae46ebSha137994 			kmem_free(memseg->pages,
135320ae46ebSha137994 			    (sizeof (ldc_page_t) * npages));
135420ae46ebSha137994 			kmem_cache_free(ldcssp->memseg_cache, memseg);
135520ae46ebSha137994 
135620ae46ebSha137994 			mutex_exit(&ldcp->lock);
135720ae46ebSha137994 			mutex_exit(&mhdl->lock);
135820ae46ebSha137994 			return (ENOMEM);
135920ae46ebSha137994 		}
136020ae46ebSha137994 
136120ae46ebSha137994 		/* Unload previous mapping */
136220ae46ebSha137994 		hat_unload(kas.a_hat, memseg->vaddr, map_size,
136320ae46ebSha137994 		    HAT_UNLOAD_NOSYNC | HAT_UNLOAD_UNLOCK);
136420ae46ebSha137994 
136520ae46ebSha137994 		/* for each cookie passed in - map into address space */
136620ae46ebSha137994 		idx = 0;
136720ae46ebSha137994 		cookie_size = 0;
136820ae46ebSha137994 		tmpaddr = memseg->vaddr;
136920ae46ebSha137994 
137020ae46ebSha137994 		for (i = 0; i < npages; i++) {
137120ae46ebSha137994 
137220ae46ebSha137994 			if (cookie_size == 0) {
137320ae46ebSha137994 				ASSERT(idx < ccount);
137420ae46ebSha137994 				cookie_addr = cookie[idx].addr & pg_mask;
137520ae46ebSha137994 				cookie_off = cookie[idx].addr & (pg_size - 1);
137620ae46ebSha137994 				cookie_size =
137720ae46ebSha137994 				    P2ROUNDUP((cookie_off + cookie[idx].size),
137820ae46ebSha137994 				    pg_size);
137920ae46ebSha137994 				idx++;
138020ae46ebSha137994 			}
138120ae46ebSha137994 
138220ae46ebSha137994 			D1(ldcp->id, "ldc_mem_map: (0x%llx) mapping "
138320ae46ebSha137994 			    "cookie 0x%llx, bal=0x%llx\n", ldcp->id,
138420ae46ebSha137994 			    cookie_addr, cookie_size);
138520ae46ebSha137994 
138620ae46ebSha137994 			/* map the cookie into address space */
138720ae46ebSha137994 			for (retries = 0; retries < ldc_max_retries;
138820ae46ebSha137994 			    retries++) {
138920ae46ebSha137994 
139020ae46ebSha137994 				rv = hv_ldc_mapin(ldcp->id, cookie_addr,
139120ae46ebSha137994 				    &memseg->pages[i].raddr, &map_perm);
139220ae46ebSha137994 				if (rv != H_EWOULDBLOCK && rv != H_ETOOMANY)
139320ae46ebSha137994 					break;
139420ae46ebSha137994 
139520ae46ebSha137994 				drv_usecwait(ldc_delay);
139620ae46ebSha137994 			}
139720ae46ebSha137994 
139820ae46ebSha137994 			if (rv || memseg->pages[i].raddr == 0) {
139920ae46ebSha137994 				DWARN(ldcp->id,
140020ae46ebSha137994 				    "ldc_mem_map: (0x%llx) hv mapin err %d\n",
140120ae46ebSha137994 				    ldcp->id, rv);
140220ae46ebSha137994 
140320ae46ebSha137994 				/* remove previous mapins */
140420ae46ebSha137994 				hat_unload(kas.a_hat, memseg->vaddr, map_size,
140520ae46ebSha137994 				    HAT_UNLOAD_NOSYNC | HAT_UNLOAD_UNLOCK);
140620ae46ebSha137994 				for (j = 0; j < i; j++) {
140720ae46ebSha137994 					rv = hv_ldc_unmap(
140820ae46ebSha137994 					    memseg->pages[j].raddr);
140920ae46ebSha137994 					if (rv) {
141020ae46ebSha137994 						DWARN(ldcp->id,
141120ae46ebSha137994 						    "ldc_mem_map: (0x%llx) "
141220ae46ebSha137994 						    "cannot unmap ra=0x%llx\n",
141320ae46ebSha137994 						    ldcp->id,
141420ae46ebSha137994 						    memseg->pages[j].raddr);
141520ae46ebSha137994 					}
141620ae46ebSha137994 				}
141720ae46ebSha137994 
141820ae46ebSha137994 				/* free kernel virtual space */
141920ae46ebSha137994 				vmem_free(heap_arena, (void *)memseg->vaddr,
142020ae46ebSha137994 				    map_size);
142120ae46ebSha137994 
142220ae46ebSha137994 				/* direct map failed - revert to shadow map */
142320ae46ebSha137994 				mtype = LDC_SHADOW_MAP;
142420ae46ebSha137994 				break;
142520ae46ebSha137994 
142620ae46ebSha137994 			} else {
142720ae46ebSha137994 
142820ae46ebSha137994 				D1(ldcp->id,
142920ae46ebSha137994 				    "ldc_mem_map: (0x%llx) vtop map 0x%llx -> "
143020ae46ebSha137994 				    "0x%llx, cookie=0x%llx, perm=0x%llx\n",
143120ae46ebSha137994 				    ldcp->id, tmpaddr, memseg->pages[i].raddr,
143220ae46ebSha137994 				    cookie_addr, perm);
143320ae46ebSha137994 
143420ae46ebSha137994 				/*
143520ae46ebSha137994 				 * NOTE: Calling hat_devload directly, causes it
143620ae46ebSha137994 				 * to look for page_t using the pfn. Since this
143720ae46ebSha137994 				 * addr is greater than the memlist, it treates
143820ae46ebSha137994 				 * it as non-memory
143920ae46ebSha137994 				 */
144020ae46ebSha137994 				sfmmu_memtte(&ldc_tte,
144120ae46ebSha137994 				    (pfn_t)(memseg->pages[i].raddr >> pg_shift),
144220ae46ebSha137994 				    PROT_READ | PROT_WRITE | HAT_NOSYNC, TTE8K);
144320ae46ebSha137994 
144420ae46ebSha137994 				D1(ldcp->id,
144520ae46ebSha137994 				    "ldc_mem_map: (0x%llx) ra 0x%llx -> "
144620ae46ebSha137994 				    "tte 0x%llx\n", ldcp->id,
144720ae46ebSha137994 				    memseg->pages[i].raddr, ldc_tte);
144820ae46ebSha137994 
144920ae46ebSha137994 				sfmmu_tteload(kas.a_hat, &ldc_tte, tmpaddr,
145020ae46ebSha137994 				    NULL, HAT_LOAD_LOCK);
145120ae46ebSha137994 
145220ae46ebSha137994 				cookie_size -= pg_size;
145320ae46ebSha137994 				cookie_addr += pg_size;
145420ae46ebSha137994 				tmpaddr += pg_size;
145520ae46ebSha137994 			}
145620ae46ebSha137994 		}
145720ae46ebSha137994 	}
145820ae46ebSha137994 
145920ae46ebSha137994 	if (mtype == LDC_SHADOW_MAP) {
146020ae46ebSha137994 		if (*vaddr == NULL) {
146120ae46ebSha137994 			memseg->vaddr = kmem_zalloc(exp_size, KM_SLEEP);
146220ae46ebSha137994 			mhdl->myshadow = B_TRUE;
146320ae46ebSha137994 
146420ae46ebSha137994 			D1(ldcp->id, "ldc_mem_map: (0x%llx) allocated "
146520ae46ebSha137994 			    "shadow page va=0x%llx\n", ldcp->id, memseg->vaddr);
146620ae46ebSha137994 		} else {
146720ae46ebSha137994 			/*
146820ae46ebSha137994 			 * Use client supplied memory for memseg->vaddr
146920ae46ebSha137994 			 * WARNING: assuming that client mem is >= exp_size
147020ae46ebSha137994 			 */
147120ae46ebSha137994 			memseg->vaddr = *vaddr;
147220ae46ebSha137994 		}
147320ae46ebSha137994 
147420ae46ebSha137994 		/* Save all page and cookie information */
147520ae46ebSha137994 		for (i = 0, tmpaddr = memseg->vaddr; i < npages; i++) {
147620ae46ebSha137994 			memseg->pages[i].raddr = va_to_pa(tmpaddr);
147720ae46ebSha137994 			tmpaddr += pg_size;
147820ae46ebSha137994 		}
147920ae46ebSha137994 
148020ae46ebSha137994 	}
148120ae46ebSha137994 
148220ae46ebSha137994 	/* save all cookies */
148320ae46ebSha137994 	bcopy(cookie, memseg->cookies, ccount * sizeof (ldc_mem_cookie_t));
148420ae46ebSha137994 
148520ae46ebSha137994 	/* update memseg_t */
148620ae46ebSha137994 	memseg->raddr = memseg->pages[0].raddr;
148720ae46ebSha137994 	memseg->size = (mtype == LDC_SHADOW_MAP) ? exp_size : map_size;
148820ae46ebSha137994 	memseg->npages = npages;
148920ae46ebSha137994 	memseg->ncookies = ccount;
149020ae46ebSha137994 	memseg->next_cookie = 0;
149120ae46ebSha137994 
149220ae46ebSha137994 	/* memory handle = mapped */
149320ae46ebSha137994 	mhdl->mtype = mtype;
149420ae46ebSha137994 	mhdl->perm = perm;
149520ae46ebSha137994 	mhdl->status = LDC_MAPPED;
149620ae46ebSha137994 
149720ae46ebSha137994 	D1(ldcp->id, "ldc_mem_map: (0x%llx) mapped 0x%llx, ra=0x%llx, "
149820ae46ebSha137994 	    "va=0x%llx, pgs=0x%llx cookies=0x%llx\n",
149920ae46ebSha137994 	    ldcp->id, mhdl, memseg->raddr, memseg->vaddr,
150020ae46ebSha137994 	    memseg->npages, memseg->ncookies);
150120ae46ebSha137994 
150220ae46ebSha137994 	if (mtype == LDC_SHADOW_MAP)
150320ae46ebSha137994 		base_off = 0;
150420ae46ebSha137994 	if (raddr)
150520ae46ebSha137994 		*raddr = (caddr_t)(memseg->raddr | base_off);
150620ae46ebSha137994 	if (vaddr)
150720ae46ebSha137994 		*vaddr = (caddr_t)((uintptr_t)memseg->vaddr | base_off);
150820ae46ebSha137994 
150920ae46ebSha137994 	mutex_exit(&ldcp->lock);
151020ae46ebSha137994 	mutex_exit(&mhdl->lock);
151120ae46ebSha137994 	return (0);
151220ae46ebSha137994 }
151320ae46ebSha137994 
151420ae46ebSha137994 /*
151520ae46ebSha137994  * Unmap a memory segment. Free shadow memory (if any).
151620ae46ebSha137994  */
151720ae46ebSha137994 int
151820ae46ebSha137994 ldc_mem_unmap(ldc_mem_handle_t mhandle)
151920ae46ebSha137994 {
152020ae46ebSha137994 	int		i, rv;
152120ae46ebSha137994 	ldc_mhdl_t	*mhdl = (ldc_mhdl_t *)mhandle;
152220ae46ebSha137994 	ldc_chan_t 	*ldcp;
152320ae46ebSha137994 	ldc_memseg_t	*memseg;
152420ae46ebSha137994 
152520ae46ebSha137994 	if (mhdl == 0 || mhdl->status != LDC_MAPPED) {
152620ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
152720ae46ebSha137994 		    "ldc_mem_unmap: (0x%llx) handle is not mapped\n",
152820ae46ebSha137994 		    mhandle);
152920ae46ebSha137994 		return (EINVAL);
153020ae46ebSha137994 	}
153120ae46ebSha137994 
153220ae46ebSha137994 	mutex_enter(&mhdl->lock);
153320ae46ebSha137994 
153420ae46ebSha137994 	ldcp = mhdl->ldcp;
153520ae46ebSha137994 	memseg = mhdl->memseg;
153620ae46ebSha137994 
153720ae46ebSha137994 	D1(ldcp->id, "ldc_mem_unmap: (0x%llx) unmapping handle 0x%llx\n",
153820ae46ebSha137994 	    ldcp->id, mhdl);
153920ae46ebSha137994 
154020ae46ebSha137994 	/* if we allocated shadow memory - free it */
154120ae46ebSha137994 	if (mhdl->mtype == LDC_SHADOW_MAP && mhdl->myshadow) {
154220ae46ebSha137994 		kmem_free(memseg->vaddr, memseg->size);
154320ae46ebSha137994 	} else if (mhdl->mtype == LDC_DIRECT_MAP) {
154420ae46ebSha137994 
154520ae46ebSha137994 		/* unmap in the case of DIRECT_MAP */
154620ae46ebSha137994 		hat_unload(kas.a_hat, memseg->vaddr, memseg->size,
154720ae46ebSha137994 		    HAT_UNLOAD_UNLOCK);
154820ae46ebSha137994 
154920ae46ebSha137994 		for (i = 0; i < memseg->npages; i++) {
155020ae46ebSha137994 			rv = hv_ldc_unmap(memseg->pages[i].raddr);
155120ae46ebSha137994 			if (rv) {
1552bbfa0259Sha137994 				DWARN(DBG_ALL_LDCS,
155320ae46ebSha137994 				    "ldc_mem_map: (0x%lx) hv unmap err %d\n",
155420ae46ebSha137994 				    ldcp->id, rv);
155520ae46ebSha137994 			}
155620ae46ebSha137994 		}
155720ae46ebSha137994 
155820ae46ebSha137994 		vmem_free(heap_arena, (void *)memseg->vaddr, memseg->size);
155920ae46ebSha137994 	}
156020ae46ebSha137994 
156120ae46ebSha137994 	/* free the allocated memseg and page structures */
156220ae46ebSha137994 	kmem_free(memseg->pages, (sizeof (ldc_page_t) * memseg->npages));
156320ae46ebSha137994 	kmem_free(memseg->cookies,
156420ae46ebSha137994 	    (sizeof (ldc_mem_cookie_t) * memseg->ncookies));
156520ae46ebSha137994 	kmem_cache_free(ldcssp->memseg_cache, memseg);
156620ae46ebSha137994 
156720ae46ebSha137994 	/* uninitialize the memory handle */
156820ae46ebSha137994 	mhdl->memseg = NULL;
156920ae46ebSha137994 	mhdl->status = LDC_UNBOUND;
157020ae46ebSha137994 
157120ae46ebSha137994 	D1(ldcp->id, "ldc_mem_unmap: (0x%llx) unmapped handle 0x%llx\n",
157220ae46ebSha137994 	    ldcp->id, mhdl);
157320ae46ebSha137994 
157420ae46ebSha137994 	mutex_exit(&mhdl->lock);
157520ae46ebSha137994 	return (0);
157620ae46ebSha137994 }
157720ae46ebSha137994 
157820ae46ebSha137994 /*
157920ae46ebSha137994  * Internal entry point for LDC mapped memory entry consistency
158020ae46ebSha137994  * semantics. Acquire copies the contents of the remote memory
158120ae46ebSha137994  * into the local shadow copy. The release operation copies the local
158220ae46ebSha137994  * contents into the remote memory. The offset and size specify the
158320ae46ebSha137994  * bounds for the memory range being synchronized.
158420ae46ebSha137994  */
158520ae46ebSha137994 static int
158620ae46ebSha137994 i_ldc_mem_acquire_release(ldc_mem_handle_t mhandle, uint8_t direction,
158720ae46ebSha137994     uint64_t offset, size_t size)
158820ae46ebSha137994 {
158920ae46ebSha137994 	int 		err;
159020ae46ebSha137994 	ldc_mhdl_t	*mhdl;
159120ae46ebSha137994 	ldc_chan_t	*ldcp;
159220ae46ebSha137994 	ldc_memseg_t	*memseg;
159320ae46ebSha137994 	caddr_t		local_vaddr;
159420ae46ebSha137994 	size_t		copy_size;
159520ae46ebSha137994 
159620ae46ebSha137994 	if (mhandle == NULL) {
159720ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
159820ae46ebSha137994 		    "i_ldc_mem_acquire_release: invalid memory handle\n");
159920ae46ebSha137994 		return (EINVAL);
160020ae46ebSha137994 	}
160120ae46ebSha137994 	mhdl = (ldc_mhdl_t *)mhandle;
160220ae46ebSha137994 
160320ae46ebSha137994 	mutex_enter(&mhdl->lock);
160420ae46ebSha137994 
160520ae46ebSha137994 	if (mhdl->status != LDC_MAPPED || mhdl->ldcp == NULL) {
160620ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
160720ae46ebSha137994 		    "i_ldc_mem_acquire_release: not mapped memory\n");
160820ae46ebSha137994 		mutex_exit(&mhdl->lock);
160920ae46ebSha137994 		return (EINVAL);
161020ae46ebSha137994 	}
161120ae46ebSha137994 
161220ae46ebSha137994 	/* do nothing for direct map */
161320ae46ebSha137994 	if (mhdl->mtype == LDC_DIRECT_MAP) {
161420ae46ebSha137994 		mutex_exit(&mhdl->lock);
161520ae46ebSha137994 		return (0);
161620ae46ebSha137994 	}
161720ae46ebSha137994 
161820ae46ebSha137994 	/* do nothing if COPY_IN+MEM_W and COPY_OUT+MEM_R */
161920ae46ebSha137994 	if ((direction == LDC_COPY_IN && (mhdl->perm & LDC_MEM_R) == 0) ||
162020ae46ebSha137994 	    (direction == LDC_COPY_OUT && (mhdl->perm & LDC_MEM_W) == 0)) {
162120ae46ebSha137994 		mutex_exit(&mhdl->lock);
162220ae46ebSha137994 		return (0);
162320ae46ebSha137994 	}
162420ae46ebSha137994 
162520ae46ebSha137994 	if (offset >= mhdl->memseg->size ||
162620ae46ebSha137994 	    (offset + size) > mhdl->memseg->size) {
162720ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
162820ae46ebSha137994 		    "i_ldc_mem_acquire_release: memory out of range\n");
162920ae46ebSha137994 		mutex_exit(&mhdl->lock);
163020ae46ebSha137994 		return (EINVAL);
163120ae46ebSha137994 	}
163220ae46ebSha137994 
163320ae46ebSha137994 	/* get the channel handle and memory segment */
163420ae46ebSha137994 	ldcp = mhdl->ldcp;
163520ae46ebSha137994 	memseg = mhdl->memseg;
163620ae46ebSha137994 
163720ae46ebSha137994 	if (mhdl->mtype == LDC_SHADOW_MAP) {
163820ae46ebSha137994 
163920ae46ebSha137994 		local_vaddr = memseg->vaddr + offset;
164020ae46ebSha137994 		copy_size = size;
164120ae46ebSha137994 
164220ae46ebSha137994 		/* copy to/from remote from/to local memory */
164320ae46ebSha137994 		err = ldc_mem_copy((ldc_handle_t)ldcp, local_vaddr, offset,
164420ae46ebSha137994 		    &copy_size, memseg->cookies, memseg->ncookies,
164520ae46ebSha137994 		    direction);
164620ae46ebSha137994 		if (err || copy_size != size) {
164720ae46ebSha137994 			DWARN(ldcp->id,
164820ae46ebSha137994 			    "i_ldc_mem_acquire_release: copy failed\n");
164920ae46ebSha137994 			mutex_exit(&mhdl->lock);
165020ae46ebSha137994 			return (err);
165120ae46ebSha137994 		}
165220ae46ebSha137994 	}
165320ae46ebSha137994 
165420ae46ebSha137994 	mutex_exit(&mhdl->lock);
165520ae46ebSha137994 
165620ae46ebSha137994 	return (0);
165720ae46ebSha137994 }
165820ae46ebSha137994 
165920ae46ebSha137994 /*
166020ae46ebSha137994  * Ensure that the contents in the remote memory seg are consistent
166120ae46ebSha137994  * with the contents if of local segment
166220ae46ebSha137994  */
166320ae46ebSha137994 int
166420ae46ebSha137994 ldc_mem_acquire(ldc_mem_handle_t mhandle, uint64_t offset, uint64_t size)
166520ae46ebSha137994 {
166620ae46ebSha137994 	return (i_ldc_mem_acquire_release(mhandle, LDC_COPY_IN, offset, size));
166720ae46ebSha137994 }
166820ae46ebSha137994 
166920ae46ebSha137994 
167020ae46ebSha137994 /*
167120ae46ebSha137994  * Ensure that the contents in the local memory seg are consistent
167220ae46ebSha137994  * with the contents if of remote segment
167320ae46ebSha137994  */
167420ae46ebSha137994 int
167520ae46ebSha137994 ldc_mem_release(ldc_mem_handle_t mhandle, uint64_t offset, uint64_t size)
167620ae46ebSha137994 {
167720ae46ebSha137994 	return (i_ldc_mem_acquire_release(mhandle, LDC_COPY_OUT, offset, size));
167820ae46ebSha137994 }
167920ae46ebSha137994 
168020ae46ebSha137994 /*
168120ae46ebSha137994  * Allocate a descriptor ring. The size of each each descriptor
168220ae46ebSha137994  * must be 8-byte aligned and the entire ring should be a multiple
168320ae46ebSha137994  * of MMU_PAGESIZE.
168420ae46ebSha137994  */
168520ae46ebSha137994 int
168620ae46ebSha137994 ldc_mem_dring_create(uint32_t len, uint32_t dsize, ldc_dring_handle_t *dhandle)
168720ae46ebSha137994 {
168820ae46ebSha137994 	ldc_dring_t *dringp;
168920ae46ebSha137994 	size_t size = (dsize * len);
169020ae46ebSha137994 
169120ae46ebSha137994 	D1(DBG_ALL_LDCS, "ldc_mem_dring_create: len=0x%x, size=0x%x\n",
169220ae46ebSha137994 	    len, dsize);
169320ae46ebSha137994 
169420ae46ebSha137994 	if (dhandle == NULL) {
169520ae46ebSha137994 		DWARN(DBG_ALL_LDCS, "ldc_mem_dring_create: invalid dhandle\n");
169620ae46ebSha137994 		return (EINVAL);
169720ae46ebSha137994 	}
169820ae46ebSha137994 
169920ae46ebSha137994 	if (len == 0) {
170020ae46ebSha137994 		DWARN(DBG_ALL_LDCS, "ldc_mem_dring_create: invalid length\n");
170120ae46ebSha137994 		return (EINVAL);
170220ae46ebSha137994 	}
170320ae46ebSha137994 
170420ae46ebSha137994 	/* descriptor size should be 8-byte aligned */
170520ae46ebSha137994 	if (dsize == 0 || (dsize & 0x7)) {
170620ae46ebSha137994 		DWARN(DBG_ALL_LDCS, "ldc_mem_dring_create: invalid size\n");
170720ae46ebSha137994 		return (EINVAL);
170820ae46ebSha137994 	}
170920ae46ebSha137994 
171020ae46ebSha137994 	*dhandle = 0;
171120ae46ebSha137994 
171220ae46ebSha137994 	/* Allocate a desc ring structure */
171320ae46ebSha137994 	dringp = kmem_zalloc(sizeof (ldc_dring_t), KM_SLEEP);
171420ae46ebSha137994 
171520ae46ebSha137994 	/* Initialize dring */
171620ae46ebSha137994 	dringp->length = len;
171720ae46ebSha137994 	dringp->dsize = dsize;
171820ae46ebSha137994 
171920ae46ebSha137994 	/* round off to multiple of pagesize */
172020ae46ebSha137994 	dringp->size = (size & MMU_PAGEMASK);
172120ae46ebSha137994 	if (size & MMU_PAGEOFFSET)
172220ae46ebSha137994 		dringp->size += MMU_PAGESIZE;
172320ae46ebSha137994 
172420ae46ebSha137994 	dringp->status = LDC_UNBOUND;
172520ae46ebSha137994 
172620ae46ebSha137994 	/* allocate descriptor ring memory */
172720ae46ebSha137994 	dringp->base = kmem_zalloc(dringp->size, KM_SLEEP);
172820ae46ebSha137994 
172920ae46ebSha137994 	/* initialize the desc ring lock */
173020ae46ebSha137994 	mutex_init(&dringp->lock, NULL, MUTEX_DRIVER, NULL);
173120ae46ebSha137994 
173220ae46ebSha137994 	/* Add descriptor ring to the head of global list */
173320ae46ebSha137994 	mutex_enter(&ldcssp->lock);
173420ae46ebSha137994 	dringp->next = ldcssp->dring_list;
173520ae46ebSha137994 	ldcssp->dring_list = dringp;
173620ae46ebSha137994 	mutex_exit(&ldcssp->lock);
173720ae46ebSha137994 
173820ae46ebSha137994 	*dhandle = (ldc_dring_handle_t)dringp;
173920ae46ebSha137994 
174020ae46ebSha137994 	D1(DBG_ALL_LDCS, "ldc_mem_dring_create: dring allocated\n");
174120ae46ebSha137994 
174220ae46ebSha137994 	return (0);
174320ae46ebSha137994 }
174420ae46ebSha137994 
174520ae46ebSha137994 
174620ae46ebSha137994 /*
174720ae46ebSha137994  * Destroy a descriptor ring.
174820ae46ebSha137994  */
174920ae46ebSha137994 int
175020ae46ebSha137994 ldc_mem_dring_destroy(ldc_dring_handle_t dhandle)
175120ae46ebSha137994 {
175220ae46ebSha137994 	ldc_dring_t *dringp;
175320ae46ebSha137994 	ldc_dring_t *tmp_dringp;
175420ae46ebSha137994 
175520ae46ebSha137994 	D1(DBG_ALL_LDCS, "ldc_mem_dring_destroy: entered\n");
175620ae46ebSha137994 
175720ae46ebSha137994 	if (dhandle == NULL) {
175820ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
175920ae46ebSha137994 		    "ldc_mem_dring_destroy: invalid desc ring handle\n");
176020ae46ebSha137994 		return (EINVAL);
176120ae46ebSha137994 	}
176220ae46ebSha137994 	dringp = (ldc_dring_t *)dhandle;
176320ae46ebSha137994 
176420ae46ebSha137994 	if (dringp->status == LDC_BOUND) {
176520ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
176620ae46ebSha137994 		    "ldc_mem_dring_destroy: desc ring is bound\n");
176720ae46ebSha137994 		return (EACCES);
176820ae46ebSha137994 	}
176920ae46ebSha137994 
177020ae46ebSha137994 	mutex_enter(&dringp->lock);
177120ae46ebSha137994 	mutex_enter(&ldcssp->lock);
177220ae46ebSha137994 
177320ae46ebSha137994 	/* remove from linked list - if not bound */
177420ae46ebSha137994 	tmp_dringp = ldcssp->dring_list;
177520ae46ebSha137994 	if (tmp_dringp == dringp) {
177620ae46ebSha137994 		ldcssp->dring_list = dringp->next;
177720ae46ebSha137994 		dringp->next = NULL;
177820ae46ebSha137994 
177920ae46ebSha137994 	} else {
178020ae46ebSha137994 		while (tmp_dringp != NULL) {
178120ae46ebSha137994 			if (tmp_dringp->next == dringp) {
178220ae46ebSha137994 				tmp_dringp->next = dringp->next;
178320ae46ebSha137994 				dringp->next = NULL;
178420ae46ebSha137994 				break;
178520ae46ebSha137994 			}
178620ae46ebSha137994 			tmp_dringp = tmp_dringp->next;
178720ae46ebSha137994 		}
178820ae46ebSha137994 		if (tmp_dringp == NULL) {
178920ae46ebSha137994 			DWARN(DBG_ALL_LDCS,
179020ae46ebSha137994 			    "ldc_mem_dring_destroy: invalid descriptor\n");
179120ae46ebSha137994 			mutex_exit(&ldcssp->lock);
179220ae46ebSha137994 			mutex_exit(&dringp->lock);
179320ae46ebSha137994 			return (EINVAL);
179420ae46ebSha137994 		}
179520ae46ebSha137994 	}
179620ae46ebSha137994 
179720ae46ebSha137994 	mutex_exit(&ldcssp->lock);
179820ae46ebSha137994 
179920ae46ebSha137994 	/* free the descriptor ring */
180020ae46ebSha137994 	kmem_free(dringp->base, dringp->size);
180120ae46ebSha137994 
180220ae46ebSha137994 	mutex_exit(&dringp->lock);
180320ae46ebSha137994 
180420ae46ebSha137994 	/* destroy dring lock */
180520ae46ebSha137994 	mutex_destroy(&dringp->lock);
180620ae46ebSha137994 
180720ae46ebSha137994 	/* free desc ring object */
180820ae46ebSha137994 	kmem_free(dringp, sizeof (ldc_dring_t));
180920ae46ebSha137994 
181020ae46ebSha137994 	return (0);
181120ae46ebSha137994 }
181220ae46ebSha137994 
181320ae46ebSha137994 /*
181420ae46ebSha137994  * Bind a previously allocated dring to a channel. The channel should
181520ae46ebSha137994  * be OPEN in order to bind the ring to the channel. Returns back a
181620ae46ebSha137994  * descriptor ring cookie. The descriptor ring is exported for remote
181720ae46ebSha137994  * access by the client at the other end of the channel. An entry for
181820ae46ebSha137994  * dring pages is stored in map table (via call to ldc_mem_bind_handle).
181920ae46ebSha137994  */
182020ae46ebSha137994 int
182120ae46ebSha137994 ldc_mem_dring_bind(ldc_handle_t handle, ldc_dring_handle_t dhandle,
182220ae46ebSha137994     uint8_t mtype, uint8_t perm, ldc_mem_cookie_t *cookie, uint32_t *ccount)
182320ae46ebSha137994 {
182420ae46ebSha137994 	int		err;
182520ae46ebSha137994 	ldc_chan_t 	*ldcp;
182620ae46ebSha137994 	ldc_dring_t	*dringp;
182720ae46ebSha137994 	ldc_mem_handle_t mhandle;
182820ae46ebSha137994 
182920ae46ebSha137994 	/* check to see if channel is initalized */
183020ae46ebSha137994 	if (handle == NULL) {
183120ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
183220ae46ebSha137994 		    "ldc_mem_dring_bind: invalid channel handle\n");
183320ae46ebSha137994 		return (EINVAL);
183420ae46ebSha137994 	}
183520ae46ebSha137994 	ldcp = (ldc_chan_t *)handle;
183620ae46ebSha137994 
183720ae46ebSha137994 	if (dhandle == NULL) {
183820ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
183920ae46ebSha137994 		    "ldc_mem_dring_bind: invalid desc ring handle\n");
184020ae46ebSha137994 		return (EINVAL);
184120ae46ebSha137994 	}
184220ae46ebSha137994 	dringp = (ldc_dring_t *)dhandle;
184320ae46ebSha137994 
184420ae46ebSha137994 	if (cookie == NULL) {
184520ae46ebSha137994 		DWARN(ldcp->id,
184620ae46ebSha137994 		    "ldc_mem_dring_bind: invalid cookie arg\n");
184720ae46ebSha137994 		return (EINVAL);
184820ae46ebSha137994 	}
184920ae46ebSha137994 
1850bbfa0259Sha137994 	/* ensure the mtype is valid */
1851bbfa0259Sha137994 	if ((mtype & (LDC_SHADOW_MAP|LDC_DIRECT_MAP)) == 0) {
1852bbfa0259Sha137994 		DWARN(ldcp->id, "ldc_mem_dring_bind: invalid map type\n");
1853bbfa0259Sha137994 		return (EINVAL);
1854bbfa0259Sha137994 	}
1855bbfa0259Sha137994 
1856bbfa0259Sha137994 	/* no need to bind as direct map if it's not HV supported or enabled */
1857bbfa0259Sha137994 	if (!ldc_dring_shmem_hv_ok || !ldc_dring_shmem_enabled) {
1858bbfa0259Sha137994 		mtype = LDC_SHADOW_MAP;
1859bbfa0259Sha137994 	}
1860bbfa0259Sha137994 
186120ae46ebSha137994 	mutex_enter(&dringp->lock);
186220ae46ebSha137994 
186320ae46ebSha137994 	if (dringp->status == LDC_BOUND) {
186420ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
186520ae46ebSha137994 		    "ldc_mem_dring_bind: (0x%llx) descriptor ring is bound\n",
186620ae46ebSha137994 		    ldcp->id);
186720ae46ebSha137994 		mutex_exit(&dringp->lock);
186820ae46ebSha137994 		return (EINVAL);
186920ae46ebSha137994 	}
187020ae46ebSha137994 
187120ae46ebSha137994 	if ((perm & LDC_MEM_RW) == 0) {
187220ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
187320ae46ebSha137994 		    "ldc_mem_dring_bind: invalid permissions\n");
187420ae46ebSha137994 		mutex_exit(&dringp->lock);
187520ae46ebSha137994 		return (EINVAL);
187620ae46ebSha137994 	}
187720ae46ebSha137994 
187820ae46ebSha137994 	if ((mtype & (LDC_SHADOW_MAP|LDC_DIRECT_MAP|LDC_IO_MAP)) == 0) {
187920ae46ebSha137994 		DWARN(DBG_ALL_LDCS, "ldc_mem_dring_bind: invalid type\n");
188020ae46ebSha137994 		mutex_exit(&dringp->lock);
188120ae46ebSha137994 		return (EINVAL);
188220ae46ebSha137994 	}
188320ae46ebSha137994 
188420ae46ebSha137994 	dringp->ldcp = ldcp;
188520ae46ebSha137994 
188620ae46ebSha137994 	/* create an memory handle */
188720ae46ebSha137994 	err = ldc_mem_alloc_handle(handle, &mhandle);
188820ae46ebSha137994 	if (err || mhandle == NULL) {
188920ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
189020ae46ebSha137994 		    "ldc_mem_dring_bind: (0x%llx) error allocating mhandle\n",
189120ae46ebSha137994 		    ldcp->id);
189220ae46ebSha137994 		mutex_exit(&dringp->lock);
189320ae46ebSha137994 		return (err);
189420ae46ebSha137994 	}
189520ae46ebSha137994 	dringp->mhdl = mhandle;
189620ae46ebSha137994 
189720ae46ebSha137994 	/* bind the descriptor ring to channel */
1898bbfa0259Sha137994 	err = i_ldc_mem_bind_handle(mhandle, dringp->base, dringp->size,
189920ae46ebSha137994 	    mtype, perm, cookie, ccount);
190020ae46ebSha137994 	if (err) {
190120ae46ebSha137994 		DWARN(ldcp->id,
190220ae46ebSha137994 		    "ldc_mem_dring_bind: (0x%llx) error binding mhandle\n",
190320ae46ebSha137994 		    ldcp->id);
190420ae46ebSha137994 		mutex_exit(&dringp->lock);
190520ae46ebSha137994 		return (err);
190620ae46ebSha137994 	}
190720ae46ebSha137994 
190820ae46ebSha137994 	/*
190920ae46ebSha137994 	 * For now return error if we get more than one cookie
191020ae46ebSha137994 	 * FUTURE: Return multiple cookies ..
191120ae46ebSha137994 	 */
191220ae46ebSha137994 	if (*ccount > 1) {
191320ae46ebSha137994 		(void) ldc_mem_unbind_handle(mhandle);
191420ae46ebSha137994 		(void) ldc_mem_free_handle(mhandle);
191520ae46ebSha137994 
191620ae46ebSha137994 		dringp->ldcp = NULL;
191720ae46ebSha137994 		dringp->mhdl = NULL;
191820ae46ebSha137994 		*ccount = 0;
191920ae46ebSha137994 
192020ae46ebSha137994 		mutex_exit(&dringp->lock);
192120ae46ebSha137994 		return (EAGAIN);
192220ae46ebSha137994 	}
192320ae46ebSha137994 
192420ae46ebSha137994 	/* Add descriptor ring to channel's exported dring list */
192520ae46ebSha137994 	mutex_enter(&ldcp->exp_dlist_lock);
192620ae46ebSha137994 	dringp->ch_next = ldcp->exp_dring_list;
192720ae46ebSha137994 	ldcp->exp_dring_list = dringp;
192820ae46ebSha137994 	mutex_exit(&ldcp->exp_dlist_lock);
192920ae46ebSha137994 
193020ae46ebSha137994 	dringp->status = LDC_BOUND;
193120ae46ebSha137994 
193220ae46ebSha137994 	mutex_exit(&dringp->lock);
193320ae46ebSha137994 
193420ae46ebSha137994 	return (0);
193520ae46ebSha137994 }
193620ae46ebSha137994 
193720ae46ebSha137994 /*
193820ae46ebSha137994  * Return the next cookie associated with the specified dring handle
193920ae46ebSha137994  */
194020ae46ebSha137994 int
194120ae46ebSha137994 ldc_mem_dring_nextcookie(ldc_dring_handle_t dhandle, ldc_mem_cookie_t *cookie)
194220ae46ebSha137994 {
194320ae46ebSha137994 	int		rv = 0;
194420ae46ebSha137994 	ldc_dring_t 	*dringp;
194520ae46ebSha137994 	ldc_chan_t	*ldcp;
194620ae46ebSha137994 
194720ae46ebSha137994 	if (dhandle == NULL) {
194820ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
194920ae46ebSha137994 		    "ldc_mem_dring_nextcookie: invalid desc ring handle\n");
195020ae46ebSha137994 		return (EINVAL);
195120ae46ebSha137994 	}
195220ae46ebSha137994 	dringp = (ldc_dring_t *)dhandle;
195320ae46ebSha137994 	mutex_enter(&dringp->lock);
195420ae46ebSha137994 
195520ae46ebSha137994 	if (dringp->status != LDC_BOUND) {
195620ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
195720ae46ebSha137994 		    "ldc_mem_dring_nextcookie: descriptor ring 0x%llx "
195820ae46ebSha137994 		    "is not bound\n", dringp);
195920ae46ebSha137994 		mutex_exit(&dringp->lock);
196020ae46ebSha137994 		return (EINVAL);
196120ae46ebSha137994 	}
196220ae46ebSha137994 
196320ae46ebSha137994 	ldcp = dringp->ldcp;
196420ae46ebSha137994 
196520ae46ebSha137994 	if (cookie == NULL) {
196620ae46ebSha137994 		DWARN(ldcp->id,
196720ae46ebSha137994 		    "ldc_mem_dring_nextcookie:(0x%llx) invalid cookie arg\n",
196820ae46ebSha137994 		    ldcp->id);
196920ae46ebSha137994 		mutex_exit(&dringp->lock);
197020ae46ebSha137994 		return (EINVAL);
197120ae46ebSha137994 	}
197220ae46ebSha137994 
197320ae46ebSha137994 	rv = ldc_mem_nextcookie((ldc_mem_handle_t)dringp->mhdl, cookie);
197420ae46ebSha137994 	mutex_exit(&dringp->lock);
197520ae46ebSha137994 
197620ae46ebSha137994 	return (rv);
197720ae46ebSha137994 }
1978bbfa0259Sha137994 
197920ae46ebSha137994 /*
198020ae46ebSha137994  * Unbind a previously bound dring from a channel.
198120ae46ebSha137994  */
198220ae46ebSha137994 int
198320ae46ebSha137994 ldc_mem_dring_unbind(ldc_dring_handle_t dhandle)
198420ae46ebSha137994 {
198520ae46ebSha137994 	ldc_dring_t 	*dringp;
198620ae46ebSha137994 	ldc_dring_t	*tmp_dringp;
198720ae46ebSha137994 	ldc_chan_t	*ldcp;
198820ae46ebSha137994 
198920ae46ebSha137994 	if (dhandle == NULL) {
199020ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
199120ae46ebSha137994 		    "ldc_mem_dring_unbind: invalid desc ring handle\n");
199220ae46ebSha137994 		return (EINVAL);
199320ae46ebSha137994 	}
199420ae46ebSha137994 	dringp = (ldc_dring_t *)dhandle;
199520ae46ebSha137994 
199620ae46ebSha137994 	mutex_enter(&dringp->lock);
199720ae46ebSha137994 
199820ae46ebSha137994 	if (dringp->status == LDC_UNBOUND) {
199920ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
200020ae46ebSha137994 		    "ldc_mem_dring_bind: descriptor ring 0x%llx is unbound\n",
200120ae46ebSha137994 		    dringp);
200220ae46ebSha137994 		mutex_exit(&dringp->lock);
200320ae46ebSha137994 		return (EINVAL);
200420ae46ebSha137994 	}
200520ae46ebSha137994 	ldcp = dringp->ldcp;
200620ae46ebSha137994 
200720ae46ebSha137994 	mutex_enter(&ldcp->exp_dlist_lock);
200820ae46ebSha137994 
200920ae46ebSha137994 	tmp_dringp = ldcp->exp_dring_list;
201020ae46ebSha137994 	if (tmp_dringp == dringp) {
201120ae46ebSha137994 		ldcp->exp_dring_list = dringp->ch_next;
201220ae46ebSha137994 		dringp->ch_next = NULL;
201320ae46ebSha137994 
201420ae46ebSha137994 	} else {
201520ae46ebSha137994 		while (tmp_dringp != NULL) {
201620ae46ebSha137994 			if (tmp_dringp->ch_next == dringp) {
201720ae46ebSha137994 				tmp_dringp->ch_next = dringp->ch_next;
201820ae46ebSha137994 				dringp->ch_next = NULL;
201920ae46ebSha137994 				break;
202020ae46ebSha137994 			}
202120ae46ebSha137994 			tmp_dringp = tmp_dringp->ch_next;
202220ae46ebSha137994 		}
202320ae46ebSha137994 		if (tmp_dringp == NULL) {
202420ae46ebSha137994 			DWARN(DBG_ALL_LDCS,
202520ae46ebSha137994 			    "ldc_mem_dring_unbind: invalid descriptor\n");
202620ae46ebSha137994 			mutex_exit(&ldcp->exp_dlist_lock);
202720ae46ebSha137994 			mutex_exit(&dringp->lock);
202820ae46ebSha137994 			return (EINVAL);
202920ae46ebSha137994 		}
203020ae46ebSha137994 	}
203120ae46ebSha137994 
203220ae46ebSha137994 	mutex_exit(&ldcp->exp_dlist_lock);
203320ae46ebSha137994 
203420ae46ebSha137994 	(void) ldc_mem_unbind_handle((ldc_mem_handle_t)dringp->mhdl);
203520ae46ebSha137994 	(void) ldc_mem_free_handle((ldc_mem_handle_t)dringp->mhdl);
203620ae46ebSha137994 
203720ae46ebSha137994 	dringp->ldcp = NULL;
203820ae46ebSha137994 	dringp->mhdl = NULL;
203920ae46ebSha137994 	dringp->status = LDC_UNBOUND;
204020ae46ebSha137994 
204120ae46ebSha137994 	mutex_exit(&dringp->lock);
204220ae46ebSha137994 
204320ae46ebSha137994 	return (0);
204420ae46ebSha137994 }
204520ae46ebSha137994 
2046bbfa0259Sha137994 #ifdef	DEBUG
2047bbfa0259Sha137994 void
2048bbfa0259Sha137994 i_ldc_mem_inject_dring_clear(ldc_chan_t *ldcp)
2049bbfa0259Sha137994 {
2050bbfa0259Sha137994 	ldc_dring_t	*dp;
2051bbfa0259Sha137994 	ldc_mhdl_t	*mhdl;
2052bbfa0259Sha137994 	ldc_mtbl_t	*mtbl;
2053bbfa0259Sha137994 	ldc_memseg_t	*memseg;
2054bbfa0259Sha137994 	uint64_t	cookie_addr;
2055bbfa0259Sha137994 	uint64_t	pg_shift, pg_size_code;
2056bbfa0259Sha137994 	int		i, rv, retries;
2057bbfa0259Sha137994 
2058bbfa0259Sha137994 	/* has a map table been allocated? */
2059bbfa0259Sha137994 	if ((mtbl = ldcp->mtbl) == NULL)
2060bbfa0259Sha137994 		return;
2061bbfa0259Sha137994 
2062bbfa0259Sha137994 	/* lock the memory table - exclusive access to channel */
2063bbfa0259Sha137994 	mutex_enter(&mtbl->lock);
2064bbfa0259Sha137994 
2065bbfa0259Sha137994 	/* lock the exported dring list */
2066bbfa0259Sha137994 	mutex_enter(&ldcp->exp_dlist_lock);
2067bbfa0259Sha137994 
2068bbfa0259Sha137994 	for (dp = ldcp->exp_dring_list; dp != NULL; dp = dp->ch_next) {
2069bbfa0259Sha137994 		if ((mhdl = (ldc_mhdl_t *)dp->mhdl) == NULL)
2070bbfa0259Sha137994 			continue;
2071bbfa0259Sha137994 
2072bbfa0259Sha137994 		if ((memseg = mhdl->memseg) == NULL)
2073bbfa0259Sha137994 			continue;
2074bbfa0259Sha137994 
2075bbfa0259Sha137994 		/* undo the pages exported */
2076bbfa0259Sha137994 		for (i = 0; i < memseg->npages; i++) {
2077bbfa0259Sha137994 
2078bbfa0259Sha137994 			/* clear the entry from the table */
2079bbfa0259Sha137994 			memseg->pages[i].mte->entry.ll = 0;
2080bbfa0259Sha137994 
20815b7cb889Sha137994 			pg_size_code = page_szc(MMU_PAGESIZE);
2082bbfa0259Sha137994 			pg_shift = page_get_shift(pg_size_code);
2083bbfa0259Sha137994 			cookie_addr = IDX2COOKIE(memseg->pages[i].index,
2084bbfa0259Sha137994 			    pg_size_code, pg_shift);
2085bbfa0259Sha137994 
2086bbfa0259Sha137994 			retries = 0;
2087bbfa0259Sha137994 			do {
2088bbfa0259Sha137994 				rv = hv_ldc_revoke(ldcp->id, cookie_addr,
2089bbfa0259Sha137994 				    memseg->pages[i].mte->cookie);
2090bbfa0259Sha137994 
2091bbfa0259Sha137994 				if (rv != H_EWOULDBLOCK)
2092bbfa0259Sha137994 					break;
2093bbfa0259Sha137994 
2094bbfa0259Sha137994 				drv_usecwait(ldc_delay);
2095bbfa0259Sha137994 
2096bbfa0259Sha137994 			} while (retries++ < ldc_max_retries);
2097bbfa0259Sha137994 
2098bbfa0259Sha137994 			if (rv != 0) {
2099bbfa0259Sha137994 				DWARN(ldcp->id,
2100bbfa0259Sha137994 				    "i_ldc_mem_inject_dring_clear(): "
2101bbfa0259Sha137994 				    "hv_ldc_revoke failed: "
2102bbfa0259Sha137994 				    "channel: 0x%lx, cookie addr: 0x%p,"
2103bbfa0259Sha137994 				    "cookie: 0x%lx, rv: %d",
2104bbfa0259Sha137994 				    ldcp->id, cookie_addr,
2105bbfa0259Sha137994 				    memseg->pages[i].mte->cookie, rv);
2106bbfa0259Sha137994 			}
2107bbfa0259Sha137994 
2108bbfa0259Sha137994 			mtbl->num_avail++;
2109bbfa0259Sha137994 		}
2110bbfa0259Sha137994 	}
2111bbfa0259Sha137994 
2112bbfa0259Sha137994 	mutex_exit(&ldcp->exp_dlist_lock);
2113bbfa0259Sha137994 	mutex_exit(&mtbl->lock);
2114bbfa0259Sha137994 }
2115bbfa0259Sha137994 #endif
2116bbfa0259Sha137994 
211720ae46ebSha137994 /*
211820ae46ebSha137994  * Get information about the dring. The base address of the descriptor
211920ae46ebSha137994  * ring along with the type and permission are returned back.
212020ae46ebSha137994  */
212120ae46ebSha137994 int
212220ae46ebSha137994 ldc_mem_dring_info(ldc_dring_handle_t dhandle, ldc_mem_info_t *minfo)
212320ae46ebSha137994 {
212420ae46ebSha137994 	ldc_dring_t	*dringp;
212520ae46ebSha137994 	int		rv;
212620ae46ebSha137994 
212720ae46ebSha137994 	if (dhandle == NULL) {
212820ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
212920ae46ebSha137994 		    "ldc_mem_dring_info: invalid desc ring handle\n");
213020ae46ebSha137994 		return (EINVAL);
213120ae46ebSha137994 	}
213220ae46ebSha137994 	dringp = (ldc_dring_t *)dhandle;
213320ae46ebSha137994 
213420ae46ebSha137994 	mutex_enter(&dringp->lock);
213520ae46ebSha137994 
213620ae46ebSha137994 	if (dringp->mhdl) {
213720ae46ebSha137994 		rv = ldc_mem_info(dringp->mhdl, minfo);
213820ae46ebSha137994 		if (rv) {
213920ae46ebSha137994 			DWARN(DBG_ALL_LDCS,
214020ae46ebSha137994 			    "ldc_mem_dring_info: error reading mem info\n");
214120ae46ebSha137994 			mutex_exit(&dringp->lock);
214220ae46ebSha137994 			return (rv);
214320ae46ebSha137994 		}
214420ae46ebSha137994 	} else {
214520ae46ebSha137994 		minfo->vaddr = dringp->base;
214620ae46ebSha137994 		minfo->raddr = NULL;
214720ae46ebSha137994 		minfo->status = dringp->status;
214820ae46ebSha137994 	}
214920ae46ebSha137994 
215020ae46ebSha137994 	mutex_exit(&dringp->lock);
215120ae46ebSha137994 
215220ae46ebSha137994 	return (0);
215320ae46ebSha137994 }
215420ae46ebSha137994 
215520ae46ebSha137994 /*
215620ae46ebSha137994  * Map an exported descriptor ring into the local address space. If the
215720ae46ebSha137994  * descriptor ring was exported for direct map access, a HV call is made
215820ae46ebSha137994  * to allocate a RA range. If the map is done via a shadow copy, local
215920ae46ebSha137994  * shadow memory is allocated.
216020ae46ebSha137994  */
216120ae46ebSha137994 int
216220ae46ebSha137994 ldc_mem_dring_map(ldc_handle_t handle, ldc_mem_cookie_t *cookie,
216320ae46ebSha137994     uint32_t ccount, uint32_t len, uint32_t dsize, uint8_t mtype,
216420ae46ebSha137994     ldc_dring_handle_t *dhandle)
216520ae46ebSha137994 {
216620ae46ebSha137994 	int		err;
216720ae46ebSha137994 	ldc_chan_t 	*ldcp = (ldc_chan_t *)handle;
216820ae46ebSha137994 	ldc_mem_handle_t mhandle;
216920ae46ebSha137994 	ldc_dring_t	*dringp;
217020ae46ebSha137994 	size_t		dring_size;
217120ae46ebSha137994 
217220ae46ebSha137994 	if (dhandle == NULL) {
217320ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
217420ae46ebSha137994 		    "ldc_mem_dring_map: invalid dhandle\n");
217520ae46ebSha137994 		return (EINVAL);
217620ae46ebSha137994 	}
217720ae46ebSha137994 
217820ae46ebSha137994 	/* check to see if channel is initalized */
217920ae46ebSha137994 	if (handle == NULL) {
218020ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
218120ae46ebSha137994 		    "ldc_mem_dring_map: invalid channel handle\n");
218220ae46ebSha137994 		return (EINVAL);
218320ae46ebSha137994 	}
218420ae46ebSha137994 	ldcp = (ldc_chan_t *)handle;
218520ae46ebSha137994 
218620ae46ebSha137994 	if (cookie == NULL) {
218720ae46ebSha137994 		DWARN(ldcp->id,
218820ae46ebSha137994 		    "ldc_mem_dring_map: (0x%llx) invalid cookie\n",
218920ae46ebSha137994 		    ldcp->id);
219020ae46ebSha137994 		return (EINVAL);
219120ae46ebSha137994 	}
219220ae46ebSha137994 
219320ae46ebSha137994 	/* FUTURE: For now we support only one cookie per dring */
219420ae46ebSha137994 	ASSERT(ccount == 1);
219520ae46ebSha137994 
219620ae46ebSha137994 	if (cookie->size < (dsize * len)) {
219720ae46ebSha137994 		DWARN(ldcp->id,
219820ae46ebSha137994 		    "ldc_mem_dring_map: (0x%llx) invalid dsize/len\n",
219920ae46ebSha137994 		    ldcp->id);
220020ae46ebSha137994 		return (EINVAL);
220120ae46ebSha137994 	}
220220ae46ebSha137994 
2203bbfa0259Sha137994 	/* ensure the mtype is valid */
2204bbfa0259Sha137994 	if ((mtype & (LDC_SHADOW_MAP|LDC_DIRECT_MAP)) == 0) {
2205bbfa0259Sha137994 		DWARN(ldcp->id, "ldc_mem_dring_map: invalid map type\n");
2206bbfa0259Sha137994 		return (EINVAL);
2207bbfa0259Sha137994 	}
2208bbfa0259Sha137994 
2209bbfa0259Sha137994 	/* do not attempt direct map if it's not HV supported or enabled */
2210bbfa0259Sha137994 	if (!ldc_dring_shmem_hv_ok || !ldc_dring_shmem_enabled) {
2211bbfa0259Sha137994 		mtype = LDC_SHADOW_MAP;
2212bbfa0259Sha137994 	}
2213bbfa0259Sha137994 
221420ae46ebSha137994 	*dhandle = 0;
221520ae46ebSha137994 
221620ae46ebSha137994 	/* Allocate an dring structure */
221720ae46ebSha137994 	dringp = kmem_zalloc(sizeof (ldc_dring_t), KM_SLEEP);
221820ae46ebSha137994 
221920ae46ebSha137994 	D1(ldcp->id,
222020ae46ebSha137994 	    "ldc_mem_dring_map: 0x%x,0x%x,0x%x,0x%llx,0x%llx\n",
222120ae46ebSha137994 	    mtype, len, dsize, cookie->addr, cookie->size);
222220ae46ebSha137994 
222320ae46ebSha137994 	/* Initialize dring */
222420ae46ebSha137994 	dringp->length = len;
222520ae46ebSha137994 	dringp->dsize = dsize;
222620ae46ebSha137994 
222720ae46ebSha137994 	/* round of to multiple of page size */
222820ae46ebSha137994 	dring_size = len * dsize;
222920ae46ebSha137994 	dringp->size = (dring_size & MMU_PAGEMASK);
223020ae46ebSha137994 	if (dring_size & MMU_PAGEOFFSET)
223120ae46ebSha137994 		dringp->size += MMU_PAGESIZE;
223220ae46ebSha137994 
223320ae46ebSha137994 	dringp->ldcp = ldcp;
223420ae46ebSha137994 
223520ae46ebSha137994 	/* create an memory handle */
223620ae46ebSha137994 	err = ldc_mem_alloc_handle(handle, &mhandle);
223720ae46ebSha137994 	if (err || mhandle == NULL) {
223820ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
223920ae46ebSha137994 		    "ldc_mem_dring_map: cannot alloc hdl err=%d\n",
224020ae46ebSha137994 		    err);
224120ae46ebSha137994 		kmem_free(dringp, sizeof (ldc_dring_t));
224220ae46ebSha137994 		return (ENOMEM);
224320ae46ebSha137994 	}
224420ae46ebSha137994 
224520ae46ebSha137994 	dringp->mhdl = mhandle;
224620ae46ebSha137994 	dringp->base = NULL;
224720ae46ebSha137994 
224820ae46ebSha137994 	/* map the dring into local memory */
2249bbfa0259Sha137994 	err = i_ldc_mem_map(mhandle, cookie, ccount, mtype, LDC_MEM_RW,
225020ae46ebSha137994 	    &(dringp->base), NULL);
225120ae46ebSha137994 	if (err || dringp->base == NULL) {
2252bbfa0259Sha137994 		DWARN(DBG_ALL_LDCS,
225320ae46ebSha137994 		    "ldc_mem_dring_map: cannot map desc ring err=%d\n", err);
225420ae46ebSha137994 		(void) ldc_mem_free_handle(mhandle);
225520ae46ebSha137994 		kmem_free(dringp, sizeof (ldc_dring_t));
225620ae46ebSha137994 		return (ENOMEM);
225720ae46ebSha137994 	}
225820ae46ebSha137994 
225920ae46ebSha137994 	/* initialize the desc ring lock */
226020ae46ebSha137994 	mutex_init(&dringp->lock, NULL, MUTEX_DRIVER, NULL);
226120ae46ebSha137994 
226220ae46ebSha137994 	/* Add descriptor ring to channel's imported dring list */
226320ae46ebSha137994 	mutex_enter(&ldcp->imp_dlist_lock);
226420ae46ebSha137994 	dringp->ch_next = ldcp->imp_dring_list;
226520ae46ebSha137994 	ldcp->imp_dring_list = dringp;
226620ae46ebSha137994 	mutex_exit(&ldcp->imp_dlist_lock);
226720ae46ebSha137994 
226820ae46ebSha137994 	dringp->status = LDC_MAPPED;
226920ae46ebSha137994 
227020ae46ebSha137994 	*dhandle = (ldc_dring_handle_t)dringp;
227120ae46ebSha137994 
227220ae46ebSha137994 	return (0);
227320ae46ebSha137994 }
227420ae46ebSha137994 
227520ae46ebSha137994 /*
227620ae46ebSha137994  * Unmap a descriptor ring. Free shadow memory (if any).
227720ae46ebSha137994  */
227820ae46ebSha137994 int
227920ae46ebSha137994 ldc_mem_dring_unmap(ldc_dring_handle_t dhandle)
228020ae46ebSha137994 {
228120ae46ebSha137994 	ldc_dring_t 	*dringp;
228220ae46ebSha137994 	ldc_dring_t	*tmp_dringp;
228320ae46ebSha137994 	ldc_chan_t	*ldcp;
228420ae46ebSha137994 
228520ae46ebSha137994 	if (dhandle == NULL) {
228620ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
228720ae46ebSha137994 		    "ldc_mem_dring_unmap: invalid desc ring handle\n");
228820ae46ebSha137994 		return (EINVAL);
228920ae46ebSha137994 	}
229020ae46ebSha137994 	dringp = (ldc_dring_t *)dhandle;
229120ae46ebSha137994 
229220ae46ebSha137994 	if (dringp->status != LDC_MAPPED) {
229320ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
229420ae46ebSha137994 		    "ldc_mem_dring_unmap: not a mapped desc ring\n");
229520ae46ebSha137994 		return (EINVAL);
229620ae46ebSha137994 	}
229720ae46ebSha137994 
229820ae46ebSha137994 	mutex_enter(&dringp->lock);
229920ae46ebSha137994 
230020ae46ebSha137994 	ldcp = dringp->ldcp;
230120ae46ebSha137994 
230220ae46ebSha137994 	mutex_enter(&ldcp->imp_dlist_lock);
230320ae46ebSha137994 
230420ae46ebSha137994 	/* find and unlink the desc ring from channel import list */
230520ae46ebSha137994 	tmp_dringp = ldcp->imp_dring_list;
230620ae46ebSha137994 	if (tmp_dringp == dringp) {
230720ae46ebSha137994 		ldcp->imp_dring_list = dringp->ch_next;
230820ae46ebSha137994 		dringp->ch_next = NULL;
230920ae46ebSha137994 
231020ae46ebSha137994 	} else {
231120ae46ebSha137994 		while (tmp_dringp != NULL) {
231220ae46ebSha137994 			if (tmp_dringp->ch_next == dringp) {
231320ae46ebSha137994 				tmp_dringp->ch_next = dringp->ch_next;
231420ae46ebSha137994 				dringp->ch_next = NULL;
231520ae46ebSha137994 				break;
231620ae46ebSha137994 			}
231720ae46ebSha137994 			tmp_dringp = tmp_dringp->ch_next;
231820ae46ebSha137994 		}
231920ae46ebSha137994 		if (tmp_dringp == NULL) {
232020ae46ebSha137994 			DWARN(DBG_ALL_LDCS,
232120ae46ebSha137994 			    "ldc_mem_dring_unmap: invalid descriptor\n");
232220ae46ebSha137994 			mutex_exit(&ldcp->imp_dlist_lock);
232320ae46ebSha137994 			mutex_exit(&dringp->lock);
232420ae46ebSha137994 			return (EINVAL);
232520ae46ebSha137994 		}
232620ae46ebSha137994 	}
232720ae46ebSha137994 
232820ae46ebSha137994 	mutex_exit(&ldcp->imp_dlist_lock);
232920ae46ebSha137994 
233020ae46ebSha137994 	/* do a LDC memory handle unmap and free */
233120ae46ebSha137994 	(void) ldc_mem_unmap(dringp->mhdl);
233220ae46ebSha137994 	(void) ldc_mem_free_handle((ldc_mem_handle_t)dringp->mhdl);
233320ae46ebSha137994 
233420ae46ebSha137994 	dringp->status = 0;
233520ae46ebSha137994 	dringp->ldcp = NULL;
233620ae46ebSha137994 
233720ae46ebSha137994 	mutex_exit(&dringp->lock);
233820ae46ebSha137994 
233920ae46ebSha137994 	/* destroy dring lock */
234020ae46ebSha137994 	mutex_destroy(&dringp->lock);
234120ae46ebSha137994 
234220ae46ebSha137994 	/* free desc ring object */
234320ae46ebSha137994 	kmem_free(dringp, sizeof (ldc_dring_t));
234420ae46ebSha137994 
234520ae46ebSha137994 	return (0);
234620ae46ebSha137994 }
234720ae46ebSha137994 
234820ae46ebSha137994 /*
234920ae46ebSha137994  * Internal entry point for descriptor ring access entry consistency
235020ae46ebSha137994  * semantics. Acquire copies the contents of the remote descriptor ring
235120ae46ebSha137994  * into the local shadow copy. The release operation copies the local
235220ae46ebSha137994  * contents into the remote dring. The start and end locations specify
235320ae46ebSha137994  * bounds for the entries being synchronized.
235420ae46ebSha137994  */
235520ae46ebSha137994 static int
235620ae46ebSha137994 i_ldc_dring_acquire_release(ldc_dring_handle_t dhandle,
235720ae46ebSha137994     uint8_t direction, uint64_t start, uint64_t end)
235820ae46ebSha137994 {
235920ae46ebSha137994 	int 			err;
236020ae46ebSha137994 	ldc_dring_t		*dringp;
236120ae46ebSha137994 	ldc_chan_t		*ldcp;
2362bbfa0259Sha137994 	ldc_mhdl_t		*mhdl;
236320ae46ebSha137994 	uint64_t		soff;
236420ae46ebSha137994 	size_t			copy_size;
236520ae46ebSha137994 
236620ae46ebSha137994 	if (dhandle == NULL) {
236720ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
236820ae46ebSha137994 		    "i_ldc_dring_acquire_release: invalid desc ring handle\n");
236920ae46ebSha137994 		return (EINVAL);
237020ae46ebSha137994 	}
237120ae46ebSha137994 	dringp = (ldc_dring_t *)dhandle;
237220ae46ebSha137994 	mutex_enter(&dringp->lock);
237320ae46ebSha137994 
237420ae46ebSha137994 	if (dringp->status != LDC_MAPPED || dringp->ldcp == NULL) {
237520ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
237620ae46ebSha137994 		    "i_ldc_dring_acquire_release: not a mapped desc ring\n");
237720ae46ebSha137994 		mutex_exit(&dringp->lock);
237820ae46ebSha137994 		return (EINVAL);
237920ae46ebSha137994 	}
238020ae46ebSha137994 
238120ae46ebSha137994 	if (start >= dringp->length || end >= dringp->length) {
238220ae46ebSha137994 		DWARN(DBG_ALL_LDCS,
238320ae46ebSha137994 		    "i_ldc_dring_acquire_release: index out of range\n");
238420ae46ebSha137994 		mutex_exit(&dringp->lock);
238520ae46ebSha137994 		return (EINVAL);
238620ae46ebSha137994 	}
238720ae46ebSha137994 
2388bbfa0259Sha137994 	mhdl = (ldc_mhdl_t *)dringp->mhdl;
2389bbfa0259Sha137994 	if (mhdl == NULL) {
2390bbfa0259Sha137994 		DWARN(DBG_ALL_LDCS,
2391bbfa0259Sha137994 		    "i_ldc_dring_acquire_release: invalid memory handle\n");
2392bbfa0259Sha137994 		mutex_exit(&dringp->lock);
2393bbfa0259Sha137994 		return (EINVAL);
2394bbfa0259Sha137994 	}
2395bbfa0259Sha137994 
2396bbfa0259Sha137994 	if (mhdl->mtype != LDC_SHADOW_MAP) {
2397bbfa0259Sha137994 		DWARN(DBG_ALL_LDCS,
2398bbfa0259Sha137994 		    "i_ldc_dring_acquire_release: invalid mtype: %d\n",
2399bbfa0259Sha137994 		    mhdl->mtype);
2400bbfa0259Sha137994 		mutex_exit(&dringp->lock);
2401bbfa0259Sha137994 		return (EINVAL);
2402bbfa0259Sha137994 	}
2403bbfa0259Sha137994 
240420ae46ebSha137994 	/* get the channel handle */
240520ae46ebSha137994 	ldcp = dringp->ldcp;
240620ae46ebSha137994 
240720ae46ebSha137994 	copy_size = (start <= end) ? (((end - start) + 1) * dringp->dsize) :
240820ae46ebSha137994 	    ((dringp->length - start) * dringp->dsize);
240920ae46ebSha137994 
241020ae46ebSha137994 	/* Calculate the relative offset for the first desc */
241120ae46ebSha137994 	soff = (start * dringp->dsize);
241220ae46ebSha137994 
241320ae46ebSha137994 	/* copy to/from remote from/to local memory */
241420ae46ebSha137994 	D1(ldcp->id, "i_ldc_dring_acquire_release: c1 off=0x%llx sz=0x%llx\n",
241520ae46ebSha137994 	    soff, copy_size);
241620ae46ebSha137994 	err = i_ldc_mem_acquire_release((ldc_mem_handle_t)dringp->mhdl,
241720ae46ebSha137994 	    direction, soff, copy_size);
241820ae46ebSha137994 	if (err) {
241920ae46ebSha137994 		DWARN(ldcp->id,
242020ae46ebSha137994 		    "i_ldc_dring_acquire_release: copy failed\n");
242120ae46ebSha137994 		mutex_exit(&dringp->lock);
242220ae46ebSha137994 		return (err);
242320ae46ebSha137994 	}
242420ae46ebSha137994 
242520ae46ebSha137994 	/* do the balance */
242620ae46ebSha137994 	if (start > end) {
242720ae46ebSha137994 		copy_size = ((end + 1) * dringp->dsize);
242820ae46ebSha137994 		soff = 0;
242920ae46ebSha137994 
243020ae46ebSha137994 		/* copy to/from remote from/to local memory */
243120ae46ebSha137994 		D1(ldcp->id, "i_ldc_dring_acquire_release: c2 "
243220ae46ebSha137994 		    "off=0x%llx sz=0x%llx\n", soff, copy_size);
243320ae46ebSha137994 		err = i_ldc_mem_acquire_release((ldc_mem_handle_t)dringp->mhdl,
243420ae46ebSha137994 		    direction, soff, copy_size);
243520ae46ebSha137994 		if (err) {
243620ae46ebSha137994 			DWARN(ldcp->id,
243720ae46ebSha137994 			    "i_ldc_dring_acquire_release: copy failed\n");
243820ae46ebSha137994 			mutex_exit(&dringp->lock);
243920ae46ebSha137994 			return (err);
244020ae46ebSha137994 		}
244120ae46ebSha137994 	}
244220ae46ebSha137994 
244320ae46ebSha137994 	mutex_exit(&dringp->lock);
244420ae46ebSha137994 
244520ae46ebSha137994 	return (0);
244620ae46ebSha137994 }
244720ae46ebSha137994 
244820ae46ebSha137994 /*
244920ae46ebSha137994  * Ensure that the contents in the local dring are consistent
245020ae46ebSha137994  * with the contents if of remote dring
245120ae46ebSha137994  */
245220ae46ebSha137994 int
245320ae46ebSha137994 ldc_mem_dring_acquire(ldc_dring_handle_t dhandle, uint64_t start, uint64_t end)
245420ae46ebSha137994 {
245520ae46ebSha137994 	return (i_ldc_dring_acquire_release(dhandle, LDC_COPY_IN, start, end));
245620ae46ebSha137994 }
245720ae46ebSha137994 
245820ae46ebSha137994 /*
245920ae46ebSha137994  * Ensure that the contents in the remote dring are consistent
246020ae46ebSha137994  * with the contents if of local dring
246120ae46ebSha137994  */
246220ae46ebSha137994 int
246320ae46ebSha137994 ldc_mem_dring_release(ldc_dring_handle_t dhandle, uint64_t start, uint64_t end)
246420ae46ebSha137994 {
246520ae46ebSha137994 	return (i_ldc_dring_acquire_release(dhandle, LDC_COPY_OUT, start, end));
246620ae46ebSha137994 }
2467