16408Sha137994 /*
26408Sha137994 * CDDL HEADER START
36408Sha137994 *
46408Sha137994 * The contents of this file are subject to the terms of the
56408Sha137994 * Common Development and Distribution License (the "License").
66408Sha137994 * You may not use this file except in compliance with the License.
76408Sha137994 *
86408Sha137994 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96408Sha137994 * or http://www.opensolaris.org/os/licensing.
106408Sha137994 * See the License for the specific language governing permissions
116408Sha137994 * and limitations under the License.
126408Sha137994 *
136408Sha137994 * When distributing Covered Code, include this CDDL HEADER in each
146408Sha137994 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156408Sha137994 * If applicable, add the following below this CDDL HEADER, with the
166408Sha137994 * fields enclosed by brackets "[]" replaced with your own identifying
176408Sha137994 * information: Portions Copyright [yyyy] [name of copyright owner]
186408Sha137994 *
196408Sha137994 * CDDL HEADER END
206408Sha137994 */
216408Sha137994
226408Sha137994 /*
23*13098SWentao.Yang@Sun.COM * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
246408Sha137994 */
256408Sha137994
266408Sha137994 /*
276408Sha137994 * sun4v LDC Link Layer Shared Memory Routines
286408Sha137994 */
296408Sha137994 #include <sys/types.h>
306408Sha137994 #include <sys/kmem.h>
316408Sha137994 #include <sys/cmn_err.h>
326408Sha137994 #include <sys/ksynch.h>
336408Sha137994 #include <sys/debug.h>
346408Sha137994 #include <sys/cyclic.h>
356408Sha137994 #include <sys/machsystm.h>
366408Sha137994 #include <sys/vm.h>
376408Sha137994 #include <sys/machcpuvar.h>
386408Sha137994 #include <sys/mmu.h>
396408Sha137994 #include <sys/pte.h>
406408Sha137994 #include <vm/hat.h>
416408Sha137994 #include <vm/as.h>
426408Sha137994 #include <vm/hat_sfmmu.h>
436408Sha137994 #include <sys/vm_machparam.h>
446408Sha137994 #include <vm/seg_kmem.h>
456408Sha137994 #include <vm/seg_kpm.h>
466408Sha137994 #include <sys/hypervisor_api.h>
476408Sha137994 #include <sys/ldc.h>
486408Sha137994 #include <sys/ldc_impl.h>
496408Sha137994
506408Sha137994 /* LDC variables used by shared memory routines */
516408Sha137994 extern ldc_soft_state_t *ldcssp;
526408Sha137994 extern int ldc_max_retries;
536408Sha137994 extern clock_t ldc_delay;
546408Sha137994
556408Sha137994 #ifdef DEBUG
566408Sha137994 extern int ldcdbg;
576408Sha137994 #endif
586408Sha137994
596408Sha137994 /* LDC internal functions used by shared memory routines */
606408Sha137994 extern void i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset);
616408Sha137994 extern int i_ldc_h2v_error(int h_error);
626408Sha137994
636408Sha137994 #ifdef DEBUG
646408Sha137994 extern void ldcdebug(int64_t id, const char *fmt, ...);
656408Sha137994 #endif
666408Sha137994
676408Sha137994 /* Memory synchronization internal functions */
686408Sha137994 static int i_ldc_mem_acquire_release(ldc_mem_handle_t mhandle,
696408Sha137994 uint8_t direction, uint64_t offset, size_t size);
706408Sha137994 static int i_ldc_dring_acquire_release(ldc_dring_handle_t dhandle,
716408Sha137994 uint8_t direction, uint64_t start, uint64_t end);
726845Sha137994 static int i_ldc_mem_map(ldc_mem_handle_t mhandle, ldc_mem_cookie_t *cookie,
736845Sha137994 uint32_t ccount, uint8_t mtype, uint8_t perm, caddr_t *vaddr,
746845Sha137994 caddr_t *raddr);
756845Sha137994 static int i_ldc_mem_bind_handle(ldc_mem_handle_t mhandle, caddr_t vaddr,
766845Sha137994 size_t len, uint8_t mtype, uint8_t perm, ldc_mem_cookie_t *cookie,
776845Sha137994 uint32_t *ccount);
786408Sha137994
796408Sha137994 /*
806408Sha137994 * LDC framework supports mapping remote domain's memory
816408Sha137994 * either directly or via shadow memory pages. Default
826408Sha137994 * support is currently implemented via shadow copy.
836408Sha137994 * Direct map can be enabled by setting 'ldc_shmem_enabled'
846408Sha137994 */
85*13098SWentao.Yang@Sun.COM int ldc_shmem_enabled = 1;
866408Sha137994
876408Sha137994 /*
886845Sha137994 * Use of directly mapped shared memory for LDC descriptor
896845Sha137994 * rings is permitted if this variable is non-zero.
906845Sha137994 */
916845Sha137994 int ldc_dring_shmem_enabled = 1;
926845Sha137994
936845Sha137994 /*
946845Sha137994 * The major and minor versions required to use directly
956845Sha137994 * mapped shared memory for LDC descriptor rings. The
966845Sha137994 * ldc_dring_shmem_hv_force variable, if set to a non-zero
976845Sha137994 * value, overrides the hypervisor API version check.
986845Sha137994 */
996845Sha137994 static int ldc_dring_shmem_hv_major = 1;
1006845Sha137994 static int ldc_dring_shmem_hv_minor = 1;
1016845Sha137994 static int ldc_dring_shmem_hv_force = 0;
1026845Sha137994
1036845Sha137994 /*
1046845Sha137994 * The results of the hypervisor service group API check.
1056845Sha137994 * A non-zero value indicates the HV includes support for
1066845Sha137994 * descriptor ring shared memory.
1076845Sha137994 */
1086845Sha137994 static int ldc_dring_shmem_hv_ok = 0;
1096845Sha137994
1106845Sha137994 /*
1116408Sha137994 * Pages exported for remote access over each channel is
1126408Sha137994 * maintained in a table registered with the Hypervisor.
1136408Sha137994 * The default number of entries in the table is set to
1146408Sha137994 * 'ldc_mtbl_entries'.
1156408Sha137994 */
1166408Sha137994 uint64_t ldc_maptable_entries = LDC_MTBL_ENTRIES;
1176408Sha137994
1186408Sha137994 #define IDX2COOKIE(idx, pg_szc, pg_shift) \
1196408Sha137994 (((pg_szc) << LDC_COOKIE_PGSZC_SHIFT) | ((idx) << (pg_shift)))
1206408Sha137994
1216408Sha137994 /*
122*13098SWentao.Yang@Sun.COM * Pages imported over each channel are maintained in a global (per-guest)
123*13098SWentao.Yang@Sun.COM * mapin table. Starting with HV LDC API version 1.2, HV supports APIs to
124*13098SWentao.Yang@Sun.COM * obtain information about the total size of the memory that can be direct
125*13098SWentao.Yang@Sun.COM * mapped through this mapin table. The minimum size of the mapin area that we
126*13098SWentao.Yang@Sun.COM * expect is defined below.
127*13098SWentao.Yang@Sun.COM */
128*13098SWentao.Yang@Sun.COM #define GIGABYTE ((uint64_t)(1 << 30))
129*13098SWentao.Yang@Sun.COM uint64_t ldc_mapin_size_min = GIGABYTE;
130*13098SWentao.Yang@Sun.COM
131*13098SWentao.Yang@Sun.COM /* HV LDC API version that supports mapin size info */
132*13098SWentao.Yang@Sun.COM #define LDC_MAPIN_VER_MAJOR 1
133*13098SWentao.Yang@Sun.COM #define LDC_MAPIN_VER_MINOR 2
134*13098SWentao.Yang@Sun.COM
135*13098SWentao.Yang@Sun.COM /*
1366845Sha137994 * Sets ldc_dring_shmem_hv_ok to a non-zero value if the HV LDC
1376845Sha137994 * API version supports directly mapped shared memory or if it has
1386845Sha137994 * been explicitly enabled via ldc_dring_shmem_hv_force.
1396845Sha137994 */
1406845Sha137994 void
i_ldc_mem_set_hsvc_vers(uint64_t major,uint64_t minor)1416845Sha137994 i_ldc_mem_set_hsvc_vers(uint64_t major, uint64_t minor)
1426845Sha137994 {
1436845Sha137994 if ((major == ldc_dring_shmem_hv_major &&
1446845Sha137994 minor >= ldc_dring_shmem_hv_minor) ||
1456845Sha137994 (major > ldc_dring_shmem_hv_major) ||
1466845Sha137994 (ldc_dring_shmem_hv_force != 0)) {
1476845Sha137994 ldc_dring_shmem_hv_ok = 1;
1486845Sha137994 }
1496845Sha137994 }
1506845Sha137994
1516845Sha137994 /*
152*13098SWentao.Yang@Sun.COM * initialize mapin table.
153*13098SWentao.Yang@Sun.COM */
154*13098SWentao.Yang@Sun.COM void
i_ldc_init_mapin(ldc_soft_state_t * ldcssp,uint64_t major,uint64_t minor)155*13098SWentao.Yang@Sun.COM i_ldc_init_mapin(ldc_soft_state_t *ldcssp, uint64_t major, uint64_t minor)
156*13098SWentao.Yang@Sun.COM {
157*13098SWentao.Yang@Sun.COM int rv;
158*13098SWentao.Yang@Sun.COM uint64_t sz;
159*13098SWentao.Yang@Sun.COM uint64_t table_type = LDC_MAPIN_TYPE_REGULAR;
160*13098SWentao.Yang@Sun.COM
161*13098SWentao.Yang@Sun.COM /* set mapin size to default. */
162*13098SWentao.Yang@Sun.COM ldcssp->mapin_size = LDC_DIRECT_MAP_SIZE_DEFAULT;
163*13098SWentao.Yang@Sun.COM
164*13098SWentao.Yang@Sun.COM /* Check if the HV supports mapin size API. */
165*13098SWentao.Yang@Sun.COM if ((major == LDC_MAPIN_VER_MAJOR &&
166*13098SWentao.Yang@Sun.COM minor < LDC_MAPIN_VER_MINOR) ||
167*13098SWentao.Yang@Sun.COM (major < LDC_MAPIN_VER_MAJOR)) {
168*13098SWentao.Yang@Sun.COM /* Older version of HV. */
169*13098SWentao.Yang@Sun.COM return;
170*13098SWentao.Yang@Sun.COM }
171*13098SWentao.Yang@Sun.COM
172*13098SWentao.Yang@Sun.COM /* Get info about the mapin size supported by HV */
173*13098SWentao.Yang@Sun.COM rv = hv_ldc_mapin_size_max(table_type, &sz);
174*13098SWentao.Yang@Sun.COM if (rv != 0) {
175*13098SWentao.Yang@Sun.COM cmn_err(CE_NOTE, "Failed to get mapin information\n");
176*13098SWentao.Yang@Sun.COM return;
177*13098SWentao.Yang@Sun.COM }
178*13098SWentao.Yang@Sun.COM
179*13098SWentao.Yang@Sun.COM /* Save the table size */
180*13098SWentao.Yang@Sun.COM ldcssp->mapin_size = sz;
181*13098SWentao.Yang@Sun.COM
182*13098SWentao.Yang@Sun.COM D1(DBG_ALL_LDCS, "%s: mapin_size read from HV is (0x%llx)\n",
183*13098SWentao.Yang@Sun.COM __func__, sz);
184*13098SWentao.Yang@Sun.COM }
185*13098SWentao.Yang@Sun.COM
186*13098SWentao.Yang@Sun.COM /*
1876408Sha137994 * Allocate a memory handle for the channel and link it into the list
1886408Sha137994 * Also choose which memory table to use if this is the first handle
1896408Sha137994 * being assigned to this channel
1906408Sha137994 */
1916408Sha137994 int
ldc_mem_alloc_handle(ldc_handle_t handle,ldc_mem_handle_t * mhandle)1926408Sha137994 ldc_mem_alloc_handle(ldc_handle_t handle, ldc_mem_handle_t *mhandle)
1936408Sha137994 {
1946408Sha137994 ldc_chan_t *ldcp;
1956408Sha137994 ldc_mhdl_t *mhdl;
1966408Sha137994
1976408Sha137994 if (handle == NULL) {
1986408Sha137994 DWARN(DBG_ALL_LDCS,
1996408Sha137994 "ldc_mem_alloc_handle: invalid channel handle\n");
2006408Sha137994 return (EINVAL);
2016408Sha137994 }
2026408Sha137994 ldcp = (ldc_chan_t *)handle;
2036408Sha137994
2046408Sha137994 mutex_enter(&ldcp->lock);
2056408Sha137994
2066408Sha137994 /* check to see if channel is initalized */
2076408Sha137994 if ((ldcp->tstate & ~TS_IN_RESET) < TS_INIT) {
2086408Sha137994 DWARN(ldcp->id,
2096408Sha137994 "ldc_mem_alloc_handle: (0x%llx) channel not initialized\n",
2106408Sha137994 ldcp->id);
2116408Sha137994 mutex_exit(&ldcp->lock);
2126408Sha137994 return (EINVAL);
2136408Sha137994 }
2146408Sha137994
2156408Sha137994 /* allocate handle for channel */
2166408Sha137994 mhdl = kmem_cache_alloc(ldcssp->memhdl_cache, KM_SLEEP);
2176408Sha137994
2186408Sha137994 /* initialize the lock */
2196408Sha137994 mutex_init(&mhdl->lock, NULL, MUTEX_DRIVER, NULL);
2206408Sha137994
2216408Sha137994 mhdl->myshadow = B_FALSE;
2226408Sha137994 mhdl->memseg = NULL;
2236408Sha137994 mhdl->ldcp = ldcp;
2246408Sha137994 mhdl->status = LDC_UNBOUND;
2256408Sha137994
2266408Sha137994 /* insert memory handle (@ head) into list */
2276408Sha137994 if (ldcp->mhdl_list == NULL) {
2286408Sha137994 ldcp->mhdl_list = mhdl;
2296408Sha137994 mhdl->next = NULL;
2306408Sha137994 } else {
2316408Sha137994 /* insert @ head */
2326408Sha137994 mhdl->next = ldcp->mhdl_list;
2336408Sha137994 ldcp->mhdl_list = mhdl;
2346408Sha137994 }
2356408Sha137994
2366408Sha137994 /* return the handle */
2376408Sha137994 *mhandle = (ldc_mem_handle_t)mhdl;
2386408Sha137994
2396408Sha137994 mutex_exit(&ldcp->lock);
2406408Sha137994
2416408Sha137994 D1(ldcp->id, "ldc_mem_alloc_handle: (0x%llx) allocated handle 0x%llx\n",
2426408Sha137994 ldcp->id, mhdl);
2436408Sha137994
2446408Sha137994 return (0);
2456408Sha137994 }
2466408Sha137994
2476408Sha137994 /*
2486408Sha137994 * Free memory handle for the channel and unlink it from the list
2496408Sha137994 */
2506408Sha137994 int
ldc_mem_free_handle(ldc_mem_handle_t mhandle)2516408Sha137994 ldc_mem_free_handle(ldc_mem_handle_t mhandle)
2526408Sha137994 {
2536408Sha137994 ldc_mhdl_t *mhdl, *phdl;
2546408Sha137994 ldc_chan_t *ldcp;
2556408Sha137994
2566408Sha137994 if (mhandle == NULL) {
2576408Sha137994 DWARN(DBG_ALL_LDCS,
2586408Sha137994 "ldc_mem_free_handle: invalid memory handle\n");
2596408Sha137994 return (EINVAL);
2606408Sha137994 }
2616408Sha137994 mhdl = (ldc_mhdl_t *)mhandle;
2626408Sha137994
2636408Sha137994 mutex_enter(&mhdl->lock);
2646408Sha137994
2656408Sha137994 ldcp = mhdl->ldcp;
2666408Sha137994
2676408Sha137994 if (mhdl->status == LDC_BOUND || mhdl->status == LDC_MAPPED) {
2686408Sha137994 DWARN(ldcp->id,
2696408Sha137994 "ldc_mem_free_handle: cannot free, 0x%llx hdl bound\n",
2706408Sha137994 mhdl);
2716408Sha137994 mutex_exit(&mhdl->lock);
2726408Sha137994 return (EINVAL);
2736408Sha137994 }
2746408Sha137994 mutex_exit(&mhdl->lock);
2756408Sha137994
2766408Sha137994 mutex_enter(&ldcp->mlist_lock);
2776408Sha137994
2786408Sha137994 phdl = ldcp->mhdl_list;
2796408Sha137994
2806408Sha137994 /* first handle */
2816408Sha137994 if (phdl == mhdl) {
2826408Sha137994 ldcp->mhdl_list = mhdl->next;
2836408Sha137994 mutex_destroy(&mhdl->lock);
2846408Sha137994 kmem_cache_free(ldcssp->memhdl_cache, mhdl);
2856408Sha137994
2866408Sha137994 D1(ldcp->id,
2876408Sha137994 "ldc_mem_free_handle: (0x%llx) freed handle 0x%llx\n",
2886408Sha137994 ldcp->id, mhdl);
2896408Sha137994 } else {
2906408Sha137994 /* walk the list - unlink and free */
2916408Sha137994 while (phdl != NULL) {
2926408Sha137994 if (phdl->next == mhdl) {
2936408Sha137994 phdl->next = mhdl->next;
2946408Sha137994 mutex_destroy(&mhdl->lock);
2956408Sha137994 kmem_cache_free(ldcssp->memhdl_cache, mhdl);
2966408Sha137994 D1(ldcp->id,
2976408Sha137994 "ldc_mem_free_handle: (0x%llx) freed "
2986408Sha137994 "handle 0x%llx\n", ldcp->id, mhdl);
2996408Sha137994 break;
3006408Sha137994 }
3016408Sha137994 phdl = phdl->next;
3026408Sha137994 }
3036408Sha137994 }
3046408Sha137994
3056408Sha137994 if (phdl == NULL) {
3066408Sha137994 DWARN(ldcp->id,
3076408Sha137994 "ldc_mem_free_handle: invalid handle 0x%llx\n", mhdl);
3086408Sha137994 mutex_exit(&ldcp->mlist_lock);
3096408Sha137994 return (EINVAL);
3106408Sha137994 }
3116408Sha137994
3126408Sha137994 mutex_exit(&ldcp->mlist_lock);
3136408Sha137994
3146408Sha137994 return (0);
3156408Sha137994 }
3166408Sha137994
3176408Sha137994 /*
3186408Sha137994 * Bind a memory handle to a virtual address.
3196408Sha137994 * The virtual address is converted to the corresponding real addresses.
3206408Sha137994 * Returns pointer to the first ldc_mem_cookie and the total number
3216408Sha137994 * of cookies for this virtual address. Other cookies can be obtained
3226408Sha137994 * using the ldc_mem_nextcookie() call. If the pages are stored in
3236408Sha137994 * consecutive locations in the table, a single cookie corresponding to
3246408Sha137994 * the first location is returned. The cookie size spans all the entries.
3256408Sha137994 *
3266408Sha137994 * If the VA corresponds to a page that is already being exported, reuse
3276408Sha137994 * the page and do not export it again. Bump the page's use count.
3286408Sha137994 */
3296408Sha137994 int
ldc_mem_bind_handle(ldc_mem_handle_t mhandle,caddr_t vaddr,size_t len,uint8_t mtype,uint8_t perm,ldc_mem_cookie_t * cookie,uint32_t * ccount)3306408Sha137994 ldc_mem_bind_handle(ldc_mem_handle_t mhandle, caddr_t vaddr, size_t len,
3316408Sha137994 uint8_t mtype, uint8_t perm, ldc_mem_cookie_t *cookie, uint32_t *ccount)
3326408Sha137994 {
3336845Sha137994 /*
3346845Sha137994 * Check if direct shared memory map is enabled, if not change
3356845Sha137994 * the mapping type to SHADOW_MAP.
3366845Sha137994 */
3376845Sha137994 if (ldc_shmem_enabled == 0)
3386845Sha137994 mtype = LDC_SHADOW_MAP;
3396845Sha137994
3406845Sha137994 return (i_ldc_mem_bind_handle(mhandle, vaddr, len, mtype, perm,
3416845Sha137994 cookie, ccount));
3426845Sha137994 }
3436845Sha137994
3446845Sha137994 static int
i_ldc_mem_bind_handle(ldc_mem_handle_t mhandle,caddr_t vaddr,size_t len,uint8_t mtype,uint8_t perm,ldc_mem_cookie_t * cookie,uint32_t * ccount)3456845Sha137994 i_ldc_mem_bind_handle(ldc_mem_handle_t mhandle, caddr_t vaddr, size_t len,
3466845Sha137994 uint8_t mtype, uint8_t perm, ldc_mem_cookie_t *cookie, uint32_t *ccount)
3476845Sha137994 {
3486408Sha137994 ldc_mhdl_t *mhdl;
3496408Sha137994 ldc_chan_t *ldcp;
3506408Sha137994 ldc_mtbl_t *mtbl;
3516408Sha137994 ldc_memseg_t *memseg;
3526408Sha137994 ldc_mte_t tmp_mte;
3536408Sha137994 uint64_t index, prev_index = 0;
3546408Sha137994 int64_t cookie_idx;
3556408Sha137994 uintptr_t raddr, ra_aligned;
3566408Sha137994 uint64_t psize, poffset, v_offset;
3576408Sha137994 uint64_t pg_shift, pg_size, pg_size_code, pg_mask;
3586408Sha137994 pgcnt_t npages;
3596408Sha137994 caddr_t v_align, addr;
3606408Sha137994 int i, rv;
3616408Sha137994
3626408Sha137994 if (mhandle == NULL) {
3636408Sha137994 DWARN(DBG_ALL_LDCS,
3646408Sha137994 "ldc_mem_bind_handle: invalid memory handle\n");
3656408Sha137994 return (EINVAL);
3666408Sha137994 }
3676408Sha137994 mhdl = (ldc_mhdl_t *)mhandle;
3686408Sha137994 ldcp = mhdl->ldcp;
3696408Sha137994
3706408Sha137994 /* clear count */
3716408Sha137994 *ccount = 0;
3726408Sha137994
3736408Sha137994 mutex_enter(&mhdl->lock);
3746408Sha137994
3756408Sha137994 if (mhdl->status == LDC_BOUND || mhdl->memseg != NULL) {
3766408Sha137994 DWARN(ldcp->id,
3776408Sha137994 "ldc_mem_bind_handle: (0x%x) handle already bound\n",
3786408Sha137994 mhandle);
3796408Sha137994 mutex_exit(&mhdl->lock);
3806408Sha137994 return (EINVAL);
3816408Sha137994 }
3826408Sha137994
3836408Sha137994 /* Force address and size to be 8-byte aligned */
3846408Sha137994 if ((((uintptr_t)vaddr | len) & 0x7) != 0) {
3856408Sha137994 DWARN(ldcp->id,
3866408Sha137994 "ldc_mem_bind_handle: addr/size is not 8-byte aligned\n");
3876408Sha137994 mutex_exit(&mhdl->lock);
3886408Sha137994 return (EINVAL);
3896408Sha137994 }
3906408Sha137994
3916845Sha137994 mutex_enter(&ldcp->lock);
3926845Sha137994
3936408Sha137994 /*
3946408Sha137994 * If this channel is binding a memory handle for the
3956408Sha137994 * first time allocate it a memory map table and initialize it
3966408Sha137994 */
3976408Sha137994 if ((mtbl = ldcp->mtbl) == NULL) {
3986408Sha137994
3996408Sha137994 /* Allocate and initialize the map table structure */
4006408Sha137994 mtbl = kmem_zalloc(sizeof (ldc_mtbl_t), KM_SLEEP);
4016408Sha137994 mtbl->num_entries = mtbl->num_avail = ldc_maptable_entries;
4026408Sha137994 mtbl->size = ldc_maptable_entries * sizeof (ldc_mte_slot_t);
4036408Sha137994 mtbl->next_entry = NULL;
4046408Sha137994 mtbl->contigmem = B_TRUE;
4056408Sha137994
4066408Sha137994 /* Allocate the table itself */
4076408Sha137994 mtbl->table = (ldc_mte_slot_t *)
4086408Sha137994 contig_mem_alloc_align(mtbl->size, MMU_PAGESIZE);
4096408Sha137994 if (mtbl->table == NULL) {
4106408Sha137994
4116408Sha137994 /* allocate a page of memory using kmem_alloc */
4126408Sha137994 mtbl->table = kmem_alloc(MMU_PAGESIZE, KM_SLEEP);
4136408Sha137994 mtbl->size = MMU_PAGESIZE;
4146408Sha137994 mtbl->contigmem = B_FALSE;
4156408Sha137994 mtbl->num_entries = mtbl->num_avail =
4166408Sha137994 mtbl->size / sizeof (ldc_mte_slot_t);
4176408Sha137994 DWARN(ldcp->id,
4186408Sha137994 "ldc_mem_bind_handle: (0x%llx) reduced tbl size "
4196408Sha137994 "to %lx entries\n", ldcp->id, mtbl->num_entries);
4206408Sha137994 }
4216408Sha137994
4226408Sha137994 /* zero out the memory */
4236408Sha137994 bzero(mtbl->table, mtbl->size);
4246408Sha137994
4256408Sha137994 /* initialize the lock */
4266408Sha137994 mutex_init(&mtbl->lock, NULL, MUTEX_DRIVER, NULL);
4276408Sha137994
4286408Sha137994 /* register table for this channel */
4296408Sha137994 rv = hv_ldc_set_map_table(ldcp->id,
4306408Sha137994 va_to_pa(mtbl->table), mtbl->num_entries);
4316408Sha137994 if (rv != 0) {
4326845Sha137994 DWARN(DBG_ALL_LDCS,
4336408Sha137994 "ldc_mem_bind_handle: (0x%lx) err %d mapping tbl",
4346408Sha137994 ldcp->id, rv);
4356408Sha137994 if (mtbl->contigmem)
4366408Sha137994 contig_mem_free(mtbl->table, mtbl->size);
4376408Sha137994 else
4386408Sha137994 kmem_free(mtbl->table, mtbl->size);
4396408Sha137994 mutex_destroy(&mtbl->lock);
4406408Sha137994 kmem_free(mtbl, sizeof (ldc_mtbl_t));
4416408Sha137994 mutex_exit(&ldcp->lock);
4426408Sha137994 mutex_exit(&mhdl->lock);
4436408Sha137994 return (EIO);
4446408Sha137994 }
4456408Sha137994
4466408Sha137994 ldcp->mtbl = mtbl;
4476408Sha137994
4486408Sha137994 D1(ldcp->id,
4496408Sha137994 "ldc_mem_bind_handle: (0x%llx) alloc'd map table 0x%llx\n",
4506408Sha137994 ldcp->id, ldcp->mtbl->table);
4516408Sha137994 }
4526408Sha137994
4536845Sha137994 mutex_exit(&ldcp->lock);
4546845Sha137994
4556408Sha137994 /* FUTURE: get the page size, pgsz code, and shift */
4566408Sha137994 pg_size = MMU_PAGESIZE;
4576408Sha137994 pg_size_code = page_szc(pg_size);
4586408Sha137994 pg_shift = page_get_shift(pg_size_code);
4596408Sha137994 pg_mask = ~(pg_size - 1);
4606408Sha137994
4616408Sha137994 D1(ldcp->id, "ldc_mem_bind_handle: (0x%llx) binding "
4626408Sha137994 "va 0x%llx pgsz=0x%llx, pgszc=0x%llx, pg_shift=0x%llx\n",
4636408Sha137994 ldcp->id, vaddr, pg_size, pg_size_code, pg_shift);
4646408Sha137994
4656408Sha137994 /* aligned VA and its offset */
4666408Sha137994 v_align = (caddr_t)(((uintptr_t)vaddr) & ~(pg_size - 1));
4676408Sha137994 v_offset = ((uintptr_t)vaddr) & (pg_size - 1);
4686408Sha137994
4696408Sha137994 npages = (len+v_offset)/pg_size;
4706408Sha137994 npages = ((len+v_offset)%pg_size == 0) ? npages : npages+1;
4716408Sha137994
4726408Sha137994 D1(ldcp->id, "ldc_mem_bind_handle: binding "
4736408Sha137994 "(0x%llx) v=0x%llx,val=0x%llx,off=0x%x,pgs=0x%x\n",
4746408Sha137994 ldcp->id, vaddr, v_align, v_offset, npages);
4756408Sha137994
4766408Sha137994 /* lock the memory table - exclusive access to channel */
4776408Sha137994 mutex_enter(&mtbl->lock);
4786408Sha137994
4796408Sha137994 if (npages > mtbl->num_avail) {
4806408Sha137994 D1(ldcp->id, "ldc_mem_bind_handle: (0x%llx) no table entries\n",
4816408Sha137994 ldcp->id);
4826408Sha137994 mutex_exit(&mtbl->lock);
4836408Sha137994 mutex_exit(&mhdl->lock);
4846408Sha137994 return (ENOMEM);
4856408Sha137994 }
4866408Sha137994
4876408Sha137994 /* Allocate a memseg structure */
4886408Sha137994 memseg = mhdl->memseg =
4896408Sha137994 kmem_cache_alloc(ldcssp->memseg_cache, KM_SLEEP);
4906408Sha137994
4916408Sha137994 /* Allocate memory to store all pages and cookies */
4926408Sha137994 memseg->pages = kmem_zalloc((sizeof (ldc_page_t) * npages), KM_SLEEP);
4936408Sha137994 memseg->cookies =
4946408Sha137994 kmem_zalloc((sizeof (ldc_mem_cookie_t) * npages), KM_SLEEP);
4956408Sha137994
4966408Sha137994 D2(ldcp->id, "ldc_mem_bind_handle: (0x%llx) processing 0x%llx pages\n",
4976408Sha137994 ldcp->id, npages);
4986408Sha137994
4996408Sha137994 addr = v_align;
5006408Sha137994
5016408Sha137994 /*
5026408Sha137994 * Table slots are used in a round-robin manner. The algorithm permits
5036408Sha137994 * inserting duplicate entries. Slots allocated earlier will typically
5046408Sha137994 * get freed before we get back to reusing the slot.Inserting duplicate
5056408Sha137994 * entries should be OK as we only lookup entries using the cookie addr
5066408Sha137994 * i.e. tbl index, during export, unexport and copy operation.
5076408Sha137994 *
5086408Sha137994 * One implementation what was tried was to search for a duplicate
5096408Sha137994 * page entry first and reuse it. The search overhead is very high and
5106408Sha137994 * in the vnet case dropped the perf by almost half, 50 to 24 mbps.
5116408Sha137994 * So it does make sense to avoid searching for duplicates.
5126408Sha137994 *
5136408Sha137994 * But during the process of searching for a free slot, if we find a
5146408Sha137994 * duplicate entry we will go ahead and use it, and bump its use count.
5156408Sha137994 */
5166408Sha137994
5176408Sha137994 /* index to start searching from */
5186408Sha137994 index = mtbl->next_entry;
5196408Sha137994 cookie_idx = -1;
5206408Sha137994
5216408Sha137994 tmp_mte.ll = 0; /* initialise fields to 0 */
5226408Sha137994
5236408Sha137994 if (mtype & LDC_DIRECT_MAP) {
5246408Sha137994 tmp_mte.mte_r = (perm & LDC_MEM_R) ? 1 : 0;
5256408Sha137994 tmp_mte.mte_w = (perm & LDC_MEM_W) ? 1 : 0;
5266408Sha137994 tmp_mte.mte_x = (perm & LDC_MEM_X) ? 1 : 0;
5276408Sha137994 }
5286408Sha137994
5296408Sha137994 if (mtype & LDC_SHADOW_MAP) {
5306408Sha137994 tmp_mte.mte_cr = (perm & LDC_MEM_R) ? 1 : 0;
5316408Sha137994 tmp_mte.mte_cw = (perm & LDC_MEM_W) ? 1 : 0;
5326408Sha137994 }
5336408Sha137994
5346408Sha137994 if (mtype & LDC_IO_MAP) {
5356408Sha137994 tmp_mte.mte_ir = (perm & LDC_MEM_R) ? 1 : 0;
5366408Sha137994 tmp_mte.mte_iw = (perm & LDC_MEM_W) ? 1 : 0;
5376408Sha137994 }
5386408Sha137994
5396408Sha137994 D1(ldcp->id, "ldc_mem_bind_handle mte=0x%llx\n", tmp_mte.ll);
5406408Sha137994
5416408Sha137994 tmp_mte.mte_pgszc = pg_size_code;
5426408Sha137994
5436408Sha137994 /* initialize each mem table entry */
5446408Sha137994 for (i = 0; i < npages; i++) {
5456408Sha137994
5466408Sha137994 /* check if slot is available in the table */
5476408Sha137994 while (mtbl->table[index].entry.ll != 0) {
5486408Sha137994
5496408Sha137994 index = (index + 1) % mtbl->num_entries;
5506408Sha137994
5516408Sha137994 if (index == mtbl->next_entry) {
5526408Sha137994 /* we have looped around */
5536408Sha137994 DWARN(DBG_ALL_LDCS,
5546408Sha137994 "ldc_mem_bind_handle: (0x%llx) cannot find "
5556408Sha137994 "entry\n", ldcp->id);
5566408Sha137994 *ccount = 0;
5576408Sha137994
5586408Sha137994 /* NOTE: free memory, remove previous entries */
5596408Sha137994 /* this shouldnt happen as num_avail was ok */
5606408Sha137994
5616408Sha137994 mutex_exit(&mtbl->lock);
5626408Sha137994 mutex_exit(&mhdl->lock);
5636408Sha137994 return (ENOMEM);
5646408Sha137994 }
5656408Sha137994 }
5666408Sha137994
5676408Sha137994 /* get the real address */
5686408Sha137994 raddr = va_to_pa((void *)addr);
5696408Sha137994 ra_aligned = ((uintptr_t)raddr & pg_mask);
5706408Sha137994
5716408Sha137994 /* build the mte */
5726408Sha137994 tmp_mte.mte_rpfn = ra_aligned >> pg_shift;
5736408Sha137994
5746408Sha137994 D1(ldcp->id, "ldc_mem_bind_handle mte=0x%llx\n", tmp_mte.ll);
5756408Sha137994
5766408Sha137994 /* update entry in table */
5776408Sha137994 mtbl->table[index].entry = tmp_mte;
5786408Sha137994
5796408Sha137994 D2(ldcp->id, "ldc_mem_bind_handle: (0x%llx) stored MTE 0x%llx"
5806408Sha137994 " into loc 0x%llx\n", ldcp->id, tmp_mte.ll, index);
5816408Sha137994
5826408Sha137994 /* calculate the size and offset for this export range */
5836408Sha137994 if (i == 0) {
5846408Sha137994 /* first page */
5856408Sha137994 psize = min((pg_size - v_offset), len);
5866408Sha137994 poffset = v_offset;
5876408Sha137994
5886408Sha137994 } else if (i == (npages - 1)) {
5896408Sha137994 /* last page */
5906408Sha137994 psize = (((uintptr_t)(vaddr + len)) &
5916408Sha137994 ((uint64_t)(pg_size-1)));
5926408Sha137994 if (psize == 0)
5936408Sha137994 psize = pg_size;
5946408Sha137994 poffset = 0;
5956408Sha137994
5966408Sha137994 } else {
5976408Sha137994 /* middle pages */
5986408Sha137994 psize = pg_size;
5996408Sha137994 poffset = 0;
6006408Sha137994 }
6016408Sha137994
6026408Sha137994 /* store entry for this page */
6036408Sha137994 memseg->pages[i].index = index;
6046408Sha137994 memseg->pages[i].raddr = raddr;
6056408Sha137994 memseg->pages[i].mte = &(mtbl->table[index]);
6066408Sha137994
6076408Sha137994 /* create the cookie */
6086408Sha137994 if (i == 0 || (index != prev_index + 1)) {
6096408Sha137994 cookie_idx++;
6106408Sha137994 memseg->cookies[cookie_idx].addr =
6116408Sha137994 IDX2COOKIE(index, pg_size_code, pg_shift);
6126408Sha137994 memseg->cookies[cookie_idx].addr |= poffset;
6136408Sha137994 memseg->cookies[cookie_idx].size = psize;
6146408Sha137994
6156408Sha137994 } else {
6166408Sha137994 memseg->cookies[cookie_idx].size += psize;
6176408Sha137994 }
6186408Sha137994
6196408Sha137994 D1(ldcp->id, "ldc_mem_bind_handle: bound "
6206408Sha137994 "(0x%llx) va=0x%llx, idx=0x%llx, "
6216408Sha137994 "ra=0x%llx(sz=0x%x,off=0x%x)\n",
6226408Sha137994 ldcp->id, addr, index, raddr, psize, poffset);
6236408Sha137994
6246408Sha137994 /* decrement number of available entries */
6256408Sha137994 mtbl->num_avail--;
6266408Sha137994
6276408Sha137994 /* increment va by page size */
6286408Sha137994 addr += pg_size;
6296408Sha137994
6306408Sha137994 /* increment index */
6316408Sha137994 prev_index = index;
6326408Sha137994 index = (index + 1) % mtbl->num_entries;
6336408Sha137994
6346408Sha137994 /* save the next slot */
6356408Sha137994 mtbl->next_entry = index;
6366408Sha137994 }
6376408Sha137994
6386408Sha137994 mutex_exit(&mtbl->lock);
6396408Sha137994
6406408Sha137994 /* memory handle = bound */
6416408Sha137994 mhdl->mtype = mtype;
6426408Sha137994 mhdl->perm = perm;
6436408Sha137994 mhdl->status = LDC_BOUND;
6446408Sha137994
6456408Sha137994 /* update memseg_t */
6466408Sha137994 memseg->vaddr = vaddr;
6476408Sha137994 memseg->raddr = memseg->pages[0].raddr;
6486408Sha137994 memseg->size = len;
6496408Sha137994 memseg->npages = npages;
6506408Sha137994 memseg->ncookies = cookie_idx + 1;
6516408Sha137994 memseg->next_cookie = (memseg->ncookies > 1) ? 1 : 0;
6526408Sha137994
6536408Sha137994 /* return count and first cookie */
6546408Sha137994 *ccount = memseg->ncookies;
6556408Sha137994 cookie->addr = memseg->cookies[0].addr;
6566408Sha137994 cookie->size = memseg->cookies[0].size;
6576408Sha137994
6586408Sha137994 D1(ldcp->id,
6596408Sha137994 "ldc_mem_bind_handle: (0x%llx) bound 0x%llx, va=0x%llx, "
6606408Sha137994 "pgs=0x%llx cookies=0x%llx\n",
6616408Sha137994 ldcp->id, mhdl, vaddr, npages, memseg->ncookies);
6626408Sha137994
6636408Sha137994 mutex_exit(&mhdl->lock);
6646408Sha137994 return (0);
6656408Sha137994 }
6666408Sha137994
6676408Sha137994 /*
6686408Sha137994 * Return the next cookie associated with the specified memory handle
6696408Sha137994 */
6706408Sha137994 int
ldc_mem_nextcookie(ldc_mem_handle_t mhandle,ldc_mem_cookie_t * cookie)6716408Sha137994 ldc_mem_nextcookie(ldc_mem_handle_t mhandle, ldc_mem_cookie_t *cookie)
6726408Sha137994 {
6736408Sha137994 ldc_mhdl_t *mhdl;
6746408Sha137994 ldc_chan_t *ldcp;
6756408Sha137994 ldc_memseg_t *memseg;
6766408Sha137994
6776408Sha137994 if (mhandle == NULL) {
6786408Sha137994 DWARN(DBG_ALL_LDCS,
6796408Sha137994 "ldc_mem_nextcookie: invalid memory handle\n");
6806408Sha137994 return (EINVAL);
6816408Sha137994 }
6826408Sha137994 mhdl = (ldc_mhdl_t *)mhandle;
6836408Sha137994
6846408Sha137994 mutex_enter(&mhdl->lock);
6856408Sha137994
6866408Sha137994 ldcp = mhdl->ldcp;
6876408Sha137994 memseg = mhdl->memseg;
6886408Sha137994
6896408Sha137994 if (cookie == 0) {
6906408Sha137994 DWARN(ldcp->id,
6916408Sha137994 "ldc_mem_nextcookie:(0x%llx) invalid cookie arg\n",
6926408Sha137994 ldcp->id);
6936408Sha137994 mutex_exit(&mhdl->lock);
6946408Sha137994 return (EINVAL);
6956408Sha137994 }
6966408Sha137994
6976408Sha137994 if (memseg->next_cookie != 0) {
6986408Sha137994 cookie->addr = memseg->cookies[memseg->next_cookie].addr;
6996408Sha137994 cookie->size = memseg->cookies[memseg->next_cookie].size;
7006408Sha137994 memseg->next_cookie++;
7016408Sha137994 if (memseg->next_cookie == memseg->ncookies)
7026408Sha137994 memseg->next_cookie = 0;
7036408Sha137994
7046408Sha137994 } else {
7056408Sha137994 DWARN(ldcp->id,
7066408Sha137994 "ldc_mem_nextcookie:(0x%llx) no more cookies\n", ldcp->id);
7076408Sha137994 cookie->addr = 0;
7086408Sha137994 cookie->size = 0;
7096408Sha137994 mutex_exit(&mhdl->lock);
7106408Sha137994 return (EINVAL);
7116408Sha137994 }
7126408Sha137994
7136408Sha137994 D1(ldcp->id,
7146408Sha137994 "ldc_mem_nextcookie: (0x%llx) cookie addr=0x%llx,sz=0x%llx\n",
7156408Sha137994 ldcp->id, cookie->addr, cookie->size);
7166408Sha137994
7176408Sha137994 mutex_exit(&mhdl->lock);
7186408Sha137994 return (0);
7196408Sha137994 }
7206408Sha137994
7216408Sha137994 /*
7226408Sha137994 * Unbind the virtual memory region associated with the specified
7236408Sha137994 * memory handle. Allassociated cookies are freed and the corresponding
7246408Sha137994 * RA space is no longer exported.
7256408Sha137994 */
7266408Sha137994 int
ldc_mem_unbind_handle(ldc_mem_handle_t mhandle)7276408Sha137994 ldc_mem_unbind_handle(ldc_mem_handle_t mhandle)
7286408Sha137994 {
7296408Sha137994 ldc_mhdl_t *mhdl;
7306408Sha137994 ldc_chan_t *ldcp;
7316408Sha137994 ldc_mtbl_t *mtbl;
7326408Sha137994 ldc_memseg_t *memseg;
7336408Sha137994 uint64_t cookie_addr;
7346408Sha137994 uint64_t pg_shift, pg_size_code;
7356845Sha137994 int i, rv, retries;
7366408Sha137994
7376408Sha137994 if (mhandle == NULL) {
7386408Sha137994 DWARN(DBG_ALL_LDCS,
7396408Sha137994 "ldc_mem_unbind_handle: invalid memory handle\n");
7406408Sha137994 return (EINVAL);
7416408Sha137994 }
7426408Sha137994 mhdl = (ldc_mhdl_t *)mhandle;
7436408Sha137994
7446408Sha137994 mutex_enter(&mhdl->lock);
7456408Sha137994
7466408Sha137994 if (mhdl->status == LDC_UNBOUND) {
7476408Sha137994 DWARN(DBG_ALL_LDCS,
7486408Sha137994 "ldc_mem_unbind_handle: (0x%x) handle is not bound\n",
7496408Sha137994 mhandle);
7506408Sha137994 mutex_exit(&mhdl->lock);
7516408Sha137994 return (EINVAL);
7526408Sha137994 }
7536408Sha137994
7546408Sha137994 ldcp = mhdl->ldcp;
7556408Sha137994 mtbl = ldcp->mtbl;
7566408Sha137994
7576408Sha137994 memseg = mhdl->memseg;
7586408Sha137994
7596408Sha137994 /* lock the memory table - exclusive access to channel */
7606408Sha137994 mutex_enter(&mtbl->lock);
7616408Sha137994
7626408Sha137994 /* undo the pages exported */
7636408Sha137994 for (i = 0; i < memseg->npages; i++) {
7646408Sha137994
7656845Sha137994 /* clear the entry from the table */
7666845Sha137994 memseg->pages[i].mte->entry.ll = 0;
7676845Sha137994
7686408Sha137994 /* check for mapped pages, revocation cookie != 0 */
7696408Sha137994 if (memseg->pages[i].mte->cookie) {
7706408Sha137994
7717226Sha137994 pg_size_code = page_szc(MMU_PAGESIZE);
7726845Sha137994 pg_shift = page_get_shift(pg_size_code);
7736408Sha137994 cookie_addr = IDX2COOKIE(memseg->pages[i].index,
7746408Sha137994 pg_size_code, pg_shift);
7756408Sha137994
7766408Sha137994 D1(ldcp->id, "ldc_mem_unbind_handle: (0x%llx) revoke "
7776408Sha137994 "cookie 0x%llx, rcookie 0x%llx\n", ldcp->id,
7786408Sha137994 cookie_addr, memseg->pages[i].mte->cookie);
7796845Sha137994
7806845Sha137994 retries = 0;
7816845Sha137994 do {
7826845Sha137994 rv = hv_ldc_revoke(ldcp->id, cookie_addr,
7836845Sha137994 memseg->pages[i].mte->cookie);
7846845Sha137994
7856845Sha137994 if (rv != H_EWOULDBLOCK)
7866845Sha137994 break;
7876845Sha137994
7886845Sha137994 drv_usecwait(ldc_delay);
7896845Sha137994
7906845Sha137994 } while (retries++ < ldc_max_retries);
7916845Sha137994
7926408Sha137994 if (rv) {
7936408Sha137994 DWARN(ldcp->id,
7946408Sha137994 "ldc_mem_unbind_handle: (0x%llx) cannot "
7956408Sha137994 "revoke mapping, cookie %llx\n", ldcp->id,
7966408Sha137994 cookie_addr);
7976408Sha137994 }
7986408Sha137994 }
7996408Sha137994
8006408Sha137994 mtbl->num_avail++;
8016408Sha137994 }
8026408Sha137994 mutex_exit(&mtbl->lock);
8036408Sha137994
8046408Sha137994 /* free the allocated memseg and page structures */
8056408Sha137994 kmem_free(memseg->pages, (sizeof (ldc_page_t) * memseg->npages));
8066408Sha137994 kmem_free(memseg->cookies,
8076408Sha137994 (sizeof (ldc_mem_cookie_t) * memseg->npages));
8086408Sha137994 kmem_cache_free(ldcssp->memseg_cache, memseg);
8096408Sha137994
8106408Sha137994 /* uninitialize the memory handle */
8116408Sha137994 mhdl->memseg = NULL;
8126408Sha137994 mhdl->status = LDC_UNBOUND;
8136408Sha137994
8146408Sha137994 D1(ldcp->id, "ldc_mem_unbind_handle: (0x%llx) unbound handle 0x%llx\n",
8156408Sha137994 ldcp->id, mhdl);
8166408Sha137994
8176408Sha137994 mutex_exit(&mhdl->lock);
8186408Sha137994 return (0);
8196408Sha137994 }
8206408Sha137994
8216408Sha137994 /*
8226408Sha137994 * Get information about the dring. The base address of the descriptor
8236408Sha137994 * ring along with the type and permission are returned back.
8246408Sha137994 */
8256408Sha137994 int
ldc_mem_info(ldc_mem_handle_t mhandle,ldc_mem_info_t * minfo)8266408Sha137994 ldc_mem_info(ldc_mem_handle_t mhandle, ldc_mem_info_t *minfo)
8276408Sha137994 {
8286408Sha137994 ldc_mhdl_t *mhdl;
8296408Sha137994
8306408Sha137994 if (mhandle == NULL) {
8316408Sha137994 DWARN(DBG_ALL_LDCS, "ldc_mem_info: invalid memory handle\n");
8326408Sha137994 return (EINVAL);
8336408Sha137994 }
8346408Sha137994 mhdl = (ldc_mhdl_t *)mhandle;
8356408Sha137994
8366408Sha137994 if (minfo == NULL) {
8376408Sha137994 DWARN(DBG_ALL_LDCS, "ldc_mem_info: invalid args\n");
8386408Sha137994 return (EINVAL);
8396408Sha137994 }
8406408Sha137994
8416408Sha137994 mutex_enter(&mhdl->lock);
8426408Sha137994
8436408Sha137994 minfo->status = mhdl->status;
8446408Sha137994 if (mhdl->status == LDC_BOUND || mhdl->status == LDC_MAPPED) {
8456408Sha137994 minfo->vaddr = mhdl->memseg->vaddr;
8466408Sha137994 minfo->raddr = mhdl->memseg->raddr;
8476408Sha137994 minfo->mtype = mhdl->mtype;
8486408Sha137994 minfo->perm = mhdl->perm;
8496408Sha137994 }
8506408Sha137994 mutex_exit(&mhdl->lock);
8516408Sha137994
8526408Sha137994 return (0);
8536408Sha137994 }
8546408Sha137994
8556408Sha137994 /*
8566408Sha137994 * Copy data either from or to the client specified virtual address
8576408Sha137994 * space to or from the exported memory associated with the cookies.
8586408Sha137994 * The direction argument determines whether the data is read from or
8596408Sha137994 * written to exported memory.
8606408Sha137994 */
8616408Sha137994 int
ldc_mem_copy(ldc_handle_t handle,caddr_t vaddr,uint64_t off,size_t * size,ldc_mem_cookie_t * cookies,uint32_t ccount,uint8_t direction)8626408Sha137994 ldc_mem_copy(ldc_handle_t handle, caddr_t vaddr, uint64_t off, size_t *size,
8636408Sha137994 ldc_mem_cookie_t *cookies, uint32_t ccount, uint8_t direction)
8646408Sha137994 {
8656408Sha137994 ldc_chan_t *ldcp;
8666408Sha137994 uint64_t local_voff, local_valign;
8676408Sha137994 uint64_t cookie_addr, cookie_size;
8686408Sha137994 uint64_t pg_shift, pg_size, pg_size_code;
8696408Sha137994 uint64_t export_caddr, export_poff, export_psize, export_size;
8706408Sha137994 uint64_t local_ra, local_poff, local_psize;
8716408Sha137994 uint64_t copy_size, copied_len = 0, total_bal = 0, idx = 0;
8726408Sha137994 pgcnt_t npages;
8736408Sha137994 size_t len = *size;
8746408Sha137994 int i, rv = 0;
8756408Sha137994
8766408Sha137994 uint64_t chid;
8776408Sha137994
8786408Sha137994 if (handle == NULL) {
8796408Sha137994 DWARN(DBG_ALL_LDCS, "ldc_mem_copy: invalid channel handle\n");
8806408Sha137994 return (EINVAL);
8816408Sha137994 }
8826408Sha137994 ldcp = (ldc_chan_t *)handle;
8836408Sha137994 chid = ldcp->id;
8846408Sha137994
8856408Sha137994 /* check to see if channel is UP */
8866408Sha137994 if (ldcp->tstate != TS_UP) {
8876408Sha137994 DWARN(chid, "ldc_mem_copy: (0x%llx) channel is not UP\n",
8886408Sha137994 chid);
8896408Sha137994 return (ECONNRESET);
8906408Sha137994 }
8916408Sha137994
8926408Sha137994 /* Force address and size to be 8-byte aligned */
8936408Sha137994 if ((((uintptr_t)vaddr | len) & 0x7) != 0) {
8946408Sha137994 DWARN(chid,
8956408Sha137994 "ldc_mem_copy: addr/sz is not 8-byte aligned\n");
8966408Sha137994 return (EINVAL);
8976408Sha137994 }
8986408Sha137994
8996408Sha137994 /* Find the size of the exported memory */
9006408Sha137994 export_size = 0;
9016408Sha137994 for (i = 0; i < ccount; i++)
9026408Sha137994 export_size += cookies[i].size;
9036408Sha137994
9046408Sha137994 /* check to see if offset is valid */
9056408Sha137994 if (off > export_size) {
9066408Sha137994 DWARN(chid,
9076408Sha137994 "ldc_mem_copy: (0x%llx) start offset > export mem size\n",
9086408Sha137994 chid);
9096408Sha137994 return (EINVAL);
9106408Sha137994 }
9116408Sha137994
9126408Sha137994 /*
9136408Sha137994 * Check to see if the export size is smaller than the size we
9146408Sha137994 * are requesting to copy - if so flag an error
9156408Sha137994 */
9166408Sha137994 if ((export_size - off) < *size) {
9176408Sha137994 DWARN(chid,
9186408Sha137994 "ldc_mem_copy: (0x%llx) copy size > export mem size\n",
9196408Sha137994 chid);
9206408Sha137994 return (EINVAL);
9216408Sha137994 }
9226408Sha137994
9236408Sha137994 total_bal = min(export_size, *size);
9246408Sha137994
9256408Sha137994 /* FUTURE: get the page size, pgsz code, and shift */
9266408Sha137994 pg_size = MMU_PAGESIZE;
9276408Sha137994 pg_size_code = page_szc(pg_size);
9286408Sha137994 pg_shift = page_get_shift(pg_size_code);
9296408Sha137994
9306408Sha137994 D1(chid, "ldc_mem_copy: copying data "
9316408Sha137994 "(0x%llx) va 0x%llx pgsz=0x%llx, pgszc=0x%llx, pg_shift=0x%llx\n",
9326408Sha137994 chid, vaddr, pg_size, pg_size_code, pg_shift);
9336408Sha137994
9346408Sha137994 /* aligned VA and its offset */
9356408Sha137994 local_valign = (((uintptr_t)vaddr) & ~(pg_size - 1));
9366408Sha137994 local_voff = ((uintptr_t)vaddr) & (pg_size - 1);
9376408Sha137994
9386408Sha137994 npages = (len+local_voff)/pg_size;
9396408Sha137994 npages = ((len+local_voff)%pg_size == 0) ? npages : npages+1;
9406408Sha137994
9416408Sha137994 D1(chid,
9426408Sha137994 "ldc_mem_copy: (0x%llx) v=0x%llx,val=0x%llx,off=0x%x,pgs=0x%x\n",
9436408Sha137994 chid, vaddr, local_valign, local_voff, npages);
9446408Sha137994
9456408Sha137994 local_ra = va_to_pa((void *)local_valign);
9466408Sha137994 local_poff = local_voff;
9476408Sha137994 local_psize = min(len, (pg_size - local_voff));
9486408Sha137994
9496408Sha137994 len -= local_psize;
9506408Sha137994
9516408Sha137994 /*
9526408Sha137994 * find the first cookie in the list of cookies
9536408Sha137994 * if the offset passed in is not zero
9546408Sha137994 */
9556408Sha137994 for (idx = 0; idx < ccount; idx++) {
9566408Sha137994 cookie_size = cookies[idx].size;
9576408Sha137994 if (off < cookie_size)
9586408Sha137994 break;
9596408Sha137994 off -= cookie_size;
9606408Sha137994 }
9616408Sha137994
9626408Sha137994 cookie_addr = cookies[idx].addr + off;
9636408Sha137994 cookie_size = cookies[idx].size - off;
9646408Sha137994
9656408Sha137994 export_caddr = cookie_addr & ~(pg_size - 1);
9666408Sha137994 export_poff = cookie_addr & (pg_size - 1);
9676408Sha137994 export_psize = min(cookie_size, (pg_size - export_poff));
9686408Sha137994
9696408Sha137994 for (;;) {
9706408Sha137994
9716408Sha137994 copy_size = min(export_psize, local_psize);
9726408Sha137994
9736408Sha137994 D1(chid,
9746408Sha137994 "ldc_mem_copy:(0x%llx) dir=0x%x, caddr=0x%llx,"
9756408Sha137994 " loc_ra=0x%llx, exp_poff=0x%llx, loc_poff=0x%llx,"
9766408Sha137994 " exp_psz=0x%llx, loc_psz=0x%llx, copy_sz=0x%llx,"
9776408Sha137994 " total_bal=0x%llx\n",
9786408Sha137994 chid, direction, export_caddr, local_ra, export_poff,
9796408Sha137994 local_poff, export_psize, local_psize, copy_size,
9806408Sha137994 total_bal);
9816408Sha137994
9826408Sha137994 rv = hv_ldc_copy(chid, direction,
9836408Sha137994 (export_caddr + export_poff), (local_ra + local_poff),
9846408Sha137994 copy_size, &copied_len);
9856408Sha137994
9866408Sha137994 if (rv != 0) {
9876408Sha137994 int error = EIO;
9886408Sha137994 uint64_t rx_hd, rx_tl;
9896408Sha137994
9906408Sha137994 DWARN(chid,
9916408Sha137994 "ldc_mem_copy: (0x%llx) err %d during copy\n",
9926408Sha137994 (unsigned long long)chid, rv);
9936408Sha137994 DWARN(chid,
9946408Sha137994 "ldc_mem_copy: (0x%llx) dir=0x%x, caddr=0x%lx, "
9956408Sha137994 "loc_ra=0x%lx, exp_poff=0x%lx, loc_poff=0x%lx,"
9966408Sha137994 " exp_psz=0x%lx, loc_psz=0x%lx, copy_sz=0x%lx,"
9976408Sha137994 " copied_len=0x%lx, total_bal=0x%lx\n",
9986408Sha137994 chid, direction, export_caddr, local_ra,
9996408Sha137994 export_poff, local_poff, export_psize, local_psize,
10006408Sha137994 copy_size, copied_len, total_bal);
10016408Sha137994
10026408Sha137994 *size = *size - total_bal;
10036408Sha137994
10046408Sha137994 /*
10056408Sha137994 * check if reason for copy error was due to
10066408Sha137994 * a channel reset. we need to grab the lock
10076408Sha137994 * just in case we have to do a reset.
10086408Sha137994 */
10096408Sha137994 mutex_enter(&ldcp->lock);
10106408Sha137994 mutex_enter(&ldcp->tx_lock);
10116408Sha137994
10126408Sha137994 rv = hv_ldc_rx_get_state(ldcp->id,
10136408Sha137994 &rx_hd, &rx_tl, &(ldcp->link_state));
10146408Sha137994 if (ldcp->link_state == LDC_CHANNEL_DOWN ||
10156408Sha137994 ldcp->link_state == LDC_CHANNEL_RESET) {
10166408Sha137994 i_ldc_reset(ldcp, B_FALSE);
10176408Sha137994 error = ECONNRESET;
10186408Sha137994 }
10196408Sha137994
10206408Sha137994 mutex_exit(&ldcp->tx_lock);
10216408Sha137994 mutex_exit(&ldcp->lock);
10226408Sha137994
10236408Sha137994 return (error);
10246408Sha137994 }
10256408Sha137994
10266408Sha137994 ASSERT(copied_len <= copy_size);
10276408Sha137994
10286408Sha137994 D2(chid, "ldc_mem_copy: copied=0x%llx\n", copied_len);
10296408Sha137994 export_poff += copied_len;
10306408Sha137994 local_poff += copied_len;
10316408Sha137994 export_psize -= copied_len;
10326408Sha137994 local_psize -= copied_len;
10336408Sha137994 cookie_size -= copied_len;
10346408Sha137994
10356408Sha137994 total_bal -= copied_len;
10366408Sha137994
10376408Sha137994 if (copy_size != copied_len)
10386408Sha137994 continue;
10396408Sha137994
10406408Sha137994 if (export_psize == 0 && total_bal != 0) {
10416408Sha137994
10426408Sha137994 if (cookie_size == 0) {
10436408Sha137994 idx++;
10446408Sha137994 cookie_addr = cookies[idx].addr;
10456408Sha137994 cookie_size = cookies[idx].size;
10466408Sha137994
10476408Sha137994 export_caddr = cookie_addr & ~(pg_size - 1);
10486408Sha137994 export_poff = cookie_addr & (pg_size - 1);
10496408Sha137994 export_psize =
10506408Sha137994 min(cookie_size, (pg_size-export_poff));
10516408Sha137994 } else {
10526408Sha137994 export_caddr += pg_size;
10536408Sha137994 export_poff = 0;
10546408Sha137994 export_psize = min(cookie_size, pg_size);
10556408Sha137994 }
10566408Sha137994 }
10576408Sha137994
10586408Sha137994 if (local_psize == 0 && total_bal != 0) {
10596408Sha137994 local_valign += pg_size;
10606408Sha137994 local_ra = va_to_pa((void *)local_valign);
10616408Sha137994 local_poff = 0;
10626408Sha137994 local_psize = min(pg_size, len);
10636408Sha137994 len -= local_psize;
10646408Sha137994 }
10656408Sha137994
10666408Sha137994 /* check if we are all done */
10676408Sha137994 if (total_bal == 0)
10686408Sha137994 break;
10696408Sha137994 }
10706408Sha137994
10716408Sha137994
10726408Sha137994 D1(chid,
10736408Sha137994 "ldc_mem_copy: (0x%llx) done copying sz=0x%llx\n",
10746408Sha137994 chid, *size);
10756408Sha137994
10766408Sha137994 return (0);
10776408Sha137994 }
10786408Sha137994
10796408Sha137994 /*
10806408Sha137994 * Copy data either from or to the client specified virtual address
10816408Sha137994 * space to or from HV physical memory.
10826408Sha137994 *
10836408Sha137994 * The direction argument determines whether the data is read from or
10846408Sha137994 * written to HV memory. direction values are LDC_COPY_IN/OUT similar
10856408Sha137994 * to the ldc_mem_copy interface
10866408Sha137994 */
10876408Sha137994 int
ldc_mem_rdwr_cookie(ldc_handle_t handle,caddr_t vaddr,size_t * size,caddr_t paddr,uint8_t direction)10886408Sha137994 ldc_mem_rdwr_cookie(ldc_handle_t handle, caddr_t vaddr, size_t *size,
10896408Sha137994 caddr_t paddr, uint8_t direction)
10906408Sha137994 {
10916408Sha137994 ldc_chan_t *ldcp;
10926408Sha137994 uint64_t local_voff, local_valign;
10936408Sha137994 uint64_t pg_shift, pg_size, pg_size_code;
10946408Sha137994 uint64_t target_pa, target_poff, target_psize, target_size;
10956408Sha137994 uint64_t local_ra, local_poff, local_psize;
10966408Sha137994 uint64_t copy_size, copied_len = 0;
10976408Sha137994 pgcnt_t npages;
10986408Sha137994 size_t len = *size;
10996408Sha137994 int rv = 0;
11006408Sha137994
11016408Sha137994 if (handle == NULL) {
11026408Sha137994 DWARN(DBG_ALL_LDCS,
11036408Sha137994 "ldc_mem_rdwr_cookie: invalid channel handle\n");
11046408Sha137994 return (EINVAL);
11056408Sha137994 }
11066408Sha137994 ldcp = (ldc_chan_t *)handle;
11076408Sha137994
11086408Sha137994 mutex_enter(&ldcp->lock);
11096408Sha137994
11106408Sha137994 /* check to see if channel is UP */
11116408Sha137994 if (ldcp->tstate != TS_UP) {
11126408Sha137994 DWARN(ldcp->id,
11136408Sha137994 "ldc_mem_rdwr_cookie: (0x%llx) channel is not UP\n",
11146408Sha137994 ldcp->id);
11156408Sha137994 mutex_exit(&ldcp->lock);
11166408Sha137994 return (ECONNRESET);
11176408Sha137994 }
11186408Sha137994
11196408Sha137994 /* Force address and size to be 8-byte aligned */
11206408Sha137994 if ((((uintptr_t)vaddr | len) & 0x7) != 0) {
11216408Sha137994 DWARN(ldcp->id,
11226408Sha137994 "ldc_mem_rdwr_cookie: addr/size is not 8-byte aligned\n");
11236408Sha137994 mutex_exit(&ldcp->lock);
11246408Sha137994 return (EINVAL);
11256408Sha137994 }
11266408Sha137994
11276408Sha137994 target_size = *size;
11286408Sha137994
11296408Sha137994 /* FUTURE: get the page size, pgsz code, and shift */
11306408Sha137994 pg_size = MMU_PAGESIZE;
11316408Sha137994 pg_size_code = page_szc(pg_size);
11326408Sha137994 pg_shift = page_get_shift(pg_size_code);
11336408Sha137994
11346408Sha137994 D1(ldcp->id, "ldc_mem_rdwr_cookie: copying data "
11356408Sha137994 "(0x%llx) va 0x%llx pgsz=0x%llx, pgszc=0x%llx, pg_shift=0x%llx\n",
11366408Sha137994 ldcp->id, vaddr, pg_size, pg_size_code, pg_shift);
11376408Sha137994
11386408Sha137994 /* aligned VA and its offset */
11396408Sha137994 local_valign = ((uintptr_t)vaddr) & ~(pg_size - 1);
11406408Sha137994 local_voff = ((uintptr_t)vaddr) & (pg_size - 1);
11416408Sha137994
11426408Sha137994 npages = (len + local_voff) / pg_size;
11436408Sha137994 npages = ((len + local_voff) % pg_size == 0) ? npages : npages+1;
11446408Sha137994
11456408Sha137994 D1(ldcp->id, "ldc_mem_rdwr_cookie: (0x%llx) v=0x%llx, "
11466408Sha137994 "val=0x%llx,off=0x%x,pgs=0x%x\n",
11476408Sha137994 ldcp->id, vaddr, local_valign, local_voff, npages);
11486408Sha137994
11496408Sha137994 local_ra = va_to_pa((void *)local_valign);
11506408Sha137994 local_poff = local_voff;
11516408Sha137994 local_psize = min(len, (pg_size - local_voff));
11526408Sha137994
11536408Sha137994 len -= local_psize;
11546408Sha137994
11556408Sha137994 target_pa = ((uintptr_t)paddr) & ~(pg_size - 1);
11566408Sha137994 target_poff = ((uintptr_t)paddr) & (pg_size - 1);
11576408Sha137994 target_psize = pg_size - target_poff;
11586408Sha137994
11596408Sha137994 for (;;) {
11606408Sha137994
11616408Sha137994 copy_size = min(target_psize, local_psize);
11626408Sha137994
11636408Sha137994 D1(ldcp->id,
11646408Sha137994 "ldc_mem_rdwr_cookie: (0x%llx) dir=0x%x, tar_pa=0x%llx,"
11656408Sha137994 " loc_ra=0x%llx, tar_poff=0x%llx, loc_poff=0x%llx,"
11666408Sha137994 " tar_psz=0x%llx, loc_psz=0x%llx, copy_sz=0x%llx,"
11676408Sha137994 " total_bal=0x%llx\n",
11686408Sha137994 ldcp->id, direction, target_pa, local_ra, target_poff,
11696408Sha137994 local_poff, target_psize, local_psize, copy_size,
11706408Sha137994 target_size);
11716408Sha137994
11726408Sha137994 rv = hv_ldc_copy(ldcp->id, direction,
11736408Sha137994 (target_pa + target_poff), (local_ra + local_poff),
11746408Sha137994 copy_size, &copied_len);
11756408Sha137994
11766408Sha137994 if (rv != 0) {
11776408Sha137994 DWARN(DBG_ALL_LDCS,
11786408Sha137994 "ldc_mem_rdwr_cookie: (0x%lx) err %d during copy\n",
11796408Sha137994 ldcp->id, rv);
11806408Sha137994 DWARN(DBG_ALL_LDCS,
11816408Sha137994 "ldc_mem_rdwr_cookie: (0x%llx) dir=%lld, "
11826408Sha137994 "tar_pa=0x%llx, loc_ra=0x%llx, tar_poff=0x%llx, "
11836408Sha137994 "loc_poff=0x%llx, tar_psz=0x%llx, loc_psz=0x%llx, "
11846408Sha137994 "copy_sz=0x%llx, total_bal=0x%llx\n",
11856408Sha137994 ldcp->id, direction, target_pa, local_ra,
11866408Sha137994 target_poff, local_poff, target_psize, local_psize,
11876408Sha137994 copy_size, target_size);
11886408Sha137994
11896408Sha137994 *size = *size - target_size;
11906408Sha137994 mutex_exit(&ldcp->lock);
11916408Sha137994 return (i_ldc_h2v_error(rv));
11926408Sha137994 }
11936408Sha137994
11946408Sha137994 D2(ldcp->id, "ldc_mem_rdwr_cookie: copied=0x%llx\n",
11956408Sha137994 copied_len);
11966408Sha137994 target_poff += copied_len;
11976408Sha137994 local_poff += copied_len;
11986408Sha137994 target_psize -= copied_len;
11996408Sha137994 local_psize -= copied_len;
12006408Sha137994
12016408Sha137994 target_size -= copied_len;
12026408Sha137994
12036408Sha137994 if (copy_size != copied_len)
12046408Sha137994 continue;
12056408Sha137994
12066408Sha137994 if (target_psize == 0 && target_size != 0) {
12076408Sha137994 target_pa += pg_size;
12086408Sha137994 target_poff = 0;
12096408Sha137994 target_psize = min(pg_size, target_size);
12106408Sha137994 }
12116408Sha137994
12126408Sha137994 if (local_psize == 0 && target_size != 0) {
12136408Sha137994 local_valign += pg_size;
12146408Sha137994 local_ra = va_to_pa((void *)local_valign);
12156408Sha137994 local_poff = 0;
12166408Sha137994 local_psize = min(pg_size, len);
12176408Sha137994 len -= local_psize;
12186408Sha137994 }
12196408Sha137994
12206408Sha137994 /* check if we are all done */
12216408Sha137994 if (target_size == 0)
12226408Sha137994 break;
12236408Sha137994 }
12246408Sha137994
12256408Sha137994 mutex_exit(&ldcp->lock);
12266408Sha137994
12276408Sha137994 D1(ldcp->id, "ldc_mem_rdwr_cookie: (0x%llx) done copying sz=0x%llx\n",
12286408Sha137994 ldcp->id, *size);
12296408Sha137994
12306408Sha137994 return (0);
12316408Sha137994 }
12326408Sha137994
12336408Sha137994 /*
12346408Sha137994 * Map an exported memory segment into the local address space. If the
12356408Sha137994 * memory range was exported for direct map access, a HV call is made
12366408Sha137994 * to allocate a RA range. If the map is done via a shadow copy, local
12376408Sha137994 * shadow memory is allocated and the base VA is returned in 'vaddr'. If
12386408Sha137994 * the mapping is a direct map then the RA is returned in 'raddr'.
12396408Sha137994 */
12406408Sha137994 int
ldc_mem_map(ldc_mem_handle_t mhandle,ldc_mem_cookie_t * cookie,uint32_t ccount,uint8_t mtype,uint8_t perm,caddr_t * vaddr,caddr_t * raddr)12416408Sha137994 ldc_mem_map(ldc_mem_handle_t mhandle, ldc_mem_cookie_t *cookie, uint32_t ccount,
12426408Sha137994 uint8_t mtype, uint8_t perm, caddr_t *vaddr, caddr_t *raddr)
12436408Sha137994 {
12446845Sha137994 /*
12456845Sha137994 * Check if direct map over shared memory is enabled, if not change
12466845Sha137994 * the mapping type to SHADOW_MAP.
12476845Sha137994 */
12486845Sha137994 if (ldc_shmem_enabled == 0)
12496845Sha137994 mtype = LDC_SHADOW_MAP;
12506845Sha137994
12516845Sha137994 return (i_ldc_mem_map(mhandle, cookie, ccount, mtype, perm,
12526845Sha137994 vaddr, raddr));
12536845Sha137994 }
12546845Sha137994
12556845Sha137994 static int
i_ldc_mem_map(ldc_mem_handle_t mhandle,ldc_mem_cookie_t * cookie,uint32_t ccount,uint8_t mtype,uint8_t perm,caddr_t * vaddr,caddr_t * raddr)12566845Sha137994 i_ldc_mem_map(ldc_mem_handle_t mhandle, ldc_mem_cookie_t *cookie,
12576845Sha137994 uint32_t ccount, uint8_t mtype, uint8_t perm, caddr_t *vaddr,
12586845Sha137994 caddr_t *raddr)
12596845Sha137994 {
12606845Sha137994
12616408Sha137994 int i, j, idx, rv, retries;
12626408Sha137994 ldc_chan_t *ldcp;
12636408Sha137994 ldc_mhdl_t *mhdl;
12646408Sha137994 ldc_memseg_t *memseg;
12656408Sha137994 caddr_t tmpaddr;
12666408Sha137994 uint64_t map_perm = perm;
12676408Sha137994 uint64_t pg_size, pg_shift, pg_size_code, pg_mask;
12686408Sha137994 uint64_t exp_size = 0, base_off, map_size, npages;
12696408Sha137994 uint64_t cookie_addr, cookie_off, cookie_size;
12706408Sha137994 tte_t ldc_tte;
12716408Sha137994
12726408Sha137994 if (mhandle == NULL) {
12736408Sha137994 DWARN(DBG_ALL_LDCS, "ldc_mem_map: invalid memory handle\n");
12746408Sha137994 return (EINVAL);
12756408Sha137994 }
12766408Sha137994 mhdl = (ldc_mhdl_t *)mhandle;
12776408Sha137994
12786408Sha137994 mutex_enter(&mhdl->lock);
12796408Sha137994
12806408Sha137994 if (mhdl->status == LDC_BOUND || mhdl->status == LDC_MAPPED ||
12816408Sha137994 mhdl->memseg != NULL) {
12826408Sha137994 DWARN(DBG_ALL_LDCS,
12836408Sha137994 "ldc_mem_map: (0x%llx) handle bound/mapped\n", mhandle);
12846408Sha137994 mutex_exit(&mhdl->lock);
12856408Sha137994 return (EINVAL);
12866408Sha137994 }
12876408Sha137994
12886408Sha137994 ldcp = mhdl->ldcp;
12896408Sha137994
12906408Sha137994 mutex_enter(&ldcp->lock);
12916408Sha137994
12926408Sha137994 if (ldcp->tstate != TS_UP) {
12936408Sha137994 DWARN(ldcp->id,
12946408Sha137994 "ldc_mem_dring_map: (0x%llx) channel is not UP\n",
12956408Sha137994 ldcp->id);
12966408Sha137994 mutex_exit(&ldcp->lock);
12976408Sha137994 mutex_exit(&mhdl->lock);
12986408Sha137994 return (ECONNRESET);
12996408Sha137994 }
13006408Sha137994
13016408Sha137994 if ((mtype & (LDC_SHADOW_MAP|LDC_DIRECT_MAP|LDC_IO_MAP)) == 0) {
13026408Sha137994 DWARN(ldcp->id, "ldc_mem_map: invalid map type\n");
13036408Sha137994 mutex_exit(&ldcp->lock);
13046408Sha137994 mutex_exit(&mhdl->lock);
13056408Sha137994 return (EINVAL);
13066408Sha137994 }
13076408Sha137994
13086408Sha137994 D1(ldcp->id, "ldc_mem_map: (0x%llx) cookie = 0x%llx,0x%llx\n",
13096408Sha137994 ldcp->id, cookie->addr, cookie->size);
13106408Sha137994
13116408Sha137994 /* FUTURE: get the page size, pgsz code, and shift */
13126408Sha137994 pg_size = MMU_PAGESIZE;
13136408Sha137994 pg_size_code = page_szc(pg_size);
13146408Sha137994 pg_shift = page_get_shift(pg_size_code);
13156408Sha137994 pg_mask = ~(pg_size - 1);
13166408Sha137994
13176408Sha137994 /* calculate the number of pages in the exported cookie */
13186408Sha137994 base_off = cookie[0].addr & (pg_size - 1);
13196408Sha137994 for (idx = 0; idx < ccount; idx++)
13206408Sha137994 exp_size += cookie[idx].size;
13216408Sha137994 map_size = P2ROUNDUP((exp_size + base_off), pg_size);
13226408Sha137994 npages = (map_size >> pg_shift);
13236408Sha137994
13246408Sha137994 /* Allocate memseg structure */
13256408Sha137994 memseg = mhdl->memseg =
13266408Sha137994 kmem_cache_alloc(ldcssp->memseg_cache, KM_SLEEP);
13276408Sha137994
13286408Sha137994 /* Allocate memory to store all pages and cookies */
13296408Sha137994 memseg->pages = kmem_zalloc((sizeof (ldc_page_t) * npages), KM_SLEEP);
13306408Sha137994 memseg->cookies =
13316408Sha137994 kmem_zalloc((sizeof (ldc_mem_cookie_t) * ccount), KM_SLEEP);
13326408Sha137994
13336408Sha137994 D2(ldcp->id, "ldc_mem_map: (0x%llx) exp_size=0x%llx, map_size=0x%llx,"
13346408Sha137994 "pages=0x%llx\n", ldcp->id, exp_size, map_size, npages);
13356408Sha137994
13366408Sha137994 /*
13376408Sha137994 * Check to see if the client is requesting direct or shadow map
13386408Sha137994 * If direct map is requested, try to map remote memory first,
13396408Sha137994 * and if that fails, revert to shadow map
13406408Sha137994 */
13416408Sha137994 if (mtype == LDC_DIRECT_MAP) {
13426408Sha137994
13436408Sha137994 /* Allocate kernel virtual space for mapping */
13446408Sha137994 memseg->vaddr = vmem_xalloc(heap_arena, map_size,
13456408Sha137994 pg_size, 0, 0, NULL, NULL, VM_NOSLEEP);
13466408Sha137994 if (memseg->vaddr == NULL) {
13476845Sha137994 DWARN(DBG_ALL_LDCS,
13486408Sha137994 "ldc_mem_map: (0x%lx) memory map failed\n",
13496408Sha137994 ldcp->id);
13506408Sha137994 kmem_free(memseg->cookies,
13516408Sha137994 (sizeof (ldc_mem_cookie_t) * ccount));
13526408Sha137994 kmem_free(memseg->pages,
13536408Sha137994 (sizeof (ldc_page_t) * npages));
13546408Sha137994 kmem_cache_free(ldcssp->memseg_cache, memseg);
13556408Sha137994
13566408Sha137994 mutex_exit(&ldcp->lock);
13576408Sha137994 mutex_exit(&mhdl->lock);
13586408Sha137994 return (ENOMEM);
13596408Sha137994 }
13606408Sha137994
13616408Sha137994 /* Unload previous mapping */
13626408Sha137994 hat_unload(kas.a_hat, memseg->vaddr, map_size,
13636408Sha137994 HAT_UNLOAD_NOSYNC | HAT_UNLOAD_UNLOCK);
13646408Sha137994
13656408Sha137994 /* for each cookie passed in - map into address space */
13666408Sha137994 idx = 0;
13676408Sha137994 cookie_size = 0;
13686408Sha137994 tmpaddr = memseg->vaddr;
13696408Sha137994
13706408Sha137994 for (i = 0; i < npages; i++) {
13716408Sha137994
13726408Sha137994 if (cookie_size == 0) {
13736408Sha137994 ASSERT(idx < ccount);
13746408Sha137994 cookie_addr = cookie[idx].addr & pg_mask;
13756408Sha137994 cookie_off = cookie[idx].addr & (pg_size - 1);
13766408Sha137994 cookie_size =
13776408Sha137994 P2ROUNDUP((cookie_off + cookie[idx].size),
13786408Sha137994 pg_size);
13796408Sha137994 idx++;
13806408Sha137994 }
13816408Sha137994
13826408Sha137994 D1(ldcp->id, "ldc_mem_map: (0x%llx) mapping "
13836408Sha137994 "cookie 0x%llx, bal=0x%llx\n", ldcp->id,
13846408Sha137994 cookie_addr, cookie_size);
13856408Sha137994
13866408Sha137994 /* map the cookie into address space */
13876408Sha137994 for (retries = 0; retries < ldc_max_retries;
13886408Sha137994 retries++) {
13896408Sha137994
13906408Sha137994 rv = hv_ldc_mapin(ldcp->id, cookie_addr,
13916408Sha137994 &memseg->pages[i].raddr, &map_perm);
13926408Sha137994 if (rv != H_EWOULDBLOCK && rv != H_ETOOMANY)
13936408Sha137994 break;
13946408Sha137994
13956408Sha137994 drv_usecwait(ldc_delay);
13966408Sha137994 }
13976408Sha137994
13986408Sha137994 if (rv || memseg->pages[i].raddr == 0) {
13996408Sha137994 DWARN(ldcp->id,
14006408Sha137994 "ldc_mem_map: (0x%llx) hv mapin err %d\n",
14016408Sha137994 ldcp->id, rv);
14026408Sha137994
14036408Sha137994 /* remove previous mapins */
14046408Sha137994 hat_unload(kas.a_hat, memseg->vaddr, map_size,
14056408Sha137994 HAT_UNLOAD_NOSYNC | HAT_UNLOAD_UNLOCK);
14066408Sha137994 for (j = 0; j < i; j++) {
14076408Sha137994 rv = hv_ldc_unmap(
14086408Sha137994 memseg->pages[j].raddr);
14096408Sha137994 if (rv) {
14106408Sha137994 DWARN(ldcp->id,
14116408Sha137994 "ldc_mem_map: (0x%llx) "
14126408Sha137994 "cannot unmap ra=0x%llx\n",
14136408Sha137994 ldcp->id,
14146408Sha137994 memseg->pages[j].raddr);
14156408Sha137994 }
14166408Sha137994 }
14176408Sha137994
14186408Sha137994 /* free kernel virtual space */
14196408Sha137994 vmem_free(heap_arena, (void *)memseg->vaddr,
14206408Sha137994 map_size);
14216408Sha137994
14226408Sha137994 /* direct map failed - revert to shadow map */
14236408Sha137994 mtype = LDC_SHADOW_MAP;
14246408Sha137994 break;
14256408Sha137994
14266408Sha137994 } else {
14276408Sha137994
14286408Sha137994 D1(ldcp->id,
14296408Sha137994 "ldc_mem_map: (0x%llx) vtop map 0x%llx -> "
14306408Sha137994 "0x%llx, cookie=0x%llx, perm=0x%llx\n",
14316408Sha137994 ldcp->id, tmpaddr, memseg->pages[i].raddr,
14326408Sha137994 cookie_addr, perm);
14336408Sha137994
14346408Sha137994 /*
14356408Sha137994 * NOTE: Calling hat_devload directly, causes it
14366408Sha137994 * to look for page_t using the pfn. Since this
14376408Sha137994 * addr is greater than the memlist, it treates
14386408Sha137994 * it as non-memory
14396408Sha137994 */
14406408Sha137994 sfmmu_memtte(&ldc_tte,
14416408Sha137994 (pfn_t)(memseg->pages[i].raddr >> pg_shift),
14426408Sha137994 PROT_READ | PROT_WRITE | HAT_NOSYNC, TTE8K);
14436408Sha137994
14446408Sha137994 D1(ldcp->id,
14456408Sha137994 "ldc_mem_map: (0x%llx) ra 0x%llx -> "
14466408Sha137994 "tte 0x%llx\n", ldcp->id,
14476408Sha137994 memseg->pages[i].raddr, ldc_tte);
14486408Sha137994
14496408Sha137994 sfmmu_tteload(kas.a_hat, &ldc_tte, tmpaddr,
14506408Sha137994 NULL, HAT_LOAD_LOCK);
14516408Sha137994
14526408Sha137994 cookie_size -= pg_size;
14536408Sha137994 cookie_addr += pg_size;
14546408Sha137994 tmpaddr += pg_size;
14556408Sha137994 }
14566408Sha137994 }
14576408Sha137994 }
14586408Sha137994
14596408Sha137994 if (mtype == LDC_SHADOW_MAP) {
14606408Sha137994 if (*vaddr == NULL) {
14616408Sha137994 memseg->vaddr = kmem_zalloc(exp_size, KM_SLEEP);
14626408Sha137994 mhdl->myshadow = B_TRUE;
14636408Sha137994
14646408Sha137994 D1(ldcp->id, "ldc_mem_map: (0x%llx) allocated "
14656408Sha137994 "shadow page va=0x%llx\n", ldcp->id, memseg->vaddr);
14666408Sha137994 } else {
14676408Sha137994 /*
14686408Sha137994 * Use client supplied memory for memseg->vaddr
14696408Sha137994 * WARNING: assuming that client mem is >= exp_size
14706408Sha137994 */
14716408Sha137994 memseg->vaddr = *vaddr;
14726408Sha137994 }
14736408Sha137994
14746408Sha137994 /* Save all page and cookie information */
14756408Sha137994 for (i = 0, tmpaddr = memseg->vaddr; i < npages; i++) {
14766408Sha137994 memseg->pages[i].raddr = va_to_pa(tmpaddr);
14776408Sha137994 tmpaddr += pg_size;
14786408Sha137994 }
14796408Sha137994
14806408Sha137994 }
14816408Sha137994
14826408Sha137994 /* save all cookies */
14836408Sha137994 bcopy(cookie, memseg->cookies, ccount * sizeof (ldc_mem_cookie_t));
14846408Sha137994
14856408Sha137994 /* update memseg_t */
14866408Sha137994 memseg->raddr = memseg->pages[0].raddr;
14876408Sha137994 memseg->size = (mtype == LDC_SHADOW_MAP) ? exp_size : map_size;
14886408Sha137994 memseg->npages = npages;
14896408Sha137994 memseg->ncookies = ccount;
14906408Sha137994 memseg->next_cookie = 0;
14916408Sha137994
14926408Sha137994 /* memory handle = mapped */
14936408Sha137994 mhdl->mtype = mtype;
14946408Sha137994 mhdl->perm = perm;
14956408Sha137994 mhdl->status = LDC_MAPPED;
14966408Sha137994
14976408Sha137994 D1(ldcp->id, "ldc_mem_map: (0x%llx) mapped 0x%llx, ra=0x%llx, "
14986408Sha137994 "va=0x%llx, pgs=0x%llx cookies=0x%llx\n",
14996408Sha137994 ldcp->id, mhdl, memseg->raddr, memseg->vaddr,
15006408Sha137994 memseg->npages, memseg->ncookies);
15016408Sha137994
15026408Sha137994 if (mtype == LDC_SHADOW_MAP)
15036408Sha137994 base_off = 0;
15046408Sha137994 if (raddr)
15056408Sha137994 *raddr = (caddr_t)(memseg->raddr | base_off);
15066408Sha137994 if (vaddr)
15076408Sha137994 *vaddr = (caddr_t)((uintptr_t)memseg->vaddr | base_off);
15086408Sha137994
15096408Sha137994 mutex_exit(&ldcp->lock);
15106408Sha137994 mutex_exit(&mhdl->lock);
15116408Sha137994 return (0);
15126408Sha137994 }
15136408Sha137994
15146408Sha137994 /*
15156408Sha137994 * Unmap a memory segment. Free shadow memory (if any).
15166408Sha137994 */
15176408Sha137994 int
ldc_mem_unmap(ldc_mem_handle_t mhandle)15186408Sha137994 ldc_mem_unmap(ldc_mem_handle_t mhandle)
15196408Sha137994 {
15206408Sha137994 int i, rv;
15216408Sha137994 ldc_mhdl_t *mhdl = (ldc_mhdl_t *)mhandle;
15226408Sha137994 ldc_chan_t *ldcp;
15236408Sha137994 ldc_memseg_t *memseg;
15246408Sha137994
15256408Sha137994 if (mhdl == 0 || mhdl->status != LDC_MAPPED) {
15266408Sha137994 DWARN(DBG_ALL_LDCS,
15276408Sha137994 "ldc_mem_unmap: (0x%llx) handle is not mapped\n",
15286408Sha137994 mhandle);
15296408Sha137994 return (EINVAL);
15306408Sha137994 }
15316408Sha137994
15326408Sha137994 mutex_enter(&mhdl->lock);
15336408Sha137994
15346408Sha137994 ldcp = mhdl->ldcp;
15356408Sha137994 memseg = mhdl->memseg;
15366408Sha137994
15376408Sha137994 D1(ldcp->id, "ldc_mem_unmap: (0x%llx) unmapping handle 0x%llx\n",
15386408Sha137994 ldcp->id, mhdl);
15396408Sha137994
15406408Sha137994 /* if we allocated shadow memory - free it */
15416408Sha137994 if (mhdl->mtype == LDC_SHADOW_MAP && mhdl->myshadow) {
15426408Sha137994 kmem_free(memseg->vaddr, memseg->size);
15436408Sha137994 } else if (mhdl->mtype == LDC_DIRECT_MAP) {
15446408Sha137994
15456408Sha137994 /* unmap in the case of DIRECT_MAP */
15466408Sha137994 hat_unload(kas.a_hat, memseg->vaddr, memseg->size,
15476408Sha137994 HAT_UNLOAD_UNLOCK);
15486408Sha137994
15496408Sha137994 for (i = 0; i < memseg->npages; i++) {
15506408Sha137994 rv = hv_ldc_unmap(memseg->pages[i].raddr);
15516408Sha137994 if (rv) {
15526845Sha137994 DWARN(DBG_ALL_LDCS,
15536408Sha137994 "ldc_mem_map: (0x%lx) hv unmap err %d\n",
15546408Sha137994 ldcp->id, rv);
15556408Sha137994 }
15566408Sha137994 }
15576408Sha137994
15586408Sha137994 vmem_free(heap_arena, (void *)memseg->vaddr, memseg->size);
15596408Sha137994 }
15606408Sha137994
15616408Sha137994 /* free the allocated memseg and page structures */
15626408Sha137994 kmem_free(memseg->pages, (sizeof (ldc_page_t) * memseg->npages));
15636408Sha137994 kmem_free(memseg->cookies,
15646408Sha137994 (sizeof (ldc_mem_cookie_t) * memseg->ncookies));
15656408Sha137994 kmem_cache_free(ldcssp->memseg_cache, memseg);
15666408Sha137994
15676408Sha137994 /* uninitialize the memory handle */
15686408Sha137994 mhdl->memseg = NULL;
15696408Sha137994 mhdl->status = LDC_UNBOUND;
15706408Sha137994
15716408Sha137994 D1(ldcp->id, "ldc_mem_unmap: (0x%llx) unmapped handle 0x%llx\n",
15726408Sha137994 ldcp->id, mhdl);
15736408Sha137994
15746408Sha137994 mutex_exit(&mhdl->lock);
15756408Sha137994 return (0);
15766408Sha137994 }
15776408Sha137994
15786408Sha137994 /*
15796408Sha137994 * Internal entry point for LDC mapped memory entry consistency
15806408Sha137994 * semantics. Acquire copies the contents of the remote memory
15816408Sha137994 * into the local shadow copy. The release operation copies the local
15826408Sha137994 * contents into the remote memory. The offset and size specify the
15836408Sha137994 * bounds for the memory range being synchronized.
15846408Sha137994 */
15856408Sha137994 static int
i_ldc_mem_acquire_release(ldc_mem_handle_t mhandle,uint8_t direction,uint64_t offset,size_t size)15866408Sha137994 i_ldc_mem_acquire_release(ldc_mem_handle_t mhandle, uint8_t direction,
15876408Sha137994 uint64_t offset, size_t size)
15886408Sha137994 {
15896408Sha137994 int err;
15906408Sha137994 ldc_mhdl_t *mhdl;
15916408Sha137994 ldc_chan_t *ldcp;
15926408Sha137994 ldc_memseg_t *memseg;
15936408Sha137994 caddr_t local_vaddr;
15946408Sha137994 size_t copy_size;
15956408Sha137994
15966408Sha137994 if (mhandle == NULL) {
15976408Sha137994 DWARN(DBG_ALL_LDCS,
15986408Sha137994 "i_ldc_mem_acquire_release: invalid memory handle\n");
15996408Sha137994 return (EINVAL);
16006408Sha137994 }
16016408Sha137994 mhdl = (ldc_mhdl_t *)mhandle;
16026408Sha137994
16036408Sha137994 mutex_enter(&mhdl->lock);
16046408Sha137994
16056408Sha137994 if (mhdl->status != LDC_MAPPED || mhdl->ldcp == NULL) {
16066408Sha137994 DWARN(DBG_ALL_LDCS,
16076408Sha137994 "i_ldc_mem_acquire_release: not mapped memory\n");
16086408Sha137994 mutex_exit(&mhdl->lock);
16096408Sha137994 return (EINVAL);
16106408Sha137994 }
16116408Sha137994
16126408Sha137994 /* do nothing for direct map */
16136408Sha137994 if (mhdl->mtype == LDC_DIRECT_MAP) {
16146408Sha137994 mutex_exit(&mhdl->lock);
16156408Sha137994 return (0);
16166408Sha137994 }
16176408Sha137994
16186408Sha137994 /* do nothing if COPY_IN+MEM_W and COPY_OUT+MEM_R */
16196408Sha137994 if ((direction == LDC_COPY_IN && (mhdl->perm & LDC_MEM_R) == 0) ||
16206408Sha137994 (direction == LDC_COPY_OUT && (mhdl->perm & LDC_MEM_W) == 0)) {
16216408Sha137994 mutex_exit(&mhdl->lock);
16226408Sha137994 return (0);
16236408Sha137994 }
16246408Sha137994
16256408Sha137994 if (offset >= mhdl->memseg->size ||
16266408Sha137994 (offset + size) > mhdl->memseg->size) {
16276408Sha137994 DWARN(DBG_ALL_LDCS,
16286408Sha137994 "i_ldc_mem_acquire_release: memory out of range\n");
16296408Sha137994 mutex_exit(&mhdl->lock);
16306408Sha137994 return (EINVAL);
16316408Sha137994 }
16326408Sha137994
16336408Sha137994 /* get the channel handle and memory segment */
16346408Sha137994 ldcp = mhdl->ldcp;
16356408Sha137994 memseg = mhdl->memseg;
16366408Sha137994
16376408Sha137994 if (mhdl->mtype == LDC_SHADOW_MAP) {
16386408Sha137994
16396408Sha137994 local_vaddr = memseg->vaddr + offset;
16406408Sha137994 copy_size = size;
16416408Sha137994
16426408Sha137994 /* copy to/from remote from/to local memory */
16436408Sha137994 err = ldc_mem_copy((ldc_handle_t)ldcp, local_vaddr, offset,
16446408Sha137994 ©_size, memseg->cookies, memseg->ncookies,
16456408Sha137994 direction);
16466408Sha137994 if (err || copy_size != size) {
16476408Sha137994 DWARN(ldcp->id,
16486408Sha137994 "i_ldc_mem_acquire_release: copy failed\n");
16496408Sha137994 mutex_exit(&mhdl->lock);
16506408Sha137994 return (err);
16516408Sha137994 }
16526408Sha137994 }
16536408Sha137994
16546408Sha137994 mutex_exit(&mhdl->lock);
16556408Sha137994
16566408Sha137994 return (0);
16576408Sha137994 }
16586408Sha137994
16596408Sha137994 /*
16606408Sha137994 * Ensure that the contents in the remote memory seg are consistent
16616408Sha137994 * with the contents if of local segment
16626408Sha137994 */
16636408Sha137994 int
ldc_mem_acquire(ldc_mem_handle_t mhandle,uint64_t offset,uint64_t size)16646408Sha137994 ldc_mem_acquire(ldc_mem_handle_t mhandle, uint64_t offset, uint64_t size)
16656408Sha137994 {
16666408Sha137994 return (i_ldc_mem_acquire_release(mhandle, LDC_COPY_IN, offset, size));
16676408Sha137994 }
16686408Sha137994
16696408Sha137994
16706408Sha137994 /*
16716408Sha137994 * Ensure that the contents in the local memory seg are consistent
16726408Sha137994 * with the contents if of remote segment
16736408Sha137994 */
16746408Sha137994 int
ldc_mem_release(ldc_mem_handle_t mhandle,uint64_t offset,uint64_t size)16756408Sha137994 ldc_mem_release(ldc_mem_handle_t mhandle, uint64_t offset, uint64_t size)
16766408Sha137994 {
16776408Sha137994 return (i_ldc_mem_acquire_release(mhandle, LDC_COPY_OUT, offset, size));
16786408Sha137994 }
16796408Sha137994
16806408Sha137994 /*
16816408Sha137994 * Allocate a descriptor ring. The size of each each descriptor
16826408Sha137994 * must be 8-byte aligned and the entire ring should be a multiple
16836408Sha137994 * of MMU_PAGESIZE.
16846408Sha137994 */
16856408Sha137994 int
ldc_mem_dring_create(uint32_t len,uint32_t dsize,ldc_dring_handle_t * dhandle)16866408Sha137994 ldc_mem_dring_create(uint32_t len, uint32_t dsize, ldc_dring_handle_t *dhandle)
16876408Sha137994 {
16886408Sha137994 ldc_dring_t *dringp;
16896408Sha137994 size_t size = (dsize * len);
16906408Sha137994
16916408Sha137994 D1(DBG_ALL_LDCS, "ldc_mem_dring_create: len=0x%x, size=0x%x\n",
16926408Sha137994 len, dsize);
16936408Sha137994
16946408Sha137994 if (dhandle == NULL) {
16956408Sha137994 DWARN(DBG_ALL_LDCS, "ldc_mem_dring_create: invalid dhandle\n");
16966408Sha137994 return (EINVAL);
16976408Sha137994 }
16986408Sha137994
16996408Sha137994 if (len == 0) {
17006408Sha137994 DWARN(DBG_ALL_LDCS, "ldc_mem_dring_create: invalid length\n");
17016408Sha137994 return (EINVAL);
17026408Sha137994 }
17036408Sha137994
17046408Sha137994 /* descriptor size should be 8-byte aligned */
17056408Sha137994 if (dsize == 0 || (dsize & 0x7)) {
17066408Sha137994 DWARN(DBG_ALL_LDCS, "ldc_mem_dring_create: invalid size\n");
17076408Sha137994 return (EINVAL);
17086408Sha137994 }
17096408Sha137994
17106408Sha137994 *dhandle = 0;
17116408Sha137994
17126408Sha137994 /* Allocate a desc ring structure */
17136408Sha137994 dringp = kmem_zalloc(sizeof (ldc_dring_t), KM_SLEEP);
17146408Sha137994
17156408Sha137994 /* Initialize dring */
17166408Sha137994 dringp->length = len;
17176408Sha137994 dringp->dsize = dsize;
17186408Sha137994
17196408Sha137994 /* round off to multiple of pagesize */
17206408Sha137994 dringp->size = (size & MMU_PAGEMASK);
17216408Sha137994 if (size & MMU_PAGEOFFSET)
17226408Sha137994 dringp->size += MMU_PAGESIZE;
17236408Sha137994
17246408Sha137994 dringp->status = LDC_UNBOUND;
17256408Sha137994
17266408Sha137994 /* allocate descriptor ring memory */
17276408Sha137994 dringp->base = kmem_zalloc(dringp->size, KM_SLEEP);
17286408Sha137994
17296408Sha137994 /* initialize the desc ring lock */
17306408Sha137994 mutex_init(&dringp->lock, NULL, MUTEX_DRIVER, NULL);
17316408Sha137994
17326408Sha137994 /* Add descriptor ring to the head of global list */
17336408Sha137994 mutex_enter(&ldcssp->lock);
17346408Sha137994 dringp->next = ldcssp->dring_list;
17356408Sha137994 ldcssp->dring_list = dringp;
17366408Sha137994 mutex_exit(&ldcssp->lock);
17376408Sha137994
17386408Sha137994 *dhandle = (ldc_dring_handle_t)dringp;
17396408Sha137994
17406408Sha137994 D1(DBG_ALL_LDCS, "ldc_mem_dring_create: dring allocated\n");
17416408Sha137994
17426408Sha137994 return (0);
17436408Sha137994 }
17446408Sha137994
17456408Sha137994
17466408Sha137994 /*
17476408Sha137994 * Destroy a descriptor ring.
17486408Sha137994 */
17496408Sha137994 int
ldc_mem_dring_destroy(ldc_dring_handle_t dhandle)17506408Sha137994 ldc_mem_dring_destroy(ldc_dring_handle_t dhandle)
17516408Sha137994 {
17526408Sha137994 ldc_dring_t *dringp;
17536408Sha137994 ldc_dring_t *tmp_dringp;
17546408Sha137994
17556408Sha137994 D1(DBG_ALL_LDCS, "ldc_mem_dring_destroy: entered\n");
17566408Sha137994
17576408Sha137994 if (dhandle == NULL) {
17586408Sha137994 DWARN(DBG_ALL_LDCS,
17596408Sha137994 "ldc_mem_dring_destroy: invalid desc ring handle\n");
17606408Sha137994 return (EINVAL);
17616408Sha137994 }
17626408Sha137994 dringp = (ldc_dring_t *)dhandle;
17636408Sha137994
17646408Sha137994 if (dringp->status == LDC_BOUND) {
17656408Sha137994 DWARN(DBG_ALL_LDCS,
17666408Sha137994 "ldc_mem_dring_destroy: desc ring is bound\n");
17676408Sha137994 return (EACCES);
17686408Sha137994 }
17696408Sha137994
17706408Sha137994 mutex_enter(&dringp->lock);
17716408Sha137994 mutex_enter(&ldcssp->lock);
17726408Sha137994
17736408Sha137994 /* remove from linked list - if not bound */
17746408Sha137994 tmp_dringp = ldcssp->dring_list;
17756408Sha137994 if (tmp_dringp == dringp) {
17766408Sha137994 ldcssp->dring_list = dringp->next;
17776408Sha137994 dringp->next = NULL;
17786408Sha137994
17796408Sha137994 } else {
17806408Sha137994 while (tmp_dringp != NULL) {
17816408Sha137994 if (tmp_dringp->next == dringp) {
17826408Sha137994 tmp_dringp->next = dringp->next;
17836408Sha137994 dringp->next = NULL;
17846408Sha137994 break;
17856408Sha137994 }
17866408Sha137994 tmp_dringp = tmp_dringp->next;
17876408Sha137994 }
17886408Sha137994 if (tmp_dringp == NULL) {
17896408Sha137994 DWARN(DBG_ALL_LDCS,
17906408Sha137994 "ldc_mem_dring_destroy: invalid descriptor\n");
17916408Sha137994 mutex_exit(&ldcssp->lock);
17926408Sha137994 mutex_exit(&dringp->lock);
17936408Sha137994 return (EINVAL);
17946408Sha137994 }
17956408Sha137994 }
17966408Sha137994
17976408Sha137994 mutex_exit(&ldcssp->lock);
17986408Sha137994
17996408Sha137994 /* free the descriptor ring */
18006408Sha137994 kmem_free(dringp->base, dringp->size);
18016408Sha137994
18026408Sha137994 mutex_exit(&dringp->lock);
18036408Sha137994
18046408Sha137994 /* destroy dring lock */
18056408Sha137994 mutex_destroy(&dringp->lock);
18066408Sha137994
18076408Sha137994 /* free desc ring object */
18086408Sha137994 kmem_free(dringp, sizeof (ldc_dring_t));
18096408Sha137994
18106408Sha137994 return (0);
18116408Sha137994 }
18126408Sha137994
18136408Sha137994 /*
18146408Sha137994 * Bind a previously allocated dring to a channel. The channel should
18156408Sha137994 * be OPEN in order to bind the ring to the channel. Returns back a
18166408Sha137994 * descriptor ring cookie. The descriptor ring is exported for remote
18176408Sha137994 * access by the client at the other end of the channel. An entry for
18186408Sha137994 * dring pages is stored in map table (via call to ldc_mem_bind_handle).
18196408Sha137994 */
18206408Sha137994 int
ldc_mem_dring_bind(ldc_handle_t handle,ldc_dring_handle_t dhandle,uint8_t mtype,uint8_t perm,ldc_mem_cookie_t * cookie,uint32_t * ccount)18216408Sha137994 ldc_mem_dring_bind(ldc_handle_t handle, ldc_dring_handle_t dhandle,
18226408Sha137994 uint8_t mtype, uint8_t perm, ldc_mem_cookie_t *cookie, uint32_t *ccount)
18236408Sha137994 {
18246408Sha137994 int err;
18256408Sha137994 ldc_chan_t *ldcp;
18266408Sha137994 ldc_dring_t *dringp;
18276408Sha137994 ldc_mem_handle_t mhandle;
18286408Sha137994
18296408Sha137994 /* check to see if channel is initalized */
18306408Sha137994 if (handle == NULL) {
18316408Sha137994 DWARN(DBG_ALL_LDCS,
18326408Sha137994 "ldc_mem_dring_bind: invalid channel handle\n");
18336408Sha137994 return (EINVAL);
18346408Sha137994 }
18356408Sha137994 ldcp = (ldc_chan_t *)handle;
18366408Sha137994
18376408Sha137994 if (dhandle == NULL) {
18386408Sha137994 DWARN(DBG_ALL_LDCS,
18396408Sha137994 "ldc_mem_dring_bind: invalid desc ring handle\n");
18406408Sha137994 return (EINVAL);
18416408Sha137994 }
18426408Sha137994 dringp = (ldc_dring_t *)dhandle;
18436408Sha137994
18446408Sha137994 if (cookie == NULL) {
18456408Sha137994 DWARN(ldcp->id,
18466408Sha137994 "ldc_mem_dring_bind: invalid cookie arg\n");
18476408Sha137994 return (EINVAL);
18486408Sha137994 }
18496408Sha137994
18506845Sha137994 /* ensure the mtype is valid */
18516845Sha137994 if ((mtype & (LDC_SHADOW_MAP|LDC_DIRECT_MAP)) == 0) {
18526845Sha137994 DWARN(ldcp->id, "ldc_mem_dring_bind: invalid map type\n");
18536845Sha137994 return (EINVAL);
18546845Sha137994 }
18556845Sha137994
18566845Sha137994 /* no need to bind as direct map if it's not HV supported or enabled */
18576845Sha137994 if (!ldc_dring_shmem_hv_ok || !ldc_dring_shmem_enabled) {
18586845Sha137994 mtype = LDC_SHADOW_MAP;
18596845Sha137994 }
18606845Sha137994
18616408Sha137994 mutex_enter(&dringp->lock);
18626408Sha137994
18636408Sha137994 if (dringp->status == LDC_BOUND) {
18646408Sha137994 DWARN(DBG_ALL_LDCS,
18656408Sha137994 "ldc_mem_dring_bind: (0x%llx) descriptor ring is bound\n",
18666408Sha137994 ldcp->id);
18676408Sha137994 mutex_exit(&dringp->lock);
18686408Sha137994 return (EINVAL);
18696408Sha137994 }
18706408Sha137994
18716408Sha137994 if ((perm & LDC_MEM_RW) == 0) {
18726408Sha137994 DWARN(DBG_ALL_LDCS,
18736408Sha137994 "ldc_mem_dring_bind: invalid permissions\n");
18746408Sha137994 mutex_exit(&dringp->lock);
18756408Sha137994 return (EINVAL);
18766408Sha137994 }
18776408Sha137994
18786408Sha137994 if ((mtype & (LDC_SHADOW_MAP|LDC_DIRECT_MAP|LDC_IO_MAP)) == 0) {
18796408Sha137994 DWARN(DBG_ALL_LDCS, "ldc_mem_dring_bind: invalid type\n");
18806408Sha137994 mutex_exit(&dringp->lock);
18816408Sha137994 return (EINVAL);
18826408Sha137994 }
18836408Sha137994
18846408Sha137994 dringp->ldcp = ldcp;
18856408Sha137994
18866408Sha137994 /* create an memory handle */
18876408Sha137994 err = ldc_mem_alloc_handle(handle, &mhandle);
18886408Sha137994 if (err || mhandle == NULL) {
18896408Sha137994 DWARN(DBG_ALL_LDCS,
18906408Sha137994 "ldc_mem_dring_bind: (0x%llx) error allocating mhandle\n",
18916408Sha137994 ldcp->id);
18926408Sha137994 mutex_exit(&dringp->lock);
18936408Sha137994 return (err);
18946408Sha137994 }
18956408Sha137994 dringp->mhdl = mhandle;
18966408Sha137994
18976408Sha137994 /* bind the descriptor ring to channel */
18986845Sha137994 err = i_ldc_mem_bind_handle(mhandle, dringp->base, dringp->size,
18996408Sha137994 mtype, perm, cookie, ccount);
19006408Sha137994 if (err) {
19016408Sha137994 DWARN(ldcp->id,
19026408Sha137994 "ldc_mem_dring_bind: (0x%llx) error binding mhandle\n",
19036408Sha137994 ldcp->id);
19046408Sha137994 mutex_exit(&dringp->lock);
19056408Sha137994 return (err);
19066408Sha137994 }
19076408Sha137994
19086408Sha137994 /*
19096408Sha137994 * For now return error if we get more than one cookie
19106408Sha137994 * FUTURE: Return multiple cookies ..
19116408Sha137994 */
19126408Sha137994 if (*ccount > 1) {
19136408Sha137994 (void) ldc_mem_unbind_handle(mhandle);
19146408Sha137994 (void) ldc_mem_free_handle(mhandle);
19156408Sha137994
19166408Sha137994 dringp->ldcp = NULL;
19176408Sha137994 dringp->mhdl = NULL;
19186408Sha137994 *ccount = 0;
19196408Sha137994
19206408Sha137994 mutex_exit(&dringp->lock);
19216408Sha137994 return (EAGAIN);
19226408Sha137994 }
19236408Sha137994
19246408Sha137994 /* Add descriptor ring to channel's exported dring list */
19256408Sha137994 mutex_enter(&ldcp->exp_dlist_lock);
19266408Sha137994 dringp->ch_next = ldcp->exp_dring_list;
19276408Sha137994 ldcp->exp_dring_list = dringp;
19286408Sha137994 mutex_exit(&ldcp->exp_dlist_lock);
19296408Sha137994
19306408Sha137994 dringp->status = LDC_BOUND;
19316408Sha137994
19326408Sha137994 mutex_exit(&dringp->lock);
19336408Sha137994
19346408Sha137994 return (0);
19356408Sha137994 }
19366408Sha137994
19376408Sha137994 /*
19386408Sha137994 * Return the next cookie associated with the specified dring handle
19396408Sha137994 */
19406408Sha137994 int
ldc_mem_dring_nextcookie(ldc_dring_handle_t dhandle,ldc_mem_cookie_t * cookie)19416408Sha137994 ldc_mem_dring_nextcookie(ldc_dring_handle_t dhandle, ldc_mem_cookie_t *cookie)
19426408Sha137994 {
19436408Sha137994 int rv = 0;
19446408Sha137994 ldc_dring_t *dringp;
19456408Sha137994 ldc_chan_t *ldcp;
19466408Sha137994
19476408Sha137994 if (dhandle == NULL) {
19486408Sha137994 DWARN(DBG_ALL_LDCS,
19496408Sha137994 "ldc_mem_dring_nextcookie: invalid desc ring handle\n");
19506408Sha137994 return (EINVAL);
19516408Sha137994 }
19526408Sha137994 dringp = (ldc_dring_t *)dhandle;
19536408Sha137994 mutex_enter(&dringp->lock);
19546408Sha137994
19556408Sha137994 if (dringp->status != LDC_BOUND) {
19566408Sha137994 DWARN(DBG_ALL_LDCS,
19576408Sha137994 "ldc_mem_dring_nextcookie: descriptor ring 0x%llx "
19586408Sha137994 "is not bound\n", dringp);
19596408Sha137994 mutex_exit(&dringp->lock);
19606408Sha137994 return (EINVAL);
19616408Sha137994 }
19626408Sha137994
19636408Sha137994 ldcp = dringp->ldcp;
19646408Sha137994
19656408Sha137994 if (cookie == NULL) {
19666408Sha137994 DWARN(ldcp->id,
19676408Sha137994 "ldc_mem_dring_nextcookie:(0x%llx) invalid cookie arg\n",
19686408Sha137994 ldcp->id);
19696408Sha137994 mutex_exit(&dringp->lock);
19706408Sha137994 return (EINVAL);
19716408Sha137994 }
19726408Sha137994
19736408Sha137994 rv = ldc_mem_nextcookie((ldc_mem_handle_t)dringp->mhdl, cookie);
19746408Sha137994 mutex_exit(&dringp->lock);
19756408Sha137994
19766408Sha137994 return (rv);
19776408Sha137994 }
19786845Sha137994
19796408Sha137994 /*
19806408Sha137994 * Unbind a previously bound dring from a channel.
19816408Sha137994 */
19826408Sha137994 int
ldc_mem_dring_unbind(ldc_dring_handle_t dhandle)19836408Sha137994 ldc_mem_dring_unbind(ldc_dring_handle_t dhandle)
19846408Sha137994 {
19856408Sha137994 ldc_dring_t *dringp;
19866408Sha137994 ldc_dring_t *tmp_dringp;
19876408Sha137994 ldc_chan_t *ldcp;
19886408Sha137994
19896408Sha137994 if (dhandle == NULL) {
19906408Sha137994 DWARN(DBG_ALL_LDCS,
19916408Sha137994 "ldc_mem_dring_unbind: invalid desc ring handle\n");
19926408Sha137994 return (EINVAL);
19936408Sha137994 }
19946408Sha137994 dringp = (ldc_dring_t *)dhandle;
19956408Sha137994
19966408Sha137994 mutex_enter(&dringp->lock);
19976408Sha137994
19986408Sha137994 if (dringp->status == LDC_UNBOUND) {
19996408Sha137994 DWARN(DBG_ALL_LDCS,
20006408Sha137994 "ldc_mem_dring_bind: descriptor ring 0x%llx is unbound\n",
20016408Sha137994 dringp);
20026408Sha137994 mutex_exit(&dringp->lock);
20036408Sha137994 return (EINVAL);
20046408Sha137994 }
20056408Sha137994 ldcp = dringp->ldcp;
20066408Sha137994
20076408Sha137994 mutex_enter(&ldcp->exp_dlist_lock);
20086408Sha137994
20096408Sha137994 tmp_dringp = ldcp->exp_dring_list;
20106408Sha137994 if (tmp_dringp == dringp) {
20116408Sha137994 ldcp->exp_dring_list = dringp->ch_next;
20126408Sha137994 dringp->ch_next = NULL;
20136408Sha137994
20146408Sha137994 } else {
20156408Sha137994 while (tmp_dringp != NULL) {
20166408Sha137994 if (tmp_dringp->ch_next == dringp) {
20176408Sha137994 tmp_dringp->ch_next = dringp->ch_next;
20186408Sha137994 dringp->ch_next = NULL;
20196408Sha137994 break;
20206408Sha137994 }
20216408Sha137994 tmp_dringp = tmp_dringp->ch_next;
20226408Sha137994 }
20236408Sha137994 if (tmp_dringp == NULL) {
20246408Sha137994 DWARN(DBG_ALL_LDCS,
20256408Sha137994 "ldc_mem_dring_unbind: invalid descriptor\n");
20266408Sha137994 mutex_exit(&ldcp->exp_dlist_lock);
20276408Sha137994 mutex_exit(&dringp->lock);
20286408Sha137994 return (EINVAL);
20296408Sha137994 }
20306408Sha137994 }
20316408Sha137994
20326408Sha137994 mutex_exit(&ldcp->exp_dlist_lock);
20336408Sha137994
20346408Sha137994 (void) ldc_mem_unbind_handle((ldc_mem_handle_t)dringp->mhdl);
20356408Sha137994 (void) ldc_mem_free_handle((ldc_mem_handle_t)dringp->mhdl);
20366408Sha137994
20376408Sha137994 dringp->ldcp = NULL;
20386408Sha137994 dringp->mhdl = NULL;
20396408Sha137994 dringp->status = LDC_UNBOUND;
20406408Sha137994
20416408Sha137994 mutex_exit(&dringp->lock);
20426408Sha137994
20436408Sha137994 return (0);
20446408Sha137994 }
20456408Sha137994
20466845Sha137994 #ifdef DEBUG
20476845Sha137994 void
i_ldc_mem_inject_dring_clear(ldc_chan_t * ldcp)20486845Sha137994 i_ldc_mem_inject_dring_clear(ldc_chan_t *ldcp)
20496845Sha137994 {
20506845Sha137994 ldc_dring_t *dp;
20516845Sha137994 ldc_mhdl_t *mhdl;
20526845Sha137994 ldc_mtbl_t *mtbl;
20536845Sha137994 ldc_memseg_t *memseg;
20546845Sha137994 uint64_t cookie_addr;
20556845Sha137994 uint64_t pg_shift, pg_size_code;
20566845Sha137994 int i, rv, retries;
20576845Sha137994
20586845Sha137994 /* has a map table been allocated? */
20596845Sha137994 if ((mtbl = ldcp->mtbl) == NULL)
20606845Sha137994 return;
20616845Sha137994
20626845Sha137994 /* lock the memory table - exclusive access to channel */
20636845Sha137994 mutex_enter(&mtbl->lock);
20646845Sha137994
20656845Sha137994 /* lock the exported dring list */
20666845Sha137994 mutex_enter(&ldcp->exp_dlist_lock);
20676845Sha137994
20686845Sha137994 for (dp = ldcp->exp_dring_list; dp != NULL; dp = dp->ch_next) {
20696845Sha137994 if ((mhdl = (ldc_mhdl_t *)dp->mhdl) == NULL)
20706845Sha137994 continue;
20716845Sha137994
20726845Sha137994 if ((memseg = mhdl->memseg) == NULL)
20736845Sha137994 continue;
20746845Sha137994
20756845Sha137994 /* undo the pages exported */
20766845Sha137994 for (i = 0; i < memseg->npages; i++) {
20776845Sha137994
20786845Sha137994 /* clear the entry from the table */
20796845Sha137994 memseg->pages[i].mte->entry.ll = 0;
20806845Sha137994
20817226Sha137994 pg_size_code = page_szc(MMU_PAGESIZE);
20826845Sha137994 pg_shift = page_get_shift(pg_size_code);
20836845Sha137994 cookie_addr = IDX2COOKIE(memseg->pages[i].index,
20846845Sha137994 pg_size_code, pg_shift);
20856845Sha137994
20866845Sha137994 retries = 0;
20876845Sha137994 do {
20886845Sha137994 rv = hv_ldc_revoke(ldcp->id, cookie_addr,
20896845Sha137994 memseg->pages[i].mte->cookie);
20906845Sha137994
20916845Sha137994 if (rv != H_EWOULDBLOCK)
20926845Sha137994 break;
20936845Sha137994
20946845Sha137994 drv_usecwait(ldc_delay);
20956845Sha137994
20966845Sha137994 } while (retries++ < ldc_max_retries);
20976845Sha137994
20986845Sha137994 if (rv != 0) {
20996845Sha137994 DWARN(ldcp->id,
21006845Sha137994 "i_ldc_mem_inject_dring_clear(): "
21016845Sha137994 "hv_ldc_revoke failed: "
21026845Sha137994 "channel: 0x%lx, cookie addr: 0x%p,"
21036845Sha137994 "cookie: 0x%lx, rv: %d",
21046845Sha137994 ldcp->id, cookie_addr,
21056845Sha137994 memseg->pages[i].mte->cookie, rv);
21066845Sha137994 }
21076845Sha137994
21086845Sha137994 mtbl->num_avail++;
21096845Sha137994 }
21106845Sha137994 }
21116845Sha137994
21126845Sha137994 mutex_exit(&ldcp->exp_dlist_lock);
21136845Sha137994 mutex_exit(&mtbl->lock);
21146845Sha137994 }
21156845Sha137994 #endif
21166845Sha137994
21176408Sha137994 /*
21186408Sha137994 * Get information about the dring. The base address of the descriptor
21196408Sha137994 * ring along with the type and permission are returned back.
21206408Sha137994 */
21216408Sha137994 int
ldc_mem_dring_info(ldc_dring_handle_t dhandle,ldc_mem_info_t * minfo)21226408Sha137994 ldc_mem_dring_info(ldc_dring_handle_t dhandle, ldc_mem_info_t *minfo)
21236408Sha137994 {
21246408Sha137994 ldc_dring_t *dringp;
21256408Sha137994 int rv;
21266408Sha137994
21276408Sha137994 if (dhandle == NULL) {
21286408Sha137994 DWARN(DBG_ALL_LDCS,
21296408Sha137994 "ldc_mem_dring_info: invalid desc ring handle\n");
21306408Sha137994 return (EINVAL);
21316408Sha137994 }
21326408Sha137994 dringp = (ldc_dring_t *)dhandle;
21336408Sha137994
21346408Sha137994 mutex_enter(&dringp->lock);
21356408Sha137994
21366408Sha137994 if (dringp->mhdl) {
21376408Sha137994 rv = ldc_mem_info(dringp->mhdl, minfo);
21386408Sha137994 if (rv) {
21396408Sha137994 DWARN(DBG_ALL_LDCS,
21406408Sha137994 "ldc_mem_dring_info: error reading mem info\n");
21416408Sha137994 mutex_exit(&dringp->lock);
21426408Sha137994 return (rv);
21436408Sha137994 }
21446408Sha137994 } else {
21456408Sha137994 minfo->vaddr = dringp->base;
21466408Sha137994 minfo->raddr = NULL;
21476408Sha137994 minfo->status = dringp->status;
21486408Sha137994 }
21496408Sha137994
21506408Sha137994 mutex_exit(&dringp->lock);
21516408Sha137994
21526408Sha137994 return (0);
21536408Sha137994 }
21546408Sha137994
21556408Sha137994 /*
21566408Sha137994 * Map an exported descriptor ring into the local address space. If the
21576408Sha137994 * descriptor ring was exported for direct map access, a HV call is made
21586408Sha137994 * to allocate a RA range. If the map is done via a shadow copy, local
21596408Sha137994 * shadow memory is allocated.
21606408Sha137994 */
21616408Sha137994 int
ldc_mem_dring_map(ldc_handle_t handle,ldc_mem_cookie_t * cookie,uint32_t ccount,uint32_t len,uint32_t dsize,uint8_t mtype,ldc_dring_handle_t * dhandle)21626408Sha137994 ldc_mem_dring_map(ldc_handle_t handle, ldc_mem_cookie_t *cookie,
21636408Sha137994 uint32_t ccount, uint32_t len, uint32_t dsize, uint8_t mtype,
21646408Sha137994 ldc_dring_handle_t *dhandle)
21656408Sha137994 {
21666408Sha137994 int err;
21676408Sha137994 ldc_chan_t *ldcp = (ldc_chan_t *)handle;
21686408Sha137994 ldc_mem_handle_t mhandle;
21696408Sha137994 ldc_dring_t *dringp;
21706408Sha137994 size_t dring_size;
21716408Sha137994
21726408Sha137994 if (dhandle == NULL) {
21736408Sha137994 DWARN(DBG_ALL_LDCS,
21746408Sha137994 "ldc_mem_dring_map: invalid dhandle\n");
21756408Sha137994 return (EINVAL);
21766408Sha137994 }
21776408Sha137994
21786408Sha137994 /* check to see if channel is initalized */
21796408Sha137994 if (handle == NULL) {
21806408Sha137994 DWARN(DBG_ALL_LDCS,
21816408Sha137994 "ldc_mem_dring_map: invalid channel handle\n");
21826408Sha137994 return (EINVAL);
21836408Sha137994 }
21846408Sha137994 ldcp = (ldc_chan_t *)handle;
21856408Sha137994
21866408Sha137994 if (cookie == NULL) {
21876408Sha137994 DWARN(ldcp->id,
21886408Sha137994 "ldc_mem_dring_map: (0x%llx) invalid cookie\n",
21896408Sha137994 ldcp->id);
21906408Sha137994 return (EINVAL);
21916408Sha137994 }
21926408Sha137994
21936408Sha137994 /* FUTURE: For now we support only one cookie per dring */
21946408Sha137994 ASSERT(ccount == 1);
21956408Sha137994
21966408Sha137994 if (cookie->size < (dsize * len)) {
21976408Sha137994 DWARN(ldcp->id,
21986408Sha137994 "ldc_mem_dring_map: (0x%llx) invalid dsize/len\n",
21996408Sha137994 ldcp->id);
22006408Sha137994 return (EINVAL);
22016408Sha137994 }
22026408Sha137994
22036845Sha137994 /* ensure the mtype is valid */
22046845Sha137994 if ((mtype & (LDC_SHADOW_MAP|LDC_DIRECT_MAP)) == 0) {
22056845Sha137994 DWARN(ldcp->id, "ldc_mem_dring_map: invalid map type\n");
22066845Sha137994 return (EINVAL);
22076845Sha137994 }
22086845Sha137994
22096845Sha137994 /* do not attempt direct map if it's not HV supported or enabled */
22106845Sha137994 if (!ldc_dring_shmem_hv_ok || !ldc_dring_shmem_enabled) {
22116845Sha137994 mtype = LDC_SHADOW_MAP;
22126845Sha137994 }
22136845Sha137994
22146408Sha137994 *dhandle = 0;
22156408Sha137994
22166408Sha137994 /* Allocate an dring structure */
22176408Sha137994 dringp = kmem_zalloc(sizeof (ldc_dring_t), KM_SLEEP);
22186408Sha137994
22196408Sha137994 D1(ldcp->id,
22206408Sha137994 "ldc_mem_dring_map: 0x%x,0x%x,0x%x,0x%llx,0x%llx\n",
22216408Sha137994 mtype, len, dsize, cookie->addr, cookie->size);
22226408Sha137994
22236408Sha137994 /* Initialize dring */
22246408Sha137994 dringp->length = len;
22256408Sha137994 dringp->dsize = dsize;
22266408Sha137994
22276408Sha137994 /* round of to multiple of page size */
22286408Sha137994 dring_size = len * dsize;
22296408Sha137994 dringp->size = (dring_size & MMU_PAGEMASK);
22306408Sha137994 if (dring_size & MMU_PAGEOFFSET)
22316408Sha137994 dringp->size += MMU_PAGESIZE;
22326408Sha137994
22336408Sha137994 dringp->ldcp = ldcp;
22346408Sha137994
22356408Sha137994 /* create an memory handle */
22366408Sha137994 err = ldc_mem_alloc_handle(handle, &mhandle);
22376408Sha137994 if (err || mhandle == NULL) {
22386408Sha137994 DWARN(DBG_ALL_LDCS,
22396408Sha137994 "ldc_mem_dring_map: cannot alloc hdl err=%d\n",
22406408Sha137994 err);
22416408Sha137994 kmem_free(dringp, sizeof (ldc_dring_t));
22426408Sha137994 return (ENOMEM);
22436408Sha137994 }
22446408Sha137994
22456408Sha137994 dringp->mhdl = mhandle;
22466408Sha137994 dringp->base = NULL;
22476408Sha137994
22486408Sha137994 /* map the dring into local memory */
22496845Sha137994 err = i_ldc_mem_map(mhandle, cookie, ccount, mtype, LDC_MEM_RW,
22506408Sha137994 &(dringp->base), NULL);
22516408Sha137994 if (err || dringp->base == NULL) {
22526845Sha137994 DWARN(DBG_ALL_LDCS,
22536408Sha137994 "ldc_mem_dring_map: cannot map desc ring err=%d\n", err);
22546408Sha137994 (void) ldc_mem_free_handle(mhandle);
22556408Sha137994 kmem_free(dringp, sizeof (ldc_dring_t));
22566408Sha137994 return (ENOMEM);
22576408Sha137994 }
22586408Sha137994
22596408Sha137994 /* initialize the desc ring lock */
22606408Sha137994 mutex_init(&dringp->lock, NULL, MUTEX_DRIVER, NULL);
22616408Sha137994
22626408Sha137994 /* Add descriptor ring to channel's imported dring list */
22636408Sha137994 mutex_enter(&ldcp->imp_dlist_lock);
22646408Sha137994 dringp->ch_next = ldcp->imp_dring_list;
22656408Sha137994 ldcp->imp_dring_list = dringp;
22666408Sha137994 mutex_exit(&ldcp->imp_dlist_lock);
22676408Sha137994
22686408Sha137994 dringp->status = LDC_MAPPED;
22696408Sha137994
22706408Sha137994 *dhandle = (ldc_dring_handle_t)dringp;
22716408Sha137994
22726408Sha137994 return (0);
22736408Sha137994 }
22746408Sha137994
22756408Sha137994 /*
22766408Sha137994 * Unmap a descriptor ring. Free shadow memory (if any).
22776408Sha137994 */
22786408Sha137994 int
ldc_mem_dring_unmap(ldc_dring_handle_t dhandle)22796408Sha137994 ldc_mem_dring_unmap(ldc_dring_handle_t dhandle)
22806408Sha137994 {
22816408Sha137994 ldc_dring_t *dringp;
22826408Sha137994 ldc_dring_t *tmp_dringp;
22836408Sha137994 ldc_chan_t *ldcp;
22846408Sha137994
22856408Sha137994 if (dhandle == NULL) {
22866408Sha137994 DWARN(DBG_ALL_LDCS,
22876408Sha137994 "ldc_mem_dring_unmap: invalid desc ring handle\n");
22886408Sha137994 return (EINVAL);
22896408Sha137994 }
22906408Sha137994 dringp = (ldc_dring_t *)dhandle;
22916408Sha137994
22926408Sha137994 if (dringp->status != LDC_MAPPED) {
22936408Sha137994 DWARN(DBG_ALL_LDCS,
22946408Sha137994 "ldc_mem_dring_unmap: not a mapped desc ring\n");
22956408Sha137994 return (EINVAL);
22966408Sha137994 }
22976408Sha137994
22986408Sha137994 mutex_enter(&dringp->lock);
22996408Sha137994
23006408Sha137994 ldcp = dringp->ldcp;
23016408Sha137994
23026408Sha137994 mutex_enter(&ldcp->imp_dlist_lock);
23036408Sha137994
23046408Sha137994 /* find and unlink the desc ring from channel import list */
23056408Sha137994 tmp_dringp = ldcp->imp_dring_list;
23066408Sha137994 if (tmp_dringp == dringp) {
23076408Sha137994 ldcp->imp_dring_list = dringp->ch_next;
23086408Sha137994 dringp->ch_next = NULL;
23096408Sha137994
23106408Sha137994 } else {
23116408Sha137994 while (tmp_dringp != NULL) {
23126408Sha137994 if (tmp_dringp->ch_next == dringp) {
23136408Sha137994 tmp_dringp->ch_next = dringp->ch_next;
23146408Sha137994 dringp->ch_next = NULL;
23156408Sha137994 break;
23166408Sha137994 }
23176408Sha137994 tmp_dringp = tmp_dringp->ch_next;
23186408Sha137994 }
23196408Sha137994 if (tmp_dringp == NULL) {
23206408Sha137994 DWARN(DBG_ALL_LDCS,
23216408Sha137994 "ldc_mem_dring_unmap: invalid descriptor\n");
23226408Sha137994 mutex_exit(&ldcp->imp_dlist_lock);
23236408Sha137994 mutex_exit(&dringp->lock);
23246408Sha137994 return (EINVAL);
23256408Sha137994 }
23266408Sha137994 }
23276408Sha137994
23286408Sha137994 mutex_exit(&ldcp->imp_dlist_lock);
23296408Sha137994
23306408Sha137994 /* do a LDC memory handle unmap and free */
23316408Sha137994 (void) ldc_mem_unmap(dringp->mhdl);
23326408Sha137994 (void) ldc_mem_free_handle((ldc_mem_handle_t)dringp->mhdl);
23336408Sha137994
23346408Sha137994 dringp->status = 0;
23356408Sha137994 dringp->ldcp = NULL;
23366408Sha137994
23376408Sha137994 mutex_exit(&dringp->lock);
23386408Sha137994
23396408Sha137994 /* destroy dring lock */
23406408Sha137994 mutex_destroy(&dringp->lock);
23416408Sha137994
23426408Sha137994 /* free desc ring object */
23436408Sha137994 kmem_free(dringp, sizeof (ldc_dring_t));
23446408Sha137994
23456408Sha137994 return (0);
23466408Sha137994 }
23476408Sha137994
23486408Sha137994 /*
23496408Sha137994 * Internal entry point for descriptor ring access entry consistency
23506408Sha137994 * semantics. Acquire copies the contents of the remote descriptor ring
23516408Sha137994 * into the local shadow copy. The release operation copies the local
23526408Sha137994 * contents into the remote dring. The start and end locations specify
23536408Sha137994 * bounds for the entries being synchronized.
23546408Sha137994 */
23556408Sha137994 static int
i_ldc_dring_acquire_release(ldc_dring_handle_t dhandle,uint8_t direction,uint64_t start,uint64_t end)23566408Sha137994 i_ldc_dring_acquire_release(ldc_dring_handle_t dhandle,
23576408Sha137994 uint8_t direction, uint64_t start, uint64_t end)
23586408Sha137994 {
23596408Sha137994 int err;
23606408Sha137994 ldc_dring_t *dringp;
23616408Sha137994 ldc_chan_t *ldcp;
23626845Sha137994 ldc_mhdl_t *mhdl;
23636408Sha137994 uint64_t soff;
23646408Sha137994 size_t copy_size;
23656408Sha137994
23666408Sha137994 if (dhandle == NULL) {
23676408Sha137994 DWARN(DBG_ALL_LDCS,
23686408Sha137994 "i_ldc_dring_acquire_release: invalid desc ring handle\n");
23696408Sha137994 return (EINVAL);
23706408Sha137994 }
23716408Sha137994 dringp = (ldc_dring_t *)dhandle;
23726408Sha137994 mutex_enter(&dringp->lock);
23736408Sha137994
23746408Sha137994 if (dringp->status != LDC_MAPPED || dringp->ldcp == NULL) {
23756408Sha137994 DWARN(DBG_ALL_LDCS,
23766408Sha137994 "i_ldc_dring_acquire_release: not a mapped desc ring\n");
23776408Sha137994 mutex_exit(&dringp->lock);
23786408Sha137994 return (EINVAL);
23796408Sha137994 }
23806408Sha137994
23816408Sha137994 if (start >= dringp->length || end >= dringp->length) {
23826408Sha137994 DWARN(DBG_ALL_LDCS,
23836408Sha137994 "i_ldc_dring_acquire_release: index out of range\n");
23846408Sha137994 mutex_exit(&dringp->lock);
23856408Sha137994 return (EINVAL);
23866408Sha137994 }
23876408Sha137994
23886845Sha137994 mhdl = (ldc_mhdl_t *)dringp->mhdl;
23896845Sha137994 if (mhdl == NULL) {
23906845Sha137994 DWARN(DBG_ALL_LDCS,
23916845Sha137994 "i_ldc_dring_acquire_release: invalid memory handle\n");
23926845Sha137994 mutex_exit(&dringp->lock);
23936845Sha137994 return (EINVAL);
23946845Sha137994 }
23956845Sha137994
23966845Sha137994 if (mhdl->mtype != LDC_SHADOW_MAP) {
23976845Sha137994 DWARN(DBG_ALL_LDCS,
23986845Sha137994 "i_ldc_dring_acquire_release: invalid mtype: %d\n",
23996845Sha137994 mhdl->mtype);
24006845Sha137994 mutex_exit(&dringp->lock);
24016845Sha137994 return (EINVAL);
24026845Sha137994 }
24036845Sha137994
24046408Sha137994 /* get the channel handle */
24056408Sha137994 ldcp = dringp->ldcp;
24066408Sha137994
24076408Sha137994 copy_size = (start <= end) ? (((end - start) + 1) * dringp->dsize) :
24086408Sha137994 ((dringp->length - start) * dringp->dsize);
24096408Sha137994
24106408Sha137994 /* Calculate the relative offset for the first desc */
24116408Sha137994 soff = (start * dringp->dsize);
24126408Sha137994
24136408Sha137994 /* copy to/from remote from/to local memory */
24146408Sha137994 D1(ldcp->id, "i_ldc_dring_acquire_release: c1 off=0x%llx sz=0x%llx\n",
24156408Sha137994 soff, copy_size);
24166408Sha137994 err = i_ldc_mem_acquire_release((ldc_mem_handle_t)dringp->mhdl,
24176408Sha137994 direction, soff, copy_size);
24186408Sha137994 if (err) {
24196408Sha137994 DWARN(ldcp->id,
24206408Sha137994 "i_ldc_dring_acquire_release: copy failed\n");
24216408Sha137994 mutex_exit(&dringp->lock);
24226408Sha137994 return (err);
24236408Sha137994 }
24246408Sha137994
24256408Sha137994 /* do the balance */
24266408Sha137994 if (start > end) {
24276408Sha137994 copy_size = ((end + 1) * dringp->dsize);
24286408Sha137994 soff = 0;
24296408Sha137994
24306408Sha137994 /* copy to/from remote from/to local memory */
24316408Sha137994 D1(ldcp->id, "i_ldc_dring_acquire_release: c2 "
24326408Sha137994 "off=0x%llx sz=0x%llx\n", soff, copy_size);
24336408Sha137994 err = i_ldc_mem_acquire_release((ldc_mem_handle_t)dringp->mhdl,
24346408Sha137994 direction, soff, copy_size);
24356408Sha137994 if (err) {
24366408Sha137994 DWARN(ldcp->id,
24376408Sha137994 "i_ldc_dring_acquire_release: copy failed\n");
24386408Sha137994 mutex_exit(&dringp->lock);
24396408Sha137994 return (err);
24406408Sha137994 }
24416408Sha137994 }
24426408Sha137994
24436408Sha137994 mutex_exit(&dringp->lock);
24446408Sha137994
24456408Sha137994 return (0);
24466408Sha137994 }
24476408Sha137994
24486408Sha137994 /*
24496408Sha137994 * Ensure that the contents in the local dring are consistent
24506408Sha137994 * with the contents if of remote dring
24516408Sha137994 */
24526408Sha137994 int
ldc_mem_dring_acquire(ldc_dring_handle_t dhandle,uint64_t start,uint64_t end)24536408Sha137994 ldc_mem_dring_acquire(ldc_dring_handle_t dhandle, uint64_t start, uint64_t end)
24546408Sha137994 {
24556408Sha137994 return (i_ldc_dring_acquire_release(dhandle, LDC_COPY_IN, start, end));
24566408Sha137994 }
24576408Sha137994
24586408Sha137994 /*
24596408Sha137994 * Ensure that the contents in the remote dring are consistent
24606408Sha137994 * with the contents if of local dring
24616408Sha137994 */
24626408Sha137994 int
ldc_mem_dring_release(ldc_dring_handle_t dhandle,uint64_t start,uint64_t end)24636408Sha137994 ldc_mem_dring_release(ldc_dring_handle_t dhandle, uint64_t start, uint64_t end)
24646408Sha137994 {
24656408Sha137994 return (i_ldc_dring_acquire_release(dhandle, LDC_COPY_OUT, start, end));
24666408Sha137994 }
2467