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