xref: /onnv-gate/usr/src/uts/sun4v/io/ldc_shm.c (revision 6408:2dba2c05f7fb)
1*6408Sha137994 /*
2*6408Sha137994  * CDDL HEADER START
3*6408Sha137994  *
4*6408Sha137994  * The contents of this file are subject to the terms of the
5*6408Sha137994  * Common Development and Distribution License (the "License").
6*6408Sha137994  * You may not use this file except in compliance with the License.
7*6408Sha137994  *
8*6408Sha137994  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*6408Sha137994  * or http://www.opensolaris.org/os/licensing.
10*6408Sha137994  * See the License for the specific language governing permissions
11*6408Sha137994  * and limitations under the License.
12*6408Sha137994  *
13*6408Sha137994  * When distributing Covered Code, include this CDDL HEADER in each
14*6408Sha137994  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*6408Sha137994  * If applicable, add the following below this CDDL HEADER, with the
16*6408Sha137994  * fields enclosed by brackets "[]" replaced with your own identifying
17*6408Sha137994  * information: Portions Copyright [yyyy] [name of copyright owner]
18*6408Sha137994  *
19*6408Sha137994  * CDDL HEADER END
20*6408Sha137994  */
21*6408Sha137994 
22*6408Sha137994 /*
23*6408Sha137994  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24*6408Sha137994  * Use is subject to license terms.
25*6408Sha137994  */
26*6408Sha137994 
27*6408Sha137994 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*6408Sha137994 
29*6408Sha137994 /*
30*6408Sha137994  * sun4v LDC Link Layer Shared Memory Routines
31*6408Sha137994  */
32*6408Sha137994 #include <sys/types.h>
33*6408Sha137994 #include <sys/kmem.h>
34*6408Sha137994 #include <sys/cmn_err.h>
35*6408Sha137994 #include <sys/ksynch.h>
36*6408Sha137994 #include <sys/debug.h>
37*6408Sha137994 #include <sys/cyclic.h>
38*6408Sha137994 #include <sys/machsystm.h>
39*6408Sha137994 #include <sys/vm.h>
40*6408Sha137994 #include <sys/machcpuvar.h>
41*6408Sha137994 #include <sys/mmu.h>
42*6408Sha137994 #include <sys/pte.h>
43*6408Sha137994 #include <vm/hat.h>
44*6408Sha137994 #include <vm/as.h>
45*6408Sha137994 #include <vm/hat_sfmmu.h>
46*6408Sha137994 #include <sys/vm_machparam.h>
47*6408Sha137994 #include <vm/seg_kmem.h>
48*6408Sha137994 #include <vm/seg_kpm.h>
49*6408Sha137994 #include <sys/hypervisor_api.h>
50*6408Sha137994 #include <sys/ldc.h>
51*6408Sha137994 #include <sys/ldc_impl.h>
52*6408Sha137994 
53*6408Sha137994 /* LDC variables used by shared memory routines */
54*6408Sha137994 extern ldc_soft_state_t *ldcssp;
55*6408Sha137994 extern int ldc_max_retries;
56*6408Sha137994 extern clock_t ldc_delay;
57*6408Sha137994 
58*6408Sha137994 #ifdef DEBUG
59*6408Sha137994 extern int ldcdbg;
60*6408Sha137994 #endif
61*6408Sha137994 
62*6408Sha137994 /* LDC internal functions used by shared memory routines */
63*6408Sha137994 extern void i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset);
64*6408Sha137994 extern int i_ldc_h2v_error(int h_error);
65*6408Sha137994 
66*6408Sha137994 #ifdef DEBUG
67*6408Sha137994 extern void ldcdebug(int64_t id, const char *fmt, ...);
68*6408Sha137994 #endif
69*6408Sha137994 
70*6408Sha137994 /* Memory synchronization internal functions */
71*6408Sha137994 static int i_ldc_mem_acquire_release(ldc_mem_handle_t mhandle,
72*6408Sha137994     uint8_t direction, uint64_t offset, size_t size);
73*6408Sha137994 static int i_ldc_dring_acquire_release(ldc_dring_handle_t dhandle,
74*6408Sha137994     uint8_t direction, uint64_t start, uint64_t end);
75*6408Sha137994 
76*6408Sha137994 /*
77*6408Sha137994  * LDC framework supports mapping remote domain's memory
78*6408Sha137994  * either directly or via shadow memory pages. Default
79*6408Sha137994  * support is currently implemented via shadow copy.
80*6408Sha137994  * Direct map can be enabled by setting 'ldc_shmem_enabled'
81*6408Sha137994  */
82*6408Sha137994 int ldc_shmem_enabled = 0;
83*6408Sha137994 
84*6408Sha137994 /*
85*6408Sha137994  * Pages exported for remote access over each channel is
86*6408Sha137994  * maintained in a table registered with the Hypervisor.
87*6408Sha137994  * The default number of entries in the table is set to
88*6408Sha137994  * 'ldc_mtbl_entries'.
89*6408Sha137994  */
90*6408Sha137994 uint64_t ldc_maptable_entries = LDC_MTBL_ENTRIES;
91*6408Sha137994 
92*6408Sha137994 #define	IDX2COOKIE(idx, pg_szc, pg_shift)				\
93*6408Sha137994 	(((pg_szc) << LDC_COOKIE_PGSZC_SHIFT) | ((idx) << (pg_shift)))
94*6408Sha137994 
95*6408Sha137994 /*
96*6408Sha137994  * Allocate a memory handle for the channel and link it into the list
97*6408Sha137994  * Also choose which memory table to use if this is the first handle
98*6408Sha137994  * being assigned to this channel
99*6408Sha137994  */
100*6408Sha137994 int
101*6408Sha137994 ldc_mem_alloc_handle(ldc_handle_t handle, ldc_mem_handle_t *mhandle)
102*6408Sha137994 {
103*6408Sha137994 	ldc_chan_t 	*ldcp;
104*6408Sha137994 	ldc_mhdl_t	*mhdl;
105*6408Sha137994 
106*6408Sha137994 	if (handle == NULL) {
107*6408Sha137994 		DWARN(DBG_ALL_LDCS,
108*6408Sha137994 		    "ldc_mem_alloc_handle: invalid channel handle\n");
109*6408Sha137994 		return (EINVAL);
110*6408Sha137994 	}
111*6408Sha137994 	ldcp = (ldc_chan_t *)handle;
112*6408Sha137994 
113*6408Sha137994 	mutex_enter(&ldcp->lock);
114*6408Sha137994 
115*6408Sha137994 	/* check to see if channel is initalized */
116*6408Sha137994 	if ((ldcp->tstate & ~TS_IN_RESET) < TS_INIT) {
117*6408Sha137994 		DWARN(ldcp->id,
118*6408Sha137994 		    "ldc_mem_alloc_handle: (0x%llx) channel not initialized\n",
119*6408Sha137994 		    ldcp->id);
120*6408Sha137994 		mutex_exit(&ldcp->lock);
121*6408Sha137994 		return (EINVAL);
122*6408Sha137994 	}
123*6408Sha137994 
124*6408Sha137994 	/* allocate handle for channel */
125*6408Sha137994 	mhdl = kmem_cache_alloc(ldcssp->memhdl_cache, KM_SLEEP);
126*6408Sha137994 
127*6408Sha137994 	/* initialize the lock */
128*6408Sha137994 	mutex_init(&mhdl->lock, NULL, MUTEX_DRIVER, NULL);
129*6408Sha137994 
130*6408Sha137994 	mhdl->myshadow = B_FALSE;
131*6408Sha137994 	mhdl->memseg = NULL;
132*6408Sha137994 	mhdl->ldcp = ldcp;
133*6408Sha137994 	mhdl->status = LDC_UNBOUND;
134*6408Sha137994 
135*6408Sha137994 	/* insert memory handle (@ head) into list */
136*6408Sha137994 	if (ldcp->mhdl_list == NULL) {
137*6408Sha137994 		ldcp->mhdl_list = mhdl;
138*6408Sha137994 		mhdl->next = NULL;
139*6408Sha137994 	} else {
140*6408Sha137994 		/* insert @ head */
141*6408Sha137994 		mhdl->next = ldcp->mhdl_list;
142*6408Sha137994 		ldcp->mhdl_list = mhdl;
143*6408Sha137994 	}
144*6408Sha137994 
145*6408Sha137994 	/* return the handle */
146*6408Sha137994 	*mhandle = (ldc_mem_handle_t)mhdl;
147*6408Sha137994 
148*6408Sha137994 	mutex_exit(&ldcp->lock);
149*6408Sha137994 
150*6408Sha137994 	D1(ldcp->id, "ldc_mem_alloc_handle: (0x%llx) allocated handle 0x%llx\n",
151*6408Sha137994 	    ldcp->id, mhdl);
152*6408Sha137994 
153*6408Sha137994 	return (0);
154*6408Sha137994 }
155*6408Sha137994 
156*6408Sha137994 /*
157*6408Sha137994  * Free memory handle for the channel and unlink it from the list
158*6408Sha137994  */
159*6408Sha137994 int
160*6408Sha137994 ldc_mem_free_handle(ldc_mem_handle_t mhandle)
161*6408Sha137994 {
162*6408Sha137994 	ldc_mhdl_t 	*mhdl, *phdl;
163*6408Sha137994 	ldc_chan_t 	*ldcp;
164*6408Sha137994 
165*6408Sha137994 	if (mhandle == NULL) {
166*6408Sha137994 		DWARN(DBG_ALL_LDCS,
167*6408Sha137994 		    "ldc_mem_free_handle: invalid memory handle\n");
168*6408Sha137994 		return (EINVAL);
169*6408Sha137994 	}
170*6408Sha137994 	mhdl = (ldc_mhdl_t *)mhandle;
171*6408Sha137994 
172*6408Sha137994 	mutex_enter(&mhdl->lock);
173*6408Sha137994 
174*6408Sha137994 	ldcp = mhdl->ldcp;
175*6408Sha137994 
176*6408Sha137994 	if (mhdl->status == LDC_BOUND || mhdl->status == LDC_MAPPED) {
177*6408Sha137994 		DWARN(ldcp->id,
178*6408Sha137994 		    "ldc_mem_free_handle: cannot free, 0x%llx hdl bound\n",
179*6408Sha137994 		    mhdl);
180*6408Sha137994 		mutex_exit(&mhdl->lock);
181*6408Sha137994 		return (EINVAL);
182*6408Sha137994 	}
183*6408Sha137994 	mutex_exit(&mhdl->lock);
184*6408Sha137994 
185*6408Sha137994 	mutex_enter(&ldcp->mlist_lock);
186*6408Sha137994 
187*6408Sha137994 	phdl = ldcp->mhdl_list;
188*6408Sha137994 
189*6408Sha137994 	/* first handle */
190*6408Sha137994 	if (phdl == mhdl) {
191*6408Sha137994 		ldcp->mhdl_list = mhdl->next;
192*6408Sha137994 		mutex_destroy(&mhdl->lock);
193*6408Sha137994 		kmem_cache_free(ldcssp->memhdl_cache, mhdl);
194*6408Sha137994 
195*6408Sha137994 		D1(ldcp->id,
196*6408Sha137994 		    "ldc_mem_free_handle: (0x%llx) freed handle 0x%llx\n",
197*6408Sha137994 		    ldcp->id, mhdl);
198*6408Sha137994 	} else {
199*6408Sha137994 		/* walk the list - unlink and free */
200*6408Sha137994 		while (phdl != NULL) {
201*6408Sha137994 			if (phdl->next == mhdl) {
202*6408Sha137994 				phdl->next = mhdl->next;
203*6408Sha137994 				mutex_destroy(&mhdl->lock);
204*6408Sha137994 				kmem_cache_free(ldcssp->memhdl_cache, mhdl);
205*6408Sha137994 				D1(ldcp->id,
206*6408Sha137994 				    "ldc_mem_free_handle: (0x%llx) freed "
207*6408Sha137994 				    "handle 0x%llx\n", ldcp->id, mhdl);
208*6408Sha137994 				break;
209*6408Sha137994 			}
210*6408Sha137994 			phdl = phdl->next;
211*6408Sha137994 		}
212*6408Sha137994 	}
213*6408Sha137994 
214*6408Sha137994 	if (phdl == NULL) {
215*6408Sha137994 		DWARN(ldcp->id,
216*6408Sha137994 		    "ldc_mem_free_handle: invalid handle 0x%llx\n", mhdl);
217*6408Sha137994 		mutex_exit(&ldcp->mlist_lock);
218*6408Sha137994 		return (EINVAL);
219*6408Sha137994 	}
220*6408Sha137994 
221*6408Sha137994 	mutex_exit(&ldcp->mlist_lock);
222*6408Sha137994 
223*6408Sha137994 	return (0);
224*6408Sha137994 }
225*6408Sha137994 
226*6408Sha137994 /*
227*6408Sha137994  * Bind a memory handle to a virtual address.
228*6408Sha137994  * The virtual address is converted to the corresponding real addresses.
229*6408Sha137994  * Returns pointer to the first ldc_mem_cookie and the total number
230*6408Sha137994  * of cookies for this virtual address. Other cookies can be obtained
231*6408Sha137994  * using the ldc_mem_nextcookie() call. If the pages are stored in
232*6408Sha137994  * consecutive locations in the table, a single cookie corresponding to
233*6408Sha137994  * the first location is returned. The cookie size spans all the entries.
234*6408Sha137994  *
235*6408Sha137994  * If the VA corresponds to a page that is already being exported, reuse
236*6408Sha137994  * the page and do not export it again. Bump the page's use count.
237*6408Sha137994  */
238*6408Sha137994 int
239*6408Sha137994 ldc_mem_bind_handle(ldc_mem_handle_t mhandle, caddr_t vaddr, size_t len,
240*6408Sha137994     uint8_t mtype, uint8_t perm, ldc_mem_cookie_t *cookie, uint32_t *ccount)
241*6408Sha137994 {
242*6408Sha137994 	ldc_mhdl_t	*mhdl;
243*6408Sha137994 	ldc_chan_t 	*ldcp;
244*6408Sha137994 	ldc_mtbl_t	*mtbl;
245*6408Sha137994 	ldc_memseg_t	*memseg;
246*6408Sha137994 	ldc_mte_t	tmp_mte;
247*6408Sha137994 	uint64_t	index, prev_index = 0;
248*6408Sha137994 	int64_t		cookie_idx;
249*6408Sha137994 	uintptr_t	raddr, ra_aligned;
250*6408Sha137994 	uint64_t	psize, poffset, v_offset;
251*6408Sha137994 	uint64_t	pg_shift, pg_size, pg_size_code, pg_mask;
252*6408Sha137994 	pgcnt_t		npages;
253*6408Sha137994 	caddr_t		v_align, addr;
254*6408Sha137994 	int 		i, rv;
255*6408Sha137994 
256*6408Sha137994 	if (mhandle == NULL) {
257*6408Sha137994 		DWARN(DBG_ALL_LDCS,
258*6408Sha137994 		    "ldc_mem_bind_handle: invalid memory handle\n");
259*6408Sha137994 		return (EINVAL);
260*6408Sha137994 	}
261*6408Sha137994 	mhdl = (ldc_mhdl_t *)mhandle;
262*6408Sha137994 	ldcp = mhdl->ldcp;
263*6408Sha137994 
264*6408Sha137994 	/* clear count */
265*6408Sha137994 	*ccount = 0;
266*6408Sha137994 
267*6408Sha137994 	mutex_enter(&mhdl->lock);
268*6408Sha137994 
269*6408Sha137994 	if (mhdl->status == LDC_BOUND || mhdl->memseg != NULL) {
270*6408Sha137994 		DWARN(ldcp->id,
271*6408Sha137994 		    "ldc_mem_bind_handle: (0x%x) handle already bound\n",
272*6408Sha137994 		    mhandle);
273*6408Sha137994 		mutex_exit(&mhdl->lock);
274*6408Sha137994 		return (EINVAL);
275*6408Sha137994 	}
276*6408Sha137994 
277*6408Sha137994 	/* Force address and size to be 8-byte aligned */
278*6408Sha137994 	if ((((uintptr_t)vaddr | len) & 0x7) != 0) {
279*6408Sha137994 		DWARN(ldcp->id,
280*6408Sha137994 		    "ldc_mem_bind_handle: addr/size is not 8-byte aligned\n");
281*6408Sha137994 		mutex_exit(&mhdl->lock);
282*6408Sha137994 		return (EINVAL);
283*6408Sha137994 	}
284*6408Sha137994 
285*6408Sha137994 	/*
286*6408Sha137994 	 * If this channel is binding a memory handle for the
287*6408Sha137994 	 * first time allocate it a memory map table and initialize it
288*6408Sha137994 	 */
289*6408Sha137994 	if ((mtbl = ldcp->mtbl) == NULL) {
290*6408Sha137994 
291*6408Sha137994 		mutex_enter(&ldcp->lock);
292*6408Sha137994 
293*6408Sha137994 		/* Allocate and initialize the map table structure */
294*6408Sha137994 		mtbl = kmem_zalloc(sizeof (ldc_mtbl_t), KM_SLEEP);
295*6408Sha137994 		mtbl->num_entries = mtbl->num_avail = ldc_maptable_entries;
296*6408Sha137994 		mtbl->size = ldc_maptable_entries * sizeof (ldc_mte_slot_t);
297*6408Sha137994 		mtbl->next_entry = NULL;
298*6408Sha137994 		mtbl->contigmem = B_TRUE;
299*6408Sha137994 
300*6408Sha137994 		/* Allocate the table itself */
301*6408Sha137994 		mtbl->table = (ldc_mte_slot_t *)
302*6408Sha137994 		    contig_mem_alloc_align(mtbl->size, MMU_PAGESIZE);
303*6408Sha137994 		if (mtbl->table == NULL) {
304*6408Sha137994 
305*6408Sha137994 			/* allocate a page of memory using kmem_alloc */
306*6408Sha137994 			mtbl->table = kmem_alloc(MMU_PAGESIZE, KM_SLEEP);
307*6408Sha137994 			mtbl->size = MMU_PAGESIZE;
308*6408Sha137994 			mtbl->contigmem = B_FALSE;
309*6408Sha137994 			mtbl->num_entries = mtbl->num_avail =
310*6408Sha137994 			    mtbl->size / sizeof (ldc_mte_slot_t);
311*6408Sha137994 			DWARN(ldcp->id,
312*6408Sha137994 			    "ldc_mem_bind_handle: (0x%llx) reduced tbl size "
313*6408Sha137994 			    "to %lx entries\n", ldcp->id, mtbl->num_entries);
314*6408Sha137994 		}
315*6408Sha137994 
316*6408Sha137994 		/* zero out the memory */
317*6408Sha137994 		bzero(mtbl->table, mtbl->size);
318*6408Sha137994 
319*6408Sha137994 		/* initialize the lock */
320*6408Sha137994 		mutex_init(&mtbl->lock, NULL, MUTEX_DRIVER, NULL);
321*6408Sha137994 
322*6408Sha137994 		/* register table for this channel */
323*6408Sha137994 		rv = hv_ldc_set_map_table(ldcp->id,
324*6408Sha137994 		    va_to_pa(mtbl->table), mtbl->num_entries);
325*6408Sha137994 		if (rv != 0) {
326*6408Sha137994 			cmn_err(CE_WARN,
327*6408Sha137994 			    "ldc_mem_bind_handle: (0x%lx) err %d mapping tbl",
328*6408Sha137994 			    ldcp->id, rv);
329*6408Sha137994 			if (mtbl->contigmem)
330*6408Sha137994 				contig_mem_free(mtbl->table, mtbl->size);
331*6408Sha137994 			else
332*6408Sha137994 				kmem_free(mtbl->table, mtbl->size);
333*6408Sha137994 			mutex_destroy(&mtbl->lock);
334*6408Sha137994 			kmem_free(mtbl, sizeof (ldc_mtbl_t));
335*6408Sha137994 			mutex_exit(&ldcp->lock);
336*6408Sha137994 			mutex_exit(&mhdl->lock);
337*6408Sha137994 			return (EIO);
338*6408Sha137994 		}
339*6408Sha137994 
340*6408Sha137994 		ldcp->mtbl = mtbl;
341*6408Sha137994 		mutex_exit(&ldcp->lock);
342*6408Sha137994 
343*6408Sha137994 		D1(ldcp->id,
344*6408Sha137994 		    "ldc_mem_bind_handle: (0x%llx) alloc'd map table 0x%llx\n",
345*6408Sha137994 		    ldcp->id, ldcp->mtbl->table);
346*6408Sha137994 	}
347*6408Sha137994 
348*6408Sha137994 	/* FUTURE: get the page size, pgsz code, and shift */
349*6408Sha137994 	pg_size = MMU_PAGESIZE;
350*6408Sha137994 	pg_size_code = page_szc(pg_size);
351*6408Sha137994 	pg_shift = page_get_shift(pg_size_code);
352*6408Sha137994 	pg_mask = ~(pg_size - 1);
353*6408Sha137994 
354*6408Sha137994 	D1(ldcp->id, "ldc_mem_bind_handle: (0x%llx) binding "
355*6408Sha137994 	    "va 0x%llx pgsz=0x%llx, pgszc=0x%llx, pg_shift=0x%llx\n",
356*6408Sha137994 	    ldcp->id, vaddr, pg_size, pg_size_code, pg_shift);
357*6408Sha137994 
358*6408Sha137994 	/* aligned VA and its offset */
359*6408Sha137994 	v_align = (caddr_t)(((uintptr_t)vaddr) & ~(pg_size - 1));
360*6408Sha137994 	v_offset = ((uintptr_t)vaddr) & (pg_size - 1);
361*6408Sha137994 
362*6408Sha137994 	npages = (len+v_offset)/pg_size;
363*6408Sha137994 	npages = ((len+v_offset)%pg_size == 0) ? npages : npages+1;
364*6408Sha137994 
365*6408Sha137994 	D1(ldcp->id, "ldc_mem_bind_handle: binding "
366*6408Sha137994 	    "(0x%llx) v=0x%llx,val=0x%llx,off=0x%x,pgs=0x%x\n",
367*6408Sha137994 	    ldcp->id, vaddr, v_align, v_offset, npages);
368*6408Sha137994 
369*6408Sha137994 	/* lock the memory table - exclusive access to channel */
370*6408Sha137994 	mutex_enter(&mtbl->lock);
371*6408Sha137994 
372*6408Sha137994 	if (npages > mtbl->num_avail) {
373*6408Sha137994 		D1(ldcp->id, "ldc_mem_bind_handle: (0x%llx) no table entries\n",
374*6408Sha137994 		    ldcp->id);
375*6408Sha137994 		mutex_exit(&mtbl->lock);
376*6408Sha137994 		mutex_exit(&mhdl->lock);
377*6408Sha137994 		return (ENOMEM);
378*6408Sha137994 	}
379*6408Sha137994 
380*6408Sha137994 	/* Allocate a memseg structure */
381*6408Sha137994 	memseg = mhdl->memseg =
382*6408Sha137994 	    kmem_cache_alloc(ldcssp->memseg_cache, KM_SLEEP);
383*6408Sha137994 
384*6408Sha137994 	/* Allocate memory to store all pages and cookies */
385*6408Sha137994 	memseg->pages = kmem_zalloc((sizeof (ldc_page_t) * npages), KM_SLEEP);
386*6408Sha137994 	memseg->cookies =
387*6408Sha137994 	    kmem_zalloc((sizeof (ldc_mem_cookie_t) * npages), KM_SLEEP);
388*6408Sha137994 
389*6408Sha137994 	D2(ldcp->id, "ldc_mem_bind_handle: (0x%llx) processing 0x%llx pages\n",
390*6408Sha137994 	    ldcp->id, npages);
391*6408Sha137994 
392*6408Sha137994 	addr = v_align;
393*6408Sha137994 
394*6408Sha137994 	/*
395*6408Sha137994 	 * Check if direct shared memory map is enabled, if not change
396*6408Sha137994 	 * the mapping type to include SHADOW_MAP.
397*6408Sha137994 	 */
398*6408Sha137994 	if (ldc_shmem_enabled == 0)
399*6408Sha137994 		mtype = LDC_SHADOW_MAP;
400*6408Sha137994 
401*6408Sha137994 	/*
402*6408Sha137994 	 * Table slots are used in a round-robin manner. The algorithm permits
403*6408Sha137994 	 * inserting duplicate entries. Slots allocated earlier will typically
404*6408Sha137994 	 * get freed before we get back to reusing the slot.Inserting duplicate
405*6408Sha137994 	 * entries should be OK as we only lookup entries using the cookie addr
406*6408Sha137994 	 * i.e. tbl index, during export, unexport and copy operation.
407*6408Sha137994 	 *
408*6408Sha137994 	 * One implementation what was tried was to search for a duplicate
409*6408Sha137994 	 * page entry first and reuse it. The search overhead is very high and
410*6408Sha137994 	 * in the vnet case dropped the perf by almost half, 50 to 24 mbps.
411*6408Sha137994 	 * So it does make sense to avoid searching for duplicates.
412*6408Sha137994 	 *
413*6408Sha137994 	 * But during the process of searching for a free slot, if we find a
414*6408Sha137994 	 * duplicate entry we will go ahead and use it, and bump its use count.
415*6408Sha137994 	 */
416*6408Sha137994 
417*6408Sha137994 	/* index to start searching from */
418*6408Sha137994 	index = mtbl->next_entry;
419*6408Sha137994 	cookie_idx = -1;
420*6408Sha137994 
421*6408Sha137994 	tmp_mte.ll = 0;	/* initialise fields to 0 */
422*6408Sha137994 
423*6408Sha137994 	if (mtype & LDC_DIRECT_MAP) {
424*6408Sha137994 		tmp_mte.mte_r = (perm & LDC_MEM_R) ? 1 : 0;
425*6408Sha137994 		tmp_mte.mte_w = (perm & LDC_MEM_W) ? 1 : 0;
426*6408Sha137994 		tmp_mte.mte_x = (perm & LDC_MEM_X) ? 1 : 0;
427*6408Sha137994 	}
428*6408Sha137994 
429*6408Sha137994 	if (mtype & LDC_SHADOW_MAP) {
430*6408Sha137994 		tmp_mte.mte_cr = (perm & LDC_MEM_R) ? 1 : 0;
431*6408Sha137994 		tmp_mte.mte_cw = (perm & LDC_MEM_W) ? 1 : 0;
432*6408Sha137994 	}
433*6408Sha137994 
434*6408Sha137994 	if (mtype & LDC_IO_MAP) {
435*6408Sha137994 		tmp_mte.mte_ir = (perm & LDC_MEM_R) ? 1 : 0;
436*6408Sha137994 		tmp_mte.mte_iw = (perm & LDC_MEM_W) ? 1 : 0;
437*6408Sha137994 	}
438*6408Sha137994 
439*6408Sha137994 	D1(ldcp->id, "ldc_mem_bind_handle mte=0x%llx\n", tmp_mte.ll);
440*6408Sha137994 
441*6408Sha137994 	tmp_mte.mte_pgszc = pg_size_code;
442*6408Sha137994 
443*6408Sha137994 	/* initialize each mem table entry */
444*6408Sha137994 	for (i = 0; i < npages; i++) {
445*6408Sha137994 
446*6408Sha137994 		/* check if slot is available in the table */
447*6408Sha137994 		while (mtbl->table[index].entry.ll != 0) {
448*6408Sha137994 
449*6408Sha137994 			index = (index + 1) % mtbl->num_entries;
450*6408Sha137994 
451*6408Sha137994 			if (index == mtbl->next_entry) {
452*6408Sha137994 				/* we have looped around */
453*6408Sha137994 				DWARN(DBG_ALL_LDCS,
454*6408Sha137994 				    "ldc_mem_bind_handle: (0x%llx) cannot find "
455*6408Sha137994 				    "entry\n", ldcp->id);
456*6408Sha137994 				*ccount = 0;
457*6408Sha137994 
458*6408Sha137994 				/* NOTE: free memory, remove previous entries */
459*6408Sha137994 				/* this shouldnt happen as num_avail was ok */
460*6408Sha137994 
461*6408Sha137994 				mutex_exit(&mtbl->lock);
462*6408Sha137994 				mutex_exit(&mhdl->lock);
463*6408Sha137994 				return (ENOMEM);
464*6408Sha137994 			}
465*6408Sha137994 		}
466*6408Sha137994 
467*6408Sha137994 		/* get the real address */
468*6408Sha137994 		raddr = va_to_pa((void *)addr);
469*6408Sha137994 		ra_aligned = ((uintptr_t)raddr & pg_mask);
470*6408Sha137994 
471*6408Sha137994 		/* build the mte */
472*6408Sha137994 		tmp_mte.mte_rpfn = ra_aligned >> pg_shift;
473*6408Sha137994 
474*6408Sha137994 		D1(ldcp->id, "ldc_mem_bind_handle mte=0x%llx\n", tmp_mte.ll);
475*6408Sha137994 
476*6408Sha137994 		/* update entry in table */
477*6408Sha137994 		mtbl->table[index].entry = tmp_mte;
478*6408Sha137994 
479*6408Sha137994 		D2(ldcp->id, "ldc_mem_bind_handle: (0x%llx) stored MTE 0x%llx"
480*6408Sha137994 		    " into loc 0x%llx\n", ldcp->id, tmp_mte.ll, index);
481*6408Sha137994 
482*6408Sha137994 		/* calculate the size and offset for this export range */
483*6408Sha137994 		if (i == 0) {
484*6408Sha137994 			/* first page */
485*6408Sha137994 			psize = min((pg_size - v_offset), len);
486*6408Sha137994 			poffset = v_offset;
487*6408Sha137994 
488*6408Sha137994 		} else if (i == (npages - 1)) {
489*6408Sha137994 			/* last page */
490*6408Sha137994 			psize =	(((uintptr_t)(vaddr + len)) &
491*6408Sha137994 			    ((uint64_t)(pg_size-1)));
492*6408Sha137994 			if (psize == 0)
493*6408Sha137994 				psize = pg_size;
494*6408Sha137994 			poffset = 0;
495*6408Sha137994 
496*6408Sha137994 		} else {
497*6408Sha137994 			/* middle pages */
498*6408Sha137994 			psize = pg_size;
499*6408Sha137994 			poffset = 0;
500*6408Sha137994 		}
501*6408Sha137994 
502*6408Sha137994 		/* store entry for this page */
503*6408Sha137994 		memseg->pages[i].index = index;
504*6408Sha137994 		memseg->pages[i].raddr = raddr;
505*6408Sha137994 		memseg->pages[i].offset = poffset;
506*6408Sha137994 		memseg->pages[i].size = psize;
507*6408Sha137994 		memseg->pages[i].mte = &(mtbl->table[index]);
508*6408Sha137994 
509*6408Sha137994 		/* create the cookie */
510*6408Sha137994 		if (i == 0 || (index != prev_index + 1)) {
511*6408Sha137994 			cookie_idx++;
512*6408Sha137994 			memseg->cookies[cookie_idx].addr =
513*6408Sha137994 			    IDX2COOKIE(index, pg_size_code, pg_shift);
514*6408Sha137994 			memseg->cookies[cookie_idx].addr |= poffset;
515*6408Sha137994 			memseg->cookies[cookie_idx].size = psize;
516*6408Sha137994 
517*6408Sha137994 		} else {
518*6408Sha137994 			memseg->cookies[cookie_idx].size += psize;
519*6408Sha137994 		}
520*6408Sha137994 
521*6408Sha137994 		D1(ldcp->id, "ldc_mem_bind_handle: bound "
522*6408Sha137994 		    "(0x%llx) va=0x%llx, idx=0x%llx, "
523*6408Sha137994 		    "ra=0x%llx(sz=0x%x,off=0x%x)\n",
524*6408Sha137994 		    ldcp->id, addr, index, raddr, psize, poffset);
525*6408Sha137994 
526*6408Sha137994 		/* decrement number of available entries */
527*6408Sha137994 		mtbl->num_avail--;
528*6408Sha137994 
529*6408Sha137994 		/* increment va by page size */
530*6408Sha137994 		addr += pg_size;
531*6408Sha137994 
532*6408Sha137994 		/* increment index */
533*6408Sha137994 		prev_index = index;
534*6408Sha137994 		index = (index + 1) % mtbl->num_entries;
535*6408Sha137994 
536*6408Sha137994 		/* save the next slot */
537*6408Sha137994 		mtbl->next_entry = index;
538*6408Sha137994 	}
539*6408Sha137994 
540*6408Sha137994 	mutex_exit(&mtbl->lock);
541*6408Sha137994 
542*6408Sha137994 	/* memory handle = bound */
543*6408Sha137994 	mhdl->mtype = mtype;
544*6408Sha137994 	mhdl->perm = perm;
545*6408Sha137994 	mhdl->status = LDC_BOUND;
546*6408Sha137994 
547*6408Sha137994 	/* update memseg_t */
548*6408Sha137994 	memseg->vaddr = vaddr;
549*6408Sha137994 	memseg->raddr = memseg->pages[0].raddr;
550*6408Sha137994 	memseg->size = len;
551*6408Sha137994 	memseg->npages = npages;
552*6408Sha137994 	memseg->ncookies = cookie_idx + 1;
553*6408Sha137994 	memseg->next_cookie = (memseg->ncookies > 1) ? 1 : 0;
554*6408Sha137994 
555*6408Sha137994 	/* return count and first cookie */
556*6408Sha137994 	*ccount = memseg->ncookies;
557*6408Sha137994 	cookie->addr = memseg->cookies[0].addr;
558*6408Sha137994 	cookie->size = memseg->cookies[0].size;
559*6408Sha137994 
560*6408Sha137994 	D1(ldcp->id,
561*6408Sha137994 	    "ldc_mem_bind_handle: (0x%llx) bound 0x%llx, va=0x%llx, "
562*6408Sha137994 	    "pgs=0x%llx cookies=0x%llx\n",
563*6408Sha137994 	    ldcp->id, mhdl, vaddr, npages, memseg->ncookies);
564*6408Sha137994 
565*6408Sha137994 	mutex_exit(&mhdl->lock);
566*6408Sha137994 	return (0);
567*6408Sha137994 }
568*6408Sha137994 
569*6408Sha137994 /*
570*6408Sha137994  * Return the next cookie associated with the specified memory handle
571*6408Sha137994  */
572*6408Sha137994 int
573*6408Sha137994 ldc_mem_nextcookie(ldc_mem_handle_t mhandle, ldc_mem_cookie_t *cookie)
574*6408Sha137994 {
575*6408Sha137994 	ldc_mhdl_t	*mhdl;
576*6408Sha137994 	ldc_chan_t 	*ldcp;
577*6408Sha137994 	ldc_memseg_t	*memseg;
578*6408Sha137994 
579*6408Sha137994 	if (mhandle == NULL) {
580*6408Sha137994 		DWARN(DBG_ALL_LDCS,
581*6408Sha137994 		    "ldc_mem_nextcookie: invalid memory handle\n");
582*6408Sha137994 		return (EINVAL);
583*6408Sha137994 	}
584*6408Sha137994 	mhdl = (ldc_mhdl_t *)mhandle;
585*6408Sha137994 
586*6408Sha137994 	mutex_enter(&mhdl->lock);
587*6408Sha137994 
588*6408Sha137994 	ldcp = mhdl->ldcp;
589*6408Sha137994 	memseg = mhdl->memseg;
590*6408Sha137994 
591*6408Sha137994 	if (cookie == 0) {
592*6408Sha137994 		DWARN(ldcp->id,
593*6408Sha137994 		    "ldc_mem_nextcookie:(0x%llx) invalid cookie arg\n",
594*6408Sha137994 		    ldcp->id);
595*6408Sha137994 		mutex_exit(&mhdl->lock);
596*6408Sha137994 		return (EINVAL);
597*6408Sha137994 	}
598*6408Sha137994 
599*6408Sha137994 	if (memseg->next_cookie != 0) {
600*6408Sha137994 		cookie->addr = memseg->cookies[memseg->next_cookie].addr;
601*6408Sha137994 		cookie->size = memseg->cookies[memseg->next_cookie].size;
602*6408Sha137994 		memseg->next_cookie++;
603*6408Sha137994 		if (memseg->next_cookie == memseg->ncookies)
604*6408Sha137994 			memseg->next_cookie = 0;
605*6408Sha137994 
606*6408Sha137994 	} else {
607*6408Sha137994 		DWARN(ldcp->id,
608*6408Sha137994 		    "ldc_mem_nextcookie:(0x%llx) no more cookies\n", ldcp->id);
609*6408Sha137994 		cookie->addr = 0;
610*6408Sha137994 		cookie->size = 0;
611*6408Sha137994 		mutex_exit(&mhdl->lock);
612*6408Sha137994 		return (EINVAL);
613*6408Sha137994 	}
614*6408Sha137994 
615*6408Sha137994 	D1(ldcp->id,
616*6408Sha137994 	    "ldc_mem_nextcookie: (0x%llx) cookie addr=0x%llx,sz=0x%llx\n",
617*6408Sha137994 	    ldcp->id, cookie->addr, cookie->size);
618*6408Sha137994 
619*6408Sha137994 	mutex_exit(&mhdl->lock);
620*6408Sha137994 	return (0);
621*6408Sha137994 }
622*6408Sha137994 
623*6408Sha137994 /*
624*6408Sha137994  * Unbind the virtual memory region associated with the specified
625*6408Sha137994  * memory handle. Allassociated cookies are freed and the corresponding
626*6408Sha137994  * RA space is no longer exported.
627*6408Sha137994  */
628*6408Sha137994 int
629*6408Sha137994 ldc_mem_unbind_handle(ldc_mem_handle_t mhandle)
630*6408Sha137994 {
631*6408Sha137994 	ldc_mhdl_t	*mhdl;
632*6408Sha137994 	ldc_chan_t 	*ldcp;
633*6408Sha137994 	ldc_mtbl_t	*mtbl;
634*6408Sha137994 	ldc_memseg_t	*memseg;
635*6408Sha137994 	uint64_t	cookie_addr;
636*6408Sha137994 	uint64_t	pg_shift, pg_size_code;
637*6408Sha137994 	int		i, rv;
638*6408Sha137994 
639*6408Sha137994 	if (mhandle == NULL) {
640*6408Sha137994 		DWARN(DBG_ALL_LDCS,
641*6408Sha137994 		    "ldc_mem_unbind_handle: invalid memory handle\n");
642*6408Sha137994 		return (EINVAL);
643*6408Sha137994 	}
644*6408Sha137994 	mhdl = (ldc_mhdl_t *)mhandle;
645*6408Sha137994 
646*6408Sha137994 	mutex_enter(&mhdl->lock);
647*6408Sha137994 
648*6408Sha137994 	if (mhdl->status == LDC_UNBOUND) {
649*6408Sha137994 		DWARN(DBG_ALL_LDCS,
650*6408Sha137994 		    "ldc_mem_unbind_handle: (0x%x) handle is not bound\n",
651*6408Sha137994 		    mhandle);
652*6408Sha137994 		mutex_exit(&mhdl->lock);
653*6408Sha137994 		return (EINVAL);
654*6408Sha137994 	}
655*6408Sha137994 
656*6408Sha137994 	ldcp = mhdl->ldcp;
657*6408Sha137994 	mtbl = ldcp->mtbl;
658*6408Sha137994 
659*6408Sha137994 	memseg = mhdl->memseg;
660*6408Sha137994 
661*6408Sha137994 	/* lock the memory table - exclusive access to channel */
662*6408Sha137994 	mutex_enter(&mtbl->lock);
663*6408Sha137994 
664*6408Sha137994 	/* undo the pages exported */
665*6408Sha137994 	for (i = 0; i < memseg->npages; i++) {
666*6408Sha137994 
667*6408Sha137994 		/* check for mapped pages, revocation cookie != 0 */
668*6408Sha137994 		if (memseg->pages[i].mte->cookie) {
669*6408Sha137994 
670*6408Sha137994 			pg_size_code = page_szc(memseg->pages[i].size);
671*6408Sha137994 			pg_shift = page_get_shift(memseg->pages[i].size);
672*6408Sha137994 			cookie_addr = IDX2COOKIE(memseg->pages[i].index,
673*6408Sha137994 			    pg_size_code, pg_shift);
674*6408Sha137994 
675*6408Sha137994 			D1(ldcp->id, "ldc_mem_unbind_handle: (0x%llx) revoke "
676*6408Sha137994 			    "cookie 0x%llx, rcookie 0x%llx\n", ldcp->id,
677*6408Sha137994 			    cookie_addr, memseg->pages[i].mte->cookie);
678*6408Sha137994 			rv = hv_ldc_revoke(ldcp->id, cookie_addr,
679*6408Sha137994 			    memseg->pages[i].mte->cookie);
680*6408Sha137994 			if (rv) {
681*6408Sha137994 				DWARN(ldcp->id,
682*6408Sha137994 				    "ldc_mem_unbind_handle: (0x%llx) cannot "
683*6408Sha137994 				    "revoke mapping, cookie %llx\n", ldcp->id,
684*6408Sha137994 				    cookie_addr);
685*6408Sha137994 			}
686*6408Sha137994 		}
687*6408Sha137994 
688*6408Sha137994 		/* clear the entry from the table */
689*6408Sha137994 		memseg->pages[i].mte->entry.ll = 0;
690*6408Sha137994 		mtbl->num_avail++;
691*6408Sha137994 	}
692*6408Sha137994 	mutex_exit(&mtbl->lock);
693*6408Sha137994 
694*6408Sha137994 	/* free the allocated memseg and page structures */
695*6408Sha137994 	kmem_free(memseg->pages, (sizeof (ldc_page_t) * memseg->npages));
696*6408Sha137994 	kmem_free(memseg->cookies,
697*6408Sha137994 	    (sizeof (ldc_mem_cookie_t) * memseg->npages));
698*6408Sha137994 	kmem_cache_free(ldcssp->memseg_cache, memseg);
699*6408Sha137994 
700*6408Sha137994 	/* uninitialize the memory handle */
701*6408Sha137994 	mhdl->memseg = NULL;
702*6408Sha137994 	mhdl->status = LDC_UNBOUND;
703*6408Sha137994 
704*6408Sha137994 	D1(ldcp->id, "ldc_mem_unbind_handle: (0x%llx) unbound handle 0x%llx\n",
705*6408Sha137994 	    ldcp->id, mhdl);
706*6408Sha137994 
707*6408Sha137994 	mutex_exit(&mhdl->lock);
708*6408Sha137994 	return (0);
709*6408Sha137994 }
710*6408Sha137994 
711*6408Sha137994 /*
712*6408Sha137994  * Get information about the dring. The base address of the descriptor
713*6408Sha137994  * ring along with the type and permission are returned back.
714*6408Sha137994  */
715*6408Sha137994 int
716*6408Sha137994 ldc_mem_info(ldc_mem_handle_t mhandle, ldc_mem_info_t *minfo)
717*6408Sha137994 {
718*6408Sha137994 	ldc_mhdl_t	*mhdl;
719*6408Sha137994 
720*6408Sha137994 	if (mhandle == NULL) {
721*6408Sha137994 		DWARN(DBG_ALL_LDCS, "ldc_mem_info: invalid memory handle\n");
722*6408Sha137994 		return (EINVAL);
723*6408Sha137994 	}
724*6408Sha137994 	mhdl = (ldc_mhdl_t *)mhandle;
725*6408Sha137994 
726*6408Sha137994 	if (minfo == NULL) {
727*6408Sha137994 		DWARN(DBG_ALL_LDCS, "ldc_mem_info: invalid args\n");
728*6408Sha137994 		return (EINVAL);
729*6408Sha137994 	}
730*6408Sha137994 
731*6408Sha137994 	mutex_enter(&mhdl->lock);
732*6408Sha137994 
733*6408Sha137994 	minfo->status = mhdl->status;
734*6408Sha137994 	if (mhdl->status == LDC_BOUND || mhdl->status == LDC_MAPPED) {
735*6408Sha137994 		minfo->vaddr = mhdl->memseg->vaddr;
736*6408Sha137994 		minfo->raddr = mhdl->memseg->raddr;
737*6408Sha137994 		minfo->mtype = mhdl->mtype;
738*6408Sha137994 		minfo->perm = mhdl->perm;
739*6408Sha137994 	}
740*6408Sha137994 	mutex_exit(&mhdl->lock);
741*6408Sha137994 
742*6408Sha137994 	return (0);
743*6408Sha137994 }
744*6408Sha137994 
745*6408Sha137994 /*
746*6408Sha137994  * Copy data either from or to the client specified virtual address
747*6408Sha137994  * space to or from the exported memory associated with the cookies.
748*6408Sha137994  * The direction argument determines whether the data is read from or
749*6408Sha137994  * written to exported memory.
750*6408Sha137994  */
751*6408Sha137994 int
752*6408Sha137994 ldc_mem_copy(ldc_handle_t handle, caddr_t vaddr, uint64_t off, size_t *size,
753*6408Sha137994     ldc_mem_cookie_t *cookies, uint32_t ccount, uint8_t direction)
754*6408Sha137994 {
755*6408Sha137994 	ldc_chan_t 	*ldcp;
756*6408Sha137994 	uint64_t	local_voff, local_valign;
757*6408Sha137994 	uint64_t	cookie_addr, cookie_size;
758*6408Sha137994 	uint64_t	pg_shift, pg_size, pg_size_code;
759*6408Sha137994 	uint64_t 	export_caddr, export_poff, export_psize, export_size;
760*6408Sha137994 	uint64_t	local_ra, local_poff, local_psize;
761*6408Sha137994 	uint64_t	copy_size, copied_len = 0, total_bal = 0, idx = 0;
762*6408Sha137994 	pgcnt_t		npages;
763*6408Sha137994 	size_t		len = *size;
764*6408Sha137994 	int 		i, rv = 0;
765*6408Sha137994 
766*6408Sha137994 	uint64_t	chid;
767*6408Sha137994 
768*6408Sha137994 	if (handle == NULL) {
769*6408Sha137994 		DWARN(DBG_ALL_LDCS, "ldc_mem_copy: invalid channel handle\n");
770*6408Sha137994 		return (EINVAL);
771*6408Sha137994 	}
772*6408Sha137994 	ldcp = (ldc_chan_t *)handle;
773*6408Sha137994 	chid = ldcp->id;
774*6408Sha137994 
775*6408Sha137994 	/* check to see if channel is UP */
776*6408Sha137994 	if (ldcp->tstate != TS_UP) {
777*6408Sha137994 		DWARN(chid, "ldc_mem_copy: (0x%llx) channel is not UP\n",
778*6408Sha137994 		    chid);
779*6408Sha137994 		return (ECONNRESET);
780*6408Sha137994 	}
781*6408Sha137994 
782*6408Sha137994 	/* Force address and size to be 8-byte aligned */
783*6408Sha137994 	if ((((uintptr_t)vaddr | len) & 0x7) != 0) {
784*6408Sha137994 		DWARN(chid,
785*6408Sha137994 		    "ldc_mem_copy: addr/sz is not 8-byte aligned\n");
786*6408Sha137994 		return (EINVAL);
787*6408Sha137994 	}
788*6408Sha137994 
789*6408Sha137994 	/* Find the size of the exported memory */
790*6408Sha137994 	export_size = 0;
791*6408Sha137994 	for (i = 0; i < ccount; i++)
792*6408Sha137994 		export_size += cookies[i].size;
793*6408Sha137994 
794*6408Sha137994 	/* check to see if offset is valid */
795*6408Sha137994 	if (off > export_size) {
796*6408Sha137994 		DWARN(chid,
797*6408Sha137994 		    "ldc_mem_copy: (0x%llx) start offset > export mem size\n",
798*6408Sha137994 		    chid);
799*6408Sha137994 		return (EINVAL);
800*6408Sha137994 	}
801*6408Sha137994 
802*6408Sha137994 	/*
803*6408Sha137994 	 * Check to see if the export size is smaller than the size we
804*6408Sha137994 	 * are requesting to copy - if so flag an error
805*6408Sha137994 	 */
806*6408Sha137994 	if ((export_size - off) < *size) {
807*6408Sha137994 		DWARN(chid,
808*6408Sha137994 		    "ldc_mem_copy: (0x%llx) copy size > export mem size\n",
809*6408Sha137994 		    chid);
810*6408Sha137994 		return (EINVAL);
811*6408Sha137994 	}
812*6408Sha137994 
813*6408Sha137994 	total_bal = min(export_size, *size);
814*6408Sha137994 
815*6408Sha137994 	/* FUTURE: get the page size, pgsz code, and shift */
816*6408Sha137994 	pg_size = MMU_PAGESIZE;
817*6408Sha137994 	pg_size_code = page_szc(pg_size);
818*6408Sha137994 	pg_shift = page_get_shift(pg_size_code);
819*6408Sha137994 
820*6408Sha137994 	D1(chid, "ldc_mem_copy: copying data "
821*6408Sha137994 	    "(0x%llx) va 0x%llx pgsz=0x%llx, pgszc=0x%llx, pg_shift=0x%llx\n",
822*6408Sha137994 	    chid, vaddr, pg_size, pg_size_code, pg_shift);
823*6408Sha137994 
824*6408Sha137994 	/* aligned VA and its offset */
825*6408Sha137994 	local_valign = (((uintptr_t)vaddr) & ~(pg_size - 1));
826*6408Sha137994 	local_voff = ((uintptr_t)vaddr) & (pg_size - 1);
827*6408Sha137994 
828*6408Sha137994 	npages = (len+local_voff)/pg_size;
829*6408Sha137994 	npages = ((len+local_voff)%pg_size == 0) ? npages : npages+1;
830*6408Sha137994 
831*6408Sha137994 	D1(chid,
832*6408Sha137994 	    "ldc_mem_copy: (0x%llx) v=0x%llx,val=0x%llx,off=0x%x,pgs=0x%x\n",
833*6408Sha137994 	    chid, vaddr, local_valign, local_voff, npages);
834*6408Sha137994 
835*6408Sha137994 	local_ra = va_to_pa((void *)local_valign);
836*6408Sha137994 	local_poff = local_voff;
837*6408Sha137994 	local_psize = min(len, (pg_size - local_voff));
838*6408Sha137994 
839*6408Sha137994 	len -= local_psize;
840*6408Sha137994 
841*6408Sha137994 	/*
842*6408Sha137994 	 * find the first cookie in the list of cookies
843*6408Sha137994 	 * if the offset passed in is not zero
844*6408Sha137994 	 */
845*6408Sha137994 	for (idx = 0; idx < ccount; idx++) {
846*6408Sha137994 		cookie_size = cookies[idx].size;
847*6408Sha137994 		if (off < cookie_size)
848*6408Sha137994 			break;
849*6408Sha137994 		off -= cookie_size;
850*6408Sha137994 	}
851*6408Sha137994 
852*6408Sha137994 	cookie_addr = cookies[idx].addr + off;
853*6408Sha137994 	cookie_size = cookies[idx].size - off;
854*6408Sha137994 
855*6408Sha137994 	export_caddr = cookie_addr & ~(pg_size - 1);
856*6408Sha137994 	export_poff = cookie_addr & (pg_size - 1);
857*6408Sha137994 	export_psize = min(cookie_size, (pg_size - export_poff));
858*6408Sha137994 
859*6408Sha137994 	for (;;) {
860*6408Sha137994 
861*6408Sha137994 		copy_size = min(export_psize, local_psize);
862*6408Sha137994 
863*6408Sha137994 		D1(chid,
864*6408Sha137994 		    "ldc_mem_copy:(0x%llx) dir=0x%x, caddr=0x%llx,"
865*6408Sha137994 		    " loc_ra=0x%llx, exp_poff=0x%llx, loc_poff=0x%llx,"
866*6408Sha137994 		    " exp_psz=0x%llx, loc_psz=0x%llx, copy_sz=0x%llx,"
867*6408Sha137994 		    " total_bal=0x%llx\n",
868*6408Sha137994 		    chid, direction, export_caddr, local_ra, export_poff,
869*6408Sha137994 		    local_poff, export_psize, local_psize, copy_size,
870*6408Sha137994 		    total_bal);
871*6408Sha137994 
872*6408Sha137994 		rv = hv_ldc_copy(chid, direction,
873*6408Sha137994 		    (export_caddr + export_poff), (local_ra + local_poff),
874*6408Sha137994 		    copy_size, &copied_len);
875*6408Sha137994 
876*6408Sha137994 		if (rv != 0) {
877*6408Sha137994 			int 		error = EIO;
878*6408Sha137994 			uint64_t	rx_hd, rx_tl;
879*6408Sha137994 
880*6408Sha137994 			DWARN(chid,
881*6408Sha137994 			    "ldc_mem_copy: (0x%llx) err %d during copy\n",
882*6408Sha137994 			    (unsigned long long)chid, rv);
883*6408Sha137994 			DWARN(chid,
884*6408Sha137994 			    "ldc_mem_copy: (0x%llx) dir=0x%x, caddr=0x%lx, "
885*6408Sha137994 			    "loc_ra=0x%lx, exp_poff=0x%lx, loc_poff=0x%lx,"
886*6408Sha137994 			    " exp_psz=0x%lx, loc_psz=0x%lx, copy_sz=0x%lx,"
887*6408Sha137994 			    " copied_len=0x%lx, total_bal=0x%lx\n",
888*6408Sha137994 			    chid, direction, export_caddr, local_ra,
889*6408Sha137994 			    export_poff, local_poff, export_psize, local_psize,
890*6408Sha137994 			    copy_size, copied_len, total_bal);
891*6408Sha137994 
892*6408Sha137994 			*size = *size - total_bal;
893*6408Sha137994 
894*6408Sha137994 			/*
895*6408Sha137994 			 * check if reason for copy error was due to
896*6408Sha137994 			 * a channel reset. we need to grab the lock
897*6408Sha137994 			 * just in case we have to do a reset.
898*6408Sha137994 			 */
899*6408Sha137994 			mutex_enter(&ldcp->lock);
900*6408Sha137994 			mutex_enter(&ldcp->tx_lock);
901*6408Sha137994 
902*6408Sha137994 			rv = hv_ldc_rx_get_state(ldcp->id,
903*6408Sha137994 			    &rx_hd, &rx_tl, &(ldcp->link_state));
904*6408Sha137994 			if (ldcp->link_state == LDC_CHANNEL_DOWN ||
905*6408Sha137994 			    ldcp->link_state == LDC_CHANNEL_RESET) {
906*6408Sha137994 				i_ldc_reset(ldcp, B_FALSE);
907*6408Sha137994 				error = ECONNRESET;
908*6408Sha137994 			}
909*6408Sha137994 
910*6408Sha137994 			mutex_exit(&ldcp->tx_lock);
911*6408Sha137994 			mutex_exit(&ldcp->lock);
912*6408Sha137994 
913*6408Sha137994 			return (error);
914*6408Sha137994 		}
915*6408Sha137994 
916*6408Sha137994 		ASSERT(copied_len <= copy_size);
917*6408Sha137994 
918*6408Sha137994 		D2(chid, "ldc_mem_copy: copied=0x%llx\n", copied_len);
919*6408Sha137994 		export_poff += copied_len;
920*6408Sha137994 		local_poff += copied_len;
921*6408Sha137994 		export_psize -= copied_len;
922*6408Sha137994 		local_psize -= copied_len;
923*6408Sha137994 		cookie_size -= copied_len;
924*6408Sha137994 
925*6408Sha137994 		total_bal -= copied_len;
926*6408Sha137994 
927*6408Sha137994 		if (copy_size != copied_len)
928*6408Sha137994 			continue;
929*6408Sha137994 
930*6408Sha137994 		if (export_psize == 0 && total_bal != 0) {
931*6408Sha137994 
932*6408Sha137994 			if (cookie_size == 0) {
933*6408Sha137994 				idx++;
934*6408Sha137994 				cookie_addr = cookies[idx].addr;
935*6408Sha137994 				cookie_size = cookies[idx].size;
936*6408Sha137994 
937*6408Sha137994 				export_caddr = cookie_addr & ~(pg_size - 1);
938*6408Sha137994 				export_poff = cookie_addr & (pg_size - 1);
939*6408Sha137994 				export_psize =
940*6408Sha137994 				    min(cookie_size, (pg_size-export_poff));
941*6408Sha137994 			} else {
942*6408Sha137994 				export_caddr += pg_size;
943*6408Sha137994 				export_poff = 0;
944*6408Sha137994 				export_psize = min(cookie_size, pg_size);
945*6408Sha137994 			}
946*6408Sha137994 		}
947*6408Sha137994 
948*6408Sha137994 		if (local_psize == 0 && total_bal != 0) {
949*6408Sha137994 			local_valign += pg_size;
950*6408Sha137994 			local_ra = va_to_pa((void *)local_valign);
951*6408Sha137994 			local_poff = 0;
952*6408Sha137994 			local_psize = min(pg_size, len);
953*6408Sha137994 			len -= local_psize;
954*6408Sha137994 		}
955*6408Sha137994 
956*6408Sha137994 		/* check if we are all done */
957*6408Sha137994 		if (total_bal == 0)
958*6408Sha137994 			break;
959*6408Sha137994 	}
960*6408Sha137994 
961*6408Sha137994 
962*6408Sha137994 	D1(chid,
963*6408Sha137994 	    "ldc_mem_copy: (0x%llx) done copying sz=0x%llx\n",
964*6408Sha137994 	    chid, *size);
965*6408Sha137994 
966*6408Sha137994 	return (0);
967*6408Sha137994 }
968*6408Sha137994 
969*6408Sha137994 /*
970*6408Sha137994  * Copy data either from or to the client specified virtual address
971*6408Sha137994  * space to or from HV physical memory.
972*6408Sha137994  *
973*6408Sha137994  * The direction argument determines whether the data is read from or
974*6408Sha137994  * written to HV memory. direction values are LDC_COPY_IN/OUT similar
975*6408Sha137994  * to the ldc_mem_copy interface
976*6408Sha137994  */
977*6408Sha137994 int
978*6408Sha137994 ldc_mem_rdwr_cookie(ldc_handle_t handle, caddr_t vaddr, size_t *size,
979*6408Sha137994     caddr_t paddr, uint8_t direction)
980*6408Sha137994 {
981*6408Sha137994 	ldc_chan_t 	*ldcp;
982*6408Sha137994 	uint64_t	local_voff, local_valign;
983*6408Sha137994 	uint64_t	pg_shift, pg_size, pg_size_code;
984*6408Sha137994 	uint64_t 	target_pa, target_poff, target_psize, target_size;
985*6408Sha137994 	uint64_t	local_ra, local_poff, local_psize;
986*6408Sha137994 	uint64_t	copy_size, copied_len = 0;
987*6408Sha137994 	pgcnt_t		npages;
988*6408Sha137994 	size_t		len = *size;
989*6408Sha137994 	int 		rv = 0;
990*6408Sha137994 
991*6408Sha137994 	if (handle == NULL) {
992*6408Sha137994 		DWARN(DBG_ALL_LDCS,
993*6408Sha137994 		    "ldc_mem_rdwr_cookie: invalid channel handle\n");
994*6408Sha137994 		return (EINVAL);
995*6408Sha137994 	}
996*6408Sha137994 	ldcp = (ldc_chan_t *)handle;
997*6408Sha137994 
998*6408Sha137994 	mutex_enter(&ldcp->lock);
999*6408Sha137994 
1000*6408Sha137994 	/* check to see if channel is UP */
1001*6408Sha137994 	if (ldcp->tstate != TS_UP) {
1002*6408Sha137994 		DWARN(ldcp->id,
1003*6408Sha137994 		    "ldc_mem_rdwr_cookie: (0x%llx) channel is not UP\n",
1004*6408Sha137994 		    ldcp->id);
1005*6408Sha137994 		mutex_exit(&ldcp->lock);
1006*6408Sha137994 		return (ECONNRESET);
1007*6408Sha137994 	}
1008*6408Sha137994 
1009*6408Sha137994 	/* Force address and size to be 8-byte aligned */
1010*6408Sha137994 	if ((((uintptr_t)vaddr | len) & 0x7) != 0) {
1011*6408Sha137994 		DWARN(ldcp->id,
1012*6408Sha137994 		    "ldc_mem_rdwr_cookie: addr/size is not 8-byte aligned\n");
1013*6408Sha137994 		mutex_exit(&ldcp->lock);
1014*6408Sha137994 		return (EINVAL);
1015*6408Sha137994 	}
1016*6408Sha137994 
1017*6408Sha137994 	target_size = *size;
1018*6408Sha137994 
1019*6408Sha137994 	/* FUTURE: get the page size, pgsz code, and shift */
1020*6408Sha137994 	pg_size = MMU_PAGESIZE;
1021*6408Sha137994 	pg_size_code = page_szc(pg_size);
1022*6408Sha137994 	pg_shift = page_get_shift(pg_size_code);
1023*6408Sha137994 
1024*6408Sha137994 	D1(ldcp->id, "ldc_mem_rdwr_cookie: copying data "
1025*6408Sha137994 	    "(0x%llx) va 0x%llx pgsz=0x%llx, pgszc=0x%llx, pg_shift=0x%llx\n",
1026*6408Sha137994 	    ldcp->id, vaddr, pg_size, pg_size_code, pg_shift);
1027*6408Sha137994 
1028*6408Sha137994 	/* aligned VA and its offset */
1029*6408Sha137994 	local_valign = ((uintptr_t)vaddr) & ~(pg_size - 1);
1030*6408Sha137994 	local_voff = ((uintptr_t)vaddr) & (pg_size - 1);
1031*6408Sha137994 
1032*6408Sha137994 	npages = (len + local_voff) / pg_size;
1033*6408Sha137994 	npages = ((len + local_voff) % pg_size == 0) ? npages : npages+1;
1034*6408Sha137994 
1035*6408Sha137994 	D1(ldcp->id, "ldc_mem_rdwr_cookie: (0x%llx) v=0x%llx, "
1036*6408Sha137994 	    "val=0x%llx,off=0x%x,pgs=0x%x\n",
1037*6408Sha137994 	    ldcp->id, vaddr, local_valign, local_voff, npages);
1038*6408Sha137994 
1039*6408Sha137994 	local_ra = va_to_pa((void *)local_valign);
1040*6408Sha137994 	local_poff = local_voff;
1041*6408Sha137994 	local_psize = min(len, (pg_size - local_voff));
1042*6408Sha137994 
1043*6408Sha137994 	len -= local_psize;
1044*6408Sha137994 
1045*6408Sha137994 	target_pa = ((uintptr_t)paddr) & ~(pg_size - 1);
1046*6408Sha137994 	target_poff = ((uintptr_t)paddr) & (pg_size - 1);
1047*6408Sha137994 	target_psize = pg_size - target_poff;
1048*6408Sha137994 
1049*6408Sha137994 	for (;;) {
1050*6408Sha137994 
1051*6408Sha137994 		copy_size = min(target_psize, local_psize);
1052*6408Sha137994 
1053*6408Sha137994 		D1(ldcp->id,
1054*6408Sha137994 		    "ldc_mem_rdwr_cookie: (0x%llx) dir=0x%x, tar_pa=0x%llx,"
1055*6408Sha137994 		    " loc_ra=0x%llx, tar_poff=0x%llx, loc_poff=0x%llx,"
1056*6408Sha137994 		    " tar_psz=0x%llx, loc_psz=0x%llx, copy_sz=0x%llx,"
1057*6408Sha137994 		    " total_bal=0x%llx\n",
1058*6408Sha137994 		    ldcp->id, direction, target_pa, local_ra, target_poff,
1059*6408Sha137994 		    local_poff, target_psize, local_psize, copy_size,
1060*6408Sha137994 		    target_size);
1061*6408Sha137994 
1062*6408Sha137994 		rv = hv_ldc_copy(ldcp->id, direction,
1063*6408Sha137994 		    (target_pa + target_poff), (local_ra + local_poff),
1064*6408Sha137994 		    copy_size, &copied_len);
1065*6408Sha137994 
1066*6408Sha137994 		if (rv != 0) {
1067*6408Sha137994 			DWARN(DBG_ALL_LDCS,
1068*6408Sha137994 			    "ldc_mem_rdwr_cookie: (0x%lx) err %d during copy\n",
1069*6408Sha137994 			    ldcp->id, rv);
1070*6408Sha137994 			DWARN(DBG_ALL_LDCS,
1071*6408Sha137994 			    "ldc_mem_rdwr_cookie: (0x%llx) dir=%lld, "
1072*6408Sha137994 			    "tar_pa=0x%llx, loc_ra=0x%llx, tar_poff=0x%llx, "
1073*6408Sha137994 			    "loc_poff=0x%llx, tar_psz=0x%llx, loc_psz=0x%llx, "
1074*6408Sha137994 			    "copy_sz=0x%llx, total_bal=0x%llx\n",
1075*6408Sha137994 			    ldcp->id, direction, target_pa, local_ra,
1076*6408Sha137994 			    target_poff, local_poff, target_psize, local_psize,
1077*6408Sha137994 			    copy_size, target_size);
1078*6408Sha137994 
1079*6408Sha137994 			*size = *size - target_size;
1080*6408Sha137994 			mutex_exit(&ldcp->lock);
1081*6408Sha137994 			return (i_ldc_h2v_error(rv));
1082*6408Sha137994 		}
1083*6408Sha137994 
1084*6408Sha137994 		D2(ldcp->id, "ldc_mem_rdwr_cookie: copied=0x%llx\n",
1085*6408Sha137994 		    copied_len);
1086*6408Sha137994 		target_poff += copied_len;
1087*6408Sha137994 		local_poff += copied_len;
1088*6408Sha137994 		target_psize -= copied_len;
1089*6408Sha137994 		local_psize -= copied_len;
1090*6408Sha137994 
1091*6408Sha137994 		target_size -= copied_len;
1092*6408Sha137994 
1093*6408Sha137994 		if (copy_size != copied_len)
1094*6408Sha137994 			continue;
1095*6408Sha137994 
1096*6408Sha137994 		if (target_psize == 0 && target_size != 0) {
1097*6408Sha137994 			target_pa += pg_size;
1098*6408Sha137994 			target_poff = 0;
1099*6408Sha137994 			target_psize = min(pg_size, target_size);
1100*6408Sha137994 		}
1101*6408Sha137994 
1102*6408Sha137994 		if (local_psize == 0 && target_size != 0) {
1103*6408Sha137994 			local_valign += pg_size;
1104*6408Sha137994 			local_ra = va_to_pa((void *)local_valign);
1105*6408Sha137994 			local_poff = 0;
1106*6408Sha137994 			local_psize = min(pg_size, len);
1107*6408Sha137994 			len -= local_psize;
1108*6408Sha137994 		}
1109*6408Sha137994 
1110*6408Sha137994 		/* check if we are all done */
1111*6408Sha137994 		if (target_size == 0)
1112*6408Sha137994 			break;
1113*6408Sha137994 	}
1114*6408Sha137994 
1115*6408Sha137994 	mutex_exit(&ldcp->lock);
1116*6408Sha137994 
1117*6408Sha137994 	D1(ldcp->id, "ldc_mem_rdwr_cookie: (0x%llx) done copying sz=0x%llx\n",
1118*6408Sha137994 	    ldcp->id, *size);
1119*6408Sha137994 
1120*6408Sha137994 	return (0);
1121*6408Sha137994 }
1122*6408Sha137994 
1123*6408Sha137994 /*
1124*6408Sha137994  * Map an exported memory segment into the local address space. If the
1125*6408Sha137994  * memory range was exported for direct map access, a HV call is made
1126*6408Sha137994  * to allocate a RA range. If the map is done via a shadow copy, local
1127*6408Sha137994  * shadow memory is allocated and the base VA is returned in 'vaddr'. If
1128*6408Sha137994  * the mapping is a direct map then the RA is returned in 'raddr'.
1129*6408Sha137994  */
1130*6408Sha137994 int
1131*6408Sha137994 ldc_mem_map(ldc_mem_handle_t mhandle, ldc_mem_cookie_t *cookie, uint32_t ccount,
1132*6408Sha137994     uint8_t mtype, uint8_t perm, caddr_t *vaddr, caddr_t *raddr)
1133*6408Sha137994 {
1134*6408Sha137994 	int		i, j, idx, rv, retries;
1135*6408Sha137994 	ldc_chan_t 	*ldcp;
1136*6408Sha137994 	ldc_mhdl_t	*mhdl;
1137*6408Sha137994 	ldc_memseg_t	*memseg;
1138*6408Sha137994 	caddr_t		tmpaddr;
1139*6408Sha137994 	uint64_t	map_perm = perm;
1140*6408Sha137994 	uint64_t	pg_size, pg_shift, pg_size_code, pg_mask;
1141*6408Sha137994 	uint64_t	exp_size = 0, base_off, map_size, npages;
1142*6408Sha137994 	uint64_t	cookie_addr, cookie_off, cookie_size;
1143*6408Sha137994 	tte_t		ldc_tte;
1144*6408Sha137994 
1145*6408Sha137994 	if (mhandle == NULL) {
1146*6408Sha137994 		DWARN(DBG_ALL_LDCS, "ldc_mem_map: invalid memory handle\n");
1147*6408Sha137994 		return (EINVAL);
1148*6408Sha137994 	}
1149*6408Sha137994 	mhdl = (ldc_mhdl_t *)mhandle;
1150*6408Sha137994 
1151*6408Sha137994 	mutex_enter(&mhdl->lock);
1152*6408Sha137994 
1153*6408Sha137994 	if (mhdl->status == LDC_BOUND || mhdl->status == LDC_MAPPED ||
1154*6408Sha137994 	    mhdl->memseg != NULL) {
1155*6408Sha137994 		DWARN(DBG_ALL_LDCS,
1156*6408Sha137994 		    "ldc_mem_map: (0x%llx) handle bound/mapped\n", mhandle);
1157*6408Sha137994 		mutex_exit(&mhdl->lock);
1158*6408Sha137994 		return (EINVAL);
1159*6408Sha137994 	}
1160*6408Sha137994 
1161*6408Sha137994 	ldcp = mhdl->ldcp;
1162*6408Sha137994 
1163*6408Sha137994 	mutex_enter(&ldcp->lock);
1164*6408Sha137994 
1165*6408Sha137994 	if (ldcp->tstate != TS_UP) {
1166*6408Sha137994 		DWARN(ldcp->id,
1167*6408Sha137994 		    "ldc_mem_dring_map: (0x%llx) channel is not UP\n",
1168*6408Sha137994 		    ldcp->id);
1169*6408Sha137994 		mutex_exit(&ldcp->lock);
1170*6408Sha137994 		mutex_exit(&mhdl->lock);
1171*6408Sha137994 		return (ECONNRESET);
1172*6408Sha137994 	}
1173*6408Sha137994 
1174*6408Sha137994 	if ((mtype & (LDC_SHADOW_MAP|LDC_DIRECT_MAP|LDC_IO_MAP)) == 0) {
1175*6408Sha137994 		DWARN(ldcp->id, "ldc_mem_map: invalid map type\n");
1176*6408Sha137994 		mutex_exit(&ldcp->lock);
1177*6408Sha137994 		mutex_exit(&mhdl->lock);
1178*6408Sha137994 		return (EINVAL);
1179*6408Sha137994 	}
1180*6408Sha137994 
1181*6408Sha137994 	D1(ldcp->id, "ldc_mem_map: (0x%llx) cookie = 0x%llx,0x%llx\n",
1182*6408Sha137994 	    ldcp->id, cookie->addr, cookie->size);
1183*6408Sha137994 
1184*6408Sha137994 	/* FUTURE: get the page size, pgsz code, and shift */
1185*6408Sha137994 	pg_size = MMU_PAGESIZE;
1186*6408Sha137994 	pg_size_code = page_szc(pg_size);
1187*6408Sha137994 	pg_shift = page_get_shift(pg_size_code);
1188*6408Sha137994 	pg_mask = ~(pg_size - 1);
1189*6408Sha137994 
1190*6408Sha137994 	/* calculate the number of pages in the exported cookie */
1191*6408Sha137994 	base_off = cookie[0].addr & (pg_size - 1);
1192*6408Sha137994 	for (idx = 0; idx < ccount; idx++)
1193*6408Sha137994 		exp_size += cookie[idx].size;
1194*6408Sha137994 	map_size = P2ROUNDUP((exp_size + base_off), pg_size);
1195*6408Sha137994 	npages = (map_size >> pg_shift);
1196*6408Sha137994 
1197*6408Sha137994 	/* Allocate memseg structure */
1198*6408Sha137994 	memseg = mhdl->memseg =
1199*6408Sha137994 	    kmem_cache_alloc(ldcssp->memseg_cache, KM_SLEEP);
1200*6408Sha137994 
1201*6408Sha137994 	/* Allocate memory to store all pages and cookies */
1202*6408Sha137994 	memseg->pages =	kmem_zalloc((sizeof (ldc_page_t) * npages), KM_SLEEP);
1203*6408Sha137994 	memseg->cookies =
1204*6408Sha137994 	    kmem_zalloc((sizeof (ldc_mem_cookie_t) * ccount), KM_SLEEP);
1205*6408Sha137994 
1206*6408Sha137994 	D2(ldcp->id, "ldc_mem_map: (0x%llx) exp_size=0x%llx, map_size=0x%llx,"
1207*6408Sha137994 	    "pages=0x%llx\n", ldcp->id, exp_size, map_size, npages);
1208*6408Sha137994 
1209*6408Sha137994 	/*
1210*6408Sha137994 	 * Check if direct map over shared memory is enabled, if not change
1211*6408Sha137994 	 * the mapping type to SHADOW_MAP.
1212*6408Sha137994 	 */
1213*6408Sha137994 	if (ldc_shmem_enabled == 0)
1214*6408Sha137994 		mtype = LDC_SHADOW_MAP;
1215*6408Sha137994 
1216*6408Sha137994 	/*
1217*6408Sha137994 	 * Check to see if the client is requesting direct or shadow map
1218*6408Sha137994 	 * If direct map is requested, try to map remote memory first,
1219*6408Sha137994 	 * and if that fails, revert to shadow map
1220*6408Sha137994 	 */
1221*6408Sha137994 	if (mtype == LDC_DIRECT_MAP) {
1222*6408Sha137994 
1223*6408Sha137994 		/* Allocate kernel virtual space for mapping */
1224*6408Sha137994 		memseg->vaddr = vmem_xalloc(heap_arena, map_size,
1225*6408Sha137994 		    pg_size, 0, 0, NULL, NULL, VM_NOSLEEP);
1226*6408Sha137994 		if (memseg->vaddr == NULL) {
1227*6408Sha137994 			cmn_err(CE_WARN,
1228*6408Sha137994 			    "ldc_mem_map: (0x%lx) memory map failed\n",
1229*6408Sha137994 			    ldcp->id);
1230*6408Sha137994 			kmem_free(memseg->cookies,
1231*6408Sha137994 			    (sizeof (ldc_mem_cookie_t) * ccount));
1232*6408Sha137994 			kmem_free(memseg->pages,
1233*6408Sha137994 			    (sizeof (ldc_page_t) * npages));
1234*6408Sha137994 			kmem_cache_free(ldcssp->memseg_cache, memseg);
1235*6408Sha137994 
1236*6408Sha137994 			mutex_exit(&ldcp->lock);
1237*6408Sha137994 			mutex_exit(&mhdl->lock);
1238*6408Sha137994 			return (ENOMEM);
1239*6408Sha137994 		}
1240*6408Sha137994 
1241*6408Sha137994 		/* Unload previous mapping */
1242*6408Sha137994 		hat_unload(kas.a_hat, memseg->vaddr, map_size,
1243*6408Sha137994 		    HAT_UNLOAD_NOSYNC | HAT_UNLOAD_UNLOCK);
1244*6408Sha137994 
1245*6408Sha137994 		/* for each cookie passed in - map into address space */
1246*6408Sha137994 		idx = 0;
1247*6408Sha137994 		cookie_size = 0;
1248*6408Sha137994 		tmpaddr = memseg->vaddr;
1249*6408Sha137994 
1250*6408Sha137994 		for (i = 0; i < npages; i++) {
1251*6408Sha137994 
1252*6408Sha137994 			if (cookie_size == 0) {
1253*6408Sha137994 				ASSERT(idx < ccount);
1254*6408Sha137994 				cookie_addr = cookie[idx].addr & pg_mask;
1255*6408Sha137994 				cookie_off = cookie[idx].addr & (pg_size - 1);
1256*6408Sha137994 				cookie_size =
1257*6408Sha137994 				    P2ROUNDUP((cookie_off + cookie[idx].size),
1258*6408Sha137994 				    pg_size);
1259*6408Sha137994 				idx++;
1260*6408Sha137994 			}
1261*6408Sha137994 
1262*6408Sha137994 			D1(ldcp->id, "ldc_mem_map: (0x%llx) mapping "
1263*6408Sha137994 			    "cookie 0x%llx, bal=0x%llx\n", ldcp->id,
1264*6408Sha137994 			    cookie_addr, cookie_size);
1265*6408Sha137994 
1266*6408Sha137994 			/* map the cookie into address space */
1267*6408Sha137994 			for (retries = 0; retries < ldc_max_retries;
1268*6408Sha137994 			    retries++) {
1269*6408Sha137994 
1270*6408Sha137994 				rv = hv_ldc_mapin(ldcp->id, cookie_addr,
1271*6408Sha137994 				    &memseg->pages[i].raddr, &map_perm);
1272*6408Sha137994 				if (rv != H_EWOULDBLOCK && rv != H_ETOOMANY)
1273*6408Sha137994 					break;
1274*6408Sha137994 
1275*6408Sha137994 				drv_usecwait(ldc_delay);
1276*6408Sha137994 			}
1277*6408Sha137994 
1278*6408Sha137994 			if (rv || memseg->pages[i].raddr == 0) {
1279*6408Sha137994 				DWARN(ldcp->id,
1280*6408Sha137994 				    "ldc_mem_map: (0x%llx) hv mapin err %d\n",
1281*6408Sha137994 				    ldcp->id, rv);
1282*6408Sha137994 
1283*6408Sha137994 				/* remove previous mapins */
1284*6408Sha137994 				hat_unload(kas.a_hat, memseg->vaddr, map_size,
1285*6408Sha137994 				    HAT_UNLOAD_NOSYNC | HAT_UNLOAD_UNLOCK);
1286*6408Sha137994 				for (j = 0; j < i; j++) {
1287*6408Sha137994 					rv = hv_ldc_unmap(
1288*6408Sha137994 					    memseg->pages[j].raddr);
1289*6408Sha137994 					if (rv) {
1290*6408Sha137994 						DWARN(ldcp->id,
1291*6408Sha137994 						    "ldc_mem_map: (0x%llx) "
1292*6408Sha137994 						    "cannot unmap ra=0x%llx\n",
1293*6408Sha137994 						    ldcp->id,
1294*6408Sha137994 						    memseg->pages[j].raddr);
1295*6408Sha137994 					}
1296*6408Sha137994 				}
1297*6408Sha137994 
1298*6408Sha137994 				/* free kernel virtual space */
1299*6408Sha137994 				vmem_free(heap_arena, (void *)memseg->vaddr,
1300*6408Sha137994 				    map_size);
1301*6408Sha137994 
1302*6408Sha137994 				/* direct map failed - revert to shadow map */
1303*6408Sha137994 				mtype = LDC_SHADOW_MAP;
1304*6408Sha137994 				break;
1305*6408Sha137994 
1306*6408Sha137994 			} else {
1307*6408Sha137994 
1308*6408Sha137994 				D1(ldcp->id,
1309*6408Sha137994 				    "ldc_mem_map: (0x%llx) vtop map 0x%llx -> "
1310*6408Sha137994 				    "0x%llx, cookie=0x%llx, perm=0x%llx\n",
1311*6408Sha137994 				    ldcp->id, tmpaddr, memseg->pages[i].raddr,
1312*6408Sha137994 				    cookie_addr, perm);
1313*6408Sha137994 
1314*6408Sha137994 				/*
1315*6408Sha137994 				 * NOTE: Calling hat_devload directly, causes it
1316*6408Sha137994 				 * to look for page_t using the pfn. Since this
1317*6408Sha137994 				 * addr is greater than the memlist, it treates
1318*6408Sha137994 				 * it as non-memory
1319*6408Sha137994 				 */
1320*6408Sha137994 				sfmmu_memtte(&ldc_tte,
1321*6408Sha137994 				    (pfn_t)(memseg->pages[i].raddr >> pg_shift),
1322*6408Sha137994 				    PROT_READ | PROT_WRITE | HAT_NOSYNC, TTE8K);
1323*6408Sha137994 
1324*6408Sha137994 				D1(ldcp->id,
1325*6408Sha137994 				    "ldc_mem_map: (0x%llx) ra 0x%llx -> "
1326*6408Sha137994 				    "tte 0x%llx\n", ldcp->id,
1327*6408Sha137994 				    memseg->pages[i].raddr, ldc_tte);
1328*6408Sha137994 
1329*6408Sha137994 				sfmmu_tteload(kas.a_hat, &ldc_tte, tmpaddr,
1330*6408Sha137994 				    NULL, HAT_LOAD_LOCK);
1331*6408Sha137994 
1332*6408Sha137994 				cookie_size -= pg_size;
1333*6408Sha137994 				cookie_addr += pg_size;
1334*6408Sha137994 				tmpaddr += pg_size;
1335*6408Sha137994 			}
1336*6408Sha137994 		}
1337*6408Sha137994 	}
1338*6408Sha137994 
1339*6408Sha137994 	if (mtype == LDC_SHADOW_MAP) {
1340*6408Sha137994 		if (*vaddr == NULL) {
1341*6408Sha137994 			memseg->vaddr = kmem_zalloc(exp_size, KM_SLEEP);
1342*6408Sha137994 			mhdl->myshadow = B_TRUE;
1343*6408Sha137994 
1344*6408Sha137994 			D1(ldcp->id, "ldc_mem_map: (0x%llx) allocated "
1345*6408Sha137994 			    "shadow page va=0x%llx\n", ldcp->id, memseg->vaddr);
1346*6408Sha137994 		} else {
1347*6408Sha137994 			/*
1348*6408Sha137994 			 * Use client supplied memory for memseg->vaddr
1349*6408Sha137994 			 * WARNING: assuming that client mem is >= exp_size
1350*6408Sha137994 			 */
1351*6408Sha137994 			memseg->vaddr = *vaddr;
1352*6408Sha137994 		}
1353*6408Sha137994 
1354*6408Sha137994 		/* Save all page and cookie information */
1355*6408Sha137994 		for (i = 0, tmpaddr = memseg->vaddr; i < npages; i++) {
1356*6408Sha137994 			memseg->pages[i].raddr = va_to_pa(tmpaddr);
1357*6408Sha137994 			memseg->pages[i].size = pg_size;
1358*6408Sha137994 			tmpaddr += pg_size;
1359*6408Sha137994 		}
1360*6408Sha137994 
1361*6408Sha137994 	}
1362*6408Sha137994 
1363*6408Sha137994 	/* save all cookies */
1364*6408Sha137994 	bcopy(cookie, memseg->cookies, ccount * sizeof (ldc_mem_cookie_t));
1365*6408Sha137994 
1366*6408Sha137994 	/* update memseg_t */
1367*6408Sha137994 	memseg->raddr = memseg->pages[0].raddr;
1368*6408Sha137994 	memseg->size = (mtype == LDC_SHADOW_MAP) ? exp_size : map_size;
1369*6408Sha137994 	memseg->npages = npages;
1370*6408Sha137994 	memseg->ncookies = ccount;
1371*6408Sha137994 	memseg->next_cookie = 0;
1372*6408Sha137994 
1373*6408Sha137994 	/* memory handle = mapped */
1374*6408Sha137994 	mhdl->mtype = mtype;
1375*6408Sha137994 	mhdl->perm = perm;
1376*6408Sha137994 	mhdl->status = LDC_MAPPED;
1377*6408Sha137994 
1378*6408Sha137994 	D1(ldcp->id, "ldc_mem_map: (0x%llx) mapped 0x%llx, ra=0x%llx, "
1379*6408Sha137994 	    "va=0x%llx, pgs=0x%llx cookies=0x%llx\n",
1380*6408Sha137994 	    ldcp->id, mhdl, memseg->raddr, memseg->vaddr,
1381*6408Sha137994 	    memseg->npages, memseg->ncookies);
1382*6408Sha137994 
1383*6408Sha137994 	if (mtype == LDC_SHADOW_MAP)
1384*6408Sha137994 		base_off = 0;
1385*6408Sha137994 	if (raddr)
1386*6408Sha137994 		*raddr = (caddr_t)(memseg->raddr | base_off);
1387*6408Sha137994 	if (vaddr)
1388*6408Sha137994 		*vaddr = (caddr_t)((uintptr_t)memseg->vaddr | base_off);
1389*6408Sha137994 
1390*6408Sha137994 	mutex_exit(&ldcp->lock);
1391*6408Sha137994 	mutex_exit(&mhdl->lock);
1392*6408Sha137994 	return (0);
1393*6408Sha137994 }
1394*6408Sha137994 
1395*6408Sha137994 /*
1396*6408Sha137994  * Unmap a memory segment. Free shadow memory (if any).
1397*6408Sha137994  */
1398*6408Sha137994 int
1399*6408Sha137994 ldc_mem_unmap(ldc_mem_handle_t mhandle)
1400*6408Sha137994 {
1401*6408Sha137994 	int		i, rv;
1402*6408Sha137994 	ldc_mhdl_t	*mhdl = (ldc_mhdl_t *)mhandle;
1403*6408Sha137994 	ldc_chan_t 	*ldcp;
1404*6408Sha137994 	ldc_memseg_t	*memseg;
1405*6408Sha137994 
1406*6408Sha137994 	if (mhdl == 0 || mhdl->status != LDC_MAPPED) {
1407*6408Sha137994 		DWARN(DBG_ALL_LDCS,
1408*6408Sha137994 		    "ldc_mem_unmap: (0x%llx) handle is not mapped\n",
1409*6408Sha137994 		    mhandle);
1410*6408Sha137994 		return (EINVAL);
1411*6408Sha137994 	}
1412*6408Sha137994 
1413*6408Sha137994 	mutex_enter(&mhdl->lock);
1414*6408Sha137994 
1415*6408Sha137994 	ldcp = mhdl->ldcp;
1416*6408Sha137994 	memseg = mhdl->memseg;
1417*6408Sha137994 
1418*6408Sha137994 	D1(ldcp->id, "ldc_mem_unmap: (0x%llx) unmapping handle 0x%llx\n",
1419*6408Sha137994 	    ldcp->id, mhdl);
1420*6408Sha137994 
1421*6408Sha137994 	/* if we allocated shadow memory - free it */
1422*6408Sha137994 	if (mhdl->mtype == LDC_SHADOW_MAP && mhdl->myshadow) {
1423*6408Sha137994 		kmem_free(memseg->vaddr, memseg->size);
1424*6408Sha137994 	} else if (mhdl->mtype == LDC_DIRECT_MAP) {
1425*6408Sha137994 
1426*6408Sha137994 		/* unmap in the case of DIRECT_MAP */
1427*6408Sha137994 		hat_unload(kas.a_hat, memseg->vaddr, memseg->size,
1428*6408Sha137994 		    HAT_UNLOAD_UNLOCK);
1429*6408Sha137994 
1430*6408Sha137994 		for (i = 0; i < memseg->npages; i++) {
1431*6408Sha137994 			rv = hv_ldc_unmap(memseg->pages[i].raddr);
1432*6408Sha137994 			if (rv) {
1433*6408Sha137994 				cmn_err(CE_WARN,
1434*6408Sha137994 				    "ldc_mem_map: (0x%lx) hv unmap err %d\n",
1435*6408Sha137994 				    ldcp->id, rv);
1436*6408Sha137994 			}
1437*6408Sha137994 		}
1438*6408Sha137994 
1439*6408Sha137994 		vmem_free(heap_arena, (void *)memseg->vaddr, memseg->size);
1440*6408Sha137994 	}
1441*6408Sha137994 
1442*6408Sha137994 	/* free the allocated memseg and page structures */
1443*6408Sha137994 	kmem_free(memseg->pages, (sizeof (ldc_page_t) * memseg->npages));
1444*6408Sha137994 	kmem_free(memseg->cookies,
1445*6408Sha137994 	    (sizeof (ldc_mem_cookie_t) * memseg->ncookies));
1446*6408Sha137994 	kmem_cache_free(ldcssp->memseg_cache, memseg);
1447*6408Sha137994 
1448*6408Sha137994 	/* uninitialize the memory handle */
1449*6408Sha137994 	mhdl->memseg = NULL;
1450*6408Sha137994 	mhdl->status = LDC_UNBOUND;
1451*6408Sha137994 
1452*6408Sha137994 	D1(ldcp->id, "ldc_mem_unmap: (0x%llx) unmapped handle 0x%llx\n",
1453*6408Sha137994 	    ldcp->id, mhdl);
1454*6408Sha137994 
1455*6408Sha137994 	mutex_exit(&mhdl->lock);
1456*6408Sha137994 	return (0);
1457*6408Sha137994 }
1458*6408Sha137994 
1459*6408Sha137994 /*
1460*6408Sha137994  * Internal entry point for LDC mapped memory entry consistency
1461*6408Sha137994  * semantics. Acquire copies the contents of the remote memory
1462*6408Sha137994  * into the local shadow copy. The release operation copies the local
1463*6408Sha137994  * contents into the remote memory. The offset and size specify the
1464*6408Sha137994  * bounds for the memory range being synchronized.
1465*6408Sha137994  */
1466*6408Sha137994 static int
1467*6408Sha137994 i_ldc_mem_acquire_release(ldc_mem_handle_t mhandle, uint8_t direction,
1468*6408Sha137994     uint64_t offset, size_t size)
1469*6408Sha137994 {
1470*6408Sha137994 	int 		err;
1471*6408Sha137994 	ldc_mhdl_t	*mhdl;
1472*6408Sha137994 	ldc_chan_t	*ldcp;
1473*6408Sha137994 	ldc_memseg_t	*memseg;
1474*6408Sha137994 	caddr_t		local_vaddr;
1475*6408Sha137994 	size_t		copy_size;
1476*6408Sha137994 
1477*6408Sha137994 	if (mhandle == NULL) {
1478*6408Sha137994 		DWARN(DBG_ALL_LDCS,
1479*6408Sha137994 		    "i_ldc_mem_acquire_release: invalid memory handle\n");
1480*6408Sha137994 		return (EINVAL);
1481*6408Sha137994 	}
1482*6408Sha137994 	mhdl = (ldc_mhdl_t *)mhandle;
1483*6408Sha137994 
1484*6408Sha137994 	mutex_enter(&mhdl->lock);
1485*6408Sha137994 
1486*6408Sha137994 	if (mhdl->status != LDC_MAPPED || mhdl->ldcp == NULL) {
1487*6408Sha137994 		DWARN(DBG_ALL_LDCS,
1488*6408Sha137994 		    "i_ldc_mem_acquire_release: not mapped memory\n");
1489*6408Sha137994 		mutex_exit(&mhdl->lock);
1490*6408Sha137994 		return (EINVAL);
1491*6408Sha137994 	}
1492*6408Sha137994 
1493*6408Sha137994 	/* do nothing for direct map */
1494*6408Sha137994 	if (mhdl->mtype == LDC_DIRECT_MAP) {
1495*6408Sha137994 		mutex_exit(&mhdl->lock);
1496*6408Sha137994 		return (0);
1497*6408Sha137994 	}
1498*6408Sha137994 
1499*6408Sha137994 	/* do nothing if COPY_IN+MEM_W and COPY_OUT+MEM_R */
1500*6408Sha137994 	if ((direction == LDC_COPY_IN && (mhdl->perm & LDC_MEM_R) == 0) ||
1501*6408Sha137994 	    (direction == LDC_COPY_OUT && (mhdl->perm & LDC_MEM_W) == 0)) {
1502*6408Sha137994 		mutex_exit(&mhdl->lock);
1503*6408Sha137994 		return (0);
1504*6408Sha137994 	}
1505*6408Sha137994 
1506*6408Sha137994 	if (offset >= mhdl->memseg->size ||
1507*6408Sha137994 	    (offset + size) > mhdl->memseg->size) {
1508*6408Sha137994 		DWARN(DBG_ALL_LDCS,
1509*6408Sha137994 		    "i_ldc_mem_acquire_release: memory out of range\n");
1510*6408Sha137994 		mutex_exit(&mhdl->lock);
1511*6408Sha137994 		return (EINVAL);
1512*6408Sha137994 	}
1513*6408Sha137994 
1514*6408Sha137994 	/* get the channel handle and memory segment */
1515*6408Sha137994 	ldcp = mhdl->ldcp;
1516*6408Sha137994 	memseg = mhdl->memseg;
1517*6408Sha137994 
1518*6408Sha137994 	if (mhdl->mtype == LDC_SHADOW_MAP) {
1519*6408Sha137994 
1520*6408Sha137994 		local_vaddr = memseg->vaddr + offset;
1521*6408Sha137994 		copy_size = size;
1522*6408Sha137994 
1523*6408Sha137994 		/* copy to/from remote from/to local memory */
1524*6408Sha137994 		err = ldc_mem_copy((ldc_handle_t)ldcp, local_vaddr, offset,
1525*6408Sha137994 		    &copy_size, memseg->cookies, memseg->ncookies,
1526*6408Sha137994 		    direction);
1527*6408Sha137994 		if (err || copy_size != size) {
1528*6408Sha137994 			DWARN(ldcp->id,
1529*6408Sha137994 			    "i_ldc_mem_acquire_release: copy failed\n");
1530*6408Sha137994 			mutex_exit(&mhdl->lock);
1531*6408Sha137994 			return (err);
1532*6408Sha137994 		}
1533*6408Sha137994 	}
1534*6408Sha137994 
1535*6408Sha137994 	mutex_exit(&mhdl->lock);
1536*6408Sha137994 
1537*6408Sha137994 	return (0);
1538*6408Sha137994 }
1539*6408Sha137994 
1540*6408Sha137994 /*
1541*6408Sha137994  * Ensure that the contents in the remote memory seg are consistent
1542*6408Sha137994  * with the contents if of local segment
1543*6408Sha137994  */
1544*6408Sha137994 int
1545*6408Sha137994 ldc_mem_acquire(ldc_mem_handle_t mhandle, uint64_t offset, uint64_t size)
1546*6408Sha137994 {
1547*6408Sha137994 	return (i_ldc_mem_acquire_release(mhandle, LDC_COPY_IN, offset, size));
1548*6408Sha137994 }
1549*6408Sha137994 
1550*6408Sha137994 
1551*6408Sha137994 /*
1552*6408Sha137994  * Ensure that the contents in the local memory seg are consistent
1553*6408Sha137994  * with the contents if of remote segment
1554*6408Sha137994  */
1555*6408Sha137994 int
1556*6408Sha137994 ldc_mem_release(ldc_mem_handle_t mhandle, uint64_t offset, uint64_t size)
1557*6408Sha137994 {
1558*6408Sha137994 	return (i_ldc_mem_acquire_release(mhandle, LDC_COPY_OUT, offset, size));
1559*6408Sha137994 }
1560*6408Sha137994 
1561*6408Sha137994 /*
1562*6408Sha137994  * Allocate a descriptor ring. The size of each each descriptor
1563*6408Sha137994  * must be 8-byte aligned and the entire ring should be a multiple
1564*6408Sha137994  * of MMU_PAGESIZE.
1565*6408Sha137994  */
1566*6408Sha137994 int
1567*6408Sha137994 ldc_mem_dring_create(uint32_t len, uint32_t dsize, ldc_dring_handle_t *dhandle)
1568*6408Sha137994 {
1569*6408Sha137994 	ldc_dring_t *dringp;
1570*6408Sha137994 	size_t size = (dsize * len);
1571*6408Sha137994 
1572*6408Sha137994 	D1(DBG_ALL_LDCS, "ldc_mem_dring_create: len=0x%x, size=0x%x\n",
1573*6408Sha137994 	    len, dsize);
1574*6408Sha137994 
1575*6408Sha137994 	if (dhandle == NULL) {
1576*6408Sha137994 		DWARN(DBG_ALL_LDCS, "ldc_mem_dring_create: invalid dhandle\n");
1577*6408Sha137994 		return (EINVAL);
1578*6408Sha137994 	}
1579*6408Sha137994 
1580*6408Sha137994 	if (len == 0) {
1581*6408Sha137994 		DWARN(DBG_ALL_LDCS, "ldc_mem_dring_create: invalid length\n");
1582*6408Sha137994 		return (EINVAL);
1583*6408Sha137994 	}
1584*6408Sha137994 
1585*6408Sha137994 	/* descriptor size should be 8-byte aligned */
1586*6408Sha137994 	if (dsize == 0 || (dsize & 0x7)) {
1587*6408Sha137994 		DWARN(DBG_ALL_LDCS, "ldc_mem_dring_create: invalid size\n");
1588*6408Sha137994 		return (EINVAL);
1589*6408Sha137994 	}
1590*6408Sha137994 
1591*6408Sha137994 	*dhandle = 0;
1592*6408Sha137994 
1593*6408Sha137994 	/* Allocate a desc ring structure */
1594*6408Sha137994 	dringp = kmem_zalloc(sizeof (ldc_dring_t), KM_SLEEP);
1595*6408Sha137994 
1596*6408Sha137994 	/* Initialize dring */
1597*6408Sha137994 	dringp->length = len;
1598*6408Sha137994 	dringp->dsize = dsize;
1599*6408Sha137994 
1600*6408Sha137994 	/* round off to multiple of pagesize */
1601*6408Sha137994 	dringp->size = (size & MMU_PAGEMASK);
1602*6408Sha137994 	if (size & MMU_PAGEOFFSET)
1603*6408Sha137994 		dringp->size += MMU_PAGESIZE;
1604*6408Sha137994 
1605*6408Sha137994 	dringp->status = LDC_UNBOUND;
1606*6408Sha137994 
1607*6408Sha137994 	/* allocate descriptor ring memory */
1608*6408Sha137994 	dringp->base = kmem_zalloc(dringp->size, KM_SLEEP);
1609*6408Sha137994 
1610*6408Sha137994 	/* initialize the desc ring lock */
1611*6408Sha137994 	mutex_init(&dringp->lock, NULL, MUTEX_DRIVER, NULL);
1612*6408Sha137994 
1613*6408Sha137994 	/* Add descriptor ring to the head of global list */
1614*6408Sha137994 	mutex_enter(&ldcssp->lock);
1615*6408Sha137994 	dringp->next = ldcssp->dring_list;
1616*6408Sha137994 	ldcssp->dring_list = dringp;
1617*6408Sha137994 	mutex_exit(&ldcssp->lock);
1618*6408Sha137994 
1619*6408Sha137994 	*dhandle = (ldc_dring_handle_t)dringp;
1620*6408Sha137994 
1621*6408Sha137994 	D1(DBG_ALL_LDCS, "ldc_mem_dring_create: dring allocated\n");
1622*6408Sha137994 
1623*6408Sha137994 	return (0);
1624*6408Sha137994 }
1625*6408Sha137994 
1626*6408Sha137994 
1627*6408Sha137994 /*
1628*6408Sha137994  * Destroy a descriptor ring.
1629*6408Sha137994  */
1630*6408Sha137994 int
1631*6408Sha137994 ldc_mem_dring_destroy(ldc_dring_handle_t dhandle)
1632*6408Sha137994 {
1633*6408Sha137994 	ldc_dring_t *dringp;
1634*6408Sha137994 	ldc_dring_t *tmp_dringp;
1635*6408Sha137994 
1636*6408Sha137994 	D1(DBG_ALL_LDCS, "ldc_mem_dring_destroy: entered\n");
1637*6408Sha137994 
1638*6408Sha137994 	if (dhandle == NULL) {
1639*6408Sha137994 		DWARN(DBG_ALL_LDCS,
1640*6408Sha137994 		    "ldc_mem_dring_destroy: invalid desc ring handle\n");
1641*6408Sha137994 		return (EINVAL);
1642*6408Sha137994 	}
1643*6408Sha137994 	dringp = (ldc_dring_t *)dhandle;
1644*6408Sha137994 
1645*6408Sha137994 	if (dringp->status == LDC_BOUND) {
1646*6408Sha137994 		DWARN(DBG_ALL_LDCS,
1647*6408Sha137994 		    "ldc_mem_dring_destroy: desc ring is bound\n");
1648*6408Sha137994 		return (EACCES);
1649*6408Sha137994 	}
1650*6408Sha137994 
1651*6408Sha137994 	mutex_enter(&dringp->lock);
1652*6408Sha137994 	mutex_enter(&ldcssp->lock);
1653*6408Sha137994 
1654*6408Sha137994 	/* remove from linked list - if not bound */
1655*6408Sha137994 	tmp_dringp = ldcssp->dring_list;
1656*6408Sha137994 	if (tmp_dringp == dringp) {
1657*6408Sha137994 		ldcssp->dring_list = dringp->next;
1658*6408Sha137994 		dringp->next = NULL;
1659*6408Sha137994 
1660*6408Sha137994 	} else {
1661*6408Sha137994 		while (tmp_dringp != NULL) {
1662*6408Sha137994 			if (tmp_dringp->next == dringp) {
1663*6408Sha137994 				tmp_dringp->next = dringp->next;
1664*6408Sha137994 				dringp->next = NULL;
1665*6408Sha137994 				break;
1666*6408Sha137994 			}
1667*6408Sha137994 			tmp_dringp = tmp_dringp->next;
1668*6408Sha137994 		}
1669*6408Sha137994 		if (tmp_dringp == NULL) {
1670*6408Sha137994 			DWARN(DBG_ALL_LDCS,
1671*6408Sha137994 			    "ldc_mem_dring_destroy: invalid descriptor\n");
1672*6408Sha137994 			mutex_exit(&ldcssp->lock);
1673*6408Sha137994 			mutex_exit(&dringp->lock);
1674*6408Sha137994 			return (EINVAL);
1675*6408Sha137994 		}
1676*6408Sha137994 	}
1677*6408Sha137994 
1678*6408Sha137994 	mutex_exit(&ldcssp->lock);
1679*6408Sha137994 
1680*6408Sha137994 	/* free the descriptor ring */
1681*6408Sha137994 	kmem_free(dringp->base, dringp->size);
1682*6408Sha137994 
1683*6408Sha137994 	mutex_exit(&dringp->lock);
1684*6408Sha137994 
1685*6408Sha137994 	/* destroy dring lock */
1686*6408Sha137994 	mutex_destroy(&dringp->lock);
1687*6408Sha137994 
1688*6408Sha137994 	/* free desc ring object */
1689*6408Sha137994 	kmem_free(dringp, sizeof (ldc_dring_t));
1690*6408Sha137994 
1691*6408Sha137994 	return (0);
1692*6408Sha137994 }
1693*6408Sha137994 
1694*6408Sha137994 /*
1695*6408Sha137994  * Bind a previously allocated dring to a channel. The channel should
1696*6408Sha137994  * be OPEN in order to bind the ring to the channel. Returns back a
1697*6408Sha137994  * descriptor ring cookie. The descriptor ring is exported for remote
1698*6408Sha137994  * access by the client at the other end of the channel. An entry for
1699*6408Sha137994  * dring pages is stored in map table (via call to ldc_mem_bind_handle).
1700*6408Sha137994  */
1701*6408Sha137994 int
1702*6408Sha137994 ldc_mem_dring_bind(ldc_handle_t handle, ldc_dring_handle_t dhandle,
1703*6408Sha137994     uint8_t mtype, uint8_t perm, ldc_mem_cookie_t *cookie, uint32_t *ccount)
1704*6408Sha137994 {
1705*6408Sha137994 	int		err;
1706*6408Sha137994 	ldc_chan_t 	*ldcp;
1707*6408Sha137994 	ldc_dring_t	*dringp;
1708*6408Sha137994 	ldc_mem_handle_t mhandle;
1709*6408Sha137994 
1710*6408Sha137994 	/* check to see if channel is initalized */
1711*6408Sha137994 	if (handle == NULL) {
1712*6408Sha137994 		DWARN(DBG_ALL_LDCS,
1713*6408Sha137994 		    "ldc_mem_dring_bind: invalid channel handle\n");
1714*6408Sha137994 		return (EINVAL);
1715*6408Sha137994 	}
1716*6408Sha137994 	ldcp = (ldc_chan_t *)handle;
1717*6408Sha137994 
1718*6408Sha137994 	if (dhandle == NULL) {
1719*6408Sha137994 		DWARN(DBG_ALL_LDCS,
1720*6408Sha137994 		    "ldc_mem_dring_bind: invalid desc ring handle\n");
1721*6408Sha137994 		return (EINVAL);
1722*6408Sha137994 	}
1723*6408Sha137994 	dringp = (ldc_dring_t *)dhandle;
1724*6408Sha137994 
1725*6408Sha137994 	if (cookie == NULL) {
1726*6408Sha137994 		DWARN(ldcp->id,
1727*6408Sha137994 		    "ldc_mem_dring_bind: invalid cookie arg\n");
1728*6408Sha137994 		return (EINVAL);
1729*6408Sha137994 	}
1730*6408Sha137994 
1731*6408Sha137994 	mutex_enter(&dringp->lock);
1732*6408Sha137994 
1733*6408Sha137994 	if (dringp->status == LDC_BOUND) {
1734*6408Sha137994 		DWARN(DBG_ALL_LDCS,
1735*6408Sha137994 		    "ldc_mem_dring_bind: (0x%llx) descriptor ring is bound\n",
1736*6408Sha137994 		    ldcp->id);
1737*6408Sha137994 		mutex_exit(&dringp->lock);
1738*6408Sha137994 		return (EINVAL);
1739*6408Sha137994 	}
1740*6408Sha137994 
1741*6408Sha137994 	if ((perm & LDC_MEM_RW) == 0) {
1742*6408Sha137994 		DWARN(DBG_ALL_LDCS,
1743*6408Sha137994 		    "ldc_mem_dring_bind: invalid permissions\n");
1744*6408Sha137994 		mutex_exit(&dringp->lock);
1745*6408Sha137994 		return (EINVAL);
1746*6408Sha137994 	}
1747*6408Sha137994 
1748*6408Sha137994 	if ((mtype & (LDC_SHADOW_MAP|LDC_DIRECT_MAP|LDC_IO_MAP)) == 0) {
1749*6408Sha137994 		DWARN(DBG_ALL_LDCS, "ldc_mem_dring_bind: invalid type\n");
1750*6408Sha137994 		mutex_exit(&dringp->lock);
1751*6408Sha137994 		return (EINVAL);
1752*6408Sha137994 	}
1753*6408Sha137994 
1754*6408Sha137994 	dringp->ldcp = ldcp;
1755*6408Sha137994 
1756*6408Sha137994 	/* create an memory handle */
1757*6408Sha137994 	err = ldc_mem_alloc_handle(handle, &mhandle);
1758*6408Sha137994 	if (err || mhandle == NULL) {
1759*6408Sha137994 		DWARN(DBG_ALL_LDCS,
1760*6408Sha137994 		    "ldc_mem_dring_bind: (0x%llx) error allocating mhandle\n",
1761*6408Sha137994 		    ldcp->id);
1762*6408Sha137994 		mutex_exit(&dringp->lock);
1763*6408Sha137994 		return (err);
1764*6408Sha137994 	}
1765*6408Sha137994 	dringp->mhdl = mhandle;
1766*6408Sha137994 
1767*6408Sha137994 	/* bind the descriptor ring to channel */
1768*6408Sha137994 	err = ldc_mem_bind_handle(mhandle, dringp->base, dringp->size,
1769*6408Sha137994 	    mtype, perm, cookie, ccount);
1770*6408Sha137994 	if (err) {
1771*6408Sha137994 		DWARN(ldcp->id,
1772*6408Sha137994 		    "ldc_mem_dring_bind: (0x%llx) error binding mhandle\n",
1773*6408Sha137994 		    ldcp->id);
1774*6408Sha137994 		mutex_exit(&dringp->lock);
1775*6408Sha137994 		return (err);
1776*6408Sha137994 	}
1777*6408Sha137994 
1778*6408Sha137994 	/*
1779*6408Sha137994 	 * For now return error if we get more than one cookie
1780*6408Sha137994 	 * FUTURE: Return multiple cookies ..
1781*6408Sha137994 	 */
1782*6408Sha137994 	if (*ccount > 1) {
1783*6408Sha137994 		(void) ldc_mem_unbind_handle(mhandle);
1784*6408Sha137994 		(void) ldc_mem_free_handle(mhandle);
1785*6408Sha137994 
1786*6408Sha137994 		dringp->ldcp = NULL;
1787*6408Sha137994 		dringp->mhdl = NULL;
1788*6408Sha137994 		*ccount = 0;
1789*6408Sha137994 
1790*6408Sha137994 		mutex_exit(&dringp->lock);
1791*6408Sha137994 		return (EAGAIN);
1792*6408Sha137994 	}
1793*6408Sha137994 
1794*6408Sha137994 	/* Add descriptor ring to channel's exported dring list */
1795*6408Sha137994 	mutex_enter(&ldcp->exp_dlist_lock);
1796*6408Sha137994 	dringp->ch_next = ldcp->exp_dring_list;
1797*6408Sha137994 	ldcp->exp_dring_list = dringp;
1798*6408Sha137994 	mutex_exit(&ldcp->exp_dlist_lock);
1799*6408Sha137994 
1800*6408Sha137994 	dringp->status = LDC_BOUND;
1801*6408Sha137994 
1802*6408Sha137994 	mutex_exit(&dringp->lock);
1803*6408Sha137994 
1804*6408Sha137994 	return (0);
1805*6408Sha137994 }
1806*6408Sha137994 
1807*6408Sha137994 /*
1808*6408Sha137994  * Return the next cookie associated with the specified dring handle
1809*6408Sha137994  */
1810*6408Sha137994 int
1811*6408Sha137994 ldc_mem_dring_nextcookie(ldc_dring_handle_t dhandle, ldc_mem_cookie_t *cookie)
1812*6408Sha137994 {
1813*6408Sha137994 	int		rv = 0;
1814*6408Sha137994 	ldc_dring_t 	*dringp;
1815*6408Sha137994 	ldc_chan_t	*ldcp;
1816*6408Sha137994 
1817*6408Sha137994 	if (dhandle == NULL) {
1818*6408Sha137994 		DWARN(DBG_ALL_LDCS,
1819*6408Sha137994 		    "ldc_mem_dring_nextcookie: invalid desc ring handle\n");
1820*6408Sha137994 		return (EINVAL);
1821*6408Sha137994 	}
1822*6408Sha137994 	dringp = (ldc_dring_t *)dhandle;
1823*6408Sha137994 	mutex_enter(&dringp->lock);
1824*6408Sha137994 
1825*6408Sha137994 	if (dringp->status != LDC_BOUND) {
1826*6408Sha137994 		DWARN(DBG_ALL_LDCS,
1827*6408Sha137994 		    "ldc_mem_dring_nextcookie: descriptor ring 0x%llx "
1828*6408Sha137994 		    "is not bound\n", dringp);
1829*6408Sha137994 		mutex_exit(&dringp->lock);
1830*6408Sha137994 		return (EINVAL);
1831*6408Sha137994 	}
1832*6408Sha137994 
1833*6408Sha137994 	ldcp = dringp->ldcp;
1834*6408Sha137994 
1835*6408Sha137994 	if (cookie == NULL) {
1836*6408Sha137994 		DWARN(ldcp->id,
1837*6408Sha137994 		    "ldc_mem_dring_nextcookie:(0x%llx) invalid cookie arg\n",
1838*6408Sha137994 		    ldcp->id);
1839*6408Sha137994 		mutex_exit(&dringp->lock);
1840*6408Sha137994 		return (EINVAL);
1841*6408Sha137994 	}
1842*6408Sha137994 
1843*6408Sha137994 	rv = ldc_mem_nextcookie((ldc_mem_handle_t)dringp->mhdl, cookie);
1844*6408Sha137994 	mutex_exit(&dringp->lock);
1845*6408Sha137994 
1846*6408Sha137994 	return (rv);
1847*6408Sha137994 }
1848*6408Sha137994 /*
1849*6408Sha137994  * Unbind a previously bound dring from a channel.
1850*6408Sha137994  */
1851*6408Sha137994 int
1852*6408Sha137994 ldc_mem_dring_unbind(ldc_dring_handle_t dhandle)
1853*6408Sha137994 {
1854*6408Sha137994 	ldc_dring_t 	*dringp;
1855*6408Sha137994 	ldc_dring_t	*tmp_dringp;
1856*6408Sha137994 	ldc_chan_t	*ldcp;
1857*6408Sha137994 
1858*6408Sha137994 	if (dhandle == NULL) {
1859*6408Sha137994 		DWARN(DBG_ALL_LDCS,
1860*6408Sha137994 		    "ldc_mem_dring_unbind: invalid desc ring handle\n");
1861*6408Sha137994 		return (EINVAL);
1862*6408Sha137994 	}
1863*6408Sha137994 	dringp = (ldc_dring_t *)dhandle;
1864*6408Sha137994 
1865*6408Sha137994 	mutex_enter(&dringp->lock);
1866*6408Sha137994 
1867*6408Sha137994 	if (dringp->status == LDC_UNBOUND) {
1868*6408Sha137994 		DWARN(DBG_ALL_LDCS,
1869*6408Sha137994 		    "ldc_mem_dring_bind: descriptor ring 0x%llx is unbound\n",
1870*6408Sha137994 		    dringp);
1871*6408Sha137994 		mutex_exit(&dringp->lock);
1872*6408Sha137994 		return (EINVAL);
1873*6408Sha137994 	}
1874*6408Sha137994 	ldcp = dringp->ldcp;
1875*6408Sha137994 
1876*6408Sha137994 	mutex_enter(&ldcp->exp_dlist_lock);
1877*6408Sha137994 
1878*6408Sha137994 	tmp_dringp = ldcp->exp_dring_list;
1879*6408Sha137994 	if (tmp_dringp == dringp) {
1880*6408Sha137994 		ldcp->exp_dring_list = dringp->ch_next;
1881*6408Sha137994 		dringp->ch_next = NULL;
1882*6408Sha137994 
1883*6408Sha137994 	} else {
1884*6408Sha137994 		while (tmp_dringp != NULL) {
1885*6408Sha137994 			if (tmp_dringp->ch_next == dringp) {
1886*6408Sha137994 				tmp_dringp->ch_next = dringp->ch_next;
1887*6408Sha137994 				dringp->ch_next = NULL;
1888*6408Sha137994 				break;
1889*6408Sha137994 			}
1890*6408Sha137994 			tmp_dringp = tmp_dringp->ch_next;
1891*6408Sha137994 		}
1892*6408Sha137994 		if (tmp_dringp == NULL) {
1893*6408Sha137994 			DWARN(DBG_ALL_LDCS,
1894*6408Sha137994 			    "ldc_mem_dring_unbind: invalid descriptor\n");
1895*6408Sha137994 			mutex_exit(&ldcp->exp_dlist_lock);
1896*6408Sha137994 			mutex_exit(&dringp->lock);
1897*6408Sha137994 			return (EINVAL);
1898*6408Sha137994 		}
1899*6408Sha137994 	}
1900*6408Sha137994 
1901*6408Sha137994 	mutex_exit(&ldcp->exp_dlist_lock);
1902*6408Sha137994 
1903*6408Sha137994 	(void) ldc_mem_unbind_handle((ldc_mem_handle_t)dringp->mhdl);
1904*6408Sha137994 	(void) ldc_mem_free_handle((ldc_mem_handle_t)dringp->mhdl);
1905*6408Sha137994 
1906*6408Sha137994 	dringp->ldcp = NULL;
1907*6408Sha137994 	dringp->mhdl = NULL;
1908*6408Sha137994 	dringp->status = LDC_UNBOUND;
1909*6408Sha137994 
1910*6408Sha137994 	mutex_exit(&dringp->lock);
1911*6408Sha137994 
1912*6408Sha137994 	return (0);
1913*6408Sha137994 }
1914*6408Sha137994 
1915*6408Sha137994 /*
1916*6408Sha137994  * Get information about the dring. The base address of the descriptor
1917*6408Sha137994  * ring along with the type and permission are returned back.
1918*6408Sha137994  */
1919*6408Sha137994 int
1920*6408Sha137994 ldc_mem_dring_info(ldc_dring_handle_t dhandle, ldc_mem_info_t *minfo)
1921*6408Sha137994 {
1922*6408Sha137994 	ldc_dring_t	*dringp;
1923*6408Sha137994 	int		rv;
1924*6408Sha137994 
1925*6408Sha137994 	if (dhandle == NULL) {
1926*6408Sha137994 		DWARN(DBG_ALL_LDCS,
1927*6408Sha137994 		    "ldc_mem_dring_info: invalid desc ring handle\n");
1928*6408Sha137994 		return (EINVAL);
1929*6408Sha137994 	}
1930*6408Sha137994 	dringp = (ldc_dring_t *)dhandle;
1931*6408Sha137994 
1932*6408Sha137994 	mutex_enter(&dringp->lock);
1933*6408Sha137994 
1934*6408Sha137994 	if (dringp->mhdl) {
1935*6408Sha137994 		rv = ldc_mem_info(dringp->mhdl, minfo);
1936*6408Sha137994 		if (rv) {
1937*6408Sha137994 			DWARN(DBG_ALL_LDCS,
1938*6408Sha137994 			    "ldc_mem_dring_info: error reading mem info\n");
1939*6408Sha137994 			mutex_exit(&dringp->lock);
1940*6408Sha137994 			return (rv);
1941*6408Sha137994 		}
1942*6408Sha137994 	} else {
1943*6408Sha137994 		minfo->vaddr = dringp->base;
1944*6408Sha137994 		minfo->raddr = NULL;
1945*6408Sha137994 		minfo->status = dringp->status;
1946*6408Sha137994 	}
1947*6408Sha137994 
1948*6408Sha137994 	mutex_exit(&dringp->lock);
1949*6408Sha137994 
1950*6408Sha137994 	return (0);
1951*6408Sha137994 }
1952*6408Sha137994 
1953*6408Sha137994 /*
1954*6408Sha137994  * Map an exported descriptor ring into the local address space. If the
1955*6408Sha137994  * descriptor ring was exported for direct map access, a HV call is made
1956*6408Sha137994  * to allocate a RA range. If the map is done via a shadow copy, local
1957*6408Sha137994  * shadow memory is allocated.
1958*6408Sha137994  */
1959*6408Sha137994 int
1960*6408Sha137994 ldc_mem_dring_map(ldc_handle_t handle, ldc_mem_cookie_t *cookie,
1961*6408Sha137994     uint32_t ccount, uint32_t len, uint32_t dsize, uint8_t mtype,
1962*6408Sha137994     ldc_dring_handle_t *dhandle)
1963*6408Sha137994 {
1964*6408Sha137994 	int		err;
1965*6408Sha137994 	ldc_chan_t 	*ldcp = (ldc_chan_t *)handle;
1966*6408Sha137994 	ldc_mem_handle_t mhandle;
1967*6408Sha137994 	ldc_dring_t	*dringp;
1968*6408Sha137994 	size_t		dring_size;
1969*6408Sha137994 
1970*6408Sha137994 	if (dhandle == NULL) {
1971*6408Sha137994 		DWARN(DBG_ALL_LDCS,
1972*6408Sha137994 		    "ldc_mem_dring_map: invalid dhandle\n");
1973*6408Sha137994 		return (EINVAL);
1974*6408Sha137994 	}
1975*6408Sha137994 
1976*6408Sha137994 	/* check to see if channel is initalized */
1977*6408Sha137994 	if (handle == NULL) {
1978*6408Sha137994 		DWARN(DBG_ALL_LDCS,
1979*6408Sha137994 		    "ldc_mem_dring_map: invalid channel handle\n");
1980*6408Sha137994 		return (EINVAL);
1981*6408Sha137994 	}
1982*6408Sha137994 	ldcp = (ldc_chan_t *)handle;
1983*6408Sha137994 
1984*6408Sha137994 	if (cookie == NULL) {
1985*6408Sha137994 		DWARN(ldcp->id,
1986*6408Sha137994 		    "ldc_mem_dring_map: (0x%llx) invalid cookie\n",
1987*6408Sha137994 		    ldcp->id);
1988*6408Sha137994 		return (EINVAL);
1989*6408Sha137994 	}
1990*6408Sha137994 
1991*6408Sha137994 	/* FUTURE: For now we support only one cookie per dring */
1992*6408Sha137994 	ASSERT(ccount == 1);
1993*6408Sha137994 
1994*6408Sha137994 	if (cookie->size < (dsize * len)) {
1995*6408Sha137994 		DWARN(ldcp->id,
1996*6408Sha137994 		    "ldc_mem_dring_map: (0x%llx) invalid dsize/len\n",
1997*6408Sha137994 		    ldcp->id);
1998*6408Sha137994 		return (EINVAL);
1999*6408Sha137994 	}
2000*6408Sha137994 
2001*6408Sha137994 	*dhandle = 0;
2002*6408Sha137994 
2003*6408Sha137994 	/* Allocate an dring structure */
2004*6408Sha137994 	dringp = kmem_zalloc(sizeof (ldc_dring_t), KM_SLEEP);
2005*6408Sha137994 
2006*6408Sha137994 	D1(ldcp->id,
2007*6408Sha137994 	    "ldc_mem_dring_map: 0x%x,0x%x,0x%x,0x%llx,0x%llx\n",
2008*6408Sha137994 	    mtype, len, dsize, cookie->addr, cookie->size);
2009*6408Sha137994 
2010*6408Sha137994 	/* Initialize dring */
2011*6408Sha137994 	dringp->length = len;
2012*6408Sha137994 	dringp->dsize = dsize;
2013*6408Sha137994 
2014*6408Sha137994 	/* round of to multiple of page size */
2015*6408Sha137994 	dring_size = len * dsize;
2016*6408Sha137994 	dringp->size = (dring_size & MMU_PAGEMASK);
2017*6408Sha137994 	if (dring_size & MMU_PAGEOFFSET)
2018*6408Sha137994 		dringp->size += MMU_PAGESIZE;
2019*6408Sha137994 
2020*6408Sha137994 	dringp->ldcp = ldcp;
2021*6408Sha137994 
2022*6408Sha137994 	/* create an memory handle */
2023*6408Sha137994 	err = ldc_mem_alloc_handle(handle, &mhandle);
2024*6408Sha137994 	if (err || mhandle == NULL) {
2025*6408Sha137994 		DWARN(DBG_ALL_LDCS,
2026*6408Sha137994 		    "ldc_mem_dring_map: cannot alloc hdl err=%d\n",
2027*6408Sha137994 		    err);
2028*6408Sha137994 		kmem_free(dringp, sizeof (ldc_dring_t));
2029*6408Sha137994 		return (ENOMEM);
2030*6408Sha137994 	}
2031*6408Sha137994 
2032*6408Sha137994 	dringp->mhdl = mhandle;
2033*6408Sha137994 	dringp->base = NULL;
2034*6408Sha137994 
2035*6408Sha137994 	/* map the dring into local memory */
2036*6408Sha137994 	err = ldc_mem_map(mhandle, cookie, ccount, mtype, LDC_MEM_RW,
2037*6408Sha137994 	    &(dringp->base), NULL);
2038*6408Sha137994 	if (err || dringp->base == NULL) {
2039*6408Sha137994 		cmn_err(CE_WARN,
2040*6408Sha137994 		    "ldc_mem_dring_map: cannot map desc ring err=%d\n", err);
2041*6408Sha137994 		(void) ldc_mem_free_handle(mhandle);
2042*6408Sha137994 		kmem_free(dringp, sizeof (ldc_dring_t));
2043*6408Sha137994 		return (ENOMEM);
2044*6408Sha137994 	}
2045*6408Sha137994 
2046*6408Sha137994 	/* initialize the desc ring lock */
2047*6408Sha137994 	mutex_init(&dringp->lock, NULL, MUTEX_DRIVER, NULL);
2048*6408Sha137994 
2049*6408Sha137994 	/* Add descriptor ring to channel's imported dring list */
2050*6408Sha137994 	mutex_enter(&ldcp->imp_dlist_lock);
2051*6408Sha137994 	dringp->ch_next = ldcp->imp_dring_list;
2052*6408Sha137994 	ldcp->imp_dring_list = dringp;
2053*6408Sha137994 	mutex_exit(&ldcp->imp_dlist_lock);
2054*6408Sha137994 
2055*6408Sha137994 	dringp->status = LDC_MAPPED;
2056*6408Sha137994 
2057*6408Sha137994 	*dhandle = (ldc_dring_handle_t)dringp;
2058*6408Sha137994 
2059*6408Sha137994 	return (0);
2060*6408Sha137994 }
2061*6408Sha137994 
2062*6408Sha137994 /*
2063*6408Sha137994  * Unmap a descriptor ring. Free shadow memory (if any).
2064*6408Sha137994  */
2065*6408Sha137994 int
2066*6408Sha137994 ldc_mem_dring_unmap(ldc_dring_handle_t dhandle)
2067*6408Sha137994 {
2068*6408Sha137994 	ldc_dring_t 	*dringp;
2069*6408Sha137994 	ldc_dring_t	*tmp_dringp;
2070*6408Sha137994 	ldc_chan_t	*ldcp;
2071*6408Sha137994 
2072*6408Sha137994 	if (dhandle == NULL) {
2073*6408Sha137994 		DWARN(DBG_ALL_LDCS,
2074*6408Sha137994 		    "ldc_mem_dring_unmap: invalid desc ring handle\n");
2075*6408Sha137994 		return (EINVAL);
2076*6408Sha137994 	}
2077*6408Sha137994 	dringp = (ldc_dring_t *)dhandle;
2078*6408Sha137994 
2079*6408Sha137994 	if (dringp->status != LDC_MAPPED) {
2080*6408Sha137994 		DWARN(DBG_ALL_LDCS,
2081*6408Sha137994 		    "ldc_mem_dring_unmap: not a mapped desc ring\n");
2082*6408Sha137994 		return (EINVAL);
2083*6408Sha137994 	}
2084*6408Sha137994 
2085*6408Sha137994 	mutex_enter(&dringp->lock);
2086*6408Sha137994 
2087*6408Sha137994 	ldcp = dringp->ldcp;
2088*6408Sha137994 
2089*6408Sha137994 	mutex_enter(&ldcp->imp_dlist_lock);
2090*6408Sha137994 
2091*6408Sha137994 	/* find and unlink the desc ring from channel import list */
2092*6408Sha137994 	tmp_dringp = ldcp->imp_dring_list;
2093*6408Sha137994 	if (tmp_dringp == dringp) {
2094*6408Sha137994 		ldcp->imp_dring_list = dringp->ch_next;
2095*6408Sha137994 		dringp->ch_next = NULL;
2096*6408Sha137994 
2097*6408Sha137994 	} else {
2098*6408Sha137994 		while (tmp_dringp != NULL) {
2099*6408Sha137994 			if (tmp_dringp->ch_next == dringp) {
2100*6408Sha137994 				tmp_dringp->ch_next = dringp->ch_next;
2101*6408Sha137994 				dringp->ch_next = NULL;
2102*6408Sha137994 				break;
2103*6408Sha137994 			}
2104*6408Sha137994 			tmp_dringp = tmp_dringp->ch_next;
2105*6408Sha137994 		}
2106*6408Sha137994 		if (tmp_dringp == NULL) {
2107*6408Sha137994 			DWARN(DBG_ALL_LDCS,
2108*6408Sha137994 			    "ldc_mem_dring_unmap: invalid descriptor\n");
2109*6408Sha137994 			mutex_exit(&ldcp->imp_dlist_lock);
2110*6408Sha137994 			mutex_exit(&dringp->lock);
2111*6408Sha137994 			return (EINVAL);
2112*6408Sha137994 		}
2113*6408Sha137994 	}
2114*6408Sha137994 
2115*6408Sha137994 	mutex_exit(&ldcp->imp_dlist_lock);
2116*6408Sha137994 
2117*6408Sha137994 	/* do a LDC memory handle unmap and free */
2118*6408Sha137994 	(void) ldc_mem_unmap(dringp->mhdl);
2119*6408Sha137994 	(void) ldc_mem_free_handle((ldc_mem_handle_t)dringp->mhdl);
2120*6408Sha137994 
2121*6408Sha137994 	dringp->status = 0;
2122*6408Sha137994 	dringp->ldcp = NULL;
2123*6408Sha137994 
2124*6408Sha137994 	mutex_exit(&dringp->lock);
2125*6408Sha137994 
2126*6408Sha137994 	/* destroy dring lock */
2127*6408Sha137994 	mutex_destroy(&dringp->lock);
2128*6408Sha137994 
2129*6408Sha137994 	/* free desc ring object */
2130*6408Sha137994 	kmem_free(dringp, sizeof (ldc_dring_t));
2131*6408Sha137994 
2132*6408Sha137994 	return (0);
2133*6408Sha137994 }
2134*6408Sha137994 
2135*6408Sha137994 /*
2136*6408Sha137994  * Internal entry point for descriptor ring access entry consistency
2137*6408Sha137994  * semantics. Acquire copies the contents of the remote descriptor ring
2138*6408Sha137994  * into the local shadow copy. The release operation copies the local
2139*6408Sha137994  * contents into the remote dring. The start and end locations specify
2140*6408Sha137994  * bounds for the entries being synchronized.
2141*6408Sha137994  */
2142*6408Sha137994 static int
2143*6408Sha137994 i_ldc_dring_acquire_release(ldc_dring_handle_t dhandle,
2144*6408Sha137994     uint8_t direction, uint64_t start, uint64_t end)
2145*6408Sha137994 {
2146*6408Sha137994 	int 			err;
2147*6408Sha137994 	ldc_dring_t		*dringp;
2148*6408Sha137994 	ldc_chan_t		*ldcp;
2149*6408Sha137994 	uint64_t		soff;
2150*6408Sha137994 	size_t			copy_size;
2151*6408Sha137994 
2152*6408Sha137994 	if (dhandle == NULL) {
2153*6408Sha137994 		DWARN(DBG_ALL_LDCS,
2154*6408Sha137994 		    "i_ldc_dring_acquire_release: invalid desc ring handle\n");
2155*6408Sha137994 		return (EINVAL);
2156*6408Sha137994 	}
2157*6408Sha137994 	dringp = (ldc_dring_t *)dhandle;
2158*6408Sha137994 	mutex_enter(&dringp->lock);
2159*6408Sha137994 
2160*6408Sha137994 	if (dringp->status != LDC_MAPPED || dringp->ldcp == NULL) {
2161*6408Sha137994 		DWARN(DBG_ALL_LDCS,
2162*6408Sha137994 		    "i_ldc_dring_acquire_release: not a mapped desc ring\n");
2163*6408Sha137994 		mutex_exit(&dringp->lock);
2164*6408Sha137994 		return (EINVAL);
2165*6408Sha137994 	}
2166*6408Sha137994 
2167*6408Sha137994 	if (start >= dringp->length || end >= dringp->length) {
2168*6408Sha137994 		DWARN(DBG_ALL_LDCS,
2169*6408Sha137994 		    "i_ldc_dring_acquire_release: index out of range\n");
2170*6408Sha137994 		mutex_exit(&dringp->lock);
2171*6408Sha137994 		return (EINVAL);
2172*6408Sha137994 	}
2173*6408Sha137994 
2174*6408Sha137994 	/* get the channel handle */
2175*6408Sha137994 	ldcp = dringp->ldcp;
2176*6408Sha137994 
2177*6408Sha137994 	copy_size = (start <= end) ? (((end - start) + 1) * dringp->dsize) :
2178*6408Sha137994 	    ((dringp->length - start) * dringp->dsize);
2179*6408Sha137994 
2180*6408Sha137994 	/* Calculate the relative offset for the first desc */
2181*6408Sha137994 	soff = (start * dringp->dsize);
2182*6408Sha137994 
2183*6408Sha137994 	/* copy to/from remote from/to local memory */
2184*6408Sha137994 	D1(ldcp->id, "i_ldc_dring_acquire_release: c1 off=0x%llx sz=0x%llx\n",
2185*6408Sha137994 	    soff, copy_size);
2186*6408Sha137994 	err = i_ldc_mem_acquire_release((ldc_mem_handle_t)dringp->mhdl,
2187*6408Sha137994 	    direction, soff, copy_size);
2188*6408Sha137994 	if (err) {
2189*6408Sha137994 		DWARN(ldcp->id,
2190*6408Sha137994 		    "i_ldc_dring_acquire_release: copy failed\n");
2191*6408Sha137994 		mutex_exit(&dringp->lock);
2192*6408Sha137994 		return (err);
2193*6408Sha137994 	}
2194*6408Sha137994 
2195*6408Sha137994 	/* do the balance */
2196*6408Sha137994 	if (start > end) {
2197*6408Sha137994 		copy_size = ((end + 1) * dringp->dsize);
2198*6408Sha137994 		soff = 0;
2199*6408Sha137994 
2200*6408Sha137994 		/* copy to/from remote from/to local memory */
2201*6408Sha137994 		D1(ldcp->id, "i_ldc_dring_acquire_release: c2 "
2202*6408Sha137994 		    "off=0x%llx sz=0x%llx\n", soff, copy_size);
2203*6408Sha137994 		err = i_ldc_mem_acquire_release((ldc_mem_handle_t)dringp->mhdl,
2204*6408Sha137994 		    direction, soff, copy_size);
2205*6408Sha137994 		if (err) {
2206*6408Sha137994 			DWARN(ldcp->id,
2207*6408Sha137994 			    "i_ldc_dring_acquire_release: copy failed\n");
2208*6408Sha137994 			mutex_exit(&dringp->lock);
2209*6408Sha137994 			return (err);
2210*6408Sha137994 		}
2211*6408Sha137994 	}
2212*6408Sha137994 
2213*6408Sha137994 	mutex_exit(&dringp->lock);
2214*6408Sha137994 
2215*6408Sha137994 	return (0);
2216*6408Sha137994 }
2217*6408Sha137994 
2218*6408Sha137994 /*
2219*6408Sha137994  * Ensure that the contents in the local dring are consistent
2220*6408Sha137994  * with the contents if of remote dring
2221*6408Sha137994  */
2222*6408Sha137994 int
2223*6408Sha137994 ldc_mem_dring_acquire(ldc_dring_handle_t dhandle, uint64_t start, uint64_t end)
2224*6408Sha137994 {
2225*6408Sha137994 	return (i_ldc_dring_acquire_release(dhandle, LDC_COPY_IN, start, end));
2226*6408Sha137994 }
2227*6408Sha137994 
2228*6408Sha137994 /*
2229*6408Sha137994  * Ensure that the contents in the remote dring are consistent
2230*6408Sha137994  * with the contents if of local dring
2231*6408Sha137994  */
2232*6408Sha137994 int
2233*6408Sha137994 ldc_mem_dring_release(ldc_dring_handle_t dhandle, uint64_t start, uint64_t end)
2234*6408Sha137994 {
2235*6408Sha137994 	return (i_ldc_dring_acquire_release(dhandle, LDC_COPY_OUT, start, end));
2236*6408Sha137994 }
2237