11991Sheppo /* 21991Sheppo * CDDL HEADER START 31991Sheppo * 41991Sheppo * The contents of this file are subject to the terms of the 51991Sheppo * Common Development and Distribution License (the "License"). 61991Sheppo * You may not use this file except in compliance with the License. 71991Sheppo * 81991Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91991Sheppo * or http://www.opensolaris.org/os/licensing. 101991Sheppo * See the License for the specific language governing permissions 111991Sheppo * and limitations under the License. 121991Sheppo * 131991Sheppo * When distributing Covered Code, include this CDDL HEADER in each 141991Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151991Sheppo * If applicable, add the following below this CDDL HEADER, with the 161991Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 171991Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 181991Sheppo * 191991Sheppo * CDDL HEADER END 201991Sheppo */ 211991Sheppo 221991Sheppo /* 23*5944Sha137994 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 241991Sheppo * Use is subject to license terms. 251991Sheppo */ 261991Sheppo 271991Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 281991Sheppo 291991Sheppo /* 302410Slm66018 * sun4v LDC Link Layer 311991Sheppo */ 321991Sheppo #include <sys/types.h> 331991Sheppo #include <sys/file.h> 341991Sheppo #include <sys/errno.h> 351991Sheppo #include <sys/open.h> 361991Sheppo #include <sys/cred.h> 371991Sheppo #include <sys/kmem.h> 381991Sheppo #include <sys/conf.h> 391991Sheppo #include <sys/cmn_err.h> 401991Sheppo #include <sys/ksynch.h> 411991Sheppo #include <sys/modctl.h> 421991Sheppo #include <sys/stat.h> /* needed for S_IFBLK and S_IFCHR */ 431991Sheppo #include <sys/debug.h> 441991Sheppo #include <sys/types.h> 451991Sheppo #include <sys/cred.h> 461991Sheppo #include <sys/promif.h> 471991Sheppo #include <sys/ddi.h> 481991Sheppo #include <sys/sunddi.h> 491991Sheppo #include <sys/cyclic.h> 501991Sheppo #include <sys/machsystm.h> 511991Sheppo #include <sys/vm.h> 521991Sheppo #include <sys/cpu.h> 531991Sheppo #include <sys/intreg.h> 541991Sheppo #include <sys/machcpuvar.h> 552531Snarayan #include <sys/mmu.h> 562531Snarayan #include <sys/pte.h> 572531Snarayan #include <vm/hat.h> 582531Snarayan #include <vm/as.h> 592531Snarayan #include <vm/hat_sfmmu.h> 602531Snarayan #include <sys/vm_machparam.h> 612531Snarayan #include <vm/seg_kmem.h> 622531Snarayan #include <vm/seg_kpm.h> 631991Sheppo #include <sys/note.h> 641991Sheppo #include <sys/ivintr.h> 651991Sheppo #include <sys/hypervisor_api.h> 661991Sheppo #include <sys/ldc.h> 671991Sheppo #include <sys/ldc_impl.h> 681991Sheppo #include <sys/cnex.h> 691991Sheppo #include <sys/hsvc.h> 70*5944Sha137994 #include <sys/sdt.h> 711991Sheppo 721991Sheppo /* Core internal functions */ 731991Sheppo static int i_ldc_h2v_error(int h_error); 741991Sheppo static int i_ldc_txq_reconf(ldc_chan_t *ldcp); 752793Slm66018 static int i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset); 762841Snarayan static int i_ldc_rxq_drain(ldc_chan_t *ldcp); 771991Sheppo static void i_ldc_reset_state(ldc_chan_t *ldcp); 782793Slm66018 static void i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset); 791991Sheppo 801991Sheppo static int i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail); 814690Snarayan static void i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head); 821991Sheppo static int i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail); 831991Sheppo static int i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head); 841991Sheppo static int i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype, 851991Sheppo uint8_t ctrlmsg); 861991Sheppo 87*5944Sha137994 static int i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head); 88*5944Sha137994 static void i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head); 89*5944Sha137994 static uint64_t i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, 90*5944Sha137994 uint64_t *tail, uint64_t *link_state); 91*5944Sha137994 static uint64_t i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, 92*5944Sha137994 uint64_t *tail, uint64_t *link_state); 93*5944Sha137994 static int i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head, 94*5944Sha137994 uint64_t rx_tail); 95*5944Sha137994 static uint_t i_ldc_chkq(ldc_chan_t *ldcp); 96*5944Sha137994 971991Sheppo /* Interrupt handling functions */ 981991Sheppo static uint_t i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2); 991991Sheppo static uint_t i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2); 100*5944Sha137994 static uint_t i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client, 101*5944Sha137994 uint64_t *notify_event); 1021991Sheppo static void i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype); 1031991Sheppo 1041991Sheppo /* Read method functions */ 1051991Sheppo static int i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep); 1061991Sheppo static int i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp, 1071991Sheppo size_t *sizep); 1081991Sheppo static int i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp, 1091991Sheppo size_t *sizep); 1101991Sheppo 1111991Sheppo /* Write method functions */ 1121991Sheppo static int i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t target_bufp, 1131991Sheppo size_t *sizep); 1141991Sheppo static int i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t target_bufp, 1151991Sheppo size_t *sizep); 1161991Sheppo static int i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t target_bufp, 1171991Sheppo size_t *sizep); 1181991Sheppo 1191991Sheppo /* Pkt processing internal functions */ 1201991Sheppo static int i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg); 1211991Sheppo static int i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg); 1221991Sheppo static int i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg); 1231991Sheppo static int i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg); 1241991Sheppo static int i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg); 1251991Sheppo static int i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg); 1261991Sheppo static int i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg); 1271991Sheppo 1281991Sheppo /* Memory synchronization internal functions */ 1291991Sheppo static int i_ldc_mem_acquire_release(ldc_mem_handle_t mhandle, 1301991Sheppo uint8_t direction, uint64_t offset, size_t size); 1311991Sheppo static int i_ldc_dring_acquire_release(ldc_dring_handle_t dhandle, 1321991Sheppo uint8_t direction, uint64_t start, uint64_t end); 1331991Sheppo 1341991Sheppo /* LDC Version */ 1351991Sheppo static ldc_ver_t ldc_versions[] = { {1, 0} }; 1361991Sheppo 1371991Sheppo /* number of supported versions */ 1381991Sheppo #define LDC_NUM_VERS (sizeof (ldc_versions) / sizeof (ldc_versions[0])) 1391991Sheppo 140*5944Sha137994 /* Invalid value for the ldc_chan_t rx_ack_head field */ 141*5944Sha137994 #define ACKPEEK_HEAD_INVALID ((uint64_t)-1) 142*5944Sha137994 143*5944Sha137994 1441991Sheppo /* Module State Pointer */ 1451991Sheppo static ldc_soft_state_t *ldcssp; 1461991Sheppo 1471991Sheppo static struct modldrv md = { 1481991Sheppo &mod_miscops, /* This is a misc module */ 1491991Sheppo "sun4v LDC module v%I%", /* Name of the module */ 1501991Sheppo }; 1511991Sheppo 1521991Sheppo static struct modlinkage ml = { 1531991Sheppo MODREV_1, 1541991Sheppo &md, 1551991Sheppo NULL 1561991Sheppo }; 1571991Sheppo 1581991Sheppo static uint64_t ldc_sup_minor; /* Supported minor number */ 1591991Sheppo static hsvc_info_t ldc_hsvc = { 1601991Sheppo HSVC_REV_1, NULL, HSVC_GROUP_LDC, 1, 0, "ldc" 1611991Sheppo }; 1621991Sheppo 1632531Snarayan /* 1642531Snarayan * LDC framework supports mapping remote domain's memory 1652531Snarayan * either directly or via shadow memory pages. Default 1662531Snarayan * support is currently implemented via shadow copy. 1672531Snarayan * Direct map can be enabled by setting 'ldc_shmem_enabled' 1682531Snarayan */ 1692531Snarayan int ldc_shmem_enabled = 0; 1702410Slm66018 1712032Slm66018 /* 1722410Slm66018 * The no. of MTU size messages that can be stored in 1732410Slm66018 * the LDC Tx queue. The number of Tx queue entries is 1742410Slm66018 * then computed as (mtu * mtu_msgs)/sizeof(queue_entry) 1752410Slm66018 */ 1762410Slm66018 uint64_t ldc_mtu_msgs = LDC_MTU_MSGS; 1772410Slm66018 1782410Slm66018 /* 1792410Slm66018 * The minimum queue length. This is the size of the smallest 1802410Slm66018 * LDC queue. If the computed value is less than this default, 1812410Slm66018 * the queue length is rounded up to 'ldc_queue_entries'. 1822410Slm66018 */ 1832410Slm66018 uint64_t ldc_queue_entries = LDC_QUEUE_ENTRIES; 1842410Slm66018 1852410Slm66018 /* 186*5944Sha137994 * The length of the reliable-mode data queue in terms of the LDC 187*5944Sha137994 * receive queue length. i.e., the number of times larger than the 188*5944Sha137994 * LDC receive queue that the data queue should be. The HV receive 189*5944Sha137994 * queue is required to be a power of 2 and this implementation 190*5944Sha137994 * assumes the data queue will also be a power of 2. By making the 191*5944Sha137994 * multiplier a power of 2, we ensure the data queue will be a 192*5944Sha137994 * power of 2. We use a multiplier because the receive queue is 193*5944Sha137994 * sized to be sane relative to the MTU and the same is needed for 194*5944Sha137994 * the data queue. 195*5944Sha137994 */ 196*5944Sha137994 uint64_t ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER; 197*5944Sha137994 198*5944Sha137994 /* 1992410Slm66018 * Pages exported for remote access over each channel is 2002410Slm66018 * maintained in a table registered with the Hypervisor. 2012410Slm66018 * The default number of entries in the table is set to 2022410Slm66018 * 'ldc_mtbl_entries'. 2032410Slm66018 */ 2042410Slm66018 uint64_t ldc_maptable_entries = LDC_MTBL_ENTRIES; 2052410Slm66018 2062410Slm66018 /* 2072410Slm66018 * LDC retry count and delay - when the HV returns EWOULDBLOCK 2082410Slm66018 * the operation is retried 'ldc_max_retries' times with a 2092410Slm66018 * wait of 'ldc_delay' usecs between each retry. 2102032Slm66018 */ 2112032Slm66018 int ldc_max_retries = LDC_MAX_RETRIES; 2122032Slm66018 clock_t ldc_delay = LDC_DELAY; 2132032Slm66018 2143151Ssg70180 /* 2153151Ssg70180 * delay between each retry of channel unregistration in 2163151Ssg70180 * ldc_close(), to wait for pending interrupts to complete. 2173151Ssg70180 */ 2183151Ssg70180 clock_t ldc_close_delay = LDC_CLOSE_DELAY; 2193151Ssg70180 2201991Sheppo #ifdef DEBUG 2211991Sheppo 2221991Sheppo /* 2231991Sheppo * Print debug messages 2241991Sheppo * 2251991Sheppo * set ldcdbg to 0x7 for enabling all msgs 2261991Sheppo * 0x4 - Warnings 2271991Sheppo * 0x2 - All debug messages 2281991Sheppo * 0x1 - Minimal debug messages 2291991Sheppo * 2301991Sheppo * set ldcdbgchan to the channel number you want to debug 2311991Sheppo * setting it to -1 prints debug messages for all channels 2321991Sheppo * NOTE: ldcdbgchan has no effect on error messages 2331991Sheppo */ 2341991Sheppo 2351991Sheppo #define DBG_ALL_LDCS -1 2361991Sheppo 2371991Sheppo int ldcdbg = 0x0; 2381991Sheppo int64_t ldcdbgchan = DBG_ALL_LDCS; 2393560Snarayan uint64_t ldc_inject_err_flag = 0; 2401991Sheppo 2411991Sheppo static void 2421991Sheppo ldcdebug(int64_t id, const char *fmt, ...) 2431991Sheppo { 2441991Sheppo char buf[512]; 2451991Sheppo va_list ap; 2461991Sheppo 2471991Sheppo /* 2481991Sheppo * Do not return if, 2491991Sheppo * caller wants to print it anyway - (id == DBG_ALL_LDCS) 2501991Sheppo * debug channel is set to all LDCs - (ldcdbgchan == DBG_ALL_LDCS) 2511991Sheppo * debug channel = caller specified channel 2521991Sheppo */ 2531991Sheppo if ((id != DBG_ALL_LDCS) && 2541991Sheppo (ldcdbgchan != DBG_ALL_LDCS) && 2551991Sheppo (ldcdbgchan != id)) { 2561991Sheppo return; 2571991Sheppo } 2581991Sheppo 2591991Sheppo va_start(ap, fmt); 2601991Sheppo (void) vsprintf(buf, fmt, ap); 2611991Sheppo va_end(ap); 2621991Sheppo 2632793Slm66018 cmn_err(CE_CONT, "?%s", buf); 2642793Slm66018 } 2652793Slm66018 2663560Snarayan #define LDC_ERR_RESET 0x1 2673560Snarayan #define LDC_ERR_PKTLOSS 0x2 268*5944Sha137994 #define LDC_ERR_DQFULL 0x4 2693560Snarayan 2702793Slm66018 static boolean_t 2713560Snarayan ldc_inject_error(ldc_chan_t *ldcp, uint64_t error) 2722793Slm66018 { 2732793Slm66018 if ((ldcdbgchan != DBG_ALL_LDCS) && (ldcdbgchan != ldcp->id)) 2742793Slm66018 return (B_FALSE); 2752793Slm66018 2763560Snarayan if ((ldc_inject_err_flag & error) == 0) 2772793Slm66018 return (B_FALSE); 2782793Slm66018 2792793Slm66018 /* clear the injection state */ 2803560Snarayan ldc_inject_err_flag &= ~error; 2812793Slm66018 2822793Slm66018 return (B_TRUE); 2831991Sheppo } 2841991Sheppo 2851991Sheppo #define D1 \ 2861991Sheppo if (ldcdbg & 0x01) \ 2871991Sheppo ldcdebug 2881991Sheppo 2891991Sheppo #define D2 \ 2901991Sheppo if (ldcdbg & 0x02) \ 2911991Sheppo ldcdebug 2921991Sheppo 2931991Sheppo #define DWARN \ 2941991Sheppo if (ldcdbg & 0x04) \ 2951991Sheppo ldcdebug 2961991Sheppo 2971991Sheppo #define DUMP_PAYLOAD(id, addr) \ 2981991Sheppo { \ 2991991Sheppo char buf[65*3]; \ 3001991Sheppo int i; \ 3011991Sheppo uint8_t *src = (uint8_t *)addr; \ 3021991Sheppo for (i = 0; i < 64; i++, src++) \ 3031991Sheppo (void) sprintf(&buf[i * 3], "|%02x", *src); \ 3041991Sheppo (void) sprintf(&buf[i * 3], "|\n"); \ 3051991Sheppo D2((id), "payload: %s", buf); \ 3061991Sheppo } 3071991Sheppo 3081991Sheppo #define DUMP_LDC_PKT(c, s, addr) \ 3091991Sheppo { \ 3101991Sheppo ldc_msg_t *msg = (ldc_msg_t *)(addr); \ 3111991Sheppo uint32_t mid = ((c)->mode != LDC_MODE_RAW) ? msg->seqid : 0; \ 3121991Sheppo if (msg->type == LDC_DATA) { \ 3131991Sheppo D2((c)->id, "%s: msg%d (/%x/%x/%x/,env[%c%c,sz=%d])", \ 3141991Sheppo (s), mid, msg->type, msg->stype, msg->ctrl, \ 3151991Sheppo (msg->env & LDC_FRAG_START) ? 'B' : ' ', \ 3161991Sheppo (msg->env & LDC_FRAG_STOP) ? 'E' : ' ', \ 3171991Sheppo (msg->env & LDC_LEN_MASK)); \ 3181991Sheppo } else { \ 3191991Sheppo D2((c)->id, "%s: msg%d (/%x/%x/%x/,env=%x)", (s), \ 3201991Sheppo mid, msg->type, msg->stype, msg->ctrl, msg->env); \ 3211991Sheppo } \ 3221991Sheppo } 3231991Sheppo 3243560Snarayan #define LDC_INJECT_RESET(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_RESET) 3253560Snarayan #define LDC_INJECT_PKTLOSS(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_PKTLOSS) 326*5944Sha137994 #define LDC_INJECT_DQFULL(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_DQFULL) 3272793Slm66018 3281991Sheppo #else 3291991Sheppo 3301991Sheppo #define DBG_ALL_LDCS -1 3311991Sheppo 3321991Sheppo #define D1 3331991Sheppo #define D2 3341991Sheppo #define DWARN 3351991Sheppo 3361991Sheppo #define DUMP_PAYLOAD(id, addr) 3371991Sheppo #define DUMP_LDC_PKT(c, s, addr) 3381991Sheppo 3392793Slm66018 #define LDC_INJECT_RESET(_ldcp) (B_FALSE) 3403560Snarayan #define LDC_INJECT_PKTLOSS(_ldcp) (B_FALSE) 341*5944Sha137994 #define LDC_INJECT_DQFULL(_ldcp) (B_FALSE) 3422793Slm66018 3431991Sheppo #endif 3441991Sheppo 345*5944Sha137994 /* 346*5944Sha137994 * dtrace SDT probes to ease tracing of the rx data queue and HV queue 347*5944Sha137994 * lengths. Just pass the head, tail, and entries values so that the 348*5944Sha137994 * length can be calculated in a dtrace script when the probe is enabled. 349*5944Sha137994 */ 350*5944Sha137994 #define TRACE_RXDQ_LENGTH(ldcp) \ 351*5944Sha137994 DTRACE_PROBE4(rxdq__size, \ 352*5944Sha137994 uint64_t, ldcp->id, \ 353*5944Sha137994 uint64_t, ldcp->rx_dq_head, \ 354*5944Sha137994 uint64_t, ldcp->rx_dq_tail, \ 355*5944Sha137994 uint64_t, ldcp->rx_dq_entries) 356*5944Sha137994 357*5944Sha137994 #define TRACE_RXHVQ_LENGTH(ldcp, head, tail) \ 358*5944Sha137994 DTRACE_PROBE4(rxhvq__size, \ 359*5944Sha137994 uint64_t, ldcp->id, \ 360*5944Sha137994 uint64_t, head, \ 361*5944Sha137994 uint64_t, tail, \ 362*5944Sha137994 uint64_t, ldcp->rx_q_entries) 363*5944Sha137994 364*5944Sha137994 /* A dtrace SDT probe to ease tracing of data queue copy operations */ 365*5944Sha137994 #define TRACE_RXDQ_COPY(ldcp, bytes) \ 366*5944Sha137994 DTRACE_PROBE2(rxdq__copy, uint64_t, ldcp->id, uint64_t, bytes) \ 367*5944Sha137994 368*5944Sha137994 /* The amount of contiguous space at the tail of the queue */ 369*5944Sha137994 #define Q_CONTIG_SPACE(head, tail, size) \ 370*5944Sha137994 ((head) <= (tail) ? ((size) - (tail)) : \ 371*5944Sha137994 ((head) - (tail) - LDC_PACKET_SIZE)) 372*5944Sha137994 3731991Sheppo #define ZERO_PKT(p) \ 3741991Sheppo bzero((p), sizeof (ldc_msg_t)); 3751991Sheppo 3761991Sheppo #define IDX2COOKIE(idx, pg_szc, pg_shift) \ 3771991Sheppo (((pg_szc) << LDC_COOKIE_PGSZC_SHIFT) | ((idx) << (pg_shift))) 3781991Sheppo 3791991Sheppo int 3801991Sheppo _init(void) 3811991Sheppo { 3821991Sheppo int status; 3831991Sheppo 3841991Sheppo status = hsvc_register(&ldc_hsvc, &ldc_sup_minor); 3851991Sheppo if (status != 0) { 3864423Sjb145095 cmn_err(CE_NOTE, "!%s: cannot negotiate hypervisor LDC services" 3871991Sheppo " group: 0x%lx major: %ld minor: %ld errno: %d", 3881991Sheppo ldc_hsvc.hsvc_modname, ldc_hsvc.hsvc_group, 3891991Sheppo ldc_hsvc.hsvc_major, ldc_hsvc.hsvc_minor, status); 3901991Sheppo return (-1); 3911991Sheppo } 3921991Sheppo 3931991Sheppo /* allocate soft state structure */ 3941991Sheppo ldcssp = kmem_zalloc(sizeof (ldc_soft_state_t), KM_SLEEP); 3951991Sheppo 3961991Sheppo /* Link the module into the system */ 3971991Sheppo status = mod_install(&ml); 3981991Sheppo if (status != 0) { 3991991Sheppo kmem_free(ldcssp, sizeof (ldc_soft_state_t)); 4001991Sheppo return (status); 4011991Sheppo } 4021991Sheppo 4031991Sheppo /* Initialize the LDC state structure */ 4041991Sheppo mutex_init(&ldcssp->lock, NULL, MUTEX_DRIVER, NULL); 4051991Sheppo 4061991Sheppo mutex_enter(&ldcssp->lock); 4071991Sheppo 4082531Snarayan /* Create a cache for memory handles */ 4092531Snarayan ldcssp->memhdl_cache = kmem_cache_create("ldc_memhdl_cache", 4102531Snarayan sizeof (ldc_mhdl_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 4112531Snarayan if (ldcssp->memhdl_cache == NULL) { 4122531Snarayan DWARN(DBG_ALL_LDCS, "_init: ldc_memhdl cache create failed\n"); 4132531Snarayan mutex_exit(&ldcssp->lock); 4142531Snarayan return (-1); 4152531Snarayan } 4162531Snarayan 4172531Snarayan /* Create cache for memory segment structures */ 4182531Snarayan ldcssp->memseg_cache = kmem_cache_create("ldc_memseg_cache", 4192531Snarayan sizeof (ldc_memseg_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 4202531Snarayan if (ldcssp->memseg_cache == NULL) { 4212531Snarayan DWARN(DBG_ALL_LDCS, "_init: ldc_memseg cache create failed\n"); 4222531Snarayan mutex_exit(&ldcssp->lock); 4232531Snarayan return (-1); 4242531Snarayan } 4252531Snarayan 4262531Snarayan 4271991Sheppo ldcssp->channel_count = 0; 4281991Sheppo ldcssp->channels_open = 0; 4291991Sheppo ldcssp->chan_list = NULL; 4301991Sheppo ldcssp->dring_list = NULL; 4311991Sheppo 4321991Sheppo mutex_exit(&ldcssp->lock); 4331991Sheppo 4341991Sheppo return (0); 4351991Sheppo } 4361991Sheppo 4371991Sheppo int 4381991Sheppo _info(struct modinfo *modinfop) 4391991Sheppo { 4401991Sheppo /* Report status of the dynamically loadable driver module */ 4411991Sheppo return (mod_info(&ml, modinfop)); 4421991Sheppo } 4431991Sheppo 4441991Sheppo int 4451991Sheppo _fini(void) 4461991Sheppo { 4471991Sheppo int rv, status; 4484690Snarayan ldc_chan_t *tmp_ldcp, *ldcp; 4494690Snarayan ldc_dring_t *tmp_dringp, *dringp; 4501991Sheppo ldc_mem_info_t minfo; 4511991Sheppo 4521991Sheppo /* Unlink the driver module from the system */ 4531991Sheppo status = mod_remove(&ml); 4541991Sheppo if (status) { 4551991Sheppo DWARN(DBG_ALL_LDCS, "_fini: mod_remove failed\n"); 4561991Sheppo return (EIO); 4571991Sheppo } 4581991Sheppo 4591991Sheppo /* Free descriptor rings */ 4601991Sheppo dringp = ldcssp->dring_list; 4611991Sheppo while (dringp != NULL) { 4624690Snarayan tmp_dringp = dringp->next; 4631991Sheppo 4641991Sheppo rv = ldc_mem_dring_info((ldc_dring_handle_t)dringp, &minfo); 4651991Sheppo if (rv == 0 && minfo.status != LDC_UNBOUND) { 4661991Sheppo if (minfo.status == LDC_BOUND) { 4671991Sheppo (void) ldc_mem_dring_unbind( 4684690Snarayan (ldc_dring_handle_t)dringp); 4691991Sheppo } 4701991Sheppo if (minfo.status == LDC_MAPPED) { 4711991Sheppo (void) ldc_mem_dring_unmap( 4724690Snarayan (ldc_dring_handle_t)dringp); 4731991Sheppo } 4741991Sheppo } 4751991Sheppo 4761991Sheppo (void) ldc_mem_dring_destroy((ldc_dring_handle_t)dringp); 4774690Snarayan dringp = tmp_dringp; 4781991Sheppo } 4791991Sheppo ldcssp->dring_list = NULL; 4801991Sheppo 4814690Snarayan /* close and finalize channels */ 4824690Snarayan ldcp = ldcssp->chan_list; 4834690Snarayan while (ldcp != NULL) { 4844690Snarayan tmp_ldcp = ldcp->next; 4854690Snarayan 4864690Snarayan (void) ldc_close((ldc_handle_t)ldcp); 4874690Snarayan (void) ldc_fini((ldc_handle_t)ldcp); 4884690Snarayan 4894690Snarayan ldcp = tmp_ldcp; 4904690Snarayan } 4914690Snarayan ldcssp->chan_list = NULL; 4924690Snarayan 4932531Snarayan /* Destroy kmem caches */ 4942531Snarayan kmem_cache_destroy(ldcssp->memhdl_cache); 4952531Snarayan kmem_cache_destroy(ldcssp->memseg_cache); 4962531Snarayan 4971991Sheppo /* 4981991Sheppo * We have successfully "removed" the driver. 4991991Sheppo * Destroying soft states 5001991Sheppo */ 5011991Sheppo mutex_destroy(&ldcssp->lock); 5021991Sheppo kmem_free(ldcssp, sizeof (ldc_soft_state_t)); 5031991Sheppo 5041991Sheppo (void) hsvc_unregister(&ldc_hsvc); 5051991Sheppo 5061991Sheppo return (status); 5071991Sheppo } 5081991Sheppo 5091991Sheppo /* -------------------------------------------------------------------------- */ 5101991Sheppo 5111991Sheppo /* 5122410Slm66018 * LDC Link Layer Internal Functions 5131991Sheppo */ 5141991Sheppo 5151991Sheppo /* 5161991Sheppo * Translate HV Errors to sun4v error codes 5171991Sheppo */ 5181991Sheppo static int 5191991Sheppo i_ldc_h2v_error(int h_error) 5201991Sheppo { 5211991Sheppo switch (h_error) { 5221991Sheppo 5231991Sheppo case H_EOK: 5241991Sheppo return (0); 5251991Sheppo 5261991Sheppo case H_ENORADDR: 5271991Sheppo return (EFAULT); 5281991Sheppo 5291991Sheppo case H_EBADPGSZ: 5301991Sheppo case H_EINVAL: 5311991Sheppo return (EINVAL); 5321991Sheppo 5331991Sheppo case H_EWOULDBLOCK: 5341991Sheppo return (EWOULDBLOCK); 5351991Sheppo 5361991Sheppo case H_ENOACCESS: 5371991Sheppo case H_ENOMAP: 5381991Sheppo return (EACCES); 5391991Sheppo 5401991Sheppo case H_EIO: 5411991Sheppo case H_ECPUERROR: 5421991Sheppo return (EIO); 5431991Sheppo 5441991Sheppo case H_ENOTSUPPORTED: 5451991Sheppo return (ENOTSUP); 5461991Sheppo 5471991Sheppo case H_ETOOMANY: 5481991Sheppo return (ENOSPC); 5491991Sheppo 5501991Sheppo case H_ECHANNEL: 5511991Sheppo return (ECHRNG); 5521991Sheppo default: 5531991Sheppo break; 5541991Sheppo } 5551991Sheppo 5561991Sheppo return (EIO); 5571991Sheppo } 5581991Sheppo 5591991Sheppo /* 5601991Sheppo * Reconfigure the transmit queue 5611991Sheppo */ 5621991Sheppo static int 5631991Sheppo i_ldc_txq_reconf(ldc_chan_t *ldcp) 5641991Sheppo { 5651991Sheppo int rv; 5661991Sheppo 5671991Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 5682336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 5692336Snarayan 5701991Sheppo rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries); 5711991Sheppo if (rv) { 5721991Sheppo cmn_err(CE_WARN, 5732793Slm66018 "i_ldc_txq_reconf: (0x%lx) cannot set qconf", ldcp->id); 5741991Sheppo return (EIO); 5751991Sheppo } 5761991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, &(ldcp->tx_head), 5771991Sheppo &(ldcp->tx_tail), &(ldcp->link_state)); 5781991Sheppo if (rv) { 5791991Sheppo cmn_err(CE_WARN, 5802793Slm66018 "i_ldc_txq_reconf: (0x%lx) cannot get qptrs", ldcp->id); 5811991Sheppo return (EIO); 5821991Sheppo } 5832793Slm66018 D1(ldcp->id, "i_ldc_txq_reconf: (0x%llx) h=0x%llx,t=0x%llx," 5841991Sheppo "s=0x%llx\n", ldcp->id, ldcp->tx_head, ldcp->tx_tail, 5851991Sheppo ldcp->link_state); 5861991Sheppo 5871991Sheppo return (0); 5881991Sheppo } 5891991Sheppo 5901991Sheppo /* 5911991Sheppo * Reconfigure the receive queue 5921991Sheppo */ 5931991Sheppo static int 5942793Slm66018 i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset) 5951991Sheppo { 5961991Sheppo int rv; 5971991Sheppo uint64_t rx_head, rx_tail; 5981991Sheppo 5991991Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 6001991Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 6011991Sheppo &(ldcp->link_state)); 6021991Sheppo if (rv) { 6031991Sheppo cmn_err(CE_WARN, 6042793Slm66018 "i_ldc_rxq_reconf: (0x%lx) cannot get state", 6051991Sheppo ldcp->id); 6061991Sheppo return (EIO); 6071991Sheppo } 6081991Sheppo 6092793Slm66018 if (force_reset || (ldcp->tstate & ~TS_IN_RESET) == TS_UP) { 6101991Sheppo rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, 6114690Snarayan ldcp->rx_q_entries); 6121991Sheppo if (rv) { 6131991Sheppo cmn_err(CE_WARN, 6142793Slm66018 "i_ldc_rxq_reconf: (0x%lx) cannot set qconf", 6151991Sheppo ldcp->id); 6161991Sheppo return (EIO); 6171991Sheppo } 6182793Slm66018 D1(ldcp->id, "i_ldc_rxq_reconf: (0x%llx) completed q reconf", 6191991Sheppo ldcp->id); 6201991Sheppo } 6211991Sheppo 6221991Sheppo return (0); 6231991Sheppo } 6241991Sheppo 6252841Snarayan 6262841Snarayan /* 6272841Snarayan * Drain the contents of the receive queue 6282841Snarayan */ 6292841Snarayan static int 6302841Snarayan i_ldc_rxq_drain(ldc_chan_t *ldcp) 6312841Snarayan { 6322841Snarayan int rv; 6332841Snarayan uint64_t rx_head, rx_tail; 6342841Snarayan 6352841Snarayan ASSERT(MUTEX_HELD(&ldcp->lock)); 6362841Snarayan rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 6372841Snarayan &(ldcp->link_state)); 6382841Snarayan if (rv) { 6392841Snarayan cmn_err(CE_WARN, "i_ldc_rxq_drain: (0x%lx) cannot get state", 6402841Snarayan ldcp->id); 6412841Snarayan return (EIO); 6422841Snarayan } 6432841Snarayan 6442841Snarayan /* flush contents by setting the head = tail */ 6452841Snarayan return (i_ldc_set_rx_head(ldcp, rx_tail)); 6462841Snarayan } 6472841Snarayan 6482841Snarayan 6491991Sheppo /* 6501991Sheppo * Reset LDC state structure and its contents 6511991Sheppo */ 6521991Sheppo static void 6531991Sheppo i_ldc_reset_state(ldc_chan_t *ldcp) 6541991Sheppo { 6551991Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 6561991Sheppo ldcp->last_msg_snt = LDC_INIT_SEQID; 6571991Sheppo ldcp->last_ack_rcd = 0; 6581991Sheppo ldcp->last_msg_rcd = 0; 6591991Sheppo ldcp->tx_ackd_head = ldcp->tx_head; 660*5944Sha137994 ldcp->stream_remains = 0; 6611991Sheppo ldcp->next_vidx = 0; 6621991Sheppo ldcp->hstate = 0; 6631991Sheppo ldcp->tstate = TS_OPEN; 6641991Sheppo ldcp->status = LDC_OPEN; 665*5944Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID; 666*5944Sha137994 ldcp->rx_dq_head = 0; 667*5944Sha137994 ldcp->rx_dq_tail = 0; 6681991Sheppo 6691991Sheppo if (ldcp->link_state == LDC_CHANNEL_UP || 6701991Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 6711991Sheppo 6721991Sheppo if (ldcp->mode == LDC_MODE_RAW) { 6731991Sheppo ldcp->status = LDC_UP; 6741991Sheppo ldcp->tstate = TS_UP; 6751991Sheppo } else { 6761991Sheppo ldcp->status = LDC_READY; 6771991Sheppo ldcp->tstate |= TS_LINK_READY; 6781991Sheppo } 6791991Sheppo } 6801991Sheppo } 6811991Sheppo 6821991Sheppo /* 6831991Sheppo * Reset a LDC channel 6841991Sheppo */ 6851991Sheppo static void 6862793Slm66018 i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset) 6871991Sheppo { 6883560Snarayan DWARN(ldcp->id, "i_ldc_reset: (0x%llx) channel reset\n", ldcp->id); 6891991Sheppo 6902336Snarayan ASSERT(MUTEX_HELD(&ldcp->lock)); 6912336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 6922336Snarayan 6932793Slm66018 /* reconfig Tx and Rx queues */ 6941991Sheppo (void) i_ldc_txq_reconf(ldcp); 6952793Slm66018 (void) i_ldc_rxq_reconf(ldcp, force_reset); 6962793Slm66018 6972793Slm66018 /* Clear Tx and Rx interrupts */ 6982793Slm66018 (void) i_ldc_clear_intr(ldcp, CNEX_TX_INTR); 6992793Slm66018 (void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 7002793Slm66018 7012793Slm66018 /* Reset channel state */ 7021991Sheppo i_ldc_reset_state(ldcp); 7032793Slm66018 7042793Slm66018 /* Mark channel in reset */ 7052793Slm66018 ldcp->tstate |= TS_IN_RESET; 7061991Sheppo } 7071991Sheppo 7082531Snarayan 7091991Sheppo /* 7101991Sheppo * Clear pending interrupts 7111991Sheppo */ 7121991Sheppo static void 7131991Sheppo i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype) 7141991Sheppo { 7151991Sheppo ldc_cnex_t *cinfo = &ldcssp->cinfo; 7161991Sheppo 7171991Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 7182793Slm66018 ASSERT(cinfo->dip != NULL); 7192793Slm66018 7202793Slm66018 switch (itype) { 7212793Slm66018 case CNEX_TX_INTR: 7222531Snarayan /* check Tx interrupt */ 7232793Slm66018 if (ldcp->tx_intr_state) 7242793Slm66018 ldcp->tx_intr_state = LDC_INTR_NONE; 7252793Slm66018 else 7262793Slm66018 return; 7272793Slm66018 break; 7282793Slm66018 7292793Slm66018 case CNEX_RX_INTR: 7302531Snarayan /* check Rx interrupt */ 7312793Slm66018 if (ldcp->rx_intr_state) 7322793Slm66018 ldcp->rx_intr_state = LDC_INTR_NONE; 7332793Slm66018 else 7342793Slm66018 return; 7352793Slm66018 break; 7362793Slm66018 } 7372793Slm66018 7382793Slm66018 (void) cinfo->clr_intr(cinfo->dip, ldcp->id, itype); 7392793Slm66018 D2(ldcp->id, 7402793Slm66018 "i_ldc_clear_intr: (0x%llx) cleared 0x%x intr\n", 7412793Slm66018 ldcp->id, itype); 7421991Sheppo } 7431991Sheppo 7441991Sheppo /* 7451991Sheppo * Set the receive queue head 7462032Slm66018 * Resets connection and returns an error if it fails. 7471991Sheppo */ 7481991Sheppo static int 7491991Sheppo i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head) 7501991Sheppo { 7512032Slm66018 int rv; 7522032Slm66018 int retries; 7531991Sheppo 7541991Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 7552032Slm66018 for (retries = 0; retries < ldc_max_retries; retries++) { 7562032Slm66018 7572032Slm66018 if ((rv = hv_ldc_rx_set_qhead(ldcp->id, head)) == 0) 7582032Slm66018 return (0); 7592032Slm66018 7602032Slm66018 if (rv != H_EWOULDBLOCK) 7612032Slm66018 break; 7622032Slm66018 7632032Slm66018 /* wait for ldc_delay usecs */ 7642032Slm66018 drv_usecwait(ldc_delay); 7652032Slm66018 } 7662032Slm66018 7672032Slm66018 cmn_err(CE_WARN, "ldc_rx_set_qhead: (0x%lx) cannot set qhead 0x%lx", 7684690Snarayan ldcp->id, head); 7692336Snarayan mutex_enter(&ldcp->tx_lock); 7702793Slm66018 i_ldc_reset(ldcp, B_TRUE); 7712336Snarayan mutex_exit(&ldcp->tx_lock); 7722032Slm66018 7732032Slm66018 return (ECONNRESET); 7741991Sheppo } 7751991Sheppo 7764690Snarayan /* 7774690Snarayan * Returns the tx_head to be used for transfer 7784690Snarayan */ 7794690Snarayan static void 7804690Snarayan i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head) 7814690Snarayan { 7824690Snarayan ldc_msg_t *pkt; 7834690Snarayan 7844690Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 7854690Snarayan 7864690Snarayan /* get current Tx head */ 7874690Snarayan *head = ldcp->tx_head; 7884690Snarayan 7894690Snarayan /* 7904690Snarayan * Reliable mode will use the ACKd head instead of the regular tx_head. 7914690Snarayan * Also in Reliable mode, advance ackd_head for all non DATA/INFO pkts, 7924690Snarayan * up to the current location of tx_head. This needs to be done 7934690Snarayan * as the peer will only ACK DATA/INFO pkts. 7944690Snarayan */ 7954690Snarayan if (ldcp->mode == LDC_MODE_RELIABLE || ldcp->mode == LDC_MODE_STREAM) { 7964690Snarayan while (ldcp->tx_ackd_head != ldcp->tx_head) { 7974690Snarayan pkt = (ldc_msg_t *)(ldcp->tx_q_va + ldcp->tx_ackd_head); 7984690Snarayan if ((pkt->type & LDC_DATA) && (pkt->stype & LDC_INFO)) { 7994690Snarayan break; 8004690Snarayan } 8014690Snarayan /* advance ACKd head */ 8024690Snarayan ldcp->tx_ackd_head = 8034690Snarayan (ldcp->tx_ackd_head + LDC_PACKET_SIZE) % 8044690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 8054690Snarayan } 8064690Snarayan *head = ldcp->tx_ackd_head; 8074690Snarayan } 8084690Snarayan } 8091991Sheppo 8101991Sheppo /* 8111991Sheppo * Returns the tx_tail to be used for transfer 8121991Sheppo * Re-reads the TX queue ptrs if and only if the 8131991Sheppo * the cached head and tail are equal (queue is full) 8141991Sheppo */ 8151991Sheppo static int 8161991Sheppo i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail) 8171991Sheppo { 8181991Sheppo int rv; 8191991Sheppo uint64_t current_head, new_tail; 8201991Sheppo 8212336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 8221991Sheppo /* Read the head and tail ptrs from HV */ 8231991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 8241991Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 8251991Sheppo if (rv) { 8261991Sheppo cmn_err(CE_WARN, 8271991Sheppo "i_ldc_get_tx_tail: (0x%lx) cannot read qptrs\n", 8281991Sheppo ldcp->id); 8291991Sheppo return (EIO); 8301991Sheppo } 8311991Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN) { 8323010Slm66018 D1(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) channel not ready\n", 8331991Sheppo ldcp->id); 8341991Sheppo return (ECONNRESET); 8351991Sheppo } 8361991Sheppo 8374690Snarayan i_ldc_get_tx_head(ldcp, ¤t_head); 8381991Sheppo 8391991Sheppo /* increment the tail */ 8401991Sheppo new_tail = (ldcp->tx_tail + LDC_PACKET_SIZE) % 8414690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 8421991Sheppo 8431991Sheppo if (new_tail == current_head) { 8441991Sheppo DWARN(ldcp->id, 8451991Sheppo "i_ldc_get_tx_tail: (0x%llx) TX queue is full\n", 8461991Sheppo ldcp->id); 8471991Sheppo return (EWOULDBLOCK); 8481991Sheppo } 8491991Sheppo 8501991Sheppo D2(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) head=0x%llx, tail=0x%llx\n", 8511991Sheppo ldcp->id, ldcp->tx_head, ldcp->tx_tail); 8521991Sheppo 8531991Sheppo *tail = ldcp->tx_tail; 8541991Sheppo return (0); 8551991Sheppo } 8561991Sheppo 8571991Sheppo /* 8581991Sheppo * Set the tail pointer. If HV returns EWOULDBLOCK, it will back off 8592032Slm66018 * and retry ldc_max_retries times before returning an error. 8601991Sheppo * Returns 0, EWOULDBLOCK or EIO 8611991Sheppo */ 8621991Sheppo static int 8631991Sheppo i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail) 8641991Sheppo { 8651991Sheppo int rv, retval = EWOULDBLOCK; 8662032Slm66018 int retries; 8671991Sheppo 8682336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 8692032Slm66018 for (retries = 0; retries < ldc_max_retries; retries++) { 8701991Sheppo 8711991Sheppo if ((rv = hv_ldc_tx_set_qtail(ldcp->id, tail)) == 0) { 8721991Sheppo retval = 0; 8731991Sheppo break; 8741991Sheppo } 8751991Sheppo if (rv != H_EWOULDBLOCK) { 8761991Sheppo DWARN(ldcp->id, "i_ldc_set_tx_tail: (0x%llx) set " 8771991Sheppo "qtail=0x%llx failed, rv=%d\n", ldcp->id, tail, rv); 8781991Sheppo retval = EIO; 8791991Sheppo break; 8801991Sheppo } 8811991Sheppo 8822032Slm66018 /* wait for ldc_delay usecs */ 8832032Slm66018 drv_usecwait(ldc_delay); 8841991Sheppo } 8851991Sheppo return (retval); 8861991Sheppo } 8871991Sheppo 8881991Sheppo /* 889*5944Sha137994 * Copy a data packet from the HV receive queue to the data queue. 890*5944Sha137994 * Caller must ensure that the data queue is not already full. 891*5944Sha137994 * 892*5944Sha137994 * The *head argument represents the current head pointer for the HV 893*5944Sha137994 * receive queue. After copying a packet from the HV receive queue, 894*5944Sha137994 * the *head pointer will be updated. This allows the caller to update 895*5944Sha137994 * the head pointer in HV using the returned *head value. 896*5944Sha137994 */ 897*5944Sha137994 void 898*5944Sha137994 i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head) 899*5944Sha137994 { 900*5944Sha137994 uint64_t q_size, dq_size; 901*5944Sha137994 902*5944Sha137994 ASSERT(MUTEX_HELD(&ldcp->lock)); 903*5944Sha137994 904*5944Sha137994 q_size = ldcp->rx_q_entries << LDC_PACKET_SHIFT; 905*5944Sha137994 dq_size = ldcp->rx_dq_entries << LDC_PACKET_SHIFT; 906*5944Sha137994 907*5944Sha137994 ASSERT(Q_CONTIG_SPACE(ldcp->rx_dq_head, ldcp->rx_dq_tail, 908*5944Sha137994 dq_size) >= LDC_PACKET_SIZE); 909*5944Sha137994 910*5944Sha137994 bcopy((void *)(ldcp->rx_q_va + *head), 911*5944Sha137994 (void *)(ldcp->rx_dq_va + ldcp->rx_dq_tail), LDC_PACKET_SIZE); 912*5944Sha137994 TRACE_RXDQ_COPY(ldcp, LDC_PACKET_SIZE); 913*5944Sha137994 914*5944Sha137994 /* Update rx head */ 915*5944Sha137994 *head = (*head + LDC_PACKET_SIZE) % q_size; 916*5944Sha137994 917*5944Sha137994 /* Update dq tail */ 918*5944Sha137994 ldcp->rx_dq_tail = (ldcp->rx_dq_tail + LDC_PACKET_SIZE) % dq_size; 919*5944Sha137994 } 920*5944Sha137994 921*5944Sha137994 /* 922*5944Sha137994 * Update the Rx data queue head pointer 923*5944Sha137994 */ 924*5944Sha137994 static int 925*5944Sha137994 i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head) 926*5944Sha137994 { 927*5944Sha137994 ldcp->rx_dq_head = head; 928*5944Sha137994 return (0); 929*5944Sha137994 } 930*5944Sha137994 931*5944Sha137994 /* 932*5944Sha137994 * Get the Rx data queue head and tail pointers 933*5944Sha137994 */ 934*5944Sha137994 static uint64_t 935*5944Sha137994 i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail, 936*5944Sha137994 uint64_t *link_state) 937*5944Sha137994 { 938*5944Sha137994 _NOTE(ARGUNUSED(link_state)) 939*5944Sha137994 *head = ldcp->rx_dq_head; 940*5944Sha137994 *tail = ldcp->rx_dq_tail; 941*5944Sha137994 return (0); 942*5944Sha137994 } 943*5944Sha137994 944*5944Sha137994 /* 945*5944Sha137994 * Wrapper for the Rx HV queue set head function. Giving the 946*5944Sha137994 * data queue and HV queue set head functions the same type. 947*5944Sha137994 */ 948*5944Sha137994 static uint64_t 949*5944Sha137994 i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail, 950*5944Sha137994 uint64_t *link_state) 951*5944Sha137994 { 952*5944Sha137994 return (i_ldc_h2v_error(hv_ldc_rx_get_state(ldcp->id, head, tail, 953*5944Sha137994 link_state))); 954*5944Sha137994 } 955*5944Sha137994 956*5944Sha137994 /* 957*5944Sha137994 * LDC receive interrupt handler 958*5944Sha137994 * triggered for channel with data pending to read 959*5944Sha137994 * i.e. Rx queue content changes 960*5944Sha137994 */ 961*5944Sha137994 static uint_t 962*5944Sha137994 i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2) 963*5944Sha137994 { 964*5944Sha137994 _NOTE(ARGUNUSED(arg2)) 965*5944Sha137994 966*5944Sha137994 ldc_chan_t *ldcp; 967*5944Sha137994 boolean_t notify; 968*5944Sha137994 uint64_t event; 969*5944Sha137994 int rv; 970*5944Sha137994 971*5944Sha137994 /* Get the channel for which interrupt was received */ 972*5944Sha137994 if (arg1 == NULL) { 973*5944Sha137994 cmn_err(CE_WARN, "i_ldc_rx_hdlr: invalid arg\n"); 974*5944Sha137994 return (DDI_INTR_UNCLAIMED); 975*5944Sha137994 } 976*5944Sha137994 977*5944Sha137994 ldcp = (ldc_chan_t *)arg1; 978*5944Sha137994 979*5944Sha137994 D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n", 980*5944Sha137994 ldcp->id, ldcp); 981*5944Sha137994 D1(ldcp->id, "i_ldc_rx_hdlr: (%llx) USR%lx/TS%lx/HS%lx, LSTATE=%lx\n", 982*5944Sha137994 ldcp->id, ldcp->status, ldcp->tstate, ldcp->hstate, 983*5944Sha137994 ldcp->link_state); 984*5944Sha137994 985*5944Sha137994 /* Lock channel */ 986*5944Sha137994 mutex_enter(&ldcp->lock); 987*5944Sha137994 988*5944Sha137994 /* Mark the interrupt as being actively handled */ 989*5944Sha137994 ldcp->rx_intr_state = LDC_INTR_ACTIVE; 990*5944Sha137994 991*5944Sha137994 (void) i_ldc_rx_process_hvq(ldcp, ¬ify, &event); 992*5944Sha137994 993*5944Sha137994 if (ldcp->mode != LDC_MODE_STREAM) { 994*5944Sha137994 /* 995*5944Sha137994 * If there are no data packets on the queue, clear 996*5944Sha137994 * the interrupt. Otherwise, the ldc_read will clear 997*5944Sha137994 * interrupts after draining the queue. To indicate the 998*5944Sha137994 * interrupt has not yet been cleared, it is marked 999*5944Sha137994 * as pending. 1000*5944Sha137994 */ 1001*5944Sha137994 if ((event & LDC_EVT_READ) == 0) { 1002*5944Sha137994 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 1003*5944Sha137994 } else { 1004*5944Sha137994 ldcp->rx_intr_state = LDC_INTR_PEND; 1005*5944Sha137994 } 1006*5944Sha137994 } 1007*5944Sha137994 1008*5944Sha137994 /* if callbacks are disabled, do not notify */ 1009*5944Sha137994 if (notify && ldcp->cb_enabled) { 1010*5944Sha137994 ldcp->cb_inprogress = B_TRUE; 1011*5944Sha137994 mutex_exit(&ldcp->lock); 1012*5944Sha137994 rv = ldcp->cb(event, ldcp->cb_arg); 1013*5944Sha137994 if (rv) { 1014*5944Sha137994 DWARN(ldcp->id, 1015*5944Sha137994 "i_ldc_rx_hdlr: (0x%llx) callback failure", 1016*5944Sha137994 ldcp->id); 1017*5944Sha137994 } 1018*5944Sha137994 mutex_enter(&ldcp->lock); 1019*5944Sha137994 ldcp->cb_inprogress = B_FALSE; 1020*5944Sha137994 } 1021*5944Sha137994 1022*5944Sha137994 if (ldcp->mode == LDC_MODE_STREAM) { 1023*5944Sha137994 /* 1024*5944Sha137994 * If we are using a secondary data queue, clear the 1025*5944Sha137994 * interrupt. We should have processed all CTRL packets 1026*5944Sha137994 * and copied all DATA packets to the secondary queue. 1027*5944Sha137994 * Even if secondary queue filled up, clear the interrupts, 1028*5944Sha137994 * this will trigger another interrupt and force the 1029*5944Sha137994 * handler to copy more data. 1030*5944Sha137994 */ 1031*5944Sha137994 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 1032*5944Sha137994 } 1033*5944Sha137994 1034*5944Sha137994 mutex_exit(&ldcp->lock); 1035*5944Sha137994 1036*5944Sha137994 D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) exiting handler", ldcp->id); 1037*5944Sha137994 1038*5944Sha137994 return (DDI_INTR_CLAIMED); 1039*5944Sha137994 } 1040*5944Sha137994 1041*5944Sha137994 /* 1042*5944Sha137994 * Wrapper for the Rx HV queue processing function to be used when 1043*5944Sha137994 * checking the Rx HV queue for data packets. Unlike the interrupt 1044*5944Sha137994 * handler code flow, the Rx interrupt is not cleared here and 1045*5944Sha137994 * callbacks are not made. 1046*5944Sha137994 */ 1047*5944Sha137994 static uint_t 1048*5944Sha137994 i_ldc_chkq(ldc_chan_t *ldcp) 1049*5944Sha137994 { 1050*5944Sha137994 boolean_t notify; 1051*5944Sha137994 uint64_t event; 1052*5944Sha137994 1053*5944Sha137994 return (i_ldc_rx_process_hvq(ldcp, ¬ify, &event)); 1054*5944Sha137994 } 1055*5944Sha137994 1056*5944Sha137994 /* 10571991Sheppo * Send a LDC message 10581991Sheppo */ 10591991Sheppo static int 10601991Sheppo i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype, 10611991Sheppo uint8_t ctrlmsg) 10621991Sheppo { 10631991Sheppo int rv; 10641991Sheppo ldc_msg_t *pkt; 10651991Sheppo uint64_t tx_tail; 10664690Snarayan uint32_t curr_seqid; 10671991Sheppo 10682336Snarayan /* Obtain Tx lock */ 10692336Snarayan mutex_enter(&ldcp->tx_lock); 10702336Snarayan 10714690Snarayan curr_seqid = ldcp->last_msg_snt; 10724690Snarayan 10731991Sheppo /* get the current tail for the message */ 10741991Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 10751991Sheppo if (rv) { 10761991Sheppo DWARN(ldcp->id, 10771991Sheppo "i_ldc_send_pkt: (0x%llx) error sending pkt, " 10781991Sheppo "type=0x%x,subtype=0x%x,ctrl=0x%x\n", 10791991Sheppo ldcp->id, pkttype, subtype, ctrlmsg); 10802336Snarayan mutex_exit(&ldcp->tx_lock); 10811991Sheppo return (rv); 10821991Sheppo } 10831991Sheppo 10841991Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 10851991Sheppo ZERO_PKT(pkt); 10861991Sheppo 10871991Sheppo /* Initialize the packet */ 10881991Sheppo pkt->type = pkttype; 10891991Sheppo pkt->stype = subtype; 10901991Sheppo pkt->ctrl = ctrlmsg; 10911991Sheppo 10921991Sheppo /* Store ackid/seqid iff it is RELIABLE mode & not a RTS/RTR message */ 10931991Sheppo if (((ctrlmsg & LDC_CTRL_MASK) != LDC_RTS) && 10941991Sheppo ((ctrlmsg & LDC_CTRL_MASK) != LDC_RTR)) { 10951991Sheppo curr_seqid++; 10961991Sheppo if (ldcp->mode != LDC_MODE_RAW) { 10971991Sheppo pkt->seqid = curr_seqid; 10981991Sheppo pkt->ackid = ldcp->last_msg_rcd; 10991991Sheppo } 11001991Sheppo } 11011991Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_send_pkt", (uint64_t)pkt); 11021991Sheppo 11031991Sheppo /* initiate the send by calling into HV and set the new tail */ 11041991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 11054690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 11061991Sheppo 11071991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 11081991Sheppo if (rv) { 11091991Sheppo DWARN(ldcp->id, 11101991Sheppo "i_ldc_send_pkt:(0x%llx) error sending pkt, " 11111991Sheppo "type=0x%x,stype=0x%x,ctrl=0x%x\n", 11121991Sheppo ldcp->id, pkttype, subtype, ctrlmsg); 11132336Snarayan mutex_exit(&ldcp->tx_lock); 11141991Sheppo return (EIO); 11151991Sheppo } 11161991Sheppo 11171991Sheppo ldcp->last_msg_snt = curr_seqid; 11181991Sheppo ldcp->tx_tail = tx_tail; 11191991Sheppo 11202336Snarayan mutex_exit(&ldcp->tx_lock); 11211991Sheppo return (0); 11221991Sheppo } 11231991Sheppo 11241991Sheppo /* 11251991Sheppo * Checks if packet was received in right order 11262410Slm66018 * in the case of a reliable link. 11271991Sheppo * Returns 0 if in order, else EIO 11281991Sheppo */ 11291991Sheppo static int 11301991Sheppo i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *msg) 11311991Sheppo { 11321991Sheppo /* No seqid checking for RAW mode */ 11331991Sheppo if (ldcp->mode == LDC_MODE_RAW) 11341991Sheppo return (0); 11351991Sheppo 11361991Sheppo /* No seqid checking for version, RTS, RTR message */ 11371991Sheppo if (msg->ctrl == LDC_VER || 11381991Sheppo msg->ctrl == LDC_RTS || 11391991Sheppo msg->ctrl == LDC_RTR) 11401991Sheppo return (0); 11411991Sheppo 11421991Sheppo /* Initial seqid to use is sent in RTS/RTR and saved in last_msg_rcd */ 11431991Sheppo if (msg->seqid != (ldcp->last_msg_rcd + 1)) { 11441991Sheppo DWARN(ldcp->id, 11451991Sheppo "i_ldc_check_seqid: (0x%llx) out-of-order pkt, got 0x%x, " 11461991Sheppo "expecting 0x%x\n", ldcp->id, msg->seqid, 11471991Sheppo (ldcp->last_msg_rcd + 1)); 11481991Sheppo return (EIO); 11491991Sheppo } 11501991Sheppo 11513560Snarayan #ifdef DEBUG 11523560Snarayan if (LDC_INJECT_PKTLOSS(ldcp)) { 11533560Snarayan DWARN(ldcp->id, 11543560Snarayan "i_ldc_check_seqid: (0x%llx) inject pkt loss\n", ldcp->id); 11553560Snarayan return (EIO); 11563560Snarayan } 11573560Snarayan #endif 11583560Snarayan 11591991Sheppo return (0); 11601991Sheppo } 11611991Sheppo 11621991Sheppo 11631991Sheppo /* 11641991Sheppo * Process an incoming version ctrl message 11651991Sheppo */ 11661991Sheppo static int 11671991Sheppo i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg) 11681991Sheppo { 11691991Sheppo int rv = 0, idx = ldcp->next_vidx; 11701991Sheppo ldc_msg_t *pkt; 11711991Sheppo uint64_t tx_tail; 11721991Sheppo ldc_ver_t *rcvd_ver; 11731991Sheppo 11741991Sheppo /* get the received version */ 11751991Sheppo rcvd_ver = (ldc_ver_t *)((uint64_t)msg + LDC_PAYLOAD_VER_OFF); 11761991Sheppo 11771991Sheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) received VER v%u.%u\n", 11781991Sheppo ldcp->id, rcvd_ver->major, rcvd_ver->minor); 11791991Sheppo 11802336Snarayan /* Obtain Tx lock */ 11812336Snarayan mutex_enter(&ldcp->tx_lock); 11822336Snarayan 11831991Sheppo switch (msg->stype) { 11841991Sheppo case LDC_INFO: 11851991Sheppo 11862793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) { 11872793Slm66018 (void) i_ldc_txq_reconf(ldcp); 11882793Slm66018 i_ldc_reset_state(ldcp); 11892793Slm66018 mutex_exit(&ldcp->tx_lock); 11902793Slm66018 return (EAGAIN); 11912793Slm66018 } 11922793Slm66018 11931991Sheppo /* get the current tail and pkt for the response */ 11941991Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 11951991Sheppo if (rv != 0) { 11961991Sheppo DWARN(ldcp->id, 11971991Sheppo "i_ldc_process_VER: (0x%llx) err sending " 11981991Sheppo "version ACK/NACK\n", ldcp->id); 11992793Slm66018 i_ldc_reset(ldcp, B_TRUE); 12002336Snarayan mutex_exit(&ldcp->tx_lock); 12011991Sheppo return (ECONNRESET); 12021991Sheppo } 12031991Sheppo 12041991Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 12051991Sheppo ZERO_PKT(pkt); 12061991Sheppo 12071991Sheppo /* initialize the packet */ 12081991Sheppo pkt->type = LDC_CTRL; 12091991Sheppo pkt->ctrl = LDC_VER; 12101991Sheppo 12111991Sheppo for (;;) { 12121991Sheppo 12131991Sheppo D1(ldcp->id, "i_ldc_process_VER: got %u.%u chk %u.%u\n", 12141991Sheppo rcvd_ver->major, rcvd_ver->minor, 12151991Sheppo ldc_versions[idx].major, ldc_versions[idx].minor); 12161991Sheppo 12171991Sheppo if (rcvd_ver->major == ldc_versions[idx].major) { 12181991Sheppo /* major version match - ACK version */ 12191991Sheppo pkt->stype = LDC_ACK; 12201991Sheppo 12211991Sheppo /* 12221991Sheppo * lower minor version to the one this endpt 12231991Sheppo * supports, if necessary 12241991Sheppo */ 12251991Sheppo if (rcvd_ver->minor > ldc_versions[idx].minor) 12261991Sheppo rcvd_ver->minor = 12274690Snarayan ldc_versions[idx].minor; 12281991Sheppo bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver)); 12291991Sheppo 12301991Sheppo break; 12311991Sheppo } 12321991Sheppo 12331991Sheppo if (rcvd_ver->major > ldc_versions[idx].major) { 12341991Sheppo 12351991Sheppo D1(ldcp->id, "i_ldc_process_VER: using next" 12361991Sheppo " lower idx=%d, v%u.%u\n", idx, 12371991Sheppo ldc_versions[idx].major, 12381991Sheppo ldc_versions[idx].minor); 12391991Sheppo 12401991Sheppo /* nack with next lower version */ 12411991Sheppo pkt->stype = LDC_NACK; 12421991Sheppo bcopy(&ldc_versions[idx], pkt->udata, 12431991Sheppo sizeof (ldc_versions[idx])); 12441991Sheppo ldcp->next_vidx = idx; 12451991Sheppo break; 12461991Sheppo } 12471991Sheppo 12481991Sheppo /* next major version */ 12491991Sheppo idx++; 12501991Sheppo 12511991Sheppo D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx); 12521991Sheppo 12531991Sheppo if (idx == LDC_NUM_VERS) { 12541991Sheppo /* no version match - send NACK */ 12551991Sheppo pkt->stype = LDC_NACK; 12561991Sheppo bzero(pkt->udata, sizeof (ldc_ver_t)); 12571991Sheppo ldcp->next_vidx = 0; 12581991Sheppo break; 12591991Sheppo } 12601991Sheppo } 12611991Sheppo 12621991Sheppo /* initiate the send by calling into HV and set the new tail */ 12631991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 12644690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 12651991Sheppo 12661991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 12671991Sheppo if (rv == 0) { 12681991Sheppo ldcp->tx_tail = tx_tail; 12691991Sheppo if (pkt->stype == LDC_ACK) { 12701991Sheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent" 12711991Sheppo " version ACK\n", ldcp->id); 12721991Sheppo /* Save the ACK'd version */ 12731991Sheppo ldcp->version.major = rcvd_ver->major; 12741991Sheppo ldcp->version.minor = rcvd_ver->minor; 12752032Slm66018 ldcp->hstate |= TS_RCVD_VER; 12761991Sheppo ldcp->tstate |= TS_VER_DONE; 12773560Snarayan D1(DBG_ALL_LDCS, 12782793Slm66018 "(0x%llx) Sent ACK, " 12792793Slm66018 "Agreed on version v%u.%u\n", 12801991Sheppo ldcp->id, rcvd_ver->major, rcvd_ver->minor); 12811991Sheppo } 12821991Sheppo } else { 12831991Sheppo DWARN(ldcp->id, 12841991Sheppo "i_ldc_process_VER: (0x%llx) error sending " 12851991Sheppo "ACK/NACK\n", ldcp->id); 12862793Slm66018 i_ldc_reset(ldcp, B_TRUE); 12872336Snarayan mutex_exit(&ldcp->tx_lock); 12881991Sheppo return (ECONNRESET); 12891991Sheppo } 12901991Sheppo 12911991Sheppo break; 12921991Sheppo 12931991Sheppo case LDC_ACK: 12942793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) { 12952793Slm66018 if (ldcp->version.major != rcvd_ver->major || 12964690Snarayan ldcp->version.minor != rcvd_ver->minor) { 12972793Slm66018 12982793Slm66018 /* mismatched version - reset connection */ 12992793Slm66018 DWARN(ldcp->id, 13004690Snarayan "i_ldc_process_VER: (0x%llx) recvd" 13014690Snarayan " ACK ver != sent ACK ver\n", ldcp->id); 13022793Slm66018 i_ldc_reset(ldcp, B_TRUE); 13032793Slm66018 mutex_exit(&ldcp->tx_lock); 13042793Slm66018 return (ECONNRESET); 13052793Slm66018 } 13062793Slm66018 } else { 13072793Slm66018 /* SUCCESS - we have agreed on a version */ 13082793Slm66018 ldcp->version.major = rcvd_ver->major; 13092793Slm66018 ldcp->version.minor = rcvd_ver->minor; 13102793Slm66018 ldcp->tstate |= TS_VER_DONE; 13112793Slm66018 } 13122793Slm66018 13133010Slm66018 D1(ldcp->id, "(0x%llx) Got ACK, Agreed on version v%u.%u\n", 13141991Sheppo ldcp->id, rcvd_ver->major, rcvd_ver->minor); 13151991Sheppo 13161991Sheppo /* initiate RTS-RTR-RDX handshake */ 13171991Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 13181991Sheppo if (rv) { 13191991Sheppo DWARN(ldcp->id, 13202793Slm66018 "i_ldc_process_VER: (0x%llx) cannot send RTS\n", 13211991Sheppo ldcp->id); 13222793Slm66018 i_ldc_reset(ldcp, B_TRUE); 13232336Snarayan mutex_exit(&ldcp->tx_lock); 13241991Sheppo return (ECONNRESET); 13251991Sheppo } 13261991Sheppo 13271991Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 13281991Sheppo ZERO_PKT(pkt); 13291991Sheppo 13301991Sheppo pkt->type = LDC_CTRL; 13311991Sheppo pkt->stype = LDC_INFO; 13321991Sheppo pkt->ctrl = LDC_RTS; 13331991Sheppo pkt->env = ldcp->mode; 13341991Sheppo if (ldcp->mode != LDC_MODE_RAW) 13351991Sheppo pkt->seqid = LDC_INIT_SEQID; 13361991Sheppo 13371991Sheppo ldcp->last_msg_rcd = LDC_INIT_SEQID; 13381991Sheppo 13391991Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_process_VER snd rts", (uint64_t)pkt); 13401991Sheppo 13411991Sheppo /* initiate the send by calling into HV and set the new tail */ 13421991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 13434690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 13441991Sheppo 13451991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 13461991Sheppo if (rv) { 13471991Sheppo D2(ldcp->id, 13481991Sheppo "i_ldc_process_VER: (0x%llx) no listener\n", 13491991Sheppo ldcp->id); 13502793Slm66018 i_ldc_reset(ldcp, B_TRUE); 13512336Snarayan mutex_exit(&ldcp->tx_lock); 13521991Sheppo return (ECONNRESET); 13531991Sheppo } 13541991Sheppo 13551991Sheppo ldcp->tx_tail = tx_tail; 13561991Sheppo ldcp->hstate |= TS_SENT_RTS; 13571991Sheppo 13581991Sheppo break; 13591991Sheppo 13601991Sheppo case LDC_NACK: 13611991Sheppo /* check if version in NACK is zero */ 13621991Sheppo if (rcvd_ver->major == 0 && rcvd_ver->minor == 0) { 13631991Sheppo /* version handshake failure */ 13641991Sheppo DWARN(DBG_ALL_LDCS, 13651991Sheppo "i_ldc_process_VER: (0x%llx) no version match\n", 13661991Sheppo ldcp->id); 13672793Slm66018 i_ldc_reset(ldcp, B_TRUE); 13682336Snarayan mutex_exit(&ldcp->tx_lock); 13691991Sheppo return (ECONNRESET); 13701991Sheppo } 13711991Sheppo 13721991Sheppo /* get the current tail and pkt for the response */ 13731991Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 13741991Sheppo if (rv != 0) { 13751991Sheppo cmn_err(CE_NOTE, 13761991Sheppo "i_ldc_process_VER: (0x%lx) err sending " 13771991Sheppo "version ACK/NACK\n", ldcp->id); 13782793Slm66018 i_ldc_reset(ldcp, B_TRUE); 13792336Snarayan mutex_exit(&ldcp->tx_lock); 13801991Sheppo return (ECONNRESET); 13811991Sheppo } 13821991Sheppo 13831991Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 13841991Sheppo ZERO_PKT(pkt); 13851991Sheppo 13861991Sheppo /* initialize the packet */ 13871991Sheppo pkt->type = LDC_CTRL; 13881991Sheppo pkt->ctrl = LDC_VER; 13891991Sheppo pkt->stype = LDC_INFO; 13901991Sheppo 13911991Sheppo /* check ver in NACK msg has a match */ 13921991Sheppo for (;;) { 13931991Sheppo if (rcvd_ver->major == ldc_versions[idx].major) { 13941991Sheppo /* 13951991Sheppo * major version match - resubmit request 13961991Sheppo * if lower minor version to the one this endpt 13971991Sheppo * supports, if necessary 13981991Sheppo */ 13991991Sheppo if (rcvd_ver->minor > ldc_versions[idx].minor) 14001991Sheppo rcvd_ver->minor = 14014690Snarayan ldc_versions[idx].minor; 14021991Sheppo bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver)); 14031991Sheppo break; 14041991Sheppo } 14051991Sheppo 14061991Sheppo if (rcvd_ver->major > ldc_versions[idx].major) { 14071991Sheppo 14081991Sheppo D1(ldcp->id, "i_ldc_process_VER: using next" 14091991Sheppo " lower idx=%d, v%u.%u\n", idx, 14101991Sheppo ldc_versions[idx].major, 14111991Sheppo ldc_versions[idx].minor); 14121991Sheppo 14131991Sheppo /* send next lower version */ 14141991Sheppo bcopy(&ldc_versions[idx], pkt->udata, 14151991Sheppo sizeof (ldc_versions[idx])); 14161991Sheppo ldcp->next_vidx = idx; 14171991Sheppo break; 14181991Sheppo } 14191991Sheppo 14201991Sheppo /* next version */ 14211991Sheppo idx++; 14221991Sheppo 14231991Sheppo D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx); 14241991Sheppo 14251991Sheppo if (idx == LDC_NUM_VERS) { 14261991Sheppo /* no version match - terminate */ 14271991Sheppo ldcp->next_vidx = 0; 14282336Snarayan mutex_exit(&ldcp->tx_lock); 14291991Sheppo return (ECONNRESET); 14301991Sheppo } 14311991Sheppo } 14321991Sheppo 14331991Sheppo /* initiate the send by calling into HV and set the new tail */ 14341991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 14354690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 14361991Sheppo 14371991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 14381991Sheppo if (rv == 0) { 14391991Sheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent version" 14401991Sheppo "INFO v%u.%u\n", ldcp->id, ldc_versions[idx].major, 14411991Sheppo ldc_versions[idx].minor); 14421991Sheppo ldcp->tx_tail = tx_tail; 14431991Sheppo } else { 14441991Sheppo cmn_err(CE_NOTE, 14451991Sheppo "i_ldc_process_VER: (0x%lx) error sending version" 14461991Sheppo "INFO\n", ldcp->id); 14472793Slm66018 i_ldc_reset(ldcp, B_TRUE); 14482336Snarayan mutex_exit(&ldcp->tx_lock); 14491991Sheppo return (ECONNRESET); 14501991Sheppo } 14511991Sheppo 14521991Sheppo break; 14531991Sheppo } 14541991Sheppo 14552336Snarayan mutex_exit(&ldcp->tx_lock); 14561991Sheppo return (rv); 14571991Sheppo } 14581991Sheppo 14591991Sheppo 14601991Sheppo /* 14611991Sheppo * Process an incoming RTS ctrl message 14621991Sheppo */ 14631991Sheppo static int 14641991Sheppo i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg) 14651991Sheppo { 14661991Sheppo int rv = 0; 14671991Sheppo ldc_msg_t *pkt; 14681991Sheppo uint64_t tx_tail; 14691991Sheppo boolean_t sent_NACK = B_FALSE; 14701991Sheppo 14711991Sheppo D2(ldcp->id, "i_ldc_process_RTS: (0x%llx) received RTS\n", ldcp->id); 14721991Sheppo 14731991Sheppo switch (msg->stype) { 14741991Sheppo case LDC_NACK: 14751991Sheppo DWARN(ldcp->id, 14761991Sheppo "i_ldc_process_RTS: (0x%llx) RTS NACK received\n", 14771991Sheppo ldcp->id); 14781991Sheppo 14791991Sheppo /* Reset the channel -- as we cannot continue */ 14802336Snarayan mutex_enter(&ldcp->tx_lock); 14812793Slm66018 i_ldc_reset(ldcp, B_TRUE); 14822336Snarayan mutex_exit(&ldcp->tx_lock); 14831991Sheppo rv = ECONNRESET; 14841991Sheppo break; 14851991Sheppo 14861991Sheppo case LDC_INFO: 14871991Sheppo 14881991Sheppo /* check mode */ 14891991Sheppo if (ldcp->mode != (ldc_mode_t)msg->env) { 14901991Sheppo cmn_err(CE_NOTE, 14911991Sheppo "i_ldc_process_RTS: (0x%lx) mode mismatch\n", 14921991Sheppo ldcp->id); 14931991Sheppo /* 14941991Sheppo * send NACK in response to MODE message 14951991Sheppo * get the current tail for the response 14961991Sheppo */ 14971991Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTS); 14981991Sheppo if (rv) { 14991991Sheppo /* if cannot send NACK - reset channel */ 15002336Snarayan mutex_enter(&ldcp->tx_lock); 15012793Slm66018 i_ldc_reset(ldcp, B_TRUE); 15022336Snarayan mutex_exit(&ldcp->tx_lock); 15031991Sheppo rv = ECONNRESET; 15041991Sheppo break; 15051991Sheppo } 15061991Sheppo sent_NACK = B_TRUE; 15071991Sheppo } 15081991Sheppo break; 15091991Sheppo default: 15101991Sheppo DWARN(ldcp->id, "i_ldc_process_RTS: (0x%llx) unexp ACK\n", 15111991Sheppo ldcp->id); 15122336Snarayan mutex_enter(&ldcp->tx_lock); 15132793Slm66018 i_ldc_reset(ldcp, B_TRUE); 15142336Snarayan mutex_exit(&ldcp->tx_lock); 15151991Sheppo rv = ECONNRESET; 15161991Sheppo break; 15171991Sheppo } 15181991Sheppo 15191991Sheppo /* 15201991Sheppo * If either the connection was reset (when rv != 0) or 15211991Sheppo * a NACK was sent, we return. In the case of a NACK 15221991Sheppo * we dont want to consume the packet that came in but 15231991Sheppo * not record that we received the RTS 15241991Sheppo */ 15251991Sheppo if (rv || sent_NACK) 15261991Sheppo return (rv); 15271991Sheppo 15281991Sheppo /* record RTS received */ 15291991Sheppo ldcp->hstate |= TS_RCVD_RTS; 15301991Sheppo 15311991Sheppo /* store initial SEQID info */ 15321991Sheppo ldcp->last_msg_snt = msg->seqid; 15331991Sheppo 15342336Snarayan /* Obtain Tx lock */ 15352336Snarayan mutex_enter(&ldcp->tx_lock); 15362336Snarayan 15371991Sheppo /* get the current tail for the response */ 15381991Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 15391991Sheppo if (rv != 0) { 15401991Sheppo cmn_err(CE_NOTE, 15411991Sheppo "i_ldc_process_RTS: (0x%lx) err sending RTR\n", 15421991Sheppo ldcp->id); 15432793Slm66018 i_ldc_reset(ldcp, B_TRUE); 15442336Snarayan mutex_exit(&ldcp->tx_lock); 15451991Sheppo return (ECONNRESET); 15461991Sheppo } 15471991Sheppo 15481991Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 15491991Sheppo ZERO_PKT(pkt); 15501991Sheppo 15511991Sheppo /* initialize the packet */ 15521991Sheppo pkt->type = LDC_CTRL; 15531991Sheppo pkt->stype = LDC_INFO; 15541991Sheppo pkt->ctrl = LDC_RTR; 15551991Sheppo pkt->env = ldcp->mode; 15561991Sheppo if (ldcp->mode != LDC_MODE_RAW) 15571991Sheppo pkt->seqid = LDC_INIT_SEQID; 15581991Sheppo 15591991Sheppo ldcp->last_msg_rcd = msg->seqid; 15601991Sheppo 15611991Sheppo /* initiate the send by calling into HV and set the new tail */ 15621991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 15634690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 15641991Sheppo 15651991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 15661991Sheppo if (rv == 0) { 15671991Sheppo D2(ldcp->id, 15681991Sheppo "i_ldc_process_RTS: (0x%llx) sent RTR\n", ldcp->id); 15691991Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_process_RTS sent rtr", (uint64_t)pkt); 15701991Sheppo 15711991Sheppo ldcp->tx_tail = tx_tail; 15721991Sheppo ldcp->hstate |= TS_SENT_RTR; 15731991Sheppo 15741991Sheppo } else { 15751991Sheppo cmn_err(CE_NOTE, 15761991Sheppo "i_ldc_process_RTS: (0x%lx) error sending RTR\n", 15771991Sheppo ldcp->id); 15782793Slm66018 i_ldc_reset(ldcp, B_TRUE); 15792336Snarayan mutex_exit(&ldcp->tx_lock); 15801991Sheppo return (ECONNRESET); 15811991Sheppo } 15821991Sheppo 15832336Snarayan mutex_exit(&ldcp->tx_lock); 15841991Sheppo return (0); 15851991Sheppo } 15861991Sheppo 15871991Sheppo /* 15881991Sheppo * Process an incoming RTR ctrl message 15891991Sheppo */ 15901991Sheppo static int 15911991Sheppo i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg) 15921991Sheppo { 15931991Sheppo int rv = 0; 15941991Sheppo boolean_t sent_NACK = B_FALSE; 15951991Sheppo 15961991Sheppo D2(ldcp->id, "i_ldc_process_RTR: (0x%llx) received RTR\n", ldcp->id); 15971991Sheppo 15981991Sheppo switch (msg->stype) { 15991991Sheppo case LDC_NACK: 16001991Sheppo /* RTR NACK received */ 16011991Sheppo DWARN(ldcp->id, 16021991Sheppo "i_ldc_process_RTR: (0x%llx) RTR NACK received\n", 16031991Sheppo ldcp->id); 16041991Sheppo 16051991Sheppo /* Reset the channel -- as we cannot continue */ 16062336Snarayan mutex_enter(&ldcp->tx_lock); 16072793Slm66018 i_ldc_reset(ldcp, B_TRUE); 16082336Snarayan mutex_exit(&ldcp->tx_lock); 16091991Sheppo rv = ECONNRESET; 16101991Sheppo 16111991Sheppo break; 16121991Sheppo 16131991Sheppo case LDC_INFO: 16141991Sheppo 16151991Sheppo /* check mode */ 16161991Sheppo if (ldcp->mode != (ldc_mode_t)msg->env) { 16171991Sheppo DWARN(ldcp->id, 16183010Slm66018 "i_ldc_process_RTR: (0x%llx) mode mismatch, " 16193010Slm66018 "expecting 0x%x, got 0x%x\n", 16203010Slm66018 ldcp->id, ldcp->mode, (ldc_mode_t)msg->env); 16211991Sheppo /* 16221991Sheppo * send NACK in response to MODE message 16231991Sheppo * get the current tail for the response 16241991Sheppo */ 16251991Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTR); 16261991Sheppo if (rv) { 16271991Sheppo /* if cannot send NACK - reset channel */ 16282336Snarayan mutex_enter(&ldcp->tx_lock); 16292793Slm66018 i_ldc_reset(ldcp, B_TRUE); 16302336Snarayan mutex_exit(&ldcp->tx_lock); 16311991Sheppo rv = ECONNRESET; 16321991Sheppo break; 16331991Sheppo } 16341991Sheppo sent_NACK = B_TRUE; 16351991Sheppo } 16361991Sheppo break; 16371991Sheppo 16381991Sheppo default: 16391991Sheppo DWARN(ldcp->id, "i_ldc_process_RTR: (0x%llx) unexp ACK\n", 16401991Sheppo ldcp->id); 16411991Sheppo 16421991Sheppo /* Reset the channel -- as we cannot continue */ 16432336Snarayan mutex_enter(&ldcp->tx_lock); 16442793Slm66018 i_ldc_reset(ldcp, B_TRUE); 16452336Snarayan mutex_exit(&ldcp->tx_lock); 16461991Sheppo rv = ECONNRESET; 16471991Sheppo break; 16481991Sheppo } 16491991Sheppo 16501991Sheppo /* 16511991Sheppo * If either the connection was reset (when rv != 0) or 16521991Sheppo * a NACK was sent, we return. In the case of a NACK 16531991Sheppo * we dont want to consume the packet that came in but 16541991Sheppo * not record that we received the RTR 16551991Sheppo */ 16561991Sheppo if (rv || sent_NACK) 16571991Sheppo return (rv); 16581991Sheppo 16591991Sheppo ldcp->last_msg_snt = msg->seqid; 16601991Sheppo ldcp->hstate |= TS_RCVD_RTR; 16611991Sheppo 16621991Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_INFO, LDC_RDX); 16631991Sheppo if (rv) { 16641991Sheppo cmn_err(CE_NOTE, 16651991Sheppo "i_ldc_process_RTR: (0x%lx) cannot send RDX\n", 16661991Sheppo ldcp->id); 16672336Snarayan mutex_enter(&ldcp->tx_lock); 16682793Slm66018 i_ldc_reset(ldcp, B_TRUE); 16692336Snarayan mutex_exit(&ldcp->tx_lock); 16701991Sheppo return (ECONNRESET); 16711991Sheppo } 16721991Sheppo D2(ldcp->id, 16731991Sheppo "i_ldc_process_RTR: (0x%llx) sent RDX\n", ldcp->id); 16741991Sheppo 16751991Sheppo ldcp->hstate |= TS_SENT_RDX; 16761991Sheppo ldcp->tstate |= TS_HSHAKE_DONE; 16772793Slm66018 if ((ldcp->tstate & TS_IN_RESET) == 0) 16782793Slm66018 ldcp->status = LDC_UP; 16791991Sheppo 16803010Slm66018 D1(ldcp->id, "(0x%llx) Handshake Complete\n", ldcp->id); 16811991Sheppo 16821991Sheppo return (0); 16831991Sheppo } 16841991Sheppo 16851991Sheppo 16861991Sheppo /* 16871991Sheppo * Process an incoming RDX ctrl message 16881991Sheppo */ 16891991Sheppo static int 16901991Sheppo i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg) 16911991Sheppo { 16921991Sheppo int rv = 0; 16931991Sheppo 16941991Sheppo D2(ldcp->id, "i_ldc_process_RDX: (0x%llx) received RDX\n", ldcp->id); 16951991Sheppo 16961991Sheppo switch (msg->stype) { 16971991Sheppo case LDC_NACK: 16981991Sheppo /* RDX NACK received */ 16991991Sheppo DWARN(ldcp->id, 17001991Sheppo "i_ldc_process_RDX: (0x%llx) RDX NACK received\n", 17011991Sheppo ldcp->id); 17021991Sheppo 17031991Sheppo /* Reset the channel -- as we cannot continue */ 17042336Snarayan mutex_enter(&ldcp->tx_lock); 17052793Slm66018 i_ldc_reset(ldcp, B_TRUE); 17062336Snarayan mutex_exit(&ldcp->tx_lock); 17071991Sheppo rv = ECONNRESET; 17081991Sheppo 17091991Sheppo break; 17101991Sheppo 17111991Sheppo case LDC_INFO: 17121991Sheppo 17131991Sheppo /* 17141991Sheppo * if channel is UP and a RDX received after data transmission 17151991Sheppo * has commenced it is an error 17161991Sheppo */ 17171991Sheppo if ((ldcp->tstate == TS_UP) && (ldcp->hstate & TS_RCVD_RDX)) { 17181991Sheppo DWARN(DBG_ALL_LDCS, 17191991Sheppo "i_ldc_process_RDX: (0x%llx) unexpected RDX" 17201991Sheppo " - LDC reset\n", ldcp->id); 17212336Snarayan mutex_enter(&ldcp->tx_lock); 17222793Slm66018 i_ldc_reset(ldcp, B_TRUE); 17232336Snarayan mutex_exit(&ldcp->tx_lock); 17241991Sheppo return (ECONNRESET); 17251991Sheppo } 17261991Sheppo 17271991Sheppo ldcp->hstate |= TS_RCVD_RDX; 17281991Sheppo ldcp->tstate |= TS_HSHAKE_DONE; 17292793Slm66018 if ((ldcp->tstate & TS_IN_RESET) == 0) 17302793Slm66018 ldcp->status = LDC_UP; 17311991Sheppo 17321991Sheppo D1(DBG_ALL_LDCS, "(0x%llx) Handshake Complete\n", ldcp->id); 17331991Sheppo break; 17341991Sheppo 17351991Sheppo default: 17361991Sheppo DWARN(ldcp->id, "i_ldc_process_RDX: (0x%llx) unexp ACK\n", 17371991Sheppo ldcp->id); 17381991Sheppo 17391991Sheppo /* Reset the channel -- as we cannot continue */ 17402336Snarayan mutex_enter(&ldcp->tx_lock); 17412793Slm66018 i_ldc_reset(ldcp, B_TRUE); 17422336Snarayan mutex_exit(&ldcp->tx_lock); 17431991Sheppo rv = ECONNRESET; 17441991Sheppo break; 17451991Sheppo } 17461991Sheppo 17471991Sheppo return (rv); 17481991Sheppo } 17491991Sheppo 17501991Sheppo /* 17511991Sheppo * Process an incoming ACK for a data packet 17521991Sheppo */ 17531991Sheppo static int 17541991Sheppo i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg) 17551991Sheppo { 17561991Sheppo int rv; 17571991Sheppo uint64_t tx_head; 17581991Sheppo ldc_msg_t *pkt; 17591991Sheppo 17602336Snarayan /* Obtain Tx lock */ 17612336Snarayan mutex_enter(&ldcp->tx_lock); 17622336Snarayan 17631991Sheppo /* 17642336Snarayan * Read the current Tx head and tail 17651991Sheppo */ 17661991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 17671991Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 17681991Sheppo if (rv != 0) { 17691991Sheppo cmn_err(CE_WARN, 17701991Sheppo "i_ldc_process_data_ACK: (0x%lx) cannot read qptrs\n", 17711991Sheppo ldcp->id); 17722336Snarayan 17732336Snarayan /* Reset the channel -- as we cannot continue */ 17742793Slm66018 i_ldc_reset(ldcp, B_TRUE); 17752336Snarayan mutex_exit(&ldcp->tx_lock); 17762336Snarayan return (ECONNRESET); 17771991Sheppo } 17781991Sheppo 17791991Sheppo /* 17801991Sheppo * loop from where the previous ACK location was to the 17811991Sheppo * current head location. This is how far the HV has 17821991Sheppo * actually send pkts. Pkts between head and tail are 17831991Sheppo * yet to be sent by HV. 17841991Sheppo */ 17851991Sheppo tx_head = ldcp->tx_ackd_head; 17861991Sheppo for (;;) { 17871991Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_head); 17881991Sheppo tx_head = (tx_head + LDC_PACKET_SIZE) % 17894690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 17901991Sheppo 17911991Sheppo if (pkt->seqid == msg->ackid) { 17921991Sheppo D2(ldcp->id, 17931991Sheppo "i_ldc_process_data_ACK: (0x%llx) found packet\n", 17941991Sheppo ldcp->id); 17951991Sheppo ldcp->last_ack_rcd = msg->ackid; 17961991Sheppo ldcp->tx_ackd_head = tx_head; 17971991Sheppo break; 17981991Sheppo } 17991991Sheppo if (tx_head == ldcp->tx_head) { 18001991Sheppo /* could not find packet */ 18011991Sheppo DWARN(ldcp->id, 18021991Sheppo "i_ldc_process_data_ACK: (0x%llx) invalid ACKid\n", 18031991Sheppo ldcp->id); 18042336Snarayan 18052336Snarayan /* Reset the channel -- as we cannot continue */ 18062793Slm66018 i_ldc_reset(ldcp, B_TRUE); 18072336Snarayan mutex_exit(&ldcp->tx_lock); 18082336Snarayan return (ECONNRESET); 18091991Sheppo } 18101991Sheppo } 18111991Sheppo 18122336Snarayan mutex_exit(&ldcp->tx_lock); 18131991Sheppo return (0); 18141991Sheppo } 18151991Sheppo 18161991Sheppo /* 18171991Sheppo * Process incoming control message 18181991Sheppo * Return 0 - session can continue 18191991Sheppo * EAGAIN - reprocess packet - state was changed 18201991Sheppo * ECONNRESET - channel was reset 18211991Sheppo */ 18221991Sheppo static int 18231991Sheppo i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *msg) 18241991Sheppo { 18251991Sheppo int rv = 0; 18261991Sheppo 18272793Slm66018 D1(ldcp->id, "i_ldc_ctrlmsg: (%llx) tstate = %lx, hstate = %lx\n", 18282793Slm66018 ldcp->id, ldcp->tstate, ldcp->hstate); 18292793Slm66018 18302793Slm66018 switch (ldcp->tstate & ~TS_IN_RESET) { 18311991Sheppo 18321991Sheppo case TS_OPEN: 18331991Sheppo case TS_READY: 18341991Sheppo 18351991Sheppo switch (msg->ctrl & LDC_CTRL_MASK) { 18361991Sheppo case LDC_VER: 18371991Sheppo /* process version message */ 18381991Sheppo rv = i_ldc_process_VER(ldcp, msg); 18391991Sheppo break; 18401991Sheppo default: 18411991Sheppo DWARN(ldcp->id, 18421991Sheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x " 18431991Sheppo "tstate=0x%x\n", ldcp->id, 18441991Sheppo (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate); 18451991Sheppo break; 18461991Sheppo } 18471991Sheppo 18481991Sheppo break; 18491991Sheppo 18501991Sheppo case TS_VREADY: 18511991Sheppo 18521991Sheppo switch (msg->ctrl & LDC_CTRL_MASK) { 18531991Sheppo case LDC_VER: 18542793Slm66018 /* process version message */ 18552793Slm66018 rv = i_ldc_process_VER(ldcp, msg); 18561991Sheppo break; 18571991Sheppo case LDC_RTS: 18581991Sheppo /* process RTS message */ 18591991Sheppo rv = i_ldc_process_RTS(ldcp, msg); 18601991Sheppo break; 18611991Sheppo case LDC_RTR: 18621991Sheppo /* process RTR message */ 18631991Sheppo rv = i_ldc_process_RTR(ldcp, msg); 18641991Sheppo break; 18651991Sheppo case LDC_RDX: 18661991Sheppo /* process RDX message */ 18671991Sheppo rv = i_ldc_process_RDX(ldcp, msg); 18681991Sheppo break; 18691991Sheppo default: 18701991Sheppo DWARN(ldcp->id, 18711991Sheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x " 18721991Sheppo "tstate=0x%x\n", ldcp->id, 18731991Sheppo (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate); 18741991Sheppo break; 18751991Sheppo } 18761991Sheppo 18771991Sheppo break; 18781991Sheppo 18791991Sheppo case TS_UP: 18801991Sheppo 18811991Sheppo switch (msg->ctrl & LDC_CTRL_MASK) { 18821991Sheppo case LDC_VER: 18831991Sheppo DWARN(ldcp->id, 18841991Sheppo "i_ldc_ctrlmsg: (0x%llx) unexpected VER " 18851991Sheppo "- LDC reset\n", ldcp->id); 18861991Sheppo /* peer is redoing version negotiation */ 18872336Snarayan mutex_enter(&ldcp->tx_lock); 18881991Sheppo (void) i_ldc_txq_reconf(ldcp); 18891991Sheppo i_ldc_reset_state(ldcp); 18902336Snarayan mutex_exit(&ldcp->tx_lock); 18911991Sheppo rv = EAGAIN; 18921991Sheppo break; 18931991Sheppo 18941991Sheppo case LDC_RDX: 18951991Sheppo /* process RDX message */ 18961991Sheppo rv = i_ldc_process_RDX(ldcp, msg); 18971991Sheppo break; 18981991Sheppo 18991991Sheppo default: 19001991Sheppo DWARN(ldcp->id, 19011991Sheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x " 19021991Sheppo "tstate=0x%x\n", ldcp->id, 19031991Sheppo (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate); 19041991Sheppo break; 19051991Sheppo } 19061991Sheppo } 19071991Sheppo 19081991Sheppo return (rv); 19091991Sheppo } 19101991Sheppo 19111991Sheppo /* 19121991Sheppo * Register channel with the channel nexus 19131991Sheppo */ 19141991Sheppo static int 19151991Sheppo i_ldc_register_channel(ldc_chan_t *ldcp) 19161991Sheppo { 19171991Sheppo int rv = 0; 19181991Sheppo ldc_cnex_t *cinfo = &ldcssp->cinfo; 19191991Sheppo 19201991Sheppo if (cinfo->dip == NULL) { 19211991Sheppo DWARN(ldcp->id, 19221991Sheppo "i_ldc_register_channel: cnex has not registered\n"); 19231991Sheppo return (EAGAIN); 19241991Sheppo } 19251991Sheppo 19261991Sheppo rv = cinfo->reg_chan(cinfo->dip, ldcp->id, ldcp->devclass); 19271991Sheppo if (rv) { 19281991Sheppo DWARN(ldcp->id, 19291991Sheppo "i_ldc_register_channel: cannot register channel\n"); 19301991Sheppo return (rv); 19311991Sheppo } 19321991Sheppo 19331991Sheppo rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR, 19341991Sheppo i_ldc_tx_hdlr, ldcp, NULL); 19351991Sheppo if (rv) { 19361991Sheppo DWARN(ldcp->id, 19371991Sheppo "i_ldc_register_channel: cannot add Tx interrupt\n"); 19381991Sheppo (void) cinfo->unreg_chan(cinfo->dip, ldcp->id); 19391991Sheppo return (rv); 19401991Sheppo } 19411991Sheppo 19421991Sheppo rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR, 19431991Sheppo i_ldc_rx_hdlr, ldcp, NULL); 19441991Sheppo if (rv) { 19451991Sheppo DWARN(ldcp->id, 19461991Sheppo "i_ldc_register_channel: cannot add Rx interrupt\n"); 19471991Sheppo (void) cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR); 19481991Sheppo (void) cinfo->unreg_chan(cinfo->dip, ldcp->id); 19491991Sheppo return (rv); 19501991Sheppo } 19511991Sheppo 19521991Sheppo ldcp->tstate |= TS_CNEX_RDY; 19531991Sheppo 19541991Sheppo return (0); 19551991Sheppo } 19561991Sheppo 19571991Sheppo /* 19581991Sheppo * Unregister a channel with the channel nexus 19591991Sheppo */ 19601991Sheppo static int 19611991Sheppo i_ldc_unregister_channel(ldc_chan_t *ldcp) 19621991Sheppo { 19631991Sheppo int rv = 0; 19641991Sheppo ldc_cnex_t *cinfo = &ldcssp->cinfo; 19651991Sheppo 19661991Sheppo if (cinfo->dip == NULL) { 19671991Sheppo DWARN(ldcp->id, 19681991Sheppo "i_ldc_unregister_channel: cnex has not registered\n"); 19691991Sheppo return (EAGAIN); 19701991Sheppo } 19711991Sheppo 19721991Sheppo if (ldcp->tstate & TS_CNEX_RDY) { 19731991Sheppo 19742336Snarayan /* Remove the Rx interrupt */ 19751991Sheppo rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR); 19761991Sheppo if (rv) { 19772793Slm66018 if (rv != EAGAIN) { 19782793Slm66018 DWARN(ldcp->id, 19792793Slm66018 "i_ldc_unregister_channel: err removing " 19802793Slm66018 "Rx intr\n"); 19812793Slm66018 return (rv); 19822793Slm66018 } 19832793Slm66018 19842793Slm66018 /* 19852793Slm66018 * If interrupts are pending and handler has 19862793Slm66018 * finished running, clear interrupt and try 19872793Slm66018 * again 19882793Slm66018 */ 19892793Slm66018 if (ldcp->rx_intr_state != LDC_INTR_PEND) 19902793Slm66018 return (rv); 19912793Slm66018 19922793Slm66018 (void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 19932793Slm66018 rv = cinfo->rem_intr(cinfo->dip, ldcp->id, 19942793Slm66018 CNEX_RX_INTR); 19952793Slm66018 if (rv) { 19962793Slm66018 DWARN(ldcp->id, "i_ldc_unregister_channel: " 19972793Slm66018 "err removing Rx interrupt\n"); 19982793Slm66018 return (rv); 19992793Slm66018 } 20001991Sheppo } 20012336Snarayan 20022336Snarayan /* Remove the Tx interrupt */ 20031991Sheppo rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR); 20041991Sheppo if (rv) { 20051991Sheppo DWARN(ldcp->id, 20061991Sheppo "i_ldc_unregister_channel: err removing Tx intr\n"); 20072336Snarayan return (rv); 20081991Sheppo } 20092336Snarayan 20102336Snarayan /* Unregister the channel */ 20111991Sheppo rv = cinfo->unreg_chan(ldcssp->cinfo.dip, ldcp->id); 20121991Sheppo if (rv) { 20131991Sheppo DWARN(ldcp->id, 20141991Sheppo "i_ldc_unregister_channel: cannot unreg channel\n"); 20152336Snarayan return (rv); 20161991Sheppo } 20171991Sheppo 20181991Sheppo ldcp->tstate &= ~TS_CNEX_RDY; 20191991Sheppo } 20201991Sheppo 20211991Sheppo return (0); 20221991Sheppo } 20231991Sheppo 20241991Sheppo 20251991Sheppo /* 20261991Sheppo * LDC transmit interrupt handler 20271991Sheppo * triggered for chanel up/down/reset events 20281991Sheppo * and Tx queue content changes 20291991Sheppo */ 20301991Sheppo static uint_t 20311991Sheppo i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2) 20321991Sheppo { 20331991Sheppo _NOTE(ARGUNUSED(arg2)) 20341991Sheppo 20351991Sheppo int rv; 20361991Sheppo ldc_chan_t *ldcp; 20371991Sheppo boolean_t notify_client = B_FALSE; 20382793Slm66018 uint64_t notify_event = 0, link_state; 20391991Sheppo 20401991Sheppo /* Get the channel for which interrupt was received */ 20411991Sheppo ASSERT(arg1 != NULL); 20421991Sheppo ldcp = (ldc_chan_t *)arg1; 20431991Sheppo 20441991Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n", 20451991Sheppo ldcp->id, ldcp); 20461991Sheppo 20471991Sheppo /* Lock channel */ 20481991Sheppo mutex_enter(&ldcp->lock); 20491991Sheppo 20502336Snarayan /* Obtain Tx lock */ 20512336Snarayan mutex_enter(&ldcp->tx_lock); 20522336Snarayan 20532531Snarayan /* mark interrupt as pending */ 20542793Slm66018 ldcp->tx_intr_state = LDC_INTR_ACTIVE; 20552793Slm66018 20562793Slm66018 /* save current link state */ 20572793Slm66018 link_state = ldcp->link_state; 20582531Snarayan 20591991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, &ldcp->tx_head, &ldcp->tx_tail, 20601991Sheppo &ldcp->link_state); 20611991Sheppo if (rv) { 20621991Sheppo cmn_err(CE_WARN, 20631991Sheppo "i_ldc_tx_hdlr: (0x%lx) cannot read queue ptrs rv=0x%d\n", 20641991Sheppo ldcp->id, rv); 20652531Snarayan i_ldc_clear_intr(ldcp, CNEX_TX_INTR); 20662336Snarayan mutex_exit(&ldcp->tx_lock); 20671991Sheppo mutex_exit(&ldcp->lock); 20681991Sheppo return (DDI_INTR_CLAIMED); 20691991Sheppo } 20701991Sheppo 20711991Sheppo /* 20721991Sheppo * reset the channel state if the channel went down 20731991Sheppo * (other side unconfigured queue) or channel was reset 20741991Sheppo * (other side reconfigured its queue) 20751991Sheppo */ 20762793Slm66018 if (link_state != ldcp->link_state && 20772793Slm66018 ldcp->link_state == LDC_CHANNEL_DOWN) { 20781991Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link down\n", ldcp->id); 20792793Slm66018 i_ldc_reset(ldcp, B_FALSE); 20801991Sheppo notify_client = B_TRUE; 20811991Sheppo notify_event = LDC_EVT_DOWN; 20821991Sheppo } 20831991Sheppo 20842793Slm66018 if (link_state != ldcp->link_state && 20852793Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) { 20861991Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link reset\n", ldcp->id); 20872793Slm66018 i_ldc_reset(ldcp, B_FALSE); 20881991Sheppo notify_client = B_TRUE; 20891991Sheppo notify_event = LDC_EVT_RESET; 20901991Sheppo } 20911991Sheppo 20922793Slm66018 if (link_state != ldcp->link_state && 20932793Slm66018 (ldcp->tstate & ~TS_IN_RESET) == TS_OPEN && 20942793Slm66018 ldcp->link_state == LDC_CHANNEL_UP) { 20951991Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link up\n", ldcp->id); 20961991Sheppo notify_client = B_TRUE; 20971991Sheppo notify_event = LDC_EVT_RESET; 20981991Sheppo ldcp->tstate |= TS_LINK_READY; 20991991Sheppo ldcp->status = LDC_READY; 21001991Sheppo } 21011991Sheppo 21021991Sheppo /* if callbacks are disabled, do not notify */ 21031991Sheppo if (!ldcp->cb_enabled) 21041991Sheppo notify_client = B_FALSE; 21051991Sheppo 21063151Ssg70180 i_ldc_clear_intr(ldcp, CNEX_TX_INTR); 21074690Snarayan mutex_exit(&ldcp->tx_lock); 21081991Sheppo 21091991Sheppo if (notify_client) { 21102793Slm66018 ldcp->cb_inprogress = B_TRUE; 21112793Slm66018 mutex_exit(&ldcp->lock); 21121991Sheppo rv = ldcp->cb(notify_event, ldcp->cb_arg); 21131991Sheppo if (rv) { 21141991Sheppo DWARN(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) callback " 21151991Sheppo "failure", ldcp->id); 21161991Sheppo } 21171991Sheppo mutex_enter(&ldcp->lock); 21181991Sheppo ldcp->cb_inprogress = B_FALSE; 21192793Slm66018 } 21202793Slm66018 21211991Sheppo mutex_exit(&ldcp->lock); 21221991Sheppo 21231991Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) exiting handler", ldcp->id); 21241991Sheppo 21251991Sheppo return (DDI_INTR_CLAIMED); 21261991Sheppo } 21271991Sheppo 21281991Sheppo /* 2129*5944Sha137994 * Process the Rx HV queue. 2130*5944Sha137994 * 2131*5944Sha137994 * Returns 0 if data packets were found and no errors were encountered, 2132*5944Sha137994 * otherwise returns an error. In either case, the *notify argument is 2133*5944Sha137994 * set to indicate whether or not the client callback function should 2134*5944Sha137994 * be invoked. The *event argument is set to contain the callback event. 2135*5944Sha137994 * 2136*5944Sha137994 * Depending on the channel mode, packets are handled differently: 2137*5944Sha137994 * 2138*5944Sha137994 * RAW MODE 2139*5944Sha137994 * For raw mode channels, when a data packet is encountered, 2140*5944Sha137994 * processing stops and all packets are left on the queue to be removed 2141*5944Sha137994 * and processed by the ldc_read code path. 2142*5944Sha137994 * 2143*5944Sha137994 * UNRELIABLE MODE 2144*5944Sha137994 * For unreliable mode, when a data packet is encountered, processing 2145*5944Sha137994 * stops, and all packets are left on the queue to be removed and 2146*5944Sha137994 * processed by the ldc_read code path. Control packets are processed 2147*5944Sha137994 * inline if they are encountered before any data packets. 2148*5944Sha137994 * 2149*5944Sha137994 * STEAMING MODE 2150*5944Sha137994 * For streaming mode channels, all packets on the receive queue 2151*5944Sha137994 * are processed: data packets are copied to the data queue and 2152*5944Sha137994 * control packets are processed inline. Packets are only left on 2153*5944Sha137994 * the receive queue when the data queue is full. 21541991Sheppo */ 21551991Sheppo static uint_t 2156*5944Sha137994 i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client, 2157*5944Sha137994 uint64_t *notify_event) 21581991Sheppo { 21591991Sheppo int rv; 21601991Sheppo uint64_t rx_head, rx_tail; 21611991Sheppo ldc_msg_t *msg; 21622793Slm66018 uint64_t link_state, first_fragment = 0; 2163*5944Sha137994 boolean_t trace_length = B_TRUE; 2164*5944Sha137994 2165*5944Sha137994 ASSERT(MUTEX_HELD(&ldcp->lock)); 2166*5944Sha137994 *notify_client = B_FALSE; 2167*5944Sha137994 *notify_event = 0; 21681991Sheppo 21691991Sheppo /* 21701991Sheppo * Read packet(s) from the queue 21711991Sheppo */ 21721991Sheppo for (;;) { 21731991Sheppo 21742793Slm66018 link_state = ldcp->link_state; 21751991Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 21761991Sheppo &ldcp->link_state); 21771991Sheppo if (rv) { 21781991Sheppo cmn_err(CE_WARN, 2179*5944Sha137994 "i_ldc_rx_process_hvq: (0x%lx) cannot read " 21801991Sheppo "queue ptrs, rv=0x%d\n", ldcp->id, rv); 21811991Sheppo i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 2182*5944Sha137994 return (EIO); 21831991Sheppo } 21841991Sheppo 21851991Sheppo /* 21861991Sheppo * reset the channel state if the channel went down 21871991Sheppo * (other side unconfigured queue) or channel was reset 21882793Slm66018 * (other side reconfigured its queue) 21891991Sheppo */ 21902793Slm66018 21912793Slm66018 if (link_state != ldcp->link_state) { 21923010Slm66018 21932793Slm66018 switch (ldcp->link_state) { 21942793Slm66018 case LDC_CHANNEL_DOWN: 2195*5944Sha137994 D1(ldcp->id, "i_ldc_rx_process_hvq: channel " 21962793Slm66018 "link down\n", ldcp->id); 21972793Slm66018 mutex_enter(&ldcp->tx_lock); 21982793Slm66018 i_ldc_reset(ldcp, B_FALSE); 21992793Slm66018 mutex_exit(&ldcp->tx_lock); 2200*5944Sha137994 *notify_client = B_TRUE; 2201*5944Sha137994 *notify_event = LDC_EVT_DOWN; 22022793Slm66018 goto loop_exit; 22032793Slm66018 22042793Slm66018 case LDC_CHANNEL_UP: 2205*5944Sha137994 D1(ldcp->id, "i_ldc_rx_process_hvq: " 22062793Slm66018 "channel link up\n", ldcp->id); 22072793Slm66018 22082793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) == TS_OPEN) { 2209*5944Sha137994 *notify_client = B_TRUE; 2210*5944Sha137994 *notify_event = LDC_EVT_RESET; 22112793Slm66018 ldcp->tstate |= TS_LINK_READY; 22122793Slm66018 ldcp->status = LDC_READY; 22132793Slm66018 } 22142793Slm66018 break; 22152793Slm66018 22162793Slm66018 case LDC_CHANNEL_RESET: 22172793Slm66018 default: 22182793Slm66018 #ifdef DEBUG 22192793Slm66018 force_reset: 22202793Slm66018 #endif 2221*5944Sha137994 D1(ldcp->id, "i_ldc_rx_process_hvq: channel " 22222793Slm66018 "link reset\n", ldcp->id); 22232793Slm66018 mutex_enter(&ldcp->tx_lock); 22242793Slm66018 i_ldc_reset(ldcp, B_FALSE); 22252793Slm66018 mutex_exit(&ldcp->tx_lock); 2226*5944Sha137994 *notify_client = B_TRUE; 2227*5944Sha137994 *notify_event = LDC_EVT_RESET; 22282793Slm66018 break; 22292793Slm66018 } 22301991Sheppo } 22312793Slm66018 22322793Slm66018 #ifdef DEBUG 22332793Slm66018 if (LDC_INJECT_RESET(ldcp)) 22342793Slm66018 goto force_reset; 22352793Slm66018 #endif 2236*5944Sha137994 if (trace_length) { 2237*5944Sha137994 TRACE_RXHVQ_LENGTH(ldcp, rx_head, rx_tail); 2238*5944Sha137994 trace_length = B_FALSE; 2239*5944Sha137994 } 22401991Sheppo 22411991Sheppo if (rx_head == rx_tail) { 2242*5944Sha137994 D2(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) " 2243*5944Sha137994 "No packets\n", ldcp->id); 22441991Sheppo break; 22451991Sheppo } 22462793Slm66018 2247*5944Sha137994 D2(ldcp->id, "i_ldc_rx_process_hvq: head=0x%llx, " 2248*5944Sha137994 "tail=0x%llx\n", rx_head, rx_tail); 2249*5944Sha137994 DUMP_LDC_PKT(ldcp, "i_ldc_rx_process_hvq rcd", 22501991Sheppo ldcp->rx_q_va + rx_head); 22511991Sheppo 22521991Sheppo /* get the message */ 22531991Sheppo msg = (ldc_msg_t *)(ldcp->rx_q_va + rx_head); 22541991Sheppo 22551991Sheppo /* if channel is in RAW mode or data pkt, notify and return */ 22561991Sheppo if (ldcp->mode == LDC_MODE_RAW) { 2257*5944Sha137994 *notify_client = B_TRUE; 2258*5944Sha137994 *notify_event |= LDC_EVT_READ; 22591991Sheppo break; 22601991Sheppo } 22611991Sheppo 22621991Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) { 22631991Sheppo 22641991Sheppo /* discard packet if channel is not up */ 22652793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) != TS_UP) { 22661991Sheppo 22671991Sheppo /* move the head one position */ 22681991Sheppo rx_head = (rx_head + LDC_PACKET_SIZE) % 22694690Snarayan (ldcp->rx_q_entries << LDC_PACKET_SHIFT); 22701991Sheppo 22711991Sheppo if (rv = i_ldc_set_rx_head(ldcp, rx_head)) 22721991Sheppo break; 22731991Sheppo 22741991Sheppo continue; 22751991Sheppo } else { 2276*5944Sha137994 uint64_t dq_head, dq_tail; 2277*5944Sha137994 2278*5944Sha137994 /* process only STREAM mode data packets */ 2279*5944Sha137994 if (ldcp->mode != LDC_MODE_STREAM) { 2280*5944Sha137994 if ((ldcp->tstate & TS_IN_RESET) == 0) 2281*5944Sha137994 *notify_client = B_TRUE; 2282*5944Sha137994 *notify_event |= LDC_EVT_READ; 2283*5944Sha137994 break; 2284*5944Sha137994 } 2285*5944Sha137994 2286*5944Sha137994 /* don't process packet if queue full */ 2287*5944Sha137994 (void) i_ldc_dq_rx_get_state(ldcp, &dq_head, 2288*5944Sha137994 &dq_tail, NULL); 2289*5944Sha137994 dq_tail = (dq_tail + LDC_PACKET_SIZE) % 2290*5944Sha137994 (ldcp->rx_dq_entries << LDC_PACKET_SHIFT); 2291*5944Sha137994 if (dq_tail == dq_head || 2292*5944Sha137994 LDC_INJECT_DQFULL(ldcp)) { 2293*5944Sha137994 rv = ENOSPC; 2294*5944Sha137994 break; 2295*5944Sha137994 } 22961991Sheppo } 22971991Sheppo } 22981991Sheppo 22991991Sheppo /* Check the sequence ID for the message received */ 23002793Slm66018 rv = i_ldc_check_seqid(ldcp, msg); 23012793Slm66018 if (rv != 0) { 23021991Sheppo 2303*5944Sha137994 DWARN(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) " 2304*5944Sha137994 "seqid error, q_ptrs=0x%lx,0x%lx", ldcp->id, 2305*5944Sha137994 rx_head, rx_tail); 23061991Sheppo 23071991Sheppo /* Reset last_msg_rcd to start of message */ 23082336Snarayan if (first_fragment != 0) { 23092336Snarayan ldcp->last_msg_rcd = first_fragment - 1; 23102336Snarayan first_fragment = 0; 23111991Sheppo } 23122336Snarayan 23131991Sheppo /* 23141991Sheppo * Send a NACK due to seqid mismatch 23151991Sheppo */ 23164690Snarayan rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK, 23171991Sheppo (msg->ctrl & LDC_CTRL_MASK)); 23181991Sheppo 23191991Sheppo if (rv) { 2320*5944Sha137994 cmn_err(CE_NOTE, "i_ldc_rx_process_hvq: " 2321*5944Sha137994 "(0x%lx) err sending CTRL/DATA NACK msg\n", 2322*5944Sha137994 ldcp->id); 23232336Snarayan 23242336Snarayan /* if cannot send NACK - reset channel */ 23252336Snarayan mutex_enter(&ldcp->tx_lock); 23262793Slm66018 i_ldc_reset(ldcp, B_TRUE); 23272336Snarayan mutex_exit(&ldcp->tx_lock); 23283560Snarayan 2329*5944Sha137994 *notify_client = B_TRUE; 2330*5944Sha137994 *notify_event = LDC_EVT_RESET; 23312336Snarayan break; 23321991Sheppo } 23331991Sheppo 23341991Sheppo /* purge receive queue */ 23351991Sheppo (void) i_ldc_set_rx_head(ldcp, rx_tail); 23361991Sheppo break; 23371991Sheppo } 23381991Sheppo 23391991Sheppo /* record the message ID */ 23401991Sheppo ldcp->last_msg_rcd = msg->seqid; 23411991Sheppo 23421991Sheppo /* process control messages */ 23431991Sheppo if (msg->type & LDC_CTRL) { 23441991Sheppo /* save current internal state */ 23451991Sheppo uint64_t tstate = ldcp->tstate; 23461991Sheppo 23471991Sheppo rv = i_ldc_ctrlmsg(ldcp, msg); 23481991Sheppo if (rv == EAGAIN) { 23491991Sheppo /* re-process pkt - state was adjusted */ 23501991Sheppo continue; 23511991Sheppo } 23521991Sheppo if (rv == ECONNRESET) { 2353*5944Sha137994 *notify_client = B_TRUE; 2354*5944Sha137994 *notify_event = LDC_EVT_RESET; 23551991Sheppo break; 23561991Sheppo } 23571991Sheppo 23581991Sheppo /* 23591991Sheppo * control message processing was successful 23601991Sheppo * channel transitioned to ready for communication 23611991Sheppo */ 23621991Sheppo if (rv == 0 && ldcp->tstate == TS_UP && 23632793Slm66018 (tstate & ~TS_IN_RESET) != 23642793Slm66018 (ldcp->tstate & ~TS_IN_RESET)) { 2365*5944Sha137994 *notify_client = B_TRUE; 2366*5944Sha137994 *notify_event = LDC_EVT_UP; 23671991Sheppo } 23681991Sheppo } 23691991Sheppo 23703560Snarayan /* process data NACKs */ 23713560Snarayan if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) { 23723560Snarayan DWARN(ldcp->id, 2373*5944Sha137994 "i_ldc_rx_process_hvq: (0x%llx) received DATA/NACK", 23743560Snarayan ldcp->id); 23753560Snarayan mutex_enter(&ldcp->tx_lock); 23763560Snarayan i_ldc_reset(ldcp, B_TRUE); 23773560Snarayan mutex_exit(&ldcp->tx_lock); 2378*5944Sha137994 *notify_client = B_TRUE; 2379*5944Sha137994 *notify_event = LDC_EVT_RESET; 23803560Snarayan break; 23813560Snarayan } 23823560Snarayan 23831991Sheppo /* process data ACKs */ 23841991Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) { 23852336Snarayan if (rv = i_ldc_process_data_ACK(ldcp, msg)) { 2386*5944Sha137994 *notify_client = B_TRUE; 2387*5944Sha137994 *notify_event = LDC_EVT_RESET; 23882336Snarayan break; 23892336Snarayan } 23901991Sheppo } 23911991Sheppo 2392*5944Sha137994 if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) { 2393*5944Sha137994 ASSERT(ldcp->mode == LDC_MODE_STREAM); 2394*5944Sha137994 2395*5944Sha137994 /* 2396*5944Sha137994 * Copy the data packet to the data queue. Note 2397*5944Sha137994 * that the copy routine updates the rx_head pointer. 2398*5944Sha137994 */ 2399*5944Sha137994 i_ldc_rxdq_copy(ldcp, &rx_head); 2400*5944Sha137994 2401*5944Sha137994 if ((ldcp->tstate & TS_IN_RESET) == 0) 2402*5944Sha137994 *notify_client = B_TRUE; 2403*5944Sha137994 *notify_event |= LDC_EVT_READ; 2404*5944Sha137994 } else { 2405*5944Sha137994 rx_head = (rx_head + LDC_PACKET_SIZE) % 2406*5944Sha137994 (ldcp->rx_q_entries << LDC_PACKET_SHIFT); 2407*5944Sha137994 } 2408*5944Sha137994 24091991Sheppo /* move the head one position */ 24102032Slm66018 if (rv = i_ldc_set_rx_head(ldcp, rx_head)) { 2411*5944Sha137994 *notify_client = B_TRUE; 2412*5944Sha137994 *notify_event = LDC_EVT_RESET; 24131991Sheppo break; 24142032Slm66018 } 24151991Sheppo 24161991Sheppo } /* for */ 24171991Sheppo 24182793Slm66018 loop_exit: 24192793Slm66018 2420*5944Sha137994 if (ldcp->mode == LDC_MODE_STREAM) { 2421*5944Sha137994 /* ACK data packets */ 2422*5944Sha137994 if ((*notify_event & 2423*5944Sha137994 (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ) { 2424*5944Sha137994 int ack_rv; 2425*5944Sha137994 ack_rv = i_ldc_send_pkt(ldcp, LDC_DATA, LDC_ACK, 0); 2426*5944Sha137994 if (ack_rv && ack_rv != EWOULDBLOCK) { 2427*5944Sha137994 cmn_err(CE_NOTE, 2428*5944Sha137994 "i_ldc_rx_process_hvq: (0x%lx) cannot " 2429*5944Sha137994 "send ACK\n", ldcp->id); 2430*5944Sha137994 2431*5944Sha137994 mutex_enter(&ldcp->tx_lock); 2432*5944Sha137994 i_ldc_reset(ldcp, B_FALSE); 2433*5944Sha137994 mutex_exit(&ldcp->tx_lock); 2434*5944Sha137994 2435*5944Sha137994 *notify_client = B_TRUE; 2436*5944Sha137994 *notify_event = LDC_EVT_RESET; 2437*5944Sha137994 goto skip_ackpeek; 2438*5944Sha137994 } 2439*5944Sha137994 } 2440*5944Sha137994 2441*5944Sha137994 /* 2442*5944Sha137994 * If we have no more space on the data queue, make sure 2443*5944Sha137994 * there are no ACKs on the rx queue waiting to be processed. 2444*5944Sha137994 */ 2445*5944Sha137994 if (rv == ENOSPC) { 2446*5944Sha137994 if (i_ldc_rx_ackpeek(ldcp, rx_head, rx_tail) != 0) { 2447*5944Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID; 2448*5944Sha137994 *notify_client = B_TRUE; 2449*5944Sha137994 *notify_event = LDC_EVT_RESET; 2450*5944Sha137994 } 2451*5944Sha137994 } else { 2452*5944Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID; 24531991Sheppo } 2454*5944Sha137994 } 2455*5944Sha137994 2456*5944Sha137994 skip_ackpeek: 2457*5944Sha137994 2458*5944Sha137994 /* Return, indicating whether or not data packets were found */ 2459*5944Sha137994 if ((*notify_event & (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ) 2460*5944Sha137994 return (0); 2461*5944Sha137994 2462*5944Sha137994 return (ENOMSG); 24631991Sheppo } 24641991Sheppo 2465*5944Sha137994 /* 2466*5944Sha137994 * Process any ACK packets on the HV receive queue. 2467*5944Sha137994 * 2468*5944Sha137994 * This function is only used by STREAMING mode channels when the 2469*5944Sha137994 * secondary data queue fills up and there are packets remaining on 2470*5944Sha137994 * the HV receive queue. 2471*5944Sha137994 */ 2472*5944Sha137994 int 2473*5944Sha137994 i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head, uint64_t rx_tail) 2474*5944Sha137994 { 2475*5944Sha137994 int rv = 0; 2476*5944Sha137994 ldc_msg_t *msg; 2477*5944Sha137994 2478*5944Sha137994 if (ldcp->rx_ack_head == ACKPEEK_HEAD_INVALID) 2479*5944Sha137994 ldcp->rx_ack_head = rx_head; 2480*5944Sha137994 2481*5944Sha137994 while (ldcp->rx_ack_head != rx_tail) { 2482*5944Sha137994 msg = (ldc_msg_t *)(ldcp->rx_q_va + ldcp->rx_ack_head); 2483*5944Sha137994 2484*5944Sha137994 if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) { 2485*5944Sha137994 if (rv = i_ldc_process_data_ACK(ldcp, msg)) 2486*5944Sha137994 break; 2487*5944Sha137994 msg->stype &= ~LDC_ACK; 2488*5944Sha137994 } 2489*5944Sha137994 2490*5944Sha137994 ldcp->rx_ack_head = 2491*5944Sha137994 (ldcp->rx_ack_head + LDC_PACKET_SIZE) % 2492*5944Sha137994 (ldcp->rx_q_entries << LDC_PACKET_SHIFT); 2493*5944Sha137994 } 2494*5944Sha137994 return (rv); 2495*5944Sha137994 } 24961991Sheppo 24971991Sheppo /* -------------------------------------------------------------------------- */ 24981991Sheppo 24991991Sheppo /* 25001991Sheppo * LDC API functions 25011991Sheppo */ 25021991Sheppo 25031991Sheppo /* 25041991Sheppo * Initialize the channel. Allocate internal structure and memory for 25051991Sheppo * TX/RX queues, and initialize locks. 25061991Sheppo */ 25071991Sheppo int 25081991Sheppo ldc_init(uint64_t id, ldc_attr_t *attr, ldc_handle_t *handle) 25091991Sheppo { 25101991Sheppo ldc_chan_t *ldcp; 25111991Sheppo int rv, exit_val; 25121991Sheppo uint64_t ra_base, nentries; 25132410Slm66018 uint64_t qlen; 25141991Sheppo 25151991Sheppo exit_val = EINVAL; /* guarantee an error if exit on failure */ 25161991Sheppo 25171991Sheppo if (attr == NULL) { 25181991Sheppo DWARN(id, "ldc_init: (0x%llx) invalid attr\n", id); 25191991Sheppo return (EINVAL); 25201991Sheppo } 25211991Sheppo if (handle == NULL) { 25221991Sheppo DWARN(id, "ldc_init: (0x%llx) invalid handle\n", id); 25231991Sheppo return (EINVAL); 25241991Sheppo } 25251991Sheppo 25261991Sheppo /* check if channel is valid */ 25271991Sheppo rv = hv_ldc_tx_qinfo(id, &ra_base, &nentries); 25281991Sheppo if (rv == H_ECHANNEL) { 25291991Sheppo DWARN(id, "ldc_init: (0x%llx) invalid channel id\n", id); 25301991Sheppo return (EINVAL); 25311991Sheppo } 25321991Sheppo 25331991Sheppo /* check if the channel has already been initialized */ 25341991Sheppo mutex_enter(&ldcssp->lock); 25351991Sheppo ldcp = ldcssp->chan_list; 25361991Sheppo while (ldcp != NULL) { 25371991Sheppo if (ldcp->id == id) { 25381991Sheppo DWARN(id, "ldc_init: (0x%llx) already initialized\n", 25391991Sheppo id); 25401991Sheppo mutex_exit(&ldcssp->lock); 25411991Sheppo return (EADDRINUSE); 25421991Sheppo } 25431991Sheppo ldcp = ldcp->next; 25441991Sheppo } 25451991Sheppo mutex_exit(&ldcssp->lock); 25461991Sheppo 25471991Sheppo ASSERT(ldcp == NULL); 25481991Sheppo 25491991Sheppo *handle = 0; 25501991Sheppo 25511991Sheppo /* Allocate an ldcp structure */ 25521991Sheppo ldcp = kmem_zalloc(sizeof (ldc_chan_t), KM_SLEEP); 25531991Sheppo 25542336Snarayan /* 25552336Snarayan * Initialize the channel and Tx lock 25562336Snarayan * 25572336Snarayan * The channel 'lock' protects the entire channel and 25582336Snarayan * should be acquired before initializing, resetting, 25592336Snarayan * destroying or reading from a channel. 25602336Snarayan * 25612336Snarayan * The 'tx_lock' should be acquired prior to transmitting 25622336Snarayan * data over the channel. The lock should also be acquired 25632336Snarayan * prior to channel reconfiguration (in order to prevent 25642336Snarayan * concurrent writes). 25652336Snarayan * 25662336Snarayan * ORDERING: When both locks are being acquired, to prevent 25672336Snarayan * deadlocks, the channel lock should be always acquired prior 25682336Snarayan * to the tx_lock. 25692336Snarayan */ 25701991Sheppo mutex_init(&ldcp->lock, NULL, MUTEX_DRIVER, NULL); 25712336Snarayan mutex_init(&ldcp->tx_lock, NULL, MUTEX_DRIVER, NULL); 25721991Sheppo 25731991Sheppo /* Initialize the channel */ 25741991Sheppo ldcp->id = id; 25751991Sheppo ldcp->cb = NULL; 25761991Sheppo ldcp->cb_arg = NULL; 25771991Sheppo ldcp->cb_inprogress = B_FALSE; 25781991Sheppo ldcp->cb_enabled = B_FALSE; 25791991Sheppo ldcp->next = NULL; 25801991Sheppo 25811991Sheppo /* Read attributes */ 25821991Sheppo ldcp->mode = attr->mode; 25831991Sheppo ldcp->devclass = attr->devclass; 25841991Sheppo ldcp->devinst = attr->instance; 25852410Slm66018 ldcp->mtu = (attr->mtu > 0) ? attr->mtu : LDC_DEFAULT_MTU; 25861991Sheppo 25871991Sheppo D1(ldcp->id, 25881991Sheppo "ldc_init: (0x%llx) channel attributes, class=0x%x, " 25892410Slm66018 "instance=0x%llx, mode=%d, mtu=%d\n", 25902410Slm66018 ldcp->id, ldcp->devclass, ldcp->devinst, ldcp->mode, ldcp->mtu); 25911991Sheppo 25921991Sheppo ldcp->next_vidx = 0; 25932793Slm66018 ldcp->tstate = TS_IN_RESET; 25941991Sheppo ldcp->hstate = 0; 25951991Sheppo ldcp->last_msg_snt = LDC_INIT_SEQID; 25961991Sheppo ldcp->last_ack_rcd = 0; 25971991Sheppo ldcp->last_msg_rcd = 0; 2598*5944Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID; 25991991Sheppo 26001991Sheppo ldcp->stream_bufferp = NULL; 26011991Sheppo ldcp->exp_dring_list = NULL; 26021991Sheppo ldcp->imp_dring_list = NULL; 26031991Sheppo ldcp->mhdl_list = NULL; 26041991Sheppo 26052793Slm66018 ldcp->tx_intr_state = LDC_INTR_NONE; 26062793Slm66018 ldcp->rx_intr_state = LDC_INTR_NONE; 26072793Slm66018 26081991Sheppo /* Initialize payload size depending on whether channel is reliable */ 26091991Sheppo switch (ldcp->mode) { 26101991Sheppo case LDC_MODE_RAW: 26111991Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RAW; 26121991Sheppo ldcp->read_p = i_ldc_read_raw; 26131991Sheppo ldcp->write_p = i_ldc_write_raw; 26141991Sheppo break; 26151991Sheppo case LDC_MODE_UNRELIABLE: 26161991Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_UNRELIABLE; 26171991Sheppo ldcp->read_p = i_ldc_read_packet; 26181991Sheppo ldcp->write_p = i_ldc_write_packet; 26191991Sheppo break; 26201991Sheppo case LDC_MODE_RELIABLE: 26211991Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RELIABLE; 26221991Sheppo ldcp->read_p = i_ldc_read_packet; 26231991Sheppo ldcp->write_p = i_ldc_write_packet; 26241991Sheppo break; 26251991Sheppo case LDC_MODE_STREAM: 26261991Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RELIABLE; 26271991Sheppo 26281991Sheppo ldcp->stream_remains = 0; 26291991Sheppo ldcp->stream_offset = 0; 26301991Sheppo ldcp->stream_bufferp = kmem_alloc(ldcp->mtu, KM_SLEEP); 26311991Sheppo ldcp->read_p = i_ldc_read_stream; 26321991Sheppo ldcp->write_p = i_ldc_write_stream; 26331991Sheppo break; 26341991Sheppo default: 26351991Sheppo exit_val = EINVAL; 26361991Sheppo goto cleanup_on_exit; 26371991Sheppo } 26381991Sheppo 26392410Slm66018 /* 26402410Slm66018 * qlen is (mtu * ldc_mtu_msgs) / pkt_payload. If this 26412410Slm66018 * value is smaller than default length of ldc_queue_entries, 26424690Snarayan * qlen is set to ldc_queue_entries. Ensure that computed 26434690Snarayan * length is a power-of-two value. 26442410Slm66018 */ 26452410Slm66018 qlen = (ldcp->mtu * ldc_mtu_msgs) / ldcp->pkt_payload; 26464690Snarayan if (!ISP2(qlen)) { 26474690Snarayan uint64_t tmp = 1; 26484690Snarayan while (qlen) { 26494690Snarayan qlen >>= 1; tmp <<= 1; 26504690Snarayan } 26514690Snarayan qlen = tmp; 26524690Snarayan } 26534690Snarayan 26542410Slm66018 ldcp->rx_q_entries = 26554690Snarayan (qlen < ldc_queue_entries) ? ldc_queue_entries : qlen; 26562410Slm66018 ldcp->tx_q_entries = ldcp->rx_q_entries; 26572410Slm66018 26584690Snarayan D1(ldcp->id, "ldc_init: queue length = 0x%llx\n", ldcp->rx_q_entries); 26592410Slm66018 26601991Sheppo /* Create a transmit queue */ 26611991Sheppo ldcp->tx_q_va = (uint64_t) 26624690Snarayan contig_mem_alloc(ldcp->tx_q_entries << LDC_PACKET_SHIFT); 26631991Sheppo if (ldcp->tx_q_va == NULL) { 26641991Sheppo cmn_err(CE_WARN, 26651991Sheppo "ldc_init: (0x%lx) TX queue allocation failed\n", 26661991Sheppo ldcp->id); 26671991Sheppo exit_val = ENOMEM; 26681991Sheppo goto cleanup_on_exit; 26691991Sheppo } 26701991Sheppo ldcp->tx_q_ra = va_to_pa((caddr_t)ldcp->tx_q_va); 26711991Sheppo 26721991Sheppo D2(ldcp->id, "ldc_init: txq_va=0x%llx, txq_ra=0x%llx, entries=0x%llx\n", 26731991Sheppo ldcp->tx_q_va, ldcp->tx_q_ra, ldcp->tx_q_entries); 26741991Sheppo 26751991Sheppo ldcp->tstate |= TS_TXQ_RDY; 26761991Sheppo 26771991Sheppo /* Create a receive queue */ 26781991Sheppo ldcp->rx_q_va = (uint64_t) 26794690Snarayan contig_mem_alloc(ldcp->rx_q_entries << LDC_PACKET_SHIFT); 26801991Sheppo if (ldcp->rx_q_va == NULL) { 26811991Sheppo cmn_err(CE_WARN, 26821991Sheppo "ldc_init: (0x%lx) RX queue allocation failed\n", 26831991Sheppo ldcp->id); 26841991Sheppo exit_val = ENOMEM; 26851991Sheppo goto cleanup_on_exit; 26861991Sheppo } 26871991Sheppo ldcp->rx_q_ra = va_to_pa((caddr_t)ldcp->rx_q_va); 26881991Sheppo 26891991Sheppo D2(ldcp->id, "ldc_init: rxq_va=0x%llx, rxq_ra=0x%llx, entries=0x%llx\n", 26901991Sheppo ldcp->rx_q_va, ldcp->rx_q_ra, ldcp->rx_q_entries); 26911991Sheppo 26921991Sheppo ldcp->tstate |= TS_RXQ_RDY; 26931991Sheppo 2694*5944Sha137994 /* Setup a separate read data queue */ 2695*5944Sha137994 if (ldcp->mode == LDC_MODE_STREAM) { 2696*5944Sha137994 ldcp->readq_get_state = i_ldc_dq_rx_get_state; 2697*5944Sha137994 ldcp->readq_set_head = i_ldc_set_rxdq_head; 2698*5944Sha137994 2699*5944Sha137994 /* Make sure the data queue multiplier is a power of 2 */ 2700*5944Sha137994 if (!ISP2(ldc_rxdq_multiplier)) { 2701*5944Sha137994 D1(ldcp->id, "ldc_init: (0x%llx) ldc_rxdq_multiplier " 2702*5944Sha137994 "not a power of 2, resetting", ldcp->id); 2703*5944Sha137994 ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER; 2704*5944Sha137994 } 2705*5944Sha137994 2706*5944Sha137994 ldcp->rx_dq_entries = ldc_rxdq_multiplier * ldcp->rx_q_entries; 2707*5944Sha137994 ldcp->rx_dq_va = (uint64_t) 2708*5944Sha137994 kmem_alloc(ldcp->rx_dq_entries << LDC_PACKET_SHIFT, 2709*5944Sha137994 KM_SLEEP); 2710*5944Sha137994 if (ldcp->rx_dq_va == NULL) { 2711*5944Sha137994 cmn_err(CE_WARN, 2712*5944Sha137994 "ldc_init: (0x%lx) RX data queue " 2713*5944Sha137994 "allocation failed\n", ldcp->id); 2714*5944Sha137994 exit_val = ENOMEM; 2715*5944Sha137994 goto cleanup_on_exit; 2716*5944Sha137994 } 2717*5944Sha137994 2718*5944Sha137994 ldcp->rx_dq_head = ldcp->rx_dq_tail = 0; 2719*5944Sha137994 2720*5944Sha137994 D2(ldcp->id, "ldc_init: rx_dq_va=0x%llx, " 2721*5944Sha137994 "rx_dq_entries=0x%llx\n", ldcp->rx_dq_va, 2722*5944Sha137994 ldcp->rx_dq_entries); 2723*5944Sha137994 } else { 2724*5944Sha137994 ldcp->readq_get_state = i_ldc_hvq_rx_get_state; 2725*5944Sha137994 ldcp->readq_set_head = i_ldc_set_rx_head; 2726*5944Sha137994 } 2727*5944Sha137994 27281991Sheppo /* Init descriptor ring and memory handle list lock */ 27291991Sheppo mutex_init(&ldcp->exp_dlist_lock, NULL, MUTEX_DRIVER, NULL); 27301991Sheppo mutex_init(&ldcp->imp_dlist_lock, NULL, MUTEX_DRIVER, NULL); 27311991Sheppo mutex_init(&ldcp->mlist_lock, NULL, MUTEX_DRIVER, NULL); 27321991Sheppo 27331991Sheppo /* mark status as INITialized */ 27341991Sheppo ldcp->status = LDC_INIT; 27351991Sheppo 27361991Sheppo /* Add to channel list */ 27371991Sheppo mutex_enter(&ldcssp->lock); 27381991Sheppo ldcp->next = ldcssp->chan_list; 27391991Sheppo ldcssp->chan_list = ldcp; 27401991Sheppo ldcssp->channel_count++; 27411991Sheppo mutex_exit(&ldcssp->lock); 27421991Sheppo 27431991Sheppo /* set the handle */ 27441991Sheppo *handle = (ldc_handle_t)ldcp; 27451991Sheppo 27461991Sheppo D1(ldcp->id, "ldc_init: (0x%llx) channel initialized\n", ldcp->id); 27471991Sheppo 27481991Sheppo return (0); 27491991Sheppo 27501991Sheppo cleanup_on_exit: 27511991Sheppo 27521991Sheppo if (ldcp->mode == LDC_MODE_STREAM && ldcp->stream_bufferp) 27531991Sheppo kmem_free(ldcp->stream_bufferp, ldcp->mtu); 27541991Sheppo 27551991Sheppo if (ldcp->tstate & TS_TXQ_RDY) 27561991Sheppo contig_mem_free((caddr_t)ldcp->tx_q_va, 27571991Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT)); 27581991Sheppo 27591991Sheppo if (ldcp->tstate & TS_RXQ_RDY) 27601991Sheppo contig_mem_free((caddr_t)ldcp->rx_q_va, 27611991Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT)); 27621991Sheppo 27632336Snarayan mutex_destroy(&ldcp->tx_lock); 27641991Sheppo mutex_destroy(&ldcp->lock); 27651991Sheppo 27661991Sheppo if (ldcp) 27671991Sheppo kmem_free(ldcp, sizeof (ldc_chan_t)); 27681991Sheppo 27691991Sheppo return (exit_val); 27701991Sheppo } 27711991Sheppo 27721991Sheppo /* 27731991Sheppo * Finalizes the LDC connection. It will return EBUSY if the 27741991Sheppo * channel is open. A ldc_close() has to be done prior to 27751991Sheppo * a ldc_fini operation. It frees TX/RX queues, associated 27761991Sheppo * with the channel 27771991Sheppo */ 27781991Sheppo int 27791991Sheppo ldc_fini(ldc_handle_t handle) 27801991Sheppo { 27811991Sheppo ldc_chan_t *ldcp; 27821991Sheppo ldc_chan_t *tmp_ldcp; 27831991Sheppo uint64_t id; 27841991Sheppo 27851991Sheppo if (handle == NULL) { 27861991Sheppo DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel handle\n"); 27871991Sheppo return (EINVAL); 27881991Sheppo } 27891991Sheppo ldcp = (ldc_chan_t *)handle; 27901991Sheppo id = ldcp->id; 27911991Sheppo 27921991Sheppo mutex_enter(&ldcp->lock); 27931991Sheppo 27942793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) > TS_INIT) { 27951991Sheppo DWARN(ldcp->id, "ldc_fini: (0x%llx) channel is open\n", 27961991Sheppo ldcp->id); 27971991Sheppo mutex_exit(&ldcp->lock); 27981991Sheppo return (EBUSY); 27991991Sheppo } 28001991Sheppo 28011991Sheppo /* Remove from the channel list */ 28021991Sheppo mutex_enter(&ldcssp->lock); 28031991Sheppo tmp_ldcp = ldcssp->chan_list; 28041991Sheppo if (tmp_ldcp == ldcp) { 28051991Sheppo ldcssp->chan_list = ldcp->next; 28061991Sheppo ldcp->next = NULL; 28071991Sheppo } else { 28081991Sheppo while (tmp_ldcp != NULL) { 28091991Sheppo if (tmp_ldcp->next == ldcp) { 28101991Sheppo tmp_ldcp->next = ldcp->next; 28111991Sheppo ldcp->next = NULL; 28121991Sheppo break; 28131991Sheppo } 28141991Sheppo tmp_ldcp = tmp_ldcp->next; 28151991Sheppo } 28161991Sheppo if (tmp_ldcp == NULL) { 28171991Sheppo DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel hdl\n"); 28181991Sheppo mutex_exit(&ldcssp->lock); 28191991Sheppo mutex_exit(&ldcp->lock); 28201991Sheppo return (EINVAL); 28211991Sheppo } 28221991Sheppo } 28231991Sheppo 28241991Sheppo ldcssp->channel_count--; 28251991Sheppo 28261991Sheppo mutex_exit(&ldcssp->lock); 28271991Sheppo 28281991Sheppo /* Free the map table for this channel */ 28291991Sheppo if (ldcp->mtbl) { 28301991Sheppo (void) hv_ldc_set_map_table(ldcp->id, NULL, NULL); 28312793Slm66018 if (ldcp->mtbl->contigmem) 28322793Slm66018 contig_mem_free(ldcp->mtbl->table, ldcp->mtbl->size); 28332793Slm66018 else 28342793Slm66018 kmem_free(ldcp->mtbl->table, ldcp->mtbl->size); 28351991Sheppo mutex_destroy(&ldcp->mtbl->lock); 28361991Sheppo kmem_free(ldcp->mtbl, sizeof (ldc_mtbl_t)); 28371991Sheppo } 28381991Sheppo 28391991Sheppo /* Destroy descriptor ring and memory handle list lock */ 28401991Sheppo mutex_destroy(&ldcp->exp_dlist_lock); 28411991Sheppo mutex_destroy(&ldcp->imp_dlist_lock); 28421991Sheppo mutex_destroy(&ldcp->mlist_lock); 28431991Sheppo 28441991Sheppo /* Free the stream buffer for STREAM_MODE */ 28451991Sheppo if (ldcp->mode == LDC_MODE_STREAM && ldcp->stream_bufferp) 28461991Sheppo kmem_free(ldcp->stream_bufferp, ldcp->mtu); 28471991Sheppo 28481991Sheppo /* Free the RX queue */ 28491991Sheppo contig_mem_free((caddr_t)ldcp->rx_q_va, 28501991Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT)); 28511991Sheppo ldcp->tstate &= ~TS_RXQ_RDY; 28521991Sheppo 2853*5944Sha137994 /* Free the RX data queue */ 2854*5944Sha137994 if (ldcp->mode == LDC_MODE_STREAM) { 2855*5944Sha137994 kmem_free((caddr_t)ldcp->rx_dq_va, 2856*5944Sha137994 (ldcp->rx_dq_entries << LDC_PACKET_SHIFT)); 2857*5944Sha137994 } 2858*5944Sha137994 28591991Sheppo /* Free the TX queue */ 28601991Sheppo contig_mem_free((caddr_t)ldcp->tx_q_va, 28611991Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT)); 28621991Sheppo ldcp->tstate &= ~TS_TXQ_RDY; 28631991Sheppo 28641991Sheppo mutex_exit(&ldcp->lock); 28651991Sheppo 28661991Sheppo /* Destroy mutex */ 28672336Snarayan mutex_destroy(&ldcp->tx_lock); 28681991Sheppo mutex_destroy(&ldcp->lock); 28691991Sheppo 28701991Sheppo /* free channel structure */ 28711991Sheppo kmem_free(ldcp, sizeof (ldc_chan_t)); 28721991Sheppo 28731991Sheppo D1(id, "ldc_fini: (0x%llx) channel finalized\n", id); 28741991Sheppo 28751991Sheppo return (0); 28761991Sheppo } 28771991Sheppo 28781991Sheppo /* 28791991Sheppo * Open the LDC channel for use. It registers the TX/RX queues 28801991Sheppo * with the Hypervisor. It also specifies the interrupt number 28811991Sheppo * and target CPU for this channel 28821991Sheppo */ 28831991Sheppo int 28841991Sheppo ldc_open(ldc_handle_t handle) 28851991Sheppo { 28861991Sheppo ldc_chan_t *ldcp; 28871991Sheppo int rv; 28881991Sheppo 28891991Sheppo if (handle == NULL) { 28901991Sheppo DWARN(DBG_ALL_LDCS, "ldc_open: invalid channel handle\n"); 28911991Sheppo return (EINVAL); 28921991Sheppo } 28931991Sheppo 28941991Sheppo ldcp = (ldc_chan_t *)handle; 28951991Sheppo 28961991Sheppo mutex_enter(&ldcp->lock); 28971991Sheppo 28981991Sheppo if (ldcp->tstate < TS_INIT) { 28991991Sheppo DWARN(ldcp->id, 29001991Sheppo "ldc_open: (0x%llx) channel not initialized\n", ldcp->id); 29011991Sheppo mutex_exit(&ldcp->lock); 29021991Sheppo return (EFAULT); 29031991Sheppo } 29042793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) >= TS_OPEN) { 29051991Sheppo DWARN(ldcp->id, 29061991Sheppo "ldc_open: (0x%llx) channel is already open\n", ldcp->id); 29071991Sheppo mutex_exit(&ldcp->lock); 29081991Sheppo return (EFAULT); 29091991Sheppo } 29101991Sheppo 29111991Sheppo /* 29121991Sheppo * Unregister/Register the tx queue with the hypervisor 29131991Sheppo */ 29141991Sheppo rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 29151991Sheppo if (rv) { 29161991Sheppo cmn_err(CE_WARN, 29171991Sheppo "ldc_open: (0x%lx) channel tx queue unconf failed\n", 29181991Sheppo ldcp->id); 29191991Sheppo mutex_exit(&ldcp->lock); 29201991Sheppo return (EIO); 29211991Sheppo } 29221991Sheppo 29231991Sheppo rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries); 29241991Sheppo if (rv) { 29251991Sheppo cmn_err(CE_WARN, 29261991Sheppo "ldc_open: (0x%lx) channel tx queue conf failed\n", 29271991Sheppo ldcp->id); 29281991Sheppo mutex_exit(&ldcp->lock); 29291991Sheppo return (EIO); 29301991Sheppo } 29311991Sheppo 29321991Sheppo D2(ldcp->id, "ldc_open: (0x%llx) registered tx queue with LDC\n", 29331991Sheppo ldcp->id); 29341991Sheppo 29351991Sheppo /* 29361991Sheppo * Unregister/Register the rx queue with the hypervisor 29371991Sheppo */ 29381991Sheppo rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 29391991Sheppo if (rv) { 29401991Sheppo cmn_err(CE_WARN, 29411991Sheppo "ldc_open: (0x%lx) channel rx queue unconf failed\n", 29421991Sheppo ldcp->id); 29431991Sheppo mutex_exit(&ldcp->lock); 29441991Sheppo return (EIO); 29451991Sheppo } 29461991Sheppo 29471991Sheppo rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, ldcp->rx_q_entries); 29481991Sheppo if (rv) { 29491991Sheppo cmn_err(CE_WARN, 29501991Sheppo "ldc_open: (0x%lx) channel rx queue conf failed\n", 29511991Sheppo ldcp->id); 29521991Sheppo mutex_exit(&ldcp->lock); 29531991Sheppo return (EIO); 29541991Sheppo } 29551991Sheppo 29561991Sheppo D2(ldcp->id, "ldc_open: (0x%llx) registered rx queue with LDC\n", 29571991Sheppo ldcp->id); 29581991Sheppo 29591991Sheppo ldcp->tstate |= TS_QCONF_RDY; 29601991Sheppo 29611991Sheppo /* Register the channel with the channel nexus */ 29621991Sheppo rv = i_ldc_register_channel(ldcp); 29631991Sheppo if (rv && rv != EAGAIN) { 29641991Sheppo cmn_err(CE_WARN, 29651991Sheppo "ldc_open: (0x%lx) channel register failed\n", ldcp->id); 29661991Sheppo (void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 29671991Sheppo (void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 29681991Sheppo mutex_exit(&ldcp->lock); 29691991Sheppo return (EIO); 29701991Sheppo } 29711991Sheppo 29721991Sheppo /* mark channel in OPEN state */ 29731991Sheppo ldcp->status = LDC_OPEN; 29741991Sheppo 29751991Sheppo /* Read channel state */ 29761991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 29771991Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 29781991Sheppo if (rv) { 29791991Sheppo cmn_err(CE_WARN, 29801991Sheppo "ldc_open: (0x%lx) cannot read channel state\n", 29811991Sheppo ldcp->id); 29821991Sheppo (void) i_ldc_unregister_channel(ldcp); 29831991Sheppo (void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 29841991Sheppo (void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 29851991Sheppo mutex_exit(&ldcp->lock); 29861991Sheppo return (EIO); 29871991Sheppo } 29881991Sheppo 29891991Sheppo /* 29901991Sheppo * set the ACKd head to current head location for reliable & 29911991Sheppo * streaming mode 29921991Sheppo */ 29931991Sheppo ldcp->tx_ackd_head = ldcp->tx_head; 29941991Sheppo 29951991Sheppo /* mark channel ready if HV report link is UP (peer alloc'd Rx queue) */ 29961991Sheppo if (ldcp->link_state == LDC_CHANNEL_UP || 29971991Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 29981991Sheppo ldcp->tstate |= TS_LINK_READY; 29991991Sheppo ldcp->status = LDC_READY; 30001991Sheppo } 30011991Sheppo 30021991Sheppo /* 30031991Sheppo * if channel is being opened in RAW mode - no handshake is needed 30041991Sheppo * switch the channel READY and UP state 30051991Sheppo */ 30061991Sheppo if (ldcp->mode == LDC_MODE_RAW) { 30071991Sheppo ldcp->tstate = TS_UP; /* set bits associated with LDC UP */ 30081991Sheppo ldcp->status = LDC_UP; 30091991Sheppo } 30101991Sheppo 30111991Sheppo mutex_exit(&ldcp->lock); 30121991Sheppo 30131991Sheppo /* 30141991Sheppo * Increment number of open channels 30151991Sheppo */ 30161991Sheppo mutex_enter(&ldcssp->lock); 30171991Sheppo ldcssp->channels_open++; 30181991Sheppo mutex_exit(&ldcssp->lock); 30191991Sheppo 30203010Slm66018 D1(ldcp->id, 30212793Slm66018 "ldc_open: (0x%llx) channel (0x%p) open for use " 30222793Slm66018 "(tstate=0x%x, status=0x%x)\n", 30232793Slm66018 ldcp->id, ldcp, ldcp->tstate, ldcp->status); 30241991Sheppo 30251991Sheppo return (0); 30261991Sheppo } 30271991Sheppo 30281991Sheppo /* 30291991Sheppo * Close the LDC connection. It will return EBUSY if there 30301991Sheppo * are memory segments or descriptor rings either bound to or 30311991Sheppo * mapped over the channel 30321991Sheppo */ 30331991Sheppo int 30341991Sheppo ldc_close(ldc_handle_t handle) 30351991Sheppo { 30361991Sheppo ldc_chan_t *ldcp; 30372336Snarayan int rv = 0, retries = 0; 30381991Sheppo boolean_t chk_done = B_FALSE; 30391991Sheppo 30401991Sheppo if (handle == NULL) { 30411991Sheppo DWARN(DBG_ALL_LDCS, "ldc_close: invalid channel handle\n"); 30421991Sheppo return (EINVAL); 30431991Sheppo } 30441991Sheppo ldcp = (ldc_chan_t *)handle; 30451991Sheppo 30461991Sheppo mutex_enter(&ldcp->lock); 30471991Sheppo 30481991Sheppo /* return error if channel is not open */ 30492793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) < TS_OPEN) { 30501991Sheppo DWARN(ldcp->id, 30511991Sheppo "ldc_close: (0x%llx) channel is not open\n", ldcp->id); 30521991Sheppo mutex_exit(&ldcp->lock); 30531991Sheppo return (EFAULT); 30541991Sheppo } 30551991Sheppo 30561991Sheppo /* if any memory handles, drings, are bound or mapped cannot close */ 30571991Sheppo if (ldcp->mhdl_list != NULL) { 30581991Sheppo DWARN(ldcp->id, 30591991Sheppo "ldc_close: (0x%llx) channel has bound memory handles\n", 30601991Sheppo ldcp->id); 30611991Sheppo mutex_exit(&ldcp->lock); 30621991Sheppo return (EBUSY); 30631991Sheppo } 30641991Sheppo if (ldcp->exp_dring_list != NULL) { 30651991Sheppo DWARN(ldcp->id, 30661991Sheppo "ldc_close: (0x%llx) channel has bound descriptor rings\n", 30671991Sheppo ldcp->id); 30681991Sheppo mutex_exit(&ldcp->lock); 30691991Sheppo return (EBUSY); 30701991Sheppo } 30711991Sheppo if (ldcp->imp_dring_list != NULL) { 30721991Sheppo DWARN(ldcp->id, 30731991Sheppo "ldc_close: (0x%llx) channel has mapped descriptor rings\n", 30741991Sheppo ldcp->id); 30751991Sheppo mutex_exit(&ldcp->lock); 30761991Sheppo return (EBUSY); 30771991Sheppo } 30781991Sheppo 30793151Ssg70180 if (ldcp->cb_inprogress) { 30803151Ssg70180 DWARN(ldcp->id, "ldc_close: (0x%llx) callback active\n", 30813151Ssg70180 ldcp->id); 30823151Ssg70180 mutex_exit(&ldcp->lock); 30833151Ssg70180 return (EWOULDBLOCK); 30843151Ssg70180 } 30853151Ssg70180 30862336Snarayan /* Obtain Tx lock */ 30872336Snarayan mutex_enter(&ldcp->tx_lock); 30882336Snarayan 30891991Sheppo /* 30901991Sheppo * Wait for pending transmits to complete i.e Tx queue to drain 30911991Sheppo * if there are pending pkts - wait 1 ms and retry again 30921991Sheppo */ 30931991Sheppo for (;;) { 30941991Sheppo 30951991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 30961991Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 30971991Sheppo if (rv) { 30981991Sheppo cmn_err(CE_WARN, 30991991Sheppo "ldc_close: (0x%lx) cannot read qptrs\n", ldcp->id); 31002336Snarayan mutex_exit(&ldcp->tx_lock); 31011991Sheppo mutex_exit(&ldcp->lock); 31021991Sheppo return (EIO); 31031991Sheppo } 31041991Sheppo 31051991Sheppo if (ldcp->tx_head == ldcp->tx_tail || 31061991Sheppo ldcp->link_state != LDC_CHANNEL_UP) { 31071991Sheppo break; 31081991Sheppo } 31091991Sheppo 31101991Sheppo if (chk_done) { 31111991Sheppo DWARN(ldcp->id, 31121991Sheppo "ldc_close: (0x%llx) Tx queue drain timeout\n", 31131991Sheppo ldcp->id); 31141991Sheppo break; 31151991Sheppo } 31161991Sheppo 31171991Sheppo /* wait for one ms and try again */ 31181991Sheppo delay(drv_usectohz(1000)); 31191991Sheppo chk_done = B_TRUE; 31201991Sheppo } 31211991Sheppo 31221991Sheppo /* 31232841Snarayan * Drain the Tx and Rx queues as we are closing the 31242841Snarayan * channel. We dont care about any pending packets. 31252841Snarayan * We have to also drain the queue prior to clearing 31262841Snarayan * pending interrupts, otherwise the HV will trigger 31272841Snarayan * an interrupt the moment the interrupt state is 31282841Snarayan * cleared. 31292793Slm66018 */ 31302793Slm66018 (void) i_ldc_txq_reconf(ldcp); 31312841Snarayan (void) i_ldc_rxq_drain(ldcp); 31322793Slm66018 31332793Slm66018 /* 31341991Sheppo * Unregister the channel with the nexus 31351991Sheppo */ 31362336Snarayan while ((rv = i_ldc_unregister_channel(ldcp)) != 0) { 31372336Snarayan 31382336Snarayan mutex_exit(&ldcp->tx_lock); 31391991Sheppo mutex_exit(&ldcp->lock); 31402336Snarayan 31412336Snarayan /* if any error other than EAGAIN return back */ 31422841Snarayan if (rv != EAGAIN || retries >= ldc_max_retries) { 31432336Snarayan cmn_err(CE_WARN, 31442336Snarayan "ldc_close: (0x%lx) unregister failed, %d\n", 31452336Snarayan ldcp->id, rv); 31462336Snarayan return (rv); 31472336Snarayan } 31482336Snarayan 31492336Snarayan /* 31502336Snarayan * As there could be pending interrupts we need 31512336Snarayan * to wait and try again 31522336Snarayan */ 31533151Ssg70180 drv_usecwait(ldc_close_delay); 31542336Snarayan mutex_enter(&ldcp->lock); 31552336Snarayan mutex_enter(&ldcp->tx_lock); 31562336Snarayan retries++; 31571991Sheppo } 31581991Sheppo 31591991Sheppo /* 31601991Sheppo * Unregister queues 31611991Sheppo */ 31621991Sheppo rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 31631991Sheppo if (rv) { 31641991Sheppo cmn_err(CE_WARN, 31651991Sheppo "ldc_close: (0x%lx) channel TX queue unconf failed\n", 31661991Sheppo ldcp->id); 31672336Snarayan mutex_exit(&ldcp->tx_lock); 31681991Sheppo mutex_exit(&ldcp->lock); 31691991Sheppo return (EIO); 31701991Sheppo } 31711991Sheppo rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 31721991Sheppo if (rv) { 31731991Sheppo cmn_err(CE_WARN, 31741991Sheppo "ldc_close: (0x%lx) channel RX queue unconf failed\n", 31751991Sheppo ldcp->id); 31762336Snarayan mutex_exit(&ldcp->tx_lock); 31771991Sheppo mutex_exit(&ldcp->lock); 31781991Sheppo return (EIO); 31791991Sheppo } 31801991Sheppo 31811991Sheppo ldcp->tstate &= ~TS_QCONF_RDY; 31821991Sheppo 31831991Sheppo /* Reset channel state information */ 31841991Sheppo i_ldc_reset_state(ldcp); 31851991Sheppo 31861991Sheppo /* Mark channel as down and in initialized state */ 31871991Sheppo ldcp->tx_ackd_head = 0; 31881991Sheppo ldcp->tx_head = 0; 31892793Slm66018 ldcp->tstate = TS_IN_RESET|TS_INIT; 31901991Sheppo ldcp->status = LDC_INIT; 31911991Sheppo 31922336Snarayan mutex_exit(&ldcp->tx_lock); 31931991Sheppo mutex_exit(&ldcp->lock); 31941991Sheppo 31951991Sheppo /* Decrement number of open channels */ 31961991Sheppo mutex_enter(&ldcssp->lock); 31971991Sheppo ldcssp->channels_open--; 31981991Sheppo mutex_exit(&ldcssp->lock); 31991991Sheppo 32001991Sheppo D1(ldcp->id, "ldc_close: (0x%llx) channel closed\n", ldcp->id); 32011991Sheppo 32021991Sheppo return (0); 32031991Sheppo } 32041991Sheppo 32051991Sheppo /* 32061991Sheppo * Register channel callback 32071991Sheppo */ 32081991Sheppo int 32091991Sheppo ldc_reg_callback(ldc_handle_t handle, 32101991Sheppo uint_t(*cb)(uint64_t event, caddr_t arg), caddr_t arg) 32111991Sheppo { 32121991Sheppo ldc_chan_t *ldcp; 32131991Sheppo 32141991Sheppo if (handle == NULL) { 32151991Sheppo DWARN(DBG_ALL_LDCS, 32161991Sheppo "ldc_reg_callback: invalid channel handle\n"); 32171991Sheppo return (EINVAL); 32181991Sheppo } 32191991Sheppo if (((uint64_t)cb) < KERNELBASE) { 32201991Sheppo DWARN(DBG_ALL_LDCS, "ldc_reg_callback: invalid callback\n"); 32211991Sheppo return (EINVAL); 32221991Sheppo } 32231991Sheppo ldcp = (ldc_chan_t *)handle; 32241991Sheppo 32251991Sheppo mutex_enter(&ldcp->lock); 32261991Sheppo 32271991Sheppo if (ldcp->cb) { 32281991Sheppo DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback exists\n", 32291991Sheppo ldcp->id); 32301991Sheppo mutex_exit(&ldcp->lock); 32311991Sheppo return (EIO); 32321991Sheppo } 32331991Sheppo if (ldcp->cb_inprogress) { 32341991Sheppo DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback active\n", 32351991Sheppo ldcp->id); 32361991Sheppo mutex_exit(&ldcp->lock); 32371991Sheppo return (EWOULDBLOCK); 32381991Sheppo } 32391991Sheppo 32401991Sheppo ldcp->cb = cb; 32411991Sheppo ldcp->cb_arg = arg; 32421991Sheppo ldcp->cb_enabled = B_TRUE; 32431991Sheppo 32441991Sheppo D1(ldcp->id, 32451991Sheppo "ldc_reg_callback: (0x%llx) registered callback for channel\n", 32461991Sheppo ldcp->id); 32471991Sheppo 32481991Sheppo mutex_exit(&ldcp->lock); 32491991Sheppo 32501991Sheppo return (0); 32511991Sheppo } 32521991Sheppo 32531991Sheppo /* 32541991Sheppo * Unregister channel callback 32551991Sheppo */ 32561991Sheppo int 32571991Sheppo ldc_unreg_callback(ldc_handle_t handle) 32581991Sheppo { 32591991Sheppo ldc_chan_t *ldcp; 32601991Sheppo 32611991Sheppo if (handle == NULL) { 32621991Sheppo DWARN(DBG_ALL_LDCS, 32631991Sheppo "ldc_unreg_callback: invalid channel handle\n"); 32641991Sheppo return (EINVAL); 32651991Sheppo } 32661991Sheppo ldcp = (ldc_chan_t *)handle; 32671991Sheppo 32681991Sheppo mutex_enter(&ldcp->lock); 32691991Sheppo 32701991Sheppo if (ldcp->cb == NULL) { 32711991Sheppo DWARN(ldcp->id, 32721991Sheppo "ldc_unreg_callback: (0x%llx) no callback exists\n", 32731991Sheppo ldcp->id); 32741991Sheppo mutex_exit(&ldcp->lock); 32751991Sheppo return (EIO); 32761991Sheppo } 32771991Sheppo if (ldcp->cb_inprogress) { 32781991Sheppo DWARN(ldcp->id, 32791991Sheppo "ldc_unreg_callback: (0x%llx) callback active\n", 32801991Sheppo ldcp->id); 32811991Sheppo mutex_exit(&ldcp->lock); 32821991Sheppo return (EWOULDBLOCK); 32831991Sheppo } 32841991Sheppo 32851991Sheppo ldcp->cb = NULL; 32861991Sheppo ldcp->cb_arg = NULL; 32871991Sheppo ldcp->cb_enabled = B_FALSE; 32881991Sheppo 32891991Sheppo D1(ldcp->id, 32901991Sheppo "ldc_unreg_callback: (0x%llx) unregistered callback for channel\n", 32911991Sheppo ldcp->id); 32921991Sheppo 32931991Sheppo mutex_exit(&ldcp->lock); 32941991Sheppo 32951991Sheppo return (0); 32961991Sheppo } 32971991Sheppo 32981991Sheppo 32991991Sheppo /* 33001991Sheppo * Bring a channel up by initiating a handshake with the peer 33011991Sheppo * This call is asynchronous. It will complete at a later point 33021991Sheppo * in time when the peer responds back with an RTR. 33031991Sheppo */ 33041991Sheppo int 33051991Sheppo ldc_up(ldc_handle_t handle) 33061991Sheppo { 33071991Sheppo int rv; 33081991Sheppo ldc_chan_t *ldcp; 33091991Sheppo ldc_msg_t *ldcmsg; 33103808Ssb155480 uint64_t tx_tail, tstate, link_state; 33111991Sheppo 33121991Sheppo if (handle == NULL) { 33131991Sheppo DWARN(DBG_ALL_LDCS, "ldc_up: invalid channel handle\n"); 33141991Sheppo return (EINVAL); 33151991Sheppo } 33161991Sheppo ldcp = (ldc_chan_t *)handle; 33171991Sheppo 33181991Sheppo mutex_enter(&ldcp->lock); 33191991Sheppo 33202793Slm66018 D1(ldcp->id, "ldc_up: (0x%llx) doing channel UP\n", ldcp->id); 33212793Slm66018 33222793Slm66018 /* clear the reset state */ 33232793Slm66018 tstate = ldcp->tstate; 33242793Slm66018 ldcp->tstate &= ~TS_IN_RESET; 33252793Slm66018 33261991Sheppo if (ldcp->tstate == TS_UP) { 33272793Slm66018 DWARN(ldcp->id, 33281991Sheppo "ldc_up: (0x%llx) channel is already in UP state\n", 33291991Sheppo ldcp->id); 33302793Slm66018 33312793Slm66018 /* mark channel as up */ 33322793Slm66018 ldcp->status = LDC_UP; 33332793Slm66018 33342793Slm66018 /* 33352793Slm66018 * if channel was in reset state and there was 33362793Slm66018 * pending data clear interrupt state. this will 33372793Slm66018 * trigger an interrupt, causing the RX handler to 33382793Slm66018 * to invoke the client's callback 33392793Slm66018 */ 33402793Slm66018 if ((tstate & TS_IN_RESET) && 33412793Slm66018 ldcp->rx_intr_state == LDC_INTR_PEND) { 33423010Slm66018 D1(ldcp->id, 33432793Slm66018 "ldc_up: (0x%llx) channel has pending data, " 33442793Slm66018 "clearing interrupt\n", ldcp->id); 33452793Slm66018 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 33462793Slm66018 } 33472793Slm66018 33481991Sheppo mutex_exit(&ldcp->lock); 33491991Sheppo return (0); 33501991Sheppo } 33511991Sheppo 33521991Sheppo /* if the channel is in RAW mode - mark it as UP, if READY */ 33531991Sheppo if (ldcp->mode == LDC_MODE_RAW && ldcp->tstate >= TS_READY) { 33541991Sheppo ldcp->tstate = TS_UP; 33551991Sheppo mutex_exit(&ldcp->lock); 33561991Sheppo return (0); 33571991Sheppo } 33581991Sheppo 33591991Sheppo /* Don't start another handshake if there is one in progress */ 33601991Sheppo if (ldcp->hstate) { 33612793Slm66018 D1(ldcp->id, 33621991Sheppo "ldc_up: (0x%llx) channel handshake in progress\n", 33631991Sheppo ldcp->id); 33641991Sheppo mutex_exit(&ldcp->lock); 33651991Sheppo return (0); 33661991Sheppo } 33671991Sheppo 33682336Snarayan mutex_enter(&ldcp->tx_lock); 33692336Snarayan 33703808Ssb155480 /* save current link state */ 33713808Ssb155480 link_state = ldcp->link_state; 33723808Ssb155480 33731991Sheppo /* get the current tail for the LDC msg */ 33741991Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 33751991Sheppo if (rv) { 33763010Slm66018 D1(ldcp->id, "ldc_up: (0x%llx) cannot initiate handshake\n", 33771991Sheppo ldcp->id); 33782336Snarayan mutex_exit(&ldcp->tx_lock); 33791991Sheppo mutex_exit(&ldcp->lock); 33801991Sheppo return (ECONNREFUSED); 33811991Sheppo } 33821991Sheppo 33833808Ssb155480 /* 33843808Ssb155480 * If i_ldc_get_tx_tail() changed link_state to either RESET or UP, 33853808Ssb155480 * from a previous state of DOWN, then mark the channel as 33863808Ssb155480 * being ready for handshake. 33873808Ssb155480 */ 33883808Ssb155480 if ((link_state == LDC_CHANNEL_DOWN) && 33893808Ssb155480 (link_state != ldcp->link_state)) { 33903808Ssb155480 33913808Ssb155480 ASSERT((ldcp->link_state == LDC_CHANNEL_RESET) || 33923808Ssb155480 (ldcp->link_state == LDC_CHANNEL_UP)); 33933808Ssb155480 33943808Ssb155480 if (ldcp->mode == LDC_MODE_RAW) { 33953808Ssb155480 ldcp->status = LDC_UP; 33963808Ssb155480 ldcp->tstate = TS_UP; 33973808Ssb155480 mutex_exit(&ldcp->tx_lock); 33983808Ssb155480 mutex_exit(&ldcp->lock); 33993808Ssb155480 return (0); 34003808Ssb155480 } else { 34013808Ssb155480 ldcp->status = LDC_READY; 34023808Ssb155480 ldcp->tstate |= TS_LINK_READY; 34033808Ssb155480 } 34043808Ssb155480 34053808Ssb155480 } 34063808Ssb155480 34071991Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 34081991Sheppo ZERO_PKT(ldcmsg); 34091991Sheppo 34101991Sheppo ldcmsg->type = LDC_CTRL; 34111991Sheppo ldcmsg->stype = LDC_INFO; 34121991Sheppo ldcmsg->ctrl = LDC_VER; 34131991Sheppo ldcp->next_vidx = 0; 34141991Sheppo bcopy(&ldc_versions[0], ldcmsg->udata, sizeof (ldc_versions[0])); 34151991Sheppo 34161991Sheppo DUMP_LDC_PKT(ldcp, "ldc_up snd ver", (uint64_t)ldcmsg); 34171991Sheppo 34181991Sheppo /* initiate the send by calling into HV and set the new tail */ 34191991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 34204690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 34211991Sheppo 34221991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 34231991Sheppo if (rv) { 34241991Sheppo DWARN(ldcp->id, 34251991Sheppo "ldc_up: (0x%llx) cannot initiate handshake rv=%d\n", 34261991Sheppo ldcp->id, rv); 34272336Snarayan mutex_exit(&ldcp->tx_lock); 34281991Sheppo mutex_exit(&ldcp->lock); 34291991Sheppo return (rv); 34301991Sheppo } 34311991Sheppo 34322032Slm66018 ldcp->hstate |= TS_SENT_VER; 34331991Sheppo ldcp->tx_tail = tx_tail; 34341991Sheppo D1(ldcp->id, "ldc_up: (0x%llx) channel up initiated\n", ldcp->id); 34351991Sheppo 34362336Snarayan mutex_exit(&ldcp->tx_lock); 34371991Sheppo mutex_exit(&ldcp->lock); 34381991Sheppo 34391991Sheppo return (rv); 34401991Sheppo } 34411991Sheppo 34421991Sheppo 34431991Sheppo /* 34442410Slm66018 * Bring a channel down by resetting its state and queues 34451991Sheppo */ 34461991Sheppo int 34472410Slm66018 ldc_down(ldc_handle_t handle) 34481991Sheppo { 34491991Sheppo ldc_chan_t *ldcp; 34501991Sheppo 34511991Sheppo if (handle == NULL) { 34522410Slm66018 DWARN(DBG_ALL_LDCS, "ldc_down: invalid channel handle\n"); 34531991Sheppo return (EINVAL); 34541991Sheppo } 34551991Sheppo ldcp = (ldc_chan_t *)handle; 34561991Sheppo mutex_enter(&ldcp->lock); 34572336Snarayan mutex_enter(&ldcp->tx_lock); 34582793Slm66018 i_ldc_reset(ldcp, B_TRUE); 34592336Snarayan mutex_exit(&ldcp->tx_lock); 34601991Sheppo mutex_exit(&ldcp->lock); 34611991Sheppo 34621991Sheppo return (0); 34631991Sheppo } 34641991Sheppo 34651991Sheppo /* 34661991Sheppo * Get the current channel status 34671991Sheppo */ 34681991Sheppo int 34691991Sheppo ldc_status(ldc_handle_t handle, ldc_status_t *status) 34701991Sheppo { 34711991Sheppo ldc_chan_t *ldcp; 34721991Sheppo 34731991Sheppo if (handle == NULL || status == NULL) { 34741991Sheppo DWARN(DBG_ALL_LDCS, "ldc_status: invalid argument\n"); 34751991Sheppo return (EINVAL); 34761991Sheppo } 34771991Sheppo ldcp = (ldc_chan_t *)handle; 34781991Sheppo 34791991Sheppo *status = ((ldc_chan_t *)handle)->status; 34801991Sheppo 34813010Slm66018 D1(ldcp->id, 34821991Sheppo "ldc_status: (0x%llx) returned status %d\n", ldcp->id, *status); 34831991Sheppo return (0); 34841991Sheppo } 34851991Sheppo 34861991Sheppo 34871991Sheppo /* 34881991Sheppo * Set the channel's callback mode - enable/disable callbacks 34891991Sheppo */ 34901991Sheppo int 34911991Sheppo ldc_set_cb_mode(ldc_handle_t handle, ldc_cb_mode_t cmode) 34921991Sheppo { 34931991Sheppo ldc_chan_t *ldcp; 34941991Sheppo 34951991Sheppo if (handle == NULL) { 34961991Sheppo DWARN(DBG_ALL_LDCS, 34971991Sheppo "ldc_set_intr_mode: invalid channel handle\n"); 34981991Sheppo return (EINVAL); 34991991Sheppo } 35001991Sheppo ldcp = (ldc_chan_t *)handle; 35011991Sheppo 35021991Sheppo /* 35031991Sheppo * Record no callbacks should be invoked 35041991Sheppo */ 35051991Sheppo mutex_enter(&ldcp->lock); 35061991Sheppo 35071991Sheppo switch (cmode) { 35081991Sheppo case LDC_CB_DISABLE: 35091991Sheppo if (!ldcp->cb_enabled) { 35101991Sheppo DWARN(ldcp->id, 35111991Sheppo "ldc_set_cb_mode: (0x%llx) callbacks disabled\n", 35121991Sheppo ldcp->id); 35131991Sheppo break; 35141991Sheppo } 35151991Sheppo ldcp->cb_enabled = B_FALSE; 35161991Sheppo 35171991Sheppo D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) disabled callbacks\n", 35181991Sheppo ldcp->id); 35191991Sheppo break; 35201991Sheppo 35211991Sheppo case LDC_CB_ENABLE: 35221991Sheppo if (ldcp->cb_enabled) { 35231991Sheppo DWARN(ldcp->id, 35241991Sheppo "ldc_set_cb_mode: (0x%llx) callbacks enabled\n", 35251991Sheppo ldcp->id); 35261991Sheppo break; 35271991Sheppo } 35281991Sheppo ldcp->cb_enabled = B_TRUE; 35291991Sheppo 35301991Sheppo D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) enabled callbacks\n", 35311991Sheppo ldcp->id); 35321991Sheppo break; 35331991Sheppo } 35341991Sheppo 35351991Sheppo mutex_exit(&ldcp->lock); 35361991Sheppo 35371991Sheppo return (0); 35381991Sheppo } 35391991Sheppo 35401991Sheppo /* 35411991Sheppo * Check to see if there are packets on the incoming queue 35422410Slm66018 * Will return hasdata = B_FALSE if there are no packets 35431991Sheppo */ 35441991Sheppo int 35452410Slm66018 ldc_chkq(ldc_handle_t handle, boolean_t *hasdata) 35461991Sheppo { 35471991Sheppo int rv; 35481991Sheppo uint64_t rx_head, rx_tail; 35491991Sheppo ldc_chan_t *ldcp; 35501991Sheppo 35511991Sheppo if (handle == NULL) { 35521991Sheppo DWARN(DBG_ALL_LDCS, "ldc_chkq: invalid channel handle\n"); 35531991Sheppo return (EINVAL); 35541991Sheppo } 35551991Sheppo ldcp = (ldc_chan_t *)handle; 35561991Sheppo 35572410Slm66018 *hasdata = B_FALSE; 35581991Sheppo 35591991Sheppo mutex_enter(&ldcp->lock); 35601991Sheppo 35611991Sheppo if (ldcp->tstate != TS_UP) { 35621991Sheppo D1(ldcp->id, 35631991Sheppo "ldc_chkq: (0x%llx) channel is not up\n", ldcp->id); 35641991Sheppo mutex_exit(&ldcp->lock); 35651991Sheppo return (ECONNRESET); 35661991Sheppo } 35671991Sheppo 35681991Sheppo /* Read packet(s) from the queue */ 35691991Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 35701991Sheppo &ldcp->link_state); 35711991Sheppo if (rv != 0) { 35721991Sheppo cmn_err(CE_WARN, 35731991Sheppo "ldc_chkq: (0x%lx) unable to read queue ptrs", ldcp->id); 35741991Sheppo mutex_exit(&ldcp->lock); 35751991Sheppo return (EIO); 35761991Sheppo } 3577*5944Sha137994 35781991Sheppo /* reset the channel state if the channel went down */ 35791991Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN || 35801991Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 35812336Snarayan mutex_enter(&ldcp->tx_lock); 35822793Slm66018 i_ldc_reset(ldcp, B_FALSE); 35832336Snarayan mutex_exit(&ldcp->tx_lock); 35841991Sheppo mutex_exit(&ldcp->lock); 35851991Sheppo return (ECONNRESET); 35861991Sheppo } 35871991Sheppo 3588*5944Sha137994 switch (ldcp->mode) { 3589*5944Sha137994 case LDC_MODE_RAW: 3590*5944Sha137994 /* 3591*5944Sha137994 * In raw mode, there are no ctrl packets, so checking 3592*5944Sha137994 * if the queue is non-empty is sufficient. 3593*5944Sha137994 */ 3594*5944Sha137994 *hasdata = (rx_head != rx_tail); 3595*5944Sha137994 break; 3596*5944Sha137994 3597*5944Sha137994 case LDC_MODE_UNRELIABLE: 3598*5944Sha137994 /* 3599*5944Sha137994 * In unreliable mode, if the queue is non-empty, we need 3600*5944Sha137994 * to check if it actually contains unread data packets. 3601*5944Sha137994 * The queue may just contain ctrl packets. 3602*5944Sha137994 */ 3603*5944Sha137994 if (rx_head != rx_tail) 3604*5944Sha137994 *hasdata = (i_ldc_chkq(ldcp) == 0); 3605*5944Sha137994 break; 3606*5944Sha137994 3607*5944Sha137994 case LDC_MODE_STREAM: 3608*5944Sha137994 /* 3609*5944Sha137994 * In stream mode, first check for 'stream_remains' > 0. 3610*5944Sha137994 * Otherwise, if the data queue head and tail pointers 3611*5944Sha137994 * differ, there must be data to read. 3612*5944Sha137994 */ 3613*5944Sha137994 if (ldcp->stream_remains > 0) 3614*5944Sha137994 *hasdata = B_TRUE; 3615*5944Sha137994 else 3616*5944Sha137994 *hasdata = (ldcp->rx_dq_head != ldcp->rx_dq_tail); 3617*5944Sha137994 break; 3618*5944Sha137994 3619*5944Sha137994 default: 3620*5944Sha137994 cmn_err(CE_WARN, "ldc_chkq: (0x%lx) unexpected channel mode " 3621*5944Sha137994 "(0x%x)", ldcp->id, ldcp->mode); 3622*5944Sha137994 mutex_exit(&ldcp->lock); 3623*5944Sha137994 return (EIO); 36241991Sheppo } 36251991Sheppo 36261991Sheppo mutex_exit(&ldcp->lock); 36271991Sheppo 36281991Sheppo return (0); 36291991Sheppo } 36301991Sheppo 36311991Sheppo 36321991Sheppo /* 36331991Sheppo * Read 'size' amount of bytes or less. If incoming buffer 36341991Sheppo * is more than 'size', ENOBUFS is returned. 36351991Sheppo * 36361991Sheppo * On return, size contains the number of bytes read. 36371991Sheppo */ 36381991Sheppo int 36391991Sheppo ldc_read(ldc_handle_t handle, caddr_t bufp, size_t *sizep) 36401991Sheppo { 36411991Sheppo ldc_chan_t *ldcp; 36421991Sheppo uint64_t rx_head = 0, rx_tail = 0; 36431991Sheppo int rv = 0, exit_val; 36441991Sheppo 36451991Sheppo if (handle == NULL) { 36461991Sheppo DWARN(DBG_ALL_LDCS, "ldc_read: invalid channel handle\n"); 36471991Sheppo return (EINVAL); 36481991Sheppo } 36491991Sheppo 36501991Sheppo ldcp = (ldc_chan_t *)handle; 36511991Sheppo 36521991Sheppo /* channel lock */ 36531991Sheppo mutex_enter(&ldcp->lock); 36541991Sheppo 36551991Sheppo if (ldcp->tstate != TS_UP) { 36561991Sheppo DWARN(ldcp->id, 36571991Sheppo "ldc_read: (0x%llx) channel is not in UP state\n", 36581991Sheppo ldcp->id); 36591991Sheppo exit_val = ECONNRESET; 3660*5944Sha137994 } else if (ldcp->mode == LDC_MODE_STREAM) { 3661*5944Sha137994 TRACE_RXDQ_LENGTH(ldcp); 3662*5944Sha137994 exit_val = ldcp->read_p(ldcp, bufp, sizep); 3663*5944Sha137994 mutex_exit(&ldcp->lock); 3664*5944Sha137994 return (exit_val); 36651991Sheppo } else { 36661991Sheppo exit_val = ldcp->read_p(ldcp, bufp, sizep); 36671991Sheppo } 36681991Sheppo 36691991Sheppo /* 36701991Sheppo * if queue has been drained - clear interrupt 36711991Sheppo */ 36721991Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 36731991Sheppo &ldcp->link_state); 36743010Slm66018 if (rv != 0) { 36753010Slm66018 cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs", 36763010Slm66018 ldcp->id); 36773010Slm66018 mutex_enter(&ldcp->tx_lock); 36783010Slm66018 i_ldc_reset(ldcp, B_TRUE); 36793010Slm66018 mutex_exit(&ldcp->tx_lock); 36803653Snarayan mutex_exit(&ldcp->lock); 36813010Slm66018 return (ECONNRESET); 36823010Slm66018 } 36832793Slm66018 36842793Slm66018 if (exit_val == 0) { 36852793Slm66018 if (ldcp->link_state == LDC_CHANNEL_DOWN || 36862793Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) { 36872793Slm66018 mutex_enter(&ldcp->tx_lock); 36882793Slm66018 i_ldc_reset(ldcp, B_FALSE); 36892793Slm66018 exit_val = ECONNRESET; 36902793Slm66018 mutex_exit(&ldcp->tx_lock); 36912793Slm66018 } 36922793Slm66018 if ((rv == 0) && 36932793Slm66018 (ldcp->rx_intr_state == LDC_INTR_PEND) && 36942793Slm66018 (rx_head == rx_tail)) { 36952793Slm66018 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 36962793Slm66018 } 36971991Sheppo } 36981991Sheppo 36991991Sheppo mutex_exit(&ldcp->lock); 37001991Sheppo return (exit_val); 37011991Sheppo } 37021991Sheppo 37031991Sheppo /* 37041991Sheppo * Basic raw mondo read - 37051991Sheppo * no interpretation of mondo contents at all. 37061991Sheppo * 37071991Sheppo * Enter and exit with ldcp->lock held by caller 37081991Sheppo */ 37091991Sheppo static int 37101991Sheppo i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep) 37111991Sheppo { 37121991Sheppo uint64_t q_size_mask; 37131991Sheppo ldc_msg_t *msgp; 37141991Sheppo uint8_t *msgbufp; 37151991Sheppo int rv = 0, space; 37161991Sheppo uint64_t rx_head, rx_tail; 37171991Sheppo 37181991Sheppo space = *sizep; 37191991Sheppo 37201991Sheppo if (space < LDC_PAYLOAD_SIZE_RAW) 37211991Sheppo return (ENOBUFS); 37221991Sheppo 37231991Sheppo ASSERT(mutex_owned(&ldcp->lock)); 37241991Sheppo 37251991Sheppo /* compute mask for increment */ 37261991Sheppo q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT; 37271991Sheppo 37281991Sheppo /* 37291991Sheppo * Read packet(s) from the queue 37301991Sheppo */ 37311991Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 37321991Sheppo &ldcp->link_state); 37331991Sheppo if (rv != 0) { 37341991Sheppo cmn_err(CE_WARN, 37351991Sheppo "ldc_read_raw: (0x%lx) unable to read queue ptrs", 37361991Sheppo ldcp->id); 37371991Sheppo return (EIO); 37381991Sheppo } 37391991Sheppo D1(ldcp->id, "ldc_read_raw: (0x%llx) rxh=0x%llx," 37404690Snarayan " rxt=0x%llx, st=0x%llx\n", 37414690Snarayan ldcp->id, rx_head, rx_tail, ldcp->link_state); 37421991Sheppo 37431991Sheppo /* reset the channel state if the channel went down */ 37442793Slm66018 if (ldcp->link_state == LDC_CHANNEL_DOWN || 37452793Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) { 37462336Snarayan mutex_enter(&ldcp->tx_lock); 37472793Slm66018 i_ldc_reset(ldcp, B_FALSE); 37482336Snarayan mutex_exit(&ldcp->tx_lock); 37491991Sheppo return (ECONNRESET); 37501991Sheppo } 37511991Sheppo 37521991Sheppo /* 37531991Sheppo * Check for empty queue 37541991Sheppo */ 37551991Sheppo if (rx_head == rx_tail) { 37561991Sheppo *sizep = 0; 37571991Sheppo return (0); 37581991Sheppo } 37591991Sheppo 37601991Sheppo /* get the message */ 37611991Sheppo msgp = (ldc_msg_t *)(ldcp->rx_q_va + rx_head); 37621991Sheppo 37631991Sheppo /* if channel is in RAW mode, copy data and return */ 37641991Sheppo msgbufp = (uint8_t *)&(msgp->raw[0]); 37651991Sheppo 37661991Sheppo bcopy(msgbufp, target_bufp, LDC_PAYLOAD_SIZE_RAW); 37671991Sheppo 37681991Sheppo DUMP_PAYLOAD(ldcp->id, msgbufp); 37691991Sheppo 37701991Sheppo *sizep = LDC_PAYLOAD_SIZE_RAW; 37711991Sheppo 37721991Sheppo rx_head = (rx_head + LDC_PACKET_SIZE) & q_size_mask; 37732032Slm66018 rv = i_ldc_set_rx_head(ldcp, rx_head); 37741991Sheppo 37751991Sheppo return (rv); 37761991Sheppo } 37771991Sheppo 37781991Sheppo /* 37791991Sheppo * Process LDC mondos to build larger packets 37801991Sheppo * with either un-reliable or reliable delivery. 37811991Sheppo * 37821991Sheppo * Enter and exit with ldcp->lock held by caller 37831991Sheppo */ 37841991Sheppo static int 37851991Sheppo i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep) 37861991Sheppo { 37871991Sheppo int rv = 0; 37881991Sheppo uint64_t rx_head = 0, rx_tail = 0; 37891991Sheppo uint64_t curr_head = 0; 37901991Sheppo ldc_msg_t *msg; 37911991Sheppo caddr_t target; 37921991Sheppo size_t len = 0, bytes_read = 0; 37932032Slm66018 int retries = 0; 3794*5944Sha137994 uint64_t q_va, q_size_mask; 37952336Snarayan uint64_t first_fragment = 0; 37961991Sheppo 37971991Sheppo target = target_bufp; 37981991Sheppo 37991991Sheppo ASSERT(mutex_owned(&ldcp->lock)); 38001991Sheppo 38012793Slm66018 /* check if the buffer and size are valid */ 38022793Slm66018 if (target_bufp == NULL || *sizep == 0) { 38032793Slm66018 DWARN(ldcp->id, "ldc_read: (0x%llx) invalid buffer/size\n", 38042793Slm66018 ldcp->id); 38052793Slm66018 return (EINVAL); 38062793Slm66018 } 38072793Slm66018 3808*5944Sha137994 /* Set q_va and compute increment mask for the appropriate queue */ 3809*5944Sha137994 if (ldcp->mode == LDC_MODE_STREAM) { 3810*5944Sha137994 q_va = ldcp->rx_dq_va; 3811*5944Sha137994 q_size_mask = (ldcp->rx_dq_entries-1)<<LDC_PACKET_SHIFT; 3812*5944Sha137994 } else { 3813*5944Sha137994 q_va = ldcp->rx_q_va; 3814*5944Sha137994 q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT; 3815*5944Sha137994 } 38161991Sheppo 38171991Sheppo /* 38181991Sheppo * Read packet(s) from the queue 38191991Sheppo */ 3820*5944Sha137994 rv = ldcp->readq_get_state(ldcp, &curr_head, &rx_tail, 38211991Sheppo &ldcp->link_state); 38221991Sheppo if (rv != 0) { 38232793Slm66018 cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs", 38241991Sheppo ldcp->id); 38252793Slm66018 mutex_enter(&ldcp->tx_lock); 38262793Slm66018 i_ldc_reset(ldcp, B_TRUE); 38272793Slm66018 mutex_exit(&ldcp->tx_lock); 38282793Slm66018 return (ECONNRESET); 38291991Sheppo } 38301991Sheppo D1(ldcp->id, "ldc_read: (0x%llx) chd=0x%llx, tl=0x%llx, st=0x%llx\n", 38311991Sheppo ldcp->id, curr_head, rx_tail, ldcp->link_state); 38321991Sheppo 38331991Sheppo /* reset the channel state if the channel went down */ 38342793Slm66018 if (ldcp->link_state != LDC_CHANNEL_UP) 38352793Slm66018 goto channel_is_reset; 38361991Sheppo 38371991Sheppo for (;;) { 38381991Sheppo 38391991Sheppo if (curr_head == rx_tail) { 3840*5944Sha137994 /* 3841*5944Sha137994 * If a data queue is being used, check the Rx HV 3842*5944Sha137994 * queue. This will copy over any new data packets 3843*5944Sha137994 * that have arrived. 3844*5944Sha137994 */ 3845*5944Sha137994 if (ldcp->mode == LDC_MODE_STREAM) 3846*5944Sha137994 (void) i_ldc_chkq(ldcp); 3847*5944Sha137994 3848*5944Sha137994 rv = ldcp->readq_get_state(ldcp, 38491991Sheppo &rx_head, &rx_tail, &ldcp->link_state); 38501991Sheppo if (rv != 0) { 38511991Sheppo cmn_err(CE_WARN, 38521991Sheppo "ldc_read: (0x%lx) cannot read queue ptrs", 38531991Sheppo ldcp->id); 38542336Snarayan mutex_enter(&ldcp->tx_lock); 38552793Slm66018 i_ldc_reset(ldcp, B_TRUE); 38562336Snarayan mutex_exit(&ldcp->tx_lock); 38571991Sheppo return (ECONNRESET); 38581991Sheppo } 3859*5944Sha137994 38602793Slm66018 if (ldcp->link_state != LDC_CHANNEL_UP) 38612793Slm66018 goto channel_is_reset; 38622793Slm66018 38632793Slm66018 if (curr_head == rx_tail) { 38642793Slm66018 38652793Slm66018 /* If in the middle of a fragmented xfer */ 38662793Slm66018 if (first_fragment != 0) { 38672793Slm66018 38682793Slm66018 /* wait for ldc_delay usecs */ 38692793Slm66018 drv_usecwait(ldc_delay); 38702793Slm66018 38712793Slm66018 if (++retries < ldc_max_retries) 38722793Slm66018 continue; 38732793Slm66018 38742793Slm66018 *sizep = 0; 3875*5944Sha137994 if (ldcp->mode != LDC_MODE_STREAM) 3876*5944Sha137994 ldcp->last_msg_rcd = 3877*5944Sha137994 first_fragment - 1; 38782793Slm66018 DWARN(DBG_ALL_LDCS, "ldc_read: " 38794690Snarayan "(0x%llx) read timeout", ldcp->id); 38802793Slm66018 return (EAGAIN); 38812793Slm66018 } 38822032Slm66018 *sizep = 0; 38832793Slm66018 break; 38841991Sheppo } 38851991Sheppo } 38862032Slm66018 retries = 0; 38871991Sheppo 38881991Sheppo D2(ldcp->id, 38891991Sheppo "ldc_read: (0x%llx) chd=0x%llx, rxhd=0x%llx, rxtl=0x%llx\n", 38901991Sheppo ldcp->id, curr_head, rx_head, rx_tail); 38911991Sheppo 38921991Sheppo /* get the message */ 3893*5944Sha137994 msg = (ldc_msg_t *)(q_va + curr_head); 38941991Sheppo 38951991Sheppo DUMP_LDC_PKT(ldcp, "ldc_read received pkt", 38961991Sheppo ldcp->rx_q_va + curr_head); 38971991Sheppo 38981991Sheppo /* Check the message ID for the message received */ 3899*5944Sha137994 if (ldcp->mode != LDC_MODE_STREAM) { 3900*5944Sha137994 if ((rv = i_ldc_check_seqid(ldcp, msg)) != 0) { 3901*5944Sha137994 3902*5944Sha137994 DWARN(ldcp->id, "ldc_read: (0x%llx) seqid " 3903*5944Sha137994 "error, q_ptrs=0x%lx,0x%lx", 3904*5944Sha137994 ldcp->id, rx_head, rx_tail); 3905*5944Sha137994 3906*5944Sha137994 /* throw away data */ 3907*5944Sha137994 bytes_read = 0; 3908*5944Sha137994 3909*5944Sha137994 /* Reset last_msg_rcd to start of message */ 3910*5944Sha137994 if (first_fragment != 0) { 3911*5944Sha137994 ldcp->last_msg_rcd = first_fragment - 1; 3912*5944Sha137994 first_fragment = 0; 3913*5944Sha137994 } 3914*5944Sha137994 /* 3915*5944Sha137994 * Send a NACK -- invalid seqid 3916*5944Sha137994 * get the current tail for the response 3917*5944Sha137994 */ 3918*5944Sha137994 rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK, 3919*5944Sha137994 (msg->ctrl & LDC_CTRL_MASK)); 3920*5944Sha137994 if (rv) { 3921*5944Sha137994 cmn_err(CE_NOTE, 3922*5944Sha137994 "ldc_read: (0x%lx) err sending " 3923*5944Sha137994 "NACK msg\n", ldcp->id); 3924*5944Sha137994 3925*5944Sha137994 /* if cannot send NACK - reset chan */ 3926*5944Sha137994 mutex_enter(&ldcp->tx_lock); 3927*5944Sha137994 i_ldc_reset(ldcp, B_FALSE); 3928*5944Sha137994 mutex_exit(&ldcp->tx_lock); 3929*5944Sha137994 rv = ECONNRESET; 3930*5944Sha137994 break; 3931*5944Sha137994 } 3932*5944Sha137994 3933*5944Sha137994 /* purge receive queue */ 3934*5944Sha137994 rv = i_ldc_set_rx_head(ldcp, rx_tail); 3935*5944Sha137994 39362336Snarayan break; 39371991Sheppo } 39381991Sheppo 3939*5944Sha137994 /* 3940*5944Sha137994 * Process any messages of type CTRL messages 3941*5944Sha137994 * Future implementations should try to pass these 3942*5944Sha137994 * to LDC link by resetting the intr state. 3943*5944Sha137994 * 3944*5944Sha137994 * NOTE: not done as a switch() as type can be 3945*5944Sha137994 * both ctrl+data 3946*5944Sha137994 */ 3947*5944Sha137994 if (msg->type & LDC_CTRL) { 3948*5944Sha137994 if (rv = i_ldc_ctrlmsg(ldcp, msg)) { 3949*5944Sha137994 if (rv == EAGAIN) 3950*5944Sha137994 continue; 3951*5944Sha137994 rv = i_ldc_set_rx_head(ldcp, rx_tail); 3952*5944Sha137994 *sizep = 0; 3953*5944Sha137994 bytes_read = 0; 3954*5944Sha137994 break; 3955*5944Sha137994 } 39561991Sheppo } 3957*5944Sha137994 3958*5944Sha137994 /* process data ACKs */ 3959*5944Sha137994 if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) { 3960*5944Sha137994 if (rv = i_ldc_process_data_ACK(ldcp, msg)) { 3961*5944Sha137994 *sizep = 0; 3962*5944Sha137994 bytes_read = 0; 3963*5944Sha137994 break; 3964*5944Sha137994 } 39652336Snarayan } 3966*5944Sha137994 3967*5944Sha137994 /* process data NACKs */ 3968*5944Sha137994 if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) { 3969*5944Sha137994 DWARN(ldcp->id, 3970*5944Sha137994 "ldc_read: (0x%llx) received DATA/NACK", 3971*5944Sha137994 ldcp->id); 3972*5944Sha137994 mutex_enter(&ldcp->tx_lock); 3973*5944Sha137994 i_ldc_reset(ldcp, B_TRUE); 3974*5944Sha137994 mutex_exit(&ldcp->tx_lock); 3975*5944Sha137994 return (ECONNRESET); 3976*5944Sha137994 } 39773560Snarayan } 39783560Snarayan 39791991Sheppo /* process data messages */ 39801991Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) { 39811991Sheppo 39821991Sheppo uint8_t *msgbuf = (uint8_t *)( 39834690Snarayan (ldcp->mode == LDC_MODE_RELIABLE || 39844690Snarayan ldcp->mode == LDC_MODE_STREAM) ? 39854690Snarayan msg->rdata : msg->udata); 39861991Sheppo 39871991Sheppo D2(ldcp->id, 39881991Sheppo "ldc_read: (0x%llx) received data msg\n", ldcp->id); 39891991Sheppo 39901991Sheppo /* get the packet length */ 39911991Sheppo len = (msg->env & LDC_LEN_MASK); 39921991Sheppo 39931991Sheppo /* 39941991Sheppo * FUTURE OPTIMIZATION: 39951991Sheppo * dont need to set q head for every 39961991Sheppo * packet we read just need to do this when 39971991Sheppo * we are done or need to wait for more 39981991Sheppo * mondos to make a full packet - this is 39991991Sheppo * currently expensive. 40001991Sheppo */ 40011991Sheppo 40022336Snarayan if (first_fragment == 0) { 40031991Sheppo 40041991Sheppo /* 40051991Sheppo * first packets should always have the start 40061991Sheppo * bit set (even for a single packet). If not 40071991Sheppo * throw away the packet 40081991Sheppo */ 40091991Sheppo if (!(msg->env & LDC_FRAG_START)) { 40101991Sheppo 40111991Sheppo DWARN(DBG_ALL_LDCS, 40121991Sheppo "ldc_read: (0x%llx) not start - " 40131991Sheppo "frag=%x\n", ldcp->id, 40141991Sheppo (msg->env) & LDC_FRAG_MASK); 40151991Sheppo 40161991Sheppo /* toss pkt, inc head, cont reading */ 40171991Sheppo bytes_read = 0; 40181991Sheppo target = target_bufp; 40191991Sheppo curr_head = 40204690Snarayan (curr_head + LDC_PACKET_SIZE) 40214690Snarayan & q_size_mask; 4022*5944Sha137994 if (rv = ldcp->readq_set_head(ldcp, 40234690Snarayan curr_head)) 40241991Sheppo break; 40251991Sheppo 40261991Sheppo continue; 40271991Sheppo } 40281991Sheppo 40292336Snarayan first_fragment = msg->seqid; 40301991Sheppo } else { 40311991Sheppo /* check to see if this is a pkt w/ START bit */ 40321991Sheppo if (msg->env & LDC_FRAG_START) { 40331991Sheppo DWARN(DBG_ALL_LDCS, 40341991Sheppo "ldc_read:(0x%llx) unexpected pkt" 40351991Sheppo " env=0x%x discarding %d bytes," 40361991Sheppo " lastmsg=%d, currentmsg=%d\n", 40371991Sheppo ldcp->id, msg->env&LDC_FRAG_MASK, 40381991Sheppo bytes_read, ldcp->last_msg_rcd, 40391991Sheppo msg->seqid); 40401991Sheppo 40411991Sheppo /* throw data we have read so far */ 40421991Sheppo bytes_read = 0; 40431991Sheppo target = target_bufp; 40442336Snarayan first_fragment = msg->seqid; 40451991Sheppo 4046*5944Sha137994 if (rv = ldcp->readq_set_head(ldcp, 40474690Snarayan curr_head)) 40481991Sheppo break; 40491991Sheppo } 40501991Sheppo } 40511991Sheppo 40521991Sheppo /* copy (next) pkt into buffer */ 40531991Sheppo if (len <= (*sizep - bytes_read)) { 40541991Sheppo bcopy(msgbuf, target, len); 40551991Sheppo target += len; 40561991Sheppo bytes_read += len; 40571991Sheppo } else { 40581991Sheppo /* 40591991Sheppo * there is not enough space in the buffer to 40601991Sheppo * read this pkt. throw message away & continue 40611991Sheppo * reading data from queue 40621991Sheppo */ 40631991Sheppo DWARN(DBG_ALL_LDCS, 40641991Sheppo "ldc_read: (0x%llx) buffer too small, " 40651991Sheppo "head=0x%lx, expect=%d, got=%d\n", ldcp->id, 40661991Sheppo curr_head, *sizep, bytes_read+len); 40671991Sheppo 40682336Snarayan first_fragment = 0; 40691991Sheppo target = target_bufp; 40701991Sheppo bytes_read = 0; 40711991Sheppo 40721991Sheppo /* throw away everything received so far */ 4073*5944Sha137994 if (rv = ldcp->readq_set_head(ldcp, curr_head)) 40741991Sheppo break; 40751991Sheppo 40761991Sheppo /* continue reading remaining pkts */ 40771991Sheppo continue; 40781991Sheppo } 40791991Sheppo } 40801991Sheppo 40811991Sheppo /* set the message id */ 4082*5944Sha137994 if (ldcp->mode != LDC_MODE_STREAM) 4083*5944Sha137994 ldcp->last_msg_rcd = msg->seqid; 40841991Sheppo 40851991Sheppo /* move the head one position */ 40861991Sheppo curr_head = (curr_head + LDC_PACKET_SIZE) & q_size_mask; 40871991Sheppo 40881991Sheppo if (msg->env & LDC_FRAG_STOP) { 40891991Sheppo 40901991Sheppo /* 40911991Sheppo * All pkts that are part of this fragmented transfer 40921991Sheppo * have been read or this was a single pkt read 40931991Sheppo * or there was an error 40941991Sheppo */ 40951991Sheppo 40961991Sheppo /* set the queue head */ 4097*5944Sha137994 if (rv = ldcp->readq_set_head(ldcp, curr_head)) 40981991Sheppo bytes_read = 0; 40991991Sheppo 41001991Sheppo *sizep = bytes_read; 41011991Sheppo 41021991Sheppo break; 41031991Sheppo } 41041991Sheppo 41054890Snarayan /* advance head if it is a CTRL packet or a DATA ACK packet */ 41064890Snarayan if ((msg->type & LDC_CTRL) || 41074890Snarayan ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK))) { 41081991Sheppo 41091991Sheppo /* set the queue head */ 4110*5944Sha137994 if (rv = ldcp->readq_set_head(ldcp, curr_head)) { 41111991Sheppo bytes_read = 0; 41121991Sheppo break; 41131991Sheppo } 41141991Sheppo 41151991Sheppo D2(ldcp->id, "ldc_read: (0x%llx) set ACK qhead 0x%llx", 41161991Sheppo ldcp->id, curr_head); 41171991Sheppo } 41181991Sheppo 41191991Sheppo } /* for (;;) */ 41201991Sheppo 41211991Sheppo D2(ldcp->id, "ldc_read: (0x%llx) end size=%d", ldcp->id, *sizep); 41221991Sheppo 41231991Sheppo return (rv); 41242793Slm66018 41252793Slm66018 channel_is_reset: 41262793Slm66018 mutex_enter(&ldcp->tx_lock); 41272793Slm66018 i_ldc_reset(ldcp, B_FALSE); 41282793Slm66018 mutex_exit(&ldcp->tx_lock); 41292793Slm66018 return (ECONNRESET); 41301991Sheppo } 41311991Sheppo 41321991Sheppo /* 41331991Sheppo * Use underlying reliable packet mechanism to fetch 41341991Sheppo * and buffer incoming packets so we can hand them back as 41351991Sheppo * a basic byte stream. 41361991Sheppo * 41371991Sheppo * Enter and exit with ldcp->lock held by caller 41381991Sheppo */ 41391991Sheppo static int 41401991Sheppo i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep) 41411991Sheppo { 41421991Sheppo int rv; 41431991Sheppo size_t size; 41441991Sheppo 41451991Sheppo ASSERT(mutex_owned(&ldcp->lock)); 41461991Sheppo 41471991Sheppo D2(ldcp->id, "i_ldc_read_stream: (0x%llx) buffer size=%d", 41484690Snarayan ldcp->id, *sizep); 41491991Sheppo 41501991Sheppo if (ldcp->stream_remains == 0) { 41511991Sheppo size = ldcp->mtu; 41521991Sheppo rv = i_ldc_read_packet(ldcp, 41534690Snarayan (caddr_t)ldcp->stream_bufferp, &size); 41541991Sheppo D2(ldcp->id, "i_ldc_read_stream: read packet (0x%llx) size=%d", 41554690Snarayan ldcp->id, size); 41561991Sheppo 41571991Sheppo if (rv != 0) 41581991Sheppo return (rv); 41591991Sheppo 41601991Sheppo ldcp->stream_remains = size; 41611991Sheppo ldcp->stream_offset = 0; 41621991Sheppo } 41631991Sheppo 41641991Sheppo size = MIN(ldcp->stream_remains, *sizep); 41651991Sheppo 41661991Sheppo bcopy(ldcp->stream_bufferp + ldcp->stream_offset, target_bufp, size); 41671991Sheppo ldcp->stream_offset += size; 41681991Sheppo ldcp->stream_remains -= size; 41691991Sheppo 41701991Sheppo D2(ldcp->id, "i_ldc_read_stream: (0x%llx) fill from buffer size=%d", 41714690Snarayan ldcp->id, size); 41721991Sheppo 41731991Sheppo *sizep = size; 41741991Sheppo return (0); 41751991Sheppo } 41761991Sheppo 41771991Sheppo /* 41781991Sheppo * Write specified amount of bytes to the channel 41791991Sheppo * in multiple pkts of pkt_payload size. Each 41801991Sheppo * packet is tagged with an unique packet ID in 41812410Slm66018 * the case of a reliable link. 41821991Sheppo * 41831991Sheppo * On return, size contains the number of bytes written. 41841991Sheppo */ 41851991Sheppo int 41861991Sheppo ldc_write(ldc_handle_t handle, caddr_t buf, size_t *sizep) 41871991Sheppo { 41881991Sheppo ldc_chan_t *ldcp; 41891991Sheppo int rv = 0; 41901991Sheppo 41911991Sheppo if (handle == NULL) { 41921991Sheppo DWARN(DBG_ALL_LDCS, "ldc_write: invalid channel handle\n"); 41931991Sheppo return (EINVAL); 41941991Sheppo } 41951991Sheppo ldcp = (ldc_chan_t *)handle; 41961991Sheppo 41972336Snarayan /* check if writes can occur */ 41982336Snarayan if (!mutex_tryenter(&ldcp->tx_lock)) { 41992336Snarayan /* 42002336Snarayan * Could not get the lock - channel could 42012336Snarayan * be in the process of being unconfigured 42022336Snarayan * or reader has encountered an error 42032336Snarayan */ 42042336Snarayan return (EAGAIN); 42052336Snarayan } 42061991Sheppo 42071991Sheppo /* check if non-zero data to write */ 42081991Sheppo if (buf == NULL || sizep == NULL) { 42091991Sheppo DWARN(ldcp->id, "ldc_write: (0x%llx) invalid data write\n", 42101991Sheppo ldcp->id); 42112336Snarayan mutex_exit(&ldcp->tx_lock); 42121991Sheppo return (EINVAL); 42131991Sheppo } 42141991Sheppo 42151991Sheppo if (*sizep == 0) { 42161991Sheppo DWARN(ldcp->id, "ldc_write: (0x%llx) write size of zero\n", 42171991Sheppo ldcp->id); 42182336Snarayan mutex_exit(&ldcp->tx_lock); 42191991Sheppo return (0); 42201991Sheppo } 42211991Sheppo 42221991Sheppo /* Check if channel is UP for data exchange */ 42231991Sheppo if (ldcp->tstate != TS_UP) { 42241991Sheppo DWARN(ldcp->id, 42251991Sheppo "ldc_write: (0x%llx) channel is not in UP state\n", 42261991Sheppo ldcp->id); 42271991Sheppo *sizep = 0; 42281991Sheppo rv = ECONNRESET; 42291991Sheppo } else { 42301991Sheppo rv = ldcp->write_p(ldcp, buf, sizep); 42311991Sheppo } 42321991Sheppo 42332336Snarayan mutex_exit(&ldcp->tx_lock); 42341991Sheppo 42351991Sheppo return (rv); 42361991Sheppo } 42371991Sheppo 42381991Sheppo /* 42391991Sheppo * Write a raw packet to the channel 42401991Sheppo * On return, size contains the number of bytes written. 42411991Sheppo */ 42421991Sheppo static int 42431991Sheppo i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep) 42441991Sheppo { 42451991Sheppo ldc_msg_t *ldcmsg; 42461991Sheppo uint64_t tx_head, tx_tail, new_tail; 42471991Sheppo int rv = 0; 42481991Sheppo size_t size; 42491991Sheppo 42502336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 42511991Sheppo ASSERT(ldcp->mode == LDC_MODE_RAW); 42521991Sheppo 42531991Sheppo size = *sizep; 42541991Sheppo 42551991Sheppo /* 42561991Sheppo * Check to see if the packet size is less than or 42571991Sheppo * equal to packet size support in raw mode 42581991Sheppo */ 42591991Sheppo if (size > ldcp->pkt_payload) { 42601991Sheppo DWARN(ldcp->id, 42611991Sheppo "ldc_write: (0x%llx) invalid size (0x%llx) for RAW mode\n", 42621991Sheppo ldcp->id, *sizep); 42631991Sheppo *sizep = 0; 42641991Sheppo return (EMSGSIZE); 42651991Sheppo } 42661991Sheppo 42671991Sheppo /* get the qptrs for the tx queue */ 42681991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 42691991Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 42701991Sheppo if (rv != 0) { 42711991Sheppo cmn_err(CE_WARN, 42721991Sheppo "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id); 42731991Sheppo *sizep = 0; 42741991Sheppo return (EIO); 42751991Sheppo } 42761991Sheppo 42771991Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN || 42781991Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 42791991Sheppo DWARN(ldcp->id, 42801991Sheppo "ldc_write: (0x%llx) channel down/reset\n", ldcp->id); 42812336Snarayan 42821991Sheppo *sizep = 0; 42832336Snarayan if (mutex_tryenter(&ldcp->lock)) { 42842793Slm66018 i_ldc_reset(ldcp, B_FALSE); 42852336Snarayan mutex_exit(&ldcp->lock); 42862336Snarayan } else { 42872336Snarayan /* 42882336Snarayan * Release Tx lock, and then reacquire channel 42892336Snarayan * and Tx lock in correct order 42902336Snarayan */ 42912336Snarayan mutex_exit(&ldcp->tx_lock); 42922336Snarayan mutex_enter(&ldcp->lock); 42932336Snarayan mutex_enter(&ldcp->tx_lock); 42942793Slm66018 i_ldc_reset(ldcp, B_FALSE); 42952336Snarayan mutex_exit(&ldcp->lock); 42962336Snarayan } 42971991Sheppo return (ECONNRESET); 42981991Sheppo } 42991991Sheppo 43001991Sheppo tx_tail = ldcp->tx_tail; 43011991Sheppo tx_head = ldcp->tx_head; 43021991Sheppo new_tail = (tx_tail + LDC_PACKET_SIZE) & 43034690Snarayan ((ldcp->tx_q_entries-1) << LDC_PACKET_SHIFT); 43041991Sheppo 43051991Sheppo if (new_tail == tx_head) { 43061991Sheppo DWARN(DBG_ALL_LDCS, 43071991Sheppo "ldc_write: (0x%llx) TX queue is full\n", ldcp->id); 43081991Sheppo *sizep = 0; 43091991Sheppo return (EWOULDBLOCK); 43101991Sheppo } 43111991Sheppo 43121991Sheppo D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d", 43131991Sheppo ldcp->id, size); 43141991Sheppo 43151991Sheppo /* Send the data now */ 43161991Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 43171991Sheppo 43182336Snarayan /* copy the data into pkt */ 43191991Sheppo bcopy((uint8_t *)buf, ldcmsg, size); 43201991Sheppo 43212336Snarayan /* increment tail */ 43221991Sheppo tx_tail = new_tail; 43231991Sheppo 43241991Sheppo /* 43251991Sheppo * All packets have been copied into the TX queue 43261991Sheppo * update the tail ptr in the HV 43271991Sheppo */ 43281991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 43291991Sheppo if (rv) { 43301991Sheppo if (rv == EWOULDBLOCK) { 43311991Sheppo DWARN(ldcp->id, "ldc_write: (0x%llx) write timed out\n", 43321991Sheppo ldcp->id); 43331991Sheppo *sizep = 0; 43341991Sheppo return (EWOULDBLOCK); 43351991Sheppo } 43361991Sheppo 43371991Sheppo *sizep = 0; 43382336Snarayan if (mutex_tryenter(&ldcp->lock)) { 43392793Slm66018 i_ldc_reset(ldcp, B_FALSE); 43402336Snarayan mutex_exit(&ldcp->lock); 43412336Snarayan } else { 43422336Snarayan /* 43432336Snarayan * Release Tx lock, and then reacquire channel 43442336Snarayan * and Tx lock in correct order 43452336Snarayan */ 43462336Snarayan mutex_exit(&ldcp->tx_lock); 43472336Snarayan mutex_enter(&ldcp->lock); 43482336Snarayan mutex_enter(&ldcp->tx_lock); 43492793Slm66018 i_ldc_reset(ldcp, B_FALSE); 43502336Snarayan mutex_exit(&ldcp->lock); 43512336Snarayan } 43521991Sheppo return (ECONNRESET); 43531991Sheppo } 43541991Sheppo 43551991Sheppo ldcp->tx_tail = tx_tail; 43561991Sheppo *sizep = size; 43571991Sheppo 43581991Sheppo D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, size); 43591991Sheppo 43601991Sheppo return (rv); 43611991Sheppo } 43621991Sheppo 43631991Sheppo 43641991Sheppo /* 43651991Sheppo * Write specified amount of bytes to the channel 43661991Sheppo * in multiple pkts of pkt_payload size. Each 43671991Sheppo * packet is tagged with an unique packet ID in 43682410Slm66018 * the case of a reliable link. 43691991Sheppo * 43701991Sheppo * On return, size contains the number of bytes written. 43711991Sheppo * This function needs to ensure that the write size is < MTU size 43721991Sheppo */ 43731991Sheppo static int 43741991Sheppo i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t buf, size_t *size) 43751991Sheppo { 43761991Sheppo ldc_msg_t *ldcmsg; 43771991Sheppo uint64_t tx_head, tx_tail, new_tail, start; 43781991Sheppo uint64_t txq_size_mask, numavail; 43791991Sheppo uint8_t *msgbuf, *source = (uint8_t *)buf; 43801991Sheppo size_t len, bytes_written = 0, remaining; 43811991Sheppo int rv; 43821991Sheppo uint32_t curr_seqid; 43831991Sheppo 43842336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 43851991Sheppo 43861991Sheppo ASSERT(ldcp->mode == LDC_MODE_RELIABLE || 43874690Snarayan ldcp->mode == LDC_MODE_UNRELIABLE || 43884690Snarayan ldcp->mode == LDC_MODE_STREAM); 43891991Sheppo 43901991Sheppo /* compute mask for increment */ 43911991Sheppo txq_size_mask = (ldcp->tx_q_entries - 1) << LDC_PACKET_SHIFT; 43921991Sheppo 43931991Sheppo /* get the qptrs for the tx queue */ 43941991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 43951991Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 43961991Sheppo if (rv != 0) { 43971991Sheppo cmn_err(CE_WARN, 43981991Sheppo "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id); 43991991Sheppo *size = 0; 44001991Sheppo return (EIO); 44011991Sheppo } 44021991Sheppo 44031991Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN || 44041991Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 44051991Sheppo DWARN(ldcp->id, 44061991Sheppo "ldc_write: (0x%llx) channel down/reset\n", ldcp->id); 44071991Sheppo *size = 0; 44082336Snarayan if (mutex_tryenter(&ldcp->lock)) { 44092793Slm66018 i_ldc_reset(ldcp, B_FALSE); 44102336Snarayan mutex_exit(&ldcp->lock); 44112336Snarayan } else { 44122336Snarayan /* 44132336Snarayan * Release Tx lock, and then reacquire channel 44142336Snarayan * and Tx lock in correct order 44152336Snarayan */ 44162336Snarayan mutex_exit(&ldcp->tx_lock); 44172336Snarayan mutex_enter(&ldcp->lock); 44182336Snarayan mutex_enter(&ldcp->tx_lock); 44192793Slm66018 i_ldc_reset(ldcp, B_FALSE); 44202336Snarayan mutex_exit(&ldcp->lock); 44212336Snarayan } 44221991Sheppo return (ECONNRESET); 44231991Sheppo } 44241991Sheppo 44251991Sheppo tx_tail = ldcp->tx_tail; 44261991Sheppo new_tail = (tx_tail + LDC_PACKET_SIZE) % 44274690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 44281991Sheppo 44291991Sheppo /* 44304690Snarayan * Check to see if the queue is full. The check is done using 44314690Snarayan * the appropriate head based on the link mode. 44321991Sheppo */ 44334690Snarayan i_ldc_get_tx_head(ldcp, &tx_head); 44344690Snarayan 44351991Sheppo if (new_tail == tx_head) { 44361991Sheppo DWARN(DBG_ALL_LDCS, 44371991Sheppo "ldc_write: (0x%llx) TX queue is full\n", ldcp->id); 44381991Sheppo *size = 0; 44391991Sheppo return (EWOULDBLOCK); 44401991Sheppo } 44411991Sheppo 44421991Sheppo /* 44431991Sheppo * Make sure that the LDC Tx queue has enough space 44441991Sheppo */ 44451991Sheppo numavail = (tx_head >> LDC_PACKET_SHIFT) - (tx_tail >> LDC_PACKET_SHIFT) 44464690Snarayan + ldcp->tx_q_entries - 1; 44471991Sheppo numavail %= ldcp->tx_q_entries; 44481991Sheppo 44491991Sheppo if (*size > (numavail * ldcp->pkt_payload)) { 44501991Sheppo DWARN(DBG_ALL_LDCS, 44511991Sheppo "ldc_write: (0x%llx) TX queue has no space\n", ldcp->id); 44521991Sheppo return (EWOULDBLOCK); 44531991Sheppo } 44541991Sheppo 44551991Sheppo D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d", 44561991Sheppo ldcp->id, *size); 44571991Sheppo 44581991Sheppo /* Send the data now */ 44591991Sheppo bytes_written = 0; 44601991Sheppo curr_seqid = ldcp->last_msg_snt; 44611991Sheppo start = tx_tail; 44621991Sheppo 44631991Sheppo while (*size > bytes_written) { 44641991Sheppo 44651991Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 44661991Sheppo 44671991Sheppo msgbuf = (uint8_t *)((ldcp->mode == LDC_MODE_RELIABLE || 44684690Snarayan ldcp->mode == LDC_MODE_STREAM) ? 44694690Snarayan ldcmsg->rdata : ldcmsg->udata); 44701991Sheppo 44711991Sheppo ldcmsg->type = LDC_DATA; 44721991Sheppo ldcmsg->stype = LDC_INFO; 44731991Sheppo ldcmsg->ctrl = 0; 44741991Sheppo 44751991Sheppo remaining = *size - bytes_written; 44761991Sheppo len = min(ldcp->pkt_payload, remaining); 44771991Sheppo ldcmsg->env = (uint8_t)len; 44781991Sheppo 44791991Sheppo curr_seqid++; 44801991Sheppo ldcmsg->seqid = curr_seqid; 44811991Sheppo 44821991Sheppo /* copy the data into pkt */ 44831991Sheppo bcopy(source, msgbuf, len); 44841991Sheppo 44851991Sheppo source += len; 44861991Sheppo bytes_written += len; 44871991Sheppo 44881991Sheppo /* increment tail */ 44891991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) & txq_size_mask; 44901991Sheppo 44911991Sheppo ASSERT(tx_tail != tx_head); 44921991Sheppo } 44931991Sheppo 44941991Sheppo /* Set the start and stop bits */ 44951991Sheppo ldcmsg->env |= LDC_FRAG_STOP; 44961991Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + start); 44971991Sheppo ldcmsg->env |= LDC_FRAG_START; 44981991Sheppo 44991991Sheppo /* 45001991Sheppo * All packets have been copied into the TX queue 45011991Sheppo * update the tail ptr in the HV 45021991Sheppo */ 45031991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 45041991Sheppo if (rv == 0) { 45051991Sheppo ldcp->tx_tail = tx_tail; 45061991Sheppo ldcp->last_msg_snt = curr_seqid; 45071991Sheppo *size = bytes_written; 45081991Sheppo } else { 45091991Sheppo int rv2; 45101991Sheppo 45111991Sheppo if (rv != EWOULDBLOCK) { 45121991Sheppo *size = 0; 45132336Snarayan if (mutex_tryenter(&ldcp->lock)) { 45142793Slm66018 i_ldc_reset(ldcp, B_FALSE); 45152336Snarayan mutex_exit(&ldcp->lock); 45162336Snarayan } else { 45172336Snarayan /* 45182336Snarayan * Release Tx lock, and then reacquire channel 45192336Snarayan * and Tx lock in correct order 45202336Snarayan */ 45212336Snarayan mutex_exit(&ldcp->tx_lock); 45222336Snarayan mutex_enter(&ldcp->lock); 45232336Snarayan mutex_enter(&ldcp->tx_lock); 45242793Slm66018 i_ldc_reset(ldcp, B_FALSE); 45252336Snarayan mutex_exit(&ldcp->lock); 45262336Snarayan } 45271991Sheppo return (ECONNRESET); 45281991Sheppo } 45291991Sheppo 45303010Slm66018 D1(ldcp->id, "hv_tx_set_tail returns 0x%x (head 0x%x, " 45314690Snarayan "old tail 0x%x, new tail 0x%x, qsize=0x%x)\n", 45324690Snarayan rv, ldcp->tx_head, ldcp->tx_tail, tx_tail, 45334690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT)); 45341991Sheppo 45351991Sheppo rv2 = hv_ldc_tx_get_state(ldcp->id, 45361991Sheppo &tx_head, &tx_tail, &ldcp->link_state); 45371991Sheppo 45383010Slm66018 D1(ldcp->id, "hv_ldc_tx_get_state returns 0x%x " 45394690Snarayan "(head 0x%x, tail 0x%x state 0x%x)\n", 45404690Snarayan rv2, tx_head, tx_tail, ldcp->link_state); 45411991Sheppo 45421991Sheppo *size = 0; 45431991Sheppo } 45441991Sheppo 45451991Sheppo D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, *size); 45461991Sheppo 45471991Sheppo return (rv); 45481991Sheppo } 45491991Sheppo 45501991Sheppo /* 45511991Sheppo * Write specified amount of bytes to the channel 45521991Sheppo * in multiple pkts of pkt_payload size. Each 45531991Sheppo * packet is tagged with an unique packet ID in 45542410Slm66018 * the case of a reliable link. 45551991Sheppo * 45561991Sheppo * On return, size contains the number of bytes written. 45571991Sheppo * This function needs to ensure that the write size is < MTU size 45581991Sheppo */ 45591991Sheppo static int 45601991Sheppo i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep) 45611991Sheppo { 45622336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 45631991Sheppo ASSERT(ldcp->mode == LDC_MODE_STREAM); 45641991Sheppo 45651991Sheppo /* Truncate packet to max of MTU size */ 45661991Sheppo if (*sizep > ldcp->mtu) *sizep = ldcp->mtu; 45671991Sheppo return (i_ldc_write_packet(ldcp, buf, sizep)); 45681991Sheppo } 45691991Sheppo 45701991Sheppo 45711991Sheppo /* 45721991Sheppo * Interfaces for channel nexus to register/unregister with LDC module 45731991Sheppo * The nexus will register functions to be used to register individual 45741991Sheppo * channels with the nexus and enable interrupts for the channels 45751991Sheppo */ 45761991Sheppo int 45771991Sheppo ldc_register(ldc_cnex_t *cinfo) 45781991Sheppo { 45791991Sheppo ldc_chan_t *ldcp; 45801991Sheppo 45811991Sheppo if (cinfo == NULL || cinfo->dip == NULL || 45821991Sheppo cinfo->reg_chan == NULL || cinfo->unreg_chan == NULL || 45831991Sheppo cinfo->add_intr == NULL || cinfo->rem_intr == NULL || 45841991Sheppo cinfo->clr_intr == NULL) { 45851991Sheppo 45861991Sheppo DWARN(DBG_ALL_LDCS, "ldc_register: invalid nexus info\n"); 45871991Sheppo return (EINVAL); 45881991Sheppo } 45891991Sheppo 45901991Sheppo mutex_enter(&ldcssp->lock); 45911991Sheppo 45921991Sheppo /* nexus registration */ 45931991Sheppo ldcssp->cinfo.dip = cinfo->dip; 45941991Sheppo ldcssp->cinfo.reg_chan = cinfo->reg_chan; 45951991Sheppo ldcssp->cinfo.unreg_chan = cinfo->unreg_chan; 45961991Sheppo ldcssp->cinfo.add_intr = cinfo->add_intr; 45971991Sheppo ldcssp->cinfo.rem_intr = cinfo->rem_intr; 45981991Sheppo ldcssp->cinfo.clr_intr = cinfo->clr_intr; 45991991Sheppo 46001991Sheppo /* register any channels that might have been previously initialized */ 46011991Sheppo ldcp = ldcssp->chan_list; 46021991Sheppo while (ldcp) { 46031991Sheppo if ((ldcp->tstate & TS_QCONF_RDY) && 46041991Sheppo (ldcp->tstate & TS_CNEX_RDY) == 0) 46051991Sheppo (void) i_ldc_register_channel(ldcp); 46061991Sheppo 46071991Sheppo ldcp = ldcp->next; 46081991Sheppo } 46091991Sheppo 46101991Sheppo mutex_exit(&ldcssp->lock); 46111991Sheppo 46121991Sheppo return (0); 46131991Sheppo } 46141991Sheppo 46151991Sheppo int 46161991Sheppo ldc_unregister(ldc_cnex_t *cinfo) 46171991Sheppo { 46181991Sheppo if (cinfo == NULL || cinfo->dip == NULL) { 46191991Sheppo DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid nexus info\n"); 46201991Sheppo return (EINVAL); 46211991Sheppo } 46221991Sheppo 46231991Sheppo mutex_enter(&ldcssp->lock); 46241991Sheppo 46251991Sheppo if (cinfo->dip != ldcssp->cinfo.dip) { 46261991Sheppo DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid dip\n"); 46271991Sheppo mutex_exit(&ldcssp->lock); 46281991Sheppo return (EINVAL); 46291991Sheppo } 46301991Sheppo 46311991Sheppo /* nexus unregister */ 46321991Sheppo ldcssp->cinfo.dip = NULL; 46331991Sheppo ldcssp->cinfo.reg_chan = NULL; 46341991Sheppo ldcssp->cinfo.unreg_chan = NULL; 46351991Sheppo ldcssp->cinfo.add_intr = NULL; 46361991Sheppo ldcssp->cinfo.rem_intr = NULL; 46371991Sheppo ldcssp->cinfo.clr_intr = NULL; 46381991Sheppo 46391991Sheppo mutex_exit(&ldcssp->lock); 46401991Sheppo 46411991Sheppo return (0); 46421991Sheppo } 46431991Sheppo 46441991Sheppo 46451991Sheppo /* ------------------------------------------------------------------------- */ 46461991Sheppo 46471991Sheppo /* 46481991Sheppo * Allocate a memory handle for the channel and link it into the list 46491991Sheppo * Also choose which memory table to use if this is the first handle 46501991Sheppo * being assigned to this channel 46511991Sheppo */ 46521991Sheppo int 46531991Sheppo ldc_mem_alloc_handle(ldc_handle_t handle, ldc_mem_handle_t *mhandle) 46541991Sheppo { 46551991Sheppo ldc_chan_t *ldcp; 46561991Sheppo ldc_mhdl_t *mhdl; 46571991Sheppo 46581991Sheppo if (handle == NULL) { 46591991Sheppo DWARN(DBG_ALL_LDCS, 46601991Sheppo "ldc_mem_alloc_handle: invalid channel handle\n"); 46611991Sheppo return (EINVAL); 46621991Sheppo } 46631991Sheppo ldcp = (ldc_chan_t *)handle; 46641991Sheppo 46651991Sheppo mutex_enter(&ldcp->lock); 46661991Sheppo 46671991Sheppo /* check to see if channel is initalized */ 46682793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) < TS_INIT) { 46691991Sheppo DWARN(ldcp->id, 46701991Sheppo "ldc_mem_alloc_handle: (0x%llx) channel not initialized\n", 46711991Sheppo ldcp->id); 46721991Sheppo mutex_exit(&ldcp->lock); 46731991Sheppo return (EINVAL); 46741991Sheppo } 46751991Sheppo 46761991Sheppo /* allocate handle for channel */ 46772531Snarayan mhdl = kmem_cache_alloc(ldcssp->memhdl_cache, KM_SLEEP); 46781991Sheppo 46791991Sheppo /* initialize the lock */ 46801991Sheppo mutex_init(&mhdl->lock, NULL, MUTEX_DRIVER, NULL); 46811991Sheppo 46822531Snarayan mhdl->myshadow = B_FALSE; 46832531Snarayan mhdl->memseg = NULL; 46842531Snarayan mhdl->ldcp = ldcp; 46851991Sheppo mhdl->status = LDC_UNBOUND; 46861991Sheppo 46871991Sheppo /* insert memory handle (@ head) into list */ 46881991Sheppo if (ldcp->mhdl_list == NULL) { 46891991Sheppo ldcp->mhdl_list = mhdl; 46901991Sheppo mhdl->next = NULL; 46911991Sheppo } else { 46921991Sheppo /* insert @ head */ 46931991Sheppo mhdl->next = ldcp->mhdl_list; 46941991Sheppo ldcp->mhdl_list = mhdl; 46951991Sheppo } 46961991Sheppo 46971991Sheppo /* return the handle */ 46981991Sheppo *mhandle = (ldc_mem_handle_t)mhdl; 46991991Sheppo 47001991Sheppo mutex_exit(&ldcp->lock); 47011991Sheppo 47021991Sheppo D1(ldcp->id, "ldc_mem_alloc_handle: (0x%llx) allocated handle 0x%llx\n", 47031991Sheppo ldcp->id, mhdl); 47041991Sheppo 47051991Sheppo return (0); 47061991Sheppo } 47071991Sheppo 47081991Sheppo /* 47091991Sheppo * Free memory handle for the channel and unlink it from the list 47101991Sheppo */ 47111991Sheppo int 47121991Sheppo ldc_mem_free_handle(ldc_mem_handle_t mhandle) 47131991Sheppo { 47141991Sheppo ldc_mhdl_t *mhdl, *phdl; 47151991Sheppo ldc_chan_t *ldcp; 47161991Sheppo 47171991Sheppo if (mhandle == NULL) { 47181991Sheppo DWARN(DBG_ALL_LDCS, 47191991Sheppo "ldc_mem_free_handle: invalid memory handle\n"); 47201991Sheppo return (EINVAL); 47211991Sheppo } 47221991Sheppo mhdl = (ldc_mhdl_t *)mhandle; 47231991Sheppo 47241991Sheppo mutex_enter(&mhdl->lock); 47251991Sheppo 47261991Sheppo ldcp = mhdl->ldcp; 47271991Sheppo 47281991Sheppo if (mhdl->status == LDC_BOUND || mhdl->status == LDC_MAPPED) { 47291991Sheppo DWARN(ldcp->id, 47301991Sheppo "ldc_mem_free_handle: cannot free, 0x%llx hdl bound\n", 47311991Sheppo mhdl); 47321991Sheppo mutex_exit(&mhdl->lock); 47331991Sheppo return (EINVAL); 47341991Sheppo } 47351991Sheppo mutex_exit(&mhdl->lock); 47361991Sheppo 47371991Sheppo mutex_enter(&ldcp->mlist_lock); 47381991Sheppo 47391991Sheppo phdl = ldcp->mhdl_list; 47401991Sheppo 47411991Sheppo /* first handle */ 47421991Sheppo if (phdl == mhdl) { 47431991Sheppo ldcp->mhdl_list = mhdl->next; 47441991Sheppo mutex_destroy(&mhdl->lock); 47452531Snarayan kmem_cache_free(ldcssp->memhdl_cache, mhdl); 47462531Snarayan 47471991Sheppo D1(ldcp->id, 47481991Sheppo "ldc_mem_free_handle: (0x%llx) freed handle 0x%llx\n", 47491991Sheppo ldcp->id, mhdl); 47501991Sheppo } else { 47511991Sheppo /* walk the list - unlink and free */ 47521991Sheppo while (phdl != NULL) { 47531991Sheppo if (phdl->next == mhdl) { 47541991Sheppo phdl->next = mhdl->next; 47551991Sheppo mutex_destroy(&mhdl->lock); 47562531Snarayan kmem_cache_free(ldcssp->memhdl_cache, mhdl); 47571991Sheppo D1(ldcp->id, 47581991Sheppo "ldc_mem_free_handle: (0x%llx) freed " 47591991Sheppo "handle 0x%llx\n", ldcp->id, mhdl); 47601991Sheppo break; 47611991Sheppo } 47621991Sheppo phdl = phdl->next; 47631991Sheppo } 47641991Sheppo } 47651991Sheppo 47661991Sheppo if (phdl == NULL) { 47671991Sheppo DWARN(ldcp->id, 47681991Sheppo "ldc_mem_free_handle: invalid handle 0x%llx\n", mhdl); 47691991Sheppo mutex_exit(&ldcp->mlist_lock); 47701991Sheppo return (EINVAL); 47711991Sheppo } 47721991Sheppo 47731991Sheppo mutex_exit(&ldcp->mlist_lock); 47741991Sheppo 47751991Sheppo return (0); 47761991Sheppo } 47771991Sheppo 47781991Sheppo /* 47791991Sheppo * Bind a memory handle to a virtual address. 47801991Sheppo * The virtual address is converted to the corresponding real addresses. 47811991Sheppo * Returns pointer to the first ldc_mem_cookie and the total number 47821991Sheppo * of cookies for this virtual address. Other cookies can be obtained 47831991Sheppo * using the ldc_mem_nextcookie() call. If the pages are stored in 47841991Sheppo * consecutive locations in the table, a single cookie corresponding to 47851991Sheppo * the first location is returned. The cookie size spans all the entries. 47861991Sheppo * 47871991Sheppo * If the VA corresponds to a page that is already being exported, reuse 47881991Sheppo * the page and do not export it again. Bump the page's use count. 47891991Sheppo */ 47901991Sheppo int 47911991Sheppo ldc_mem_bind_handle(ldc_mem_handle_t mhandle, caddr_t vaddr, size_t len, 47921991Sheppo uint8_t mtype, uint8_t perm, ldc_mem_cookie_t *cookie, uint32_t *ccount) 47931991Sheppo { 47941991Sheppo ldc_mhdl_t *mhdl; 47951991Sheppo ldc_chan_t *ldcp; 47961991Sheppo ldc_mtbl_t *mtbl; 47971991Sheppo ldc_memseg_t *memseg; 47981991Sheppo ldc_mte_t tmp_mte; 47991991Sheppo uint64_t index, prev_index = 0; 48001991Sheppo int64_t cookie_idx; 48011991Sheppo uintptr_t raddr, ra_aligned; 48021991Sheppo uint64_t psize, poffset, v_offset; 48031991Sheppo uint64_t pg_shift, pg_size, pg_size_code, pg_mask; 48041991Sheppo pgcnt_t npages; 48051991Sheppo caddr_t v_align, addr; 48062531Snarayan int i, rv; 48071991Sheppo 48081991Sheppo if (mhandle == NULL) { 48091991Sheppo DWARN(DBG_ALL_LDCS, 48101991Sheppo "ldc_mem_bind_handle: invalid memory handle\n"); 48111991Sheppo return (EINVAL); 48121991Sheppo } 48131991Sheppo mhdl = (ldc_mhdl_t *)mhandle; 48141991Sheppo ldcp = mhdl->ldcp; 48151991Sheppo 48161991Sheppo /* clear count */ 48171991Sheppo *ccount = 0; 48181991Sheppo 48191991Sheppo mutex_enter(&mhdl->lock); 48201991Sheppo 48211991Sheppo if (mhdl->status == LDC_BOUND || mhdl->memseg != NULL) { 48221991Sheppo DWARN(ldcp->id, 48231991Sheppo "ldc_mem_bind_handle: (0x%x) handle already bound\n", 48241991Sheppo mhandle); 48251991Sheppo mutex_exit(&mhdl->lock); 48261991Sheppo return (EINVAL); 48271991Sheppo } 48281991Sheppo 48291991Sheppo /* Force address and size to be 8-byte aligned */ 48301991Sheppo if ((((uintptr_t)vaddr | len) & 0x7) != 0) { 48311991Sheppo DWARN(ldcp->id, 48321991Sheppo "ldc_mem_bind_handle: addr/size is not 8-byte aligned\n"); 48331991Sheppo mutex_exit(&mhdl->lock); 48341991Sheppo return (EINVAL); 48351991Sheppo } 48361991Sheppo 48372531Snarayan /* 48382531Snarayan * If this channel is binding a memory handle for the 48392531Snarayan * first time allocate it a memory map table and initialize it 48402531Snarayan */ 48412531Snarayan if ((mtbl = ldcp->mtbl) == NULL) { 48422531Snarayan 48432531Snarayan mutex_enter(&ldcp->lock); 48442531Snarayan 48452531Snarayan /* Allocate and initialize the map table structure */ 48462531Snarayan mtbl = kmem_zalloc(sizeof (ldc_mtbl_t), KM_SLEEP); 48472531Snarayan mtbl->num_entries = mtbl->num_avail = ldc_maptable_entries; 48482531Snarayan mtbl->size = ldc_maptable_entries * sizeof (ldc_mte_slot_t); 48492531Snarayan mtbl->next_entry = NULL; 48502793Slm66018 mtbl->contigmem = B_TRUE; 48512531Snarayan 48522531Snarayan /* Allocate the table itself */ 48532531Snarayan mtbl->table = (ldc_mte_slot_t *) 48544690Snarayan contig_mem_alloc_align(mtbl->size, MMU_PAGESIZE); 48552531Snarayan if (mtbl->table == NULL) { 48562793Slm66018 48572793Slm66018 /* allocate a page of memory using kmem_alloc */ 48582793Slm66018 mtbl->table = kmem_alloc(MMU_PAGESIZE, KM_SLEEP); 48592793Slm66018 mtbl->size = MMU_PAGESIZE; 48602793Slm66018 mtbl->contigmem = B_FALSE; 48612793Slm66018 mtbl->num_entries = mtbl->num_avail = 48624690Snarayan mtbl->size / sizeof (ldc_mte_slot_t); 48632793Slm66018 DWARN(ldcp->id, 48642793Slm66018 "ldc_mem_bind_handle: (0x%llx) reduced tbl size " 48652793Slm66018 "to %lx entries\n", ldcp->id, mtbl->num_entries); 48662531Snarayan } 48672531Snarayan 48682531Snarayan /* zero out the memory */ 48692531Snarayan bzero(mtbl->table, mtbl->size); 48702531Snarayan 48712531Snarayan /* initialize the lock */ 48722531Snarayan mutex_init(&mtbl->lock, NULL, MUTEX_DRIVER, NULL); 48732531Snarayan 48742531Snarayan /* register table for this channel */ 48752531Snarayan rv = hv_ldc_set_map_table(ldcp->id, 48762531Snarayan va_to_pa(mtbl->table), mtbl->num_entries); 48772531Snarayan if (rv != 0) { 48782531Snarayan cmn_err(CE_WARN, 48792531Snarayan "ldc_mem_bind_handle: (0x%lx) err %d mapping tbl", 48802531Snarayan ldcp->id, rv); 48812793Slm66018 if (mtbl->contigmem) 48822793Slm66018 contig_mem_free(mtbl->table, mtbl->size); 48832793Slm66018 else 48842793Slm66018 kmem_free(mtbl->table, mtbl->size); 48852531Snarayan mutex_destroy(&mtbl->lock); 48862531Snarayan kmem_free(mtbl, sizeof (ldc_mtbl_t)); 48872531Snarayan mutex_exit(&ldcp->lock); 48882531Snarayan mutex_exit(&mhdl->lock); 48892531Snarayan return (EIO); 48902531Snarayan } 48912531Snarayan 48922531Snarayan ldcp->mtbl = mtbl; 48932531Snarayan mutex_exit(&ldcp->lock); 48942531Snarayan 48952531Snarayan D1(ldcp->id, 48962531Snarayan "ldc_mem_bind_handle: (0x%llx) alloc'd map table 0x%llx\n", 48972531Snarayan ldcp->id, ldcp->mtbl->table); 48982531Snarayan } 48992531Snarayan 49001991Sheppo /* FUTURE: get the page size, pgsz code, and shift */ 49011991Sheppo pg_size = MMU_PAGESIZE; 49021991Sheppo pg_size_code = page_szc(pg_size); 49031991Sheppo pg_shift = page_get_shift(pg_size_code); 49041991Sheppo pg_mask = ~(pg_size - 1); 49051991Sheppo 49061991Sheppo D1(ldcp->id, "ldc_mem_bind_handle: (0x%llx) binding " 49071991Sheppo "va 0x%llx pgsz=0x%llx, pgszc=0x%llx, pg_shift=0x%llx\n", 49081991Sheppo ldcp->id, vaddr, pg_size, pg_size_code, pg_shift); 49091991Sheppo 49101991Sheppo /* aligned VA and its offset */ 49111991Sheppo v_align = (caddr_t)(((uintptr_t)vaddr) & ~(pg_size - 1)); 49121991Sheppo v_offset = ((uintptr_t)vaddr) & (pg_size - 1); 49131991Sheppo 49141991Sheppo npages = (len+v_offset)/pg_size; 49151991Sheppo npages = ((len+v_offset)%pg_size == 0) ? npages : npages+1; 49161991Sheppo 49171991Sheppo D1(ldcp->id, "ldc_mem_bind_handle: binding " 49181991Sheppo "(0x%llx) v=0x%llx,val=0x%llx,off=0x%x,pgs=0x%x\n", 49191991Sheppo ldcp->id, vaddr, v_align, v_offset, npages); 49201991Sheppo 49211991Sheppo /* lock the memory table - exclusive access to channel */ 49221991Sheppo mutex_enter(&mtbl->lock); 49231991Sheppo 49241991Sheppo if (npages > mtbl->num_avail) { 49252793Slm66018 D1(ldcp->id, "ldc_mem_bind_handle: (0x%llx) no table entries\n", 49261991Sheppo ldcp->id); 49271991Sheppo mutex_exit(&mtbl->lock); 49281991Sheppo mutex_exit(&mhdl->lock); 49291991Sheppo return (ENOMEM); 49301991Sheppo } 49311991Sheppo 49321991Sheppo /* Allocate a memseg structure */ 49332531Snarayan memseg = mhdl->memseg = 49344690Snarayan kmem_cache_alloc(ldcssp->memseg_cache, KM_SLEEP); 49351991Sheppo 49361991Sheppo /* Allocate memory to store all pages and cookies */ 49371991Sheppo memseg->pages = kmem_zalloc((sizeof (ldc_page_t) * npages), KM_SLEEP); 49381991Sheppo memseg->cookies = 49394690Snarayan kmem_zalloc((sizeof (ldc_mem_cookie_t) * npages), KM_SLEEP); 49401991Sheppo 49411991Sheppo D2(ldcp->id, "ldc_mem_bind_handle: (0x%llx) processing 0x%llx pages\n", 49421991Sheppo ldcp->id, npages); 49431991Sheppo 49441991Sheppo addr = v_align; 49451991Sheppo 49461991Sheppo /* 49472531Snarayan * Check if direct shared memory map is enabled, if not change 49482531Snarayan * the mapping type to include SHADOW_MAP. 49492531Snarayan */ 49502531Snarayan if (ldc_shmem_enabled == 0) 49512531Snarayan mtype = LDC_SHADOW_MAP; 49522531Snarayan 49532531Snarayan /* 49541991Sheppo * Table slots are used in a round-robin manner. The algorithm permits 49551991Sheppo * inserting duplicate entries. Slots allocated earlier will typically 49561991Sheppo * get freed before we get back to reusing the slot.Inserting duplicate 49571991Sheppo * entries should be OK as we only lookup entries using the cookie addr 49581991Sheppo * i.e. tbl index, during export, unexport and copy operation. 49591991Sheppo * 49601991Sheppo * One implementation what was tried was to search for a duplicate 49611991Sheppo * page entry first and reuse it. The search overhead is very high and 49621991Sheppo * in the vnet case dropped the perf by almost half, 50 to 24 mbps. 49631991Sheppo * So it does make sense to avoid searching for duplicates. 49641991Sheppo * 49651991Sheppo * But during the process of searching for a free slot, if we find a 49661991Sheppo * duplicate entry we will go ahead and use it, and bump its use count. 49671991Sheppo */ 49681991Sheppo 49691991Sheppo /* index to start searching from */ 49701991Sheppo index = mtbl->next_entry; 49711991Sheppo cookie_idx = -1; 49721991Sheppo 49731991Sheppo tmp_mte.ll = 0; /* initialise fields to 0 */ 49741991Sheppo 49751991Sheppo if (mtype & LDC_DIRECT_MAP) { 49761991Sheppo tmp_mte.mte_r = (perm & LDC_MEM_R) ? 1 : 0; 49771991Sheppo tmp_mte.mte_w = (perm & LDC_MEM_W) ? 1 : 0; 49781991Sheppo tmp_mte.mte_x = (perm & LDC_MEM_X) ? 1 : 0; 49791991Sheppo } 49801991Sheppo 49811991Sheppo if (mtype & LDC_SHADOW_MAP) { 49821991Sheppo tmp_mte.mte_cr = (perm & LDC_MEM_R) ? 1 : 0; 49831991Sheppo tmp_mte.mte_cw = (perm & LDC_MEM_W) ? 1 : 0; 49841991Sheppo } 49851991Sheppo 49861991Sheppo if (mtype & LDC_IO_MAP) { 49871991Sheppo tmp_mte.mte_ir = (perm & LDC_MEM_R) ? 1 : 0; 49881991Sheppo tmp_mte.mte_iw = (perm & LDC_MEM_W) ? 1 : 0; 49891991Sheppo } 49901991Sheppo 49911991Sheppo D1(ldcp->id, "ldc_mem_bind_handle mte=0x%llx\n", tmp_mte.ll); 49921991Sheppo 49931991Sheppo tmp_mte.mte_pgszc = pg_size_code; 49941991Sheppo 49951991Sheppo /* initialize each mem table entry */ 49961991Sheppo for (i = 0; i < npages; i++) { 49971991Sheppo 49981991Sheppo /* check if slot is available in the table */ 49991991Sheppo while (mtbl->table[index].entry.ll != 0) { 50001991Sheppo 50011991Sheppo index = (index + 1) % mtbl->num_entries; 50021991Sheppo 50031991Sheppo if (index == mtbl->next_entry) { 50041991Sheppo /* we have looped around */ 50051991Sheppo DWARN(DBG_ALL_LDCS, 50061991Sheppo "ldc_mem_bind_handle: (0x%llx) cannot find " 50071991Sheppo "entry\n", ldcp->id); 50081991Sheppo *ccount = 0; 50091991Sheppo 50101991Sheppo /* NOTE: free memory, remove previous entries */ 50111991Sheppo /* this shouldnt happen as num_avail was ok */ 50121991Sheppo 50131991Sheppo mutex_exit(&mtbl->lock); 50141991Sheppo mutex_exit(&mhdl->lock); 50151991Sheppo return (ENOMEM); 50161991Sheppo } 50171991Sheppo } 50181991Sheppo 50191991Sheppo /* get the real address */ 50201991Sheppo raddr = va_to_pa((void *)addr); 50211991Sheppo ra_aligned = ((uintptr_t)raddr & pg_mask); 50221991Sheppo 50231991Sheppo /* build the mte */ 50241991Sheppo tmp_mte.mte_rpfn = ra_aligned >> pg_shift; 50251991Sheppo 50261991Sheppo D1(ldcp->id, "ldc_mem_bind_handle mte=0x%llx\n", tmp_mte.ll); 50271991Sheppo 50281991Sheppo /* update entry in table */ 50291991Sheppo mtbl->table[index].entry = tmp_mte; 50301991Sheppo 50311991Sheppo D2(ldcp->id, "ldc_mem_bind_handle: (0x%llx) stored MTE 0x%llx" 50321991Sheppo " into loc 0x%llx\n", ldcp->id, tmp_mte.ll, index); 50331991Sheppo 50341991Sheppo /* calculate the size and offset for this export range */ 50351991Sheppo if (i == 0) { 50361991Sheppo /* first page */ 50371991Sheppo psize = min((pg_size - v_offset), len); 50381991Sheppo poffset = v_offset; 50391991Sheppo 50401991Sheppo } else if (i == (npages - 1)) { 50411991Sheppo /* last page */ 50421991Sheppo psize = (((uintptr_t)(vaddr + len)) & 50434690Snarayan ((uint64_t)(pg_size-1))); 50441991Sheppo if (psize == 0) 50451991Sheppo psize = pg_size; 50461991Sheppo poffset = 0; 50471991Sheppo 50481991Sheppo } else { 50491991Sheppo /* middle pages */ 50501991Sheppo psize = pg_size; 50511991Sheppo poffset = 0; 50521991Sheppo } 50531991Sheppo 50541991Sheppo /* store entry for this page */ 50551991Sheppo memseg->pages[i].index = index; 50561991Sheppo memseg->pages[i].raddr = raddr; 50571991Sheppo memseg->pages[i].offset = poffset; 50581991Sheppo memseg->pages[i].size = psize; 50591991Sheppo memseg->pages[i].mte = &(mtbl->table[index]); 50601991Sheppo 50611991Sheppo /* create the cookie */ 50621991Sheppo if (i == 0 || (index != prev_index + 1)) { 50631991Sheppo cookie_idx++; 50641991Sheppo memseg->cookies[cookie_idx].addr = 50654690Snarayan IDX2COOKIE(index, pg_size_code, pg_shift); 50661991Sheppo memseg->cookies[cookie_idx].addr |= poffset; 50671991Sheppo memseg->cookies[cookie_idx].size = psize; 50681991Sheppo 50691991Sheppo } else { 50701991Sheppo memseg->cookies[cookie_idx].size += psize; 50711991Sheppo } 50721991Sheppo 50731991Sheppo D1(ldcp->id, "ldc_mem_bind_handle: bound " 50741991Sheppo "(0x%llx) va=0x%llx, idx=0x%llx, " 50751991Sheppo "ra=0x%llx(sz=0x%x,off=0x%x)\n", 50761991Sheppo ldcp->id, addr, index, raddr, psize, poffset); 50771991Sheppo 50781991Sheppo /* decrement number of available entries */ 50791991Sheppo mtbl->num_avail--; 50801991Sheppo 50811991Sheppo /* increment va by page size */ 50821991Sheppo addr += pg_size; 50831991Sheppo 50841991Sheppo /* increment index */ 50851991Sheppo prev_index = index; 50861991Sheppo index = (index + 1) % mtbl->num_entries; 50871991Sheppo 50881991Sheppo /* save the next slot */ 50891991Sheppo mtbl->next_entry = index; 50901991Sheppo } 50911991Sheppo 50921991Sheppo mutex_exit(&mtbl->lock); 50931991Sheppo 50941991Sheppo /* memory handle = bound */ 50951991Sheppo mhdl->mtype = mtype; 50961991Sheppo mhdl->perm = perm; 50971991Sheppo mhdl->status = LDC_BOUND; 50981991Sheppo 50991991Sheppo /* update memseg_t */ 51001991Sheppo memseg->vaddr = vaddr; 51011991Sheppo memseg->raddr = memseg->pages[0].raddr; 51021991Sheppo memseg->size = len; 51031991Sheppo memseg->npages = npages; 51041991Sheppo memseg->ncookies = cookie_idx + 1; 51051991Sheppo memseg->next_cookie = (memseg->ncookies > 1) ? 1 : 0; 51061991Sheppo 51071991Sheppo /* return count and first cookie */ 51081991Sheppo *ccount = memseg->ncookies; 51091991Sheppo cookie->addr = memseg->cookies[0].addr; 51101991Sheppo cookie->size = memseg->cookies[0].size; 51111991Sheppo 51121991Sheppo D1(ldcp->id, 51131991Sheppo "ldc_mem_bind_handle: (0x%llx) bound 0x%llx, va=0x%llx, " 51141991Sheppo "pgs=0x%llx cookies=0x%llx\n", 51151991Sheppo ldcp->id, mhdl, vaddr, npages, memseg->ncookies); 51161991Sheppo 51171991Sheppo mutex_exit(&mhdl->lock); 51181991Sheppo return (0); 51191991Sheppo } 51201991Sheppo 51211991Sheppo /* 51221991Sheppo * Return the next cookie associated with the specified memory handle 51231991Sheppo */ 51241991Sheppo int 51251991Sheppo ldc_mem_nextcookie(ldc_mem_handle_t mhandle, ldc_mem_cookie_t *cookie) 51261991Sheppo { 51271991Sheppo ldc_mhdl_t *mhdl; 51281991Sheppo ldc_chan_t *ldcp; 51291991Sheppo ldc_memseg_t *memseg; 51301991Sheppo 51311991Sheppo if (mhandle == NULL) { 51321991Sheppo DWARN(DBG_ALL_LDCS, 51331991Sheppo "ldc_mem_nextcookie: invalid memory handle\n"); 51341991Sheppo return (EINVAL); 51351991Sheppo } 51361991Sheppo mhdl = (ldc_mhdl_t *)mhandle; 51371991Sheppo 51381991Sheppo mutex_enter(&mhdl->lock); 51391991Sheppo 51401991Sheppo ldcp = mhdl->ldcp; 51411991Sheppo memseg = mhdl->memseg; 51421991Sheppo 51431991Sheppo if (cookie == 0) { 51441991Sheppo DWARN(ldcp->id, 51451991Sheppo "ldc_mem_nextcookie:(0x%llx) invalid cookie arg\n", 51461991Sheppo ldcp->id); 51471991Sheppo mutex_exit(&mhdl->lock); 51481991Sheppo return (EINVAL); 51491991Sheppo } 51501991Sheppo 51511991Sheppo if (memseg->next_cookie != 0) { 51521991Sheppo cookie->addr = memseg->cookies[memseg->next_cookie].addr; 51531991Sheppo cookie->size = memseg->cookies[memseg->next_cookie].size; 51541991Sheppo memseg->next_cookie++; 51551991Sheppo if (memseg->next_cookie == memseg->ncookies) 51561991Sheppo memseg->next_cookie = 0; 51571991Sheppo 51581991Sheppo } else { 51591991Sheppo DWARN(ldcp->id, 51601991Sheppo "ldc_mem_nextcookie:(0x%llx) no more cookies\n", ldcp->id); 51611991Sheppo cookie->addr = 0; 51621991Sheppo cookie->size = 0; 51631991Sheppo mutex_exit(&mhdl->lock); 51641991Sheppo return (EINVAL); 51651991Sheppo } 51661991Sheppo 51671991Sheppo D1(ldcp->id, 51681991Sheppo "ldc_mem_nextcookie: (0x%llx) cookie addr=0x%llx,sz=0x%llx\n", 51691991Sheppo ldcp->id, cookie->addr, cookie->size); 51701991Sheppo 51711991Sheppo mutex_exit(&mhdl->lock); 51721991Sheppo return (0); 51731991Sheppo } 51741991Sheppo 51751991Sheppo /* 51761991Sheppo * Unbind the virtual memory region associated with the specified 51771991Sheppo * memory handle. Allassociated cookies are freed and the corresponding 51781991Sheppo * RA space is no longer exported. 51791991Sheppo */ 51801991Sheppo int 51811991Sheppo ldc_mem_unbind_handle(ldc_mem_handle_t mhandle) 51821991Sheppo { 51831991Sheppo ldc_mhdl_t *mhdl; 51841991Sheppo ldc_chan_t *ldcp; 51851991Sheppo ldc_mtbl_t *mtbl; 51861991Sheppo ldc_memseg_t *memseg; 51872531Snarayan uint64_t cookie_addr; 51882531Snarayan uint64_t pg_shift, pg_size_code; 51892531Snarayan int i, rv; 51901991Sheppo 51911991Sheppo if (mhandle == NULL) { 51921991Sheppo DWARN(DBG_ALL_LDCS, 51931991Sheppo "ldc_mem_unbind_handle: invalid memory handle\n"); 51941991Sheppo return (EINVAL); 51951991Sheppo } 51961991Sheppo mhdl = (ldc_mhdl_t *)mhandle; 51971991Sheppo 51981991Sheppo mutex_enter(&mhdl->lock); 51991991Sheppo 52001991Sheppo if (mhdl->status == LDC_UNBOUND) { 52011991Sheppo DWARN(DBG_ALL_LDCS, 52021991Sheppo "ldc_mem_unbind_handle: (0x%x) handle is not bound\n", 52031991Sheppo mhandle); 52041991Sheppo mutex_exit(&mhdl->lock); 52051991Sheppo return (EINVAL); 52061991Sheppo } 52071991Sheppo 52081991Sheppo ldcp = mhdl->ldcp; 52091991Sheppo mtbl = ldcp->mtbl; 52101991Sheppo 52111991Sheppo memseg = mhdl->memseg; 52121991Sheppo 52131991Sheppo /* lock the memory table - exclusive access to channel */ 52141991Sheppo mutex_enter(&mtbl->lock); 52151991Sheppo 52161991Sheppo /* undo the pages exported */ 52171991Sheppo for (i = 0; i < memseg->npages; i++) { 52181991Sheppo 52192531Snarayan /* check for mapped pages, revocation cookie != 0 */ 52201991Sheppo if (memseg->pages[i].mte->cookie) { 52212531Snarayan 52222531Snarayan pg_size_code = page_szc(memseg->pages[i].size); 52232531Snarayan pg_shift = page_get_shift(memseg->pages[i].size); 52242531Snarayan cookie_addr = IDX2COOKIE(memseg->pages[i].index, 52252531Snarayan pg_size_code, pg_shift); 52262531Snarayan 52272531Snarayan D1(ldcp->id, "ldc_mem_unbind_handle: (0x%llx) revoke " 52282531Snarayan "cookie 0x%llx, rcookie 0x%llx\n", ldcp->id, 52292531Snarayan cookie_addr, memseg->pages[i].mte->cookie); 52302531Snarayan rv = hv_ldc_revoke(ldcp->id, cookie_addr, 52312531Snarayan memseg->pages[i].mte->cookie); 52322531Snarayan if (rv) { 52332531Snarayan DWARN(ldcp->id, 52342531Snarayan "ldc_mem_unbind_handle: (0x%llx) cannot " 52352531Snarayan "revoke mapping, cookie %llx\n", ldcp->id, 52362531Snarayan cookie_addr); 52372531Snarayan } 52381991Sheppo } 52391991Sheppo 52401991Sheppo /* clear the entry from the table */ 52411991Sheppo memseg->pages[i].mte->entry.ll = 0; 52421991Sheppo mtbl->num_avail++; 52431991Sheppo } 52441991Sheppo mutex_exit(&mtbl->lock); 52451991Sheppo 52461991Sheppo /* free the allocated memseg and page structures */ 52471991Sheppo kmem_free(memseg->pages, (sizeof (ldc_page_t) * memseg->npages)); 52481991Sheppo kmem_free(memseg->cookies, 52491991Sheppo (sizeof (ldc_mem_cookie_t) * memseg->npages)); 52502531Snarayan kmem_cache_free(ldcssp->memseg_cache, memseg); 52511991Sheppo 52521991Sheppo /* uninitialize the memory handle */ 52531991Sheppo mhdl->memseg = NULL; 52541991Sheppo mhdl->status = LDC_UNBOUND; 52551991Sheppo 52561991Sheppo D1(ldcp->id, "ldc_mem_unbind_handle: (0x%llx) unbound handle 0x%llx\n", 52571991Sheppo ldcp->id, mhdl); 52581991Sheppo 52591991Sheppo mutex_exit(&mhdl->lock); 52601991Sheppo return (0); 52611991Sheppo } 52621991Sheppo 52631991Sheppo /* 52641991Sheppo * Get information about the dring. The base address of the descriptor 52651991Sheppo * ring along with the type and permission are returned back. 52661991Sheppo */ 52671991Sheppo int 52681991Sheppo ldc_mem_info(ldc_mem_handle_t mhandle, ldc_mem_info_t *minfo) 52691991Sheppo { 52701991Sheppo ldc_mhdl_t *mhdl; 52711991Sheppo 52721991Sheppo if (mhandle == NULL) { 52731991Sheppo DWARN(DBG_ALL_LDCS, "ldc_mem_info: invalid memory handle\n"); 52741991Sheppo return (EINVAL); 52751991Sheppo } 52761991Sheppo mhdl = (ldc_mhdl_t *)mhandle; 52771991Sheppo 52781991Sheppo if (minfo == NULL) { 52791991Sheppo DWARN(DBG_ALL_LDCS, "ldc_mem_info: invalid args\n"); 52801991Sheppo return (EINVAL); 52811991Sheppo } 52821991Sheppo 52831991Sheppo mutex_enter(&mhdl->lock); 52841991Sheppo 52851991Sheppo minfo->status = mhdl->status; 52861991Sheppo if (mhdl->status == LDC_BOUND || mhdl->status == LDC_MAPPED) { 52871991Sheppo minfo->vaddr = mhdl->memseg->vaddr; 52881991Sheppo minfo->raddr = mhdl->memseg->raddr; 52891991Sheppo minfo->mtype = mhdl->mtype; 52901991Sheppo minfo->perm = mhdl->perm; 52911991Sheppo } 52921991Sheppo mutex_exit(&mhdl->lock); 52931991Sheppo 52941991Sheppo return (0); 52951991Sheppo } 52961991Sheppo 52971991Sheppo /* 52981991Sheppo * Copy data either from or to the client specified virtual address 52991991Sheppo * space to or from the exported memory associated with the cookies. 53001991Sheppo * The direction argument determines whether the data is read from or 53011991Sheppo * written to exported memory. 53021991Sheppo */ 53031991Sheppo int 53041991Sheppo ldc_mem_copy(ldc_handle_t handle, caddr_t vaddr, uint64_t off, size_t *size, 53051991Sheppo ldc_mem_cookie_t *cookies, uint32_t ccount, uint8_t direction) 53061991Sheppo { 53071991Sheppo ldc_chan_t *ldcp; 53081991Sheppo uint64_t local_voff, local_valign; 53091991Sheppo uint64_t cookie_addr, cookie_size; 53101991Sheppo uint64_t pg_shift, pg_size, pg_size_code; 53111991Sheppo uint64_t export_caddr, export_poff, export_psize, export_size; 53121991Sheppo uint64_t local_ra, local_poff, local_psize; 53131991Sheppo uint64_t copy_size, copied_len = 0, total_bal = 0, idx = 0; 53141991Sheppo pgcnt_t npages; 53151991Sheppo size_t len = *size; 53161991Sheppo int i, rv = 0; 53171991Sheppo 53182793Slm66018 uint64_t chid; 53192793Slm66018 53201991Sheppo if (handle == NULL) { 53211991Sheppo DWARN(DBG_ALL_LDCS, "ldc_mem_copy: invalid channel handle\n"); 53221991Sheppo return (EINVAL); 53231991Sheppo } 53241991Sheppo ldcp = (ldc_chan_t *)handle; 53252793Slm66018 chid = ldcp->id; 53261991Sheppo 53271991Sheppo /* check to see if channel is UP */ 53281991Sheppo if (ldcp->tstate != TS_UP) { 53292793Slm66018 DWARN(chid, "ldc_mem_copy: (0x%llx) channel is not UP\n", 53302793Slm66018 chid); 53312793Slm66018 return (ECONNRESET); 53321991Sheppo } 53331991Sheppo 53341991Sheppo /* Force address and size to be 8-byte aligned */ 53351991Sheppo if ((((uintptr_t)vaddr | len) & 0x7) != 0) { 53362793Slm66018 DWARN(chid, 53371991Sheppo "ldc_mem_copy: addr/sz is not 8-byte aligned\n"); 53381991Sheppo return (EINVAL); 53391991Sheppo } 53401991Sheppo 53411991Sheppo /* Find the size of the exported memory */ 53421991Sheppo export_size = 0; 53431991Sheppo for (i = 0; i < ccount; i++) 53441991Sheppo export_size += cookies[i].size; 53451991Sheppo 53461991Sheppo /* check to see if offset is valid */ 53471991Sheppo if (off > export_size) { 53482793Slm66018 DWARN(chid, 53491991Sheppo "ldc_mem_copy: (0x%llx) start offset > export mem size\n", 53502793Slm66018 chid); 53511991Sheppo return (EINVAL); 53521991Sheppo } 53531991Sheppo 53541991Sheppo /* 53551991Sheppo * Check to see if the export size is smaller than the size we 53561991Sheppo * are requesting to copy - if so flag an error 53571991Sheppo */ 53581991Sheppo if ((export_size - off) < *size) { 53592793Slm66018 DWARN(chid, 53601991Sheppo "ldc_mem_copy: (0x%llx) copy size > export mem size\n", 53612793Slm66018 chid); 53621991Sheppo return (EINVAL); 53631991Sheppo } 53641991Sheppo 53651991Sheppo total_bal = min(export_size, *size); 53661991Sheppo 53671991Sheppo /* FUTURE: get the page size, pgsz code, and shift */ 53681991Sheppo pg_size = MMU_PAGESIZE; 53691991Sheppo pg_size_code = page_szc(pg_size); 53701991Sheppo pg_shift = page_get_shift(pg_size_code); 53711991Sheppo 53722793Slm66018 D1(chid, "ldc_mem_copy: copying data " 53731991Sheppo "(0x%llx) va 0x%llx pgsz=0x%llx, pgszc=0x%llx, pg_shift=0x%llx\n", 53742793Slm66018 chid, vaddr, pg_size, pg_size_code, pg_shift); 53751991Sheppo 53761991Sheppo /* aligned VA and its offset */ 53771991Sheppo local_valign = (((uintptr_t)vaddr) & ~(pg_size - 1)); 53781991Sheppo local_voff = ((uintptr_t)vaddr) & (pg_size - 1); 53791991Sheppo 53801991Sheppo npages = (len+local_voff)/pg_size; 53811991Sheppo npages = ((len+local_voff)%pg_size == 0) ? npages : npages+1; 53821991Sheppo 53832793Slm66018 D1(chid, 53841991Sheppo "ldc_mem_copy: (0x%llx) v=0x%llx,val=0x%llx,off=0x%x,pgs=0x%x\n", 53852793Slm66018 chid, vaddr, local_valign, local_voff, npages); 53861991Sheppo 53871991Sheppo local_ra = va_to_pa((void *)local_valign); 53881991Sheppo local_poff = local_voff; 53891991Sheppo local_psize = min(len, (pg_size - local_voff)); 53901991Sheppo 53911991Sheppo len -= local_psize; 53921991Sheppo 53931991Sheppo /* 53941991Sheppo * find the first cookie in the list of cookies 53951991Sheppo * if the offset passed in is not zero 53961991Sheppo */ 53971991Sheppo for (idx = 0; idx < ccount; idx++) { 53981991Sheppo cookie_size = cookies[idx].size; 53991991Sheppo if (off < cookie_size) 54001991Sheppo break; 54011991Sheppo off -= cookie_size; 54021991Sheppo } 54031991Sheppo 54041991Sheppo cookie_addr = cookies[idx].addr + off; 54051991Sheppo cookie_size = cookies[idx].size - off; 54061991Sheppo 54071991Sheppo export_caddr = cookie_addr & ~(pg_size - 1); 54081991Sheppo export_poff = cookie_addr & (pg_size - 1); 54091991Sheppo export_psize = min(cookie_size, (pg_size - export_poff)); 54101991Sheppo 54111991Sheppo for (;;) { 54121991Sheppo 54131991Sheppo copy_size = min(export_psize, local_psize); 54141991Sheppo 54152793Slm66018 D1(chid, 54161991Sheppo "ldc_mem_copy:(0x%llx) dir=0x%x, caddr=0x%llx," 54171991Sheppo " loc_ra=0x%llx, exp_poff=0x%llx, loc_poff=0x%llx," 54181991Sheppo " exp_psz=0x%llx, loc_psz=0x%llx, copy_sz=0x%llx," 54191991Sheppo " total_bal=0x%llx\n", 54202793Slm66018 chid, direction, export_caddr, local_ra, export_poff, 54211991Sheppo local_poff, export_psize, local_psize, copy_size, 54221991Sheppo total_bal); 54231991Sheppo 54242793Slm66018 rv = hv_ldc_copy(chid, direction, 54251991Sheppo (export_caddr + export_poff), (local_ra + local_poff), 54261991Sheppo copy_size, &copied_len); 54271991Sheppo 54281991Sheppo if (rv != 0) { 54292793Slm66018 int error = EIO; 54302793Slm66018 uint64_t rx_hd, rx_tl; 54312793Slm66018 54322793Slm66018 DWARN(chid, 54332793Slm66018 "ldc_mem_copy: (0x%llx) err %d during copy\n", 54342793Slm66018 (unsigned long long)chid, rv); 54352793Slm66018 DWARN(chid, 54362793Slm66018 "ldc_mem_copy: (0x%llx) dir=0x%x, caddr=0x%lx, " 54372531Snarayan "loc_ra=0x%lx, exp_poff=0x%lx, loc_poff=0x%lx," 54382531Snarayan " exp_psz=0x%lx, loc_psz=0x%lx, copy_sz=0x%lx," 54392531Snarayan " copied_len=0x%lx, total_bal=0x%lx\n", 54402793Slm66018 chid, direction, export_caddr, local_ra, 54411991Sheppo export_poff, local_poff, export_psize, local_psize, 54421991Sheppo copy_size, copied_len, total_bal); 54431991Sheppo 54441991Sheppo *size = *size - total_bal; 54452793Slm66018 54462793Slm66018 /* 54472793Slm66018 * check if reason for copy error was due to 54482793Slm66018 * a channel reset. we need to grab the lock 54492793Slm66018 * just in case we have to do a reset. 54502793Slm66018 */ 54512793Slm66018 mutex_enter(&ldcp->lock); 54522793Slm66018 mutex_enter(&ldcp->tx_lock); 54532793Slm66018 54542793Slm66018 rv = hv_ldc_rx_get_state(ldcp->id, 54552793Slm66018 &rx_hd, &rx_tl, &(ldcp->link_state)); 54562793Slm66018 if (ldcp->link_state == LDC_CHANNEL_DOWN || 54572793Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) { 54582793Slm66018 i_ldc_reset(ldcp, B_FALSE); 54592793Slm66018 error = ECONNRESET; 54602793Slm66018 } 54612793Slm66018 54622793Slm66018 mutex_exit(&ldcp->tx_lock); 54631991Sheppo mutex_exit(&ldcp->lock); 54642793Slm66018 54652793Slm66018 return (error); 54661991Sheppo } 54671991Sheppo 54681991Sheppo ASSERT(copied_len <= copy_size); 54691991Sheppo 54702793Slm66018 D2(chid, "ldc_mem_copy: copied=0x%llx\n", copied_len); 54711991Sheppo export_poff += copied_len; 54721991Sheppo local_poff += copied_len; 54731991Sheppo export_psize -= copied_len; 54741991Sheppo local_psize -= copied_len; 54751991Sheppo cookie_size -= copied_len; 54761991Sheppo 54771991Sheppo total_bal -= copied_len; 54781991Sheppo 54791991Sheppo if (copy_size != copied_len) 54801991Sheppo continue; 54811991Sheppo 54821991Sheppo if (export_psize == 0 && total_bal != 0) { 54831991Sheppo 54841991Sheppo if (cookie_size == 0) { 54851991Sheppo idx++; 54861991Sheppo cookie_addr = cookies[idx].addr; 54871991Sheppo cookie_size = cookies[idx].size; 54881991Sheppo 54891991Sheppo export_caddr = cookie_addr & ~(pg_size - 1); 54901991Sheppo export_poff = cookie_addr & (pg_size - 1); 54911991Sheppo export_psize = 54924690Snarayan min(cookie_size, (pg_size-export_poff)); 54931991Sheppo } else { 54941991Sheppo export_caddr += pg_size; 54951991Sheppo export_poff = 0; 54961991Sheppo export_psize = min(cookie_size, pg_size); 54971991Sheppo } 54981991Sheppo } 54991991Sheppo 55001991Sheppo if (local_psize == 0 && total_bal != 0) { 55011991Sheppo local_valign += pg_size; 55021991Sheppo local_ra = va_to_pa((void *)local_valign); 55031991Sheppo local_poff = 0; 55041991Sheppo local_psize = min(pg_size, len); 55051991Sheppo len -= local_psize; 55061991Sheppo } 55071991Sheppo 55081991Sheppo /* check if we are all done */ 55091991Sheppo if (total_bal == 0) 55101991Sheppo break; 55111991Sheppo } 55121991Sheppo 55132793Slm66018 55142793Slm66018 D1(chid, 55151991Sheppo "ldc_mem_copy: (0x%llx) done copying sz=0x%llx\n", 55162793Slm66018 chid, *size); 55171991Sheppo 55181991Sheppo return (0); 55191991Sheppo } 55201991Sheppo 55211991Sheppo /* 55221991Sheppo * Copy data either from or to the client specified virtual address 55231991Sheppo * space to or from HV physical memory. 55241991Sheppo * 55251991Sheppo * The direction argument determines whether the data is read from or 55261991Sheppo * written to HV memory. direction values are LDC_COPY_IN/OUT similar 55271991Sheppo * to the ldc_mem_copy interface 55281991Sheppo */ 55291991Sheppo int 55302793Slm66018 ldc_mem_rdwr_cookie(ldc_handle_t handle, caddr_t vaddr, size_t *size, 55311991Sheppo caddr_t paddr, uint8_t direction) 55321991Sheppo { 55331991Sheppo ldc_chan_t *ldcp; 55341991Sheppo uint64_t local_voff, local_valign; 55351991Sheppo uint64_t pg_shift, pg_size, pg_size_code; 55361991Sheppo uint64_t target_pa, target_poff, target_psize, target_size; 55371991Sheppo uint64_t local_ra, local_poff, local_psize; 55381991Sheppo uint64_t copy_size, copied_len = 0; 55391991Sheppo pgcnt_t npages; 55401991Sheppo size_t len = *size; 55411991Sheppo int rv = 0; 55421991Sheppo 55431991Sheppo if (handle == NULL) { 55441991Sheppo DWARN(DBG_ALL_LDCS, 55452793Slm66018 "ldc_mem_rdwr_cookie: invalid channel handle\n"); 55461991Sheppo return (EINVAL); 55471991Sheppo } 55481991Sheppo ldcp = (ldc_chan_t *)handle; 55491991Sheppo 55501991Sheppo mutex_enter(&ldcp->lock); 55511991Sheppo 55521991Sheppo /* check to see if channel is UP */ 55531991Sheppo if (ldcp->tstate != TS_UP) { 55541991Sheppo DWARN(ldcp->id, 55552793Slm66018 "ldc_mem_rdwr_cookie: (0x%llx) channel is not UP\n", 55561991Sheppo ldcp->id); 55571991Sheppo mutex_exit(&ldcp->lock); 55582793Slm66018 return (ECONNRESET); 55591991Sheppo } 55601991Sheppo 55611991Sheppo /* Force address and size to be 8-byte aligned */ 55621991Sheppo if ((((uintptr_t)vaddr | len) & 0x7) != 0) { 55631991Sheppo DWARN(ldcp->id, 55642793Slm66018 "ldc_mem_rdwr_cookie: addr/size is not 8-byte aligned\n"); 55651991Sheppo mutex_exit(&ldcp->lock); 55661991Sheppo return (EINVAL); 55671991Sheppo } 55681991Sheppo 55691991Sheppo target_size = *size; 55701991Sheppo 55711991Sheppo /* FUTURE: get the page size, pgsz code, and shift */ 55721991Sheppo pg_size = MMU_PAGESIZE; 55731991Sheppo pg_size_code = page_szc(pg_size); 55741991Sheppo pg_shift = page_get_shift(pg_size_code); 55751991Sheppo 55762793Slm66018 D1(ldcp->id, "ldc_mem_rdwr_cookie: copying data " 55771991Sheppo "(0x%llx) va 0x%llx pgsz=0x%llx, pgszc=0x%llx, pg_shift=0x%llx\n", 55781991Sheppo ldcp->id, vaddr, pg_size, pg_size_code, pg_shift); 55791991Sheppo 55801991Sheppo /* aligned VA and its offset */ 55811991Sheppo local_valign = ((uintptr_t)vaddr) & ~(pg_size - 1); 55821991Sheppo local_voff = ((uintptr_t)vaddr) & (pg_size - 1); 55831991Sheppo 55841991Sheppo npages = (len + local_voff) / pg_size; 55851991Sheppo npages = ((len + local_voff) % pg_size == 0) ? npages : npages+1; 55861991Sheppo 55872793Slm66018 D1(ldcp->id, "ldc_mem_rdwr_cookie: (0x%llx) v=0x%llx, " 55882793Slm66018 "val=0x%llx,off=0x%x,pgs=0x%x\n", 55891991Sheppo ldcp->id, vaddr, local_valign, local_voff, npages); 55901991Sheppo 55911991Sheppo local_ra = va_to_pa((void *)local_valign); 55921991Sheppo local_poff = local_voff; 55931991Sheppo local_psize = min(len, (pg_size - local_voff)); 55941991Sheppo 55951991Sheppo len -= local_psize; 55961991Sheppo 55971991Sheppo target_pa = ((uintptr_t)paddr) & ~(pg_size - 1); 55981991Sheppo target_poff = ((uintptr_t)paddr) & (pg_size - 1); 55991991Sheppo target_psize = pg_size - target_poff; 56001991Sheppo 56011991Sheppo for (;;) { 56021991Sheppo 56031991Sheppo copy_size = min(target_psize, local_psize); 56041991Sheppo 56051991Sheppo D1(ldcp->id, 56062793Slm66018 "ldc_mem_rdwr_cookie: (0x%llx) dir=0x%x, tar_pa=0x%llx," 56071991Sheppo " loc_ra=0x%llx, tar_poff=0x%llx, loc_poff=0x%llx," 56081991Sheppo " tar_psz=0x%llx, loc_psz=0x%llx, copy_sz=0x%llx," 56091991Sheppo " total_bal=0x%llx\n", 56101991Sheppo ldcp->id, direction, target_pa, local_ra, target_poff, 56111991Sheppo local_poff, target_psize, local_psize, copy_size, 56121991Sheppo target_size); 56131991Sheppo 56141991Sheppo rv = hv_ldc_copy(ldcp->id, direction, 56151991Sheppo (target_pa + target_poff), (local_ra + local_poff), 56161991Sheppo copy_size, &copied_len); 56171991Sheppo 56181991Sheppo if (rv != 0) { 56192793Slm66018 DWARN(DBG_ALL_LDCS, 56202793Slm66018 "ldc_mem_rdwr_cookie: (0x%lx) err %d during copy\n", 56211991Sheppo ldcp->id, rv); 56221991Sheppo DWARN(DBG_ALL_LDCS, 56232793Slm66018 "ldc_mem_rdwr_cookie: (0x%llx) dir=%lld, " 56242793Slm66018 "tar_pa=0x%llx, loc_ra=0x%llx, tar_poff=0x%llx, " 56252793Slm66018 "loc_poff=0x%llx, tar_psz=0x%llx, loc_psz=0x%llx, " 56262793Slm66018 "copy_sz=0x%llx, total_bal=0x%llx\n", 56271991Sheppo ldcp->id, direction, target_pa, local_ra, 56281991Sheppo target_poff, local_poff, target_psize, local_psize, 56291991Sheppo copy_size, target_size); 56301991Sheppo 56311991Sheppo *size = *size - target_size; 56321991Sheppo mutex_exit(&ldcp->lock); 56331991Sheppo return (i_ldc_h2v_error(rv)); 56341991Sheppo } 56351991Sheppo 56362793Slm66018 D2(ldcp->id, "ldc_mem_rdwr_cookie: copied=0x%llx\n", 56372793Slm66018 copied_len); 56381991Sheppo target_poff += copied_len; 56391991Sheppo local_poff += copied_len; 56401991Sheppo target_psize -= copied_len; 56411991Sheppo local_psize -= copied_len; 56421991Sheppo 56431991Sheppo target_size -= copied_len; 56441991Sheppo 56451991Sheppo if (copy_size != copied_len) 56461991Sheppo continue; 56471991Sheppo 56481991Sheppo if (target_psize == 0 && target_size != 0) { 56491991Sheppo target_pa += pg_size; 56501991Sheppo target_poff = 0; 56511991Sheppo target_psize = min(pg_size, target_size); 56521991Sheppo } 56531991Sheppo 56541991Sheppo if (local_psize == 0 && target_size != 0) { 56551991Sheppo local_valign += pg_size; 56561991Sheppo local_ra = va_to_pa((void *)local_valign); 56571991Sheppo local_poff = 0; 56581991Sheppo local_psize = min(pg_size, len); 56591991Sheppo len -= local_psize; 56601991Sheppo } 56611991Sheppo 56621991Sheppo /* check if we are all done */ 56631991Sheppo if (target_size == 0) 56641991Sheppo break; 56651991Sheppo } 56661991Sheppo 56671991Sheppo mutex_exit(&ldcp->lock); 56681991Sheppo 56692793Slm66018 D1(ldcp->id, "ldc_mem_rdwr_cookie: (0x%llx) done copying sz=0x%llx\n", 56701991Sheppo ldcp->id, *size); 56711991Sheppo 56721991Sheppo return (0); 56731991Sheppo } 56741991Sheppo 56751991Sheppo /* 56761991Sheppo * Map an exported memory segment into the local address space. If the 56771991Sheppo * memory range was exported for direct map access, a HV call is made 56781991Sheppo * to allocate a RA range. If the map is done via a shadow copy, local 56791991Sheppo * shadow memory is allocated and the base VA is returned in 'vaddr'. If 56801991Sheppo * the mapping is a direct map then the RA is returned in 'raddr'. 56811991Sheppo */ 56821991Sheppo int 56831991Sheppo ldc_mem_map(ldc_mem_handle_t mhandle, ldc_mem_cookie_t *cookie, uint32_t ccount, 56842531Snarayan uint8_t mtype, uint8_t perm, caddr_t *vaddr, caddr_t *raddr) 56851991Sheppo { 56862531Snarayan int i, j, idx, rv, retries; 56871991Sheppo ldc_chan_t *ldcp; 56881991Sheppo ldc_mhdl_t *mhdl; 56891991Sheppo ldc_memseg_t *memseg; 56902531Snarayan caddr_t tmpaddr; 56912531Snarayan uint64_t map_perm = perm; 56922531Snarayan uint64_t pg_size, pg_shift, pg_size_code, pg_mask; 56932531Snarayan uint64_t exp_size = 0, base_off, map_size, npages; 56942531Snarayan uint64_t cookie_addr, cookie_off, cookie_size; 56952531Snarayan tte_t ldc_tte; 56961991Sheppo 56971991Sheppo if (mhandle == NULL) { 56981991Sheppo DWARN(DBG_ALL_LDCS, "ldc_mem_map: invalid memory handle\n"); 56991991Sheppo return (EINVAL); 57001991Sheppo } 57011991Sheppo mhdl = (ldc_mhdl_t *)mhandle; 57021991Sheppo 57031991Sheppo mutex_enter(&mhdl->lock); 57041991Sheppo 57051991Sheppo if (mhdl->status == LDC_BOUND || mhdl->status == LDC_MAPPED || 57061991Sheppo mhdl->memseg != NULL) { 57071991Sheppo DWARN(DBG_ALL_LDCS, 57081991Sheppo "ldc_mem_map: (0x%llx) handle bound/mapped\n", mhandle); 57091991Sheppo mutex_exit(&mhdl->lock); 57101991Sheppo return (EINVAL); 57111991Sheppo } 57121991Sheppo 57131991Sheppo ldcp = mhdl->ldcp; 57141991Sheppo 57151991Sheppo mutex_enter(&ldcp->lock); 57161991Sheppo 57171991Sheppo if (ldcp->tstate != TS_UP) { 57181991Sheppo DWARN(ldcp->id, 57191991Sheppo "ldc_mem_dring_map: (0x%llx) channel is not UP\n", 57201991Sheppo ldcp->id); 57211991Sheppo mutex_exit(&ldcp->lock); 57221991Sheppo mutex_exit(&mhdl->lock); 57232793Slm66018 return (ECONNRESET); 57241991Sheppo } 57251991Sheppo 57261991Sheppo if ((mtype & (LDC_SHADOW_MAP|LDC_DIRECT_MAP|LDC_IO_MAP)) == 0) { 57271991Sheppo DWARN(ldcp->id, "ldc_mem_map: invalid map type\n"); 57281991Sheppo mutex_exit(&ldcp->lock); 57291991Sheppo mutex_exit(&mhdl->lock); 57301991Sheppo return (EINVAL); 57311991Sheppo } 57321991Sheppo 57331991Sheppo D1(ldcp->id, "ldc_mem_map: (0x%llx) cookie = 0x%llx,0x%llx\n", 57342336Snarayan ldcp->id, cookie->addr, cookie->size); 57351991Sheppo 57361991Sheppo /* FUTURE: get the page size, pgsz code, and shift */ 57371991Sheppo pg_size = MMU_PAGESIZE; 57381991Sheppo pg_size_code = page_szc(pg_size); 57391991Sheppo pg_shift = page_get_shift(pg_size_code); 57402531Snarayan pg_mask = ~(pg_size - 1); 57411991Sheppo 57421991Sheppo /* calculate the number of pages in the exported cookie */ 57432531Snarayan base_off = cookie[0].addr & (pg_size - 1); 57442531Snarayan for (idx = 0; idx < ccount; idx++) 57451991Sheppo exp_size += cookie[idx].size; 57462531Snarayan map_size = P2ROUNDUP((exp_size + base_off), pg_size); 57472531Snarayan npages = (map_size >> pg_shift); 57481991Sheppo 57491991Sheppo /* Allocate memseg structure */ 57502531Snarayan memseg = mhdl->memseg = 57514690Snarayan kmem_cache_alloc(ldcssp->memseg_cache, KM_SLEEP); 57521991Sheppo 57531991Sheppo /* Allocate memory to store all pages and cookies */ 57541991Sheppo memseg->pages = kmem_zalloc((sizeof (ldc_page_t) * npages), KM_SLEEP); 57551991Sheppo memseg->cookies = 57564690Snarayan kmem_zalloc((sizeof (ldc_mem_cookie_t) * ccount), KM_SLEEP); 57571991Sheppo 57582531Snarayan D2(ldcp->id, "ldc_mem_map: (0x%llx) exp_size=0x%llx, map_size=0x%llx," 57592531Snarayan "pages=0x%llx\n", ldcp->id, exp_size, map_size, npages); 57602531Snarayan 57612531Snarayan /* 57622531Snarayan * Check if direct map over shared memory is enabled, if not change 57632531Snarayan * the mapping type to SHADOW_MAP. 57642531Snarayan */ 57652531Snarayan if (ldc_shmem_enabled == 0) 57662531Snarayan mtype = LDC_SHADOW_MAP; 57672531Snarayan 57682531Snarayan /* 57692531Snarayan * Check to see if the client is requesting direct or shadow map 57702531Snarayan * If direct map is requested, try to map remote memory first, 57712531Snarayan * and if that fails, revert to shadow map 57722531Snarayan */ 57732531Snarayan if (mtype == LDC_DIRECT_MAP) { 57742531Snarayan 57752531Snarayan /* Allocate kernel virtual space for mapping */ 57762531Snarayan memseg->vaddr = vmem_xalloc(heap_arena, map_size, 57772531Snarayan pg_size, 0, 0, NULL, NULL, VM_NOSLEEP); 57782531Snarayan if (memseg->vaddr == NULL) { 57792531Snarayan cmn_err(CE_WARN, 57802531Snarayan "ldc_mem_map: (0x%lx) memory map failed\n", 57812531Snarayan ldcp->id); 57822531Snarayan kmem_free(memseg->cookies, 57832531Snarayan (sizeof (ldc_mem_cookie_t) * ccount)); 57842531Snarayan kmem_free(memseg->pages, 57852531Snarayan (sizeof (ldc_page_t) * npages)); 57862531Snarayan kmem_cache_free(ldcssp->memseg_cache, memseg); 57872531Snarayan 57882531Snarayan mutex_exit(&ldcp->lock); 57892531Snarayan mutex_exit(&mhdl->lock); 57902531Snarayan return (ENOMEM); 57912531Snarayan } 57922531Snarayan 57932531Snarayan /* Unload previous mapping */ 57942531Snarayan hat_unload(kas.a_hat, memseg->vaddr, map_size, 57952531Snarayan HAT_UNLOAD_NOSYNC | HAT_UNLOAD_UNLOCK); 57962531Snarayan 57972531Snarayan /* for each cookie passed in - map into address space */ 57982531Snarayan idx = 0; 57992531Snarayan cookie_size = 0; 58002531Snarayan tmpaddr = memseg->vaddr; 58012531Snarayan 58022531Snarayan for (i = 0; i < npages; i++) { 58032531Snarayan 58042531Snarayan if (cookie_size == 0) { 58052531Snarayan ASSERT(idx < ccount); 58062531Snarayan cookie_addr = cookie[idx].addr & pg_mask; 58072531Snarayan cookie_off = cookie[idx].addr & (pg_size - 1); 58082531Snarayan cookie_size = 58092531Snarayan P2ROUNDUP((cookie_off + cookie[idx].size), 58104690Snarayan pg_size); 58112531Snarayan idx++; 58122531Snarayan } 58132531Snarayan 58142531Snarayan D1(ldcp->id, "ldc_mem_map: (0x%llx) mapping " 58152531Snarayan "cookie 0x%llx, bal=0x%llx\n", ldcp->id, 58162531Snarayan cookie_addr, cookie_size); 58172531Snarayan 58182531Snarayan /* map the cookie into address space */ 58192531Snarayan for (retries = 0; retries < ldc_max_retries; 58202531Snarayan retries++) { 58212531Snarayan 58222531Snarayan rv = hv_ldc_mapin(ldcp->id, cookie_addr, 58232531Snarayan &memseg->pages[i].raddr, &map_perm); 58242531Snarayan if (rv != H_EWOULDBLOCK && rv != H_ETOOMANY) 58252531Snarayan break; 58262531Snarayan 58272531Snarayan drv_usecwait(ldc_delay); 58282531Snarayan } 58292531Snarayan 58302531Snarayan if (rv || memseg->pages[i].raddr == 0) { 58312531Snarayan DWARN(ldcp->id, 58322531Snarayan "ldc_mem_map: (0x%llx) hv mapin err %d\n", 58332531Snarayan ldcp->id, rv); 58342531Snarayan 58352531Snarayan /* remove previous mapins */ 58362531Snarayan hat_unload(kas.a_hat, memseg->vaddr, map_size, 58372531Snarayan HAT_UNLOAD_NOSYNC | HAT_UNLOAD_UNLOCK); 58382531Snarayan for (j = 0; j < i; j++) { 58392531Snarayan rv = hv_ldc_unmap( 58404690Snarayan memseg->pages[j].raddr); 58412531Snarayan if (rv) { 58422531Snarayan DWARN(ldcp->id, 58432531Snarayan "ldc_mem_map: (0x%llx) " 58442531Snarayan "cannot unmap ra=0x%llx\n", 58454690Snarayan ldcp->id, 58462531Snarayan memseg->pages[j].raddr); 58472531Snarayan } 58482531Snarayan } 58492531Snarayan 58502531Snarayan /* free kernel virtual space */ 58512531Snarayan vmem_free(heap_arena, (void *)memseg->vaddr, 58522748Slm66018 map_size); 58532531Snarayan 58542531Snarayan /* direct map failed - revert to shadow map */ 58552531Snarayan mtype = LDC_SHADOW_MAP; 58562531Snarayan break; 58572531Snarayan 58582531Snarayan } else { 58592531Snarayan 58602531Snarayan D1(ldcp->id, 58612531Snarayan "ldc_mem_map: (0x%llx) vtop map 0x%llx -> " 58622531Snarayan "0x%llx, cookie=0x%llx, perm=0x%llx\n", 58632531Snarayan ldcp->id, tmpaddr, memseg->pages[i].raddr, 58642531Snarayan cookie_addr, perm); 58652531Snarayan 58662531Snarayan /* 58672531Snarayan * NOTE: Calling hat_devload directly, causes it 58682531Snarayan * to look for page_t using the pfn. Since this 58692531Snarayan * addr is greater than the memlist, it treates 58702531Snarayan * it as non-memory 58712531Snarayan */ 58722531Snarayan sfmmu_memtte(&ldc_tte, 58732531Snarayan (pfn_t)(memseg->pages[i].raddr >> pg_shift), 58742531Snarayan PROT_READ | PROT_WRITE | HAT_NOSYNC, TTE8K); 58752531Snarayan 58762531Snarayan D1(ldcp->id, 58772531Snarayan "ldc_mem_map: (0x%llx) ra 0x%llx -> " 58782531Snarayan "tte 0x%llx\n", ldcp->id, 58792531Snarayan memseg->pages[i].raddr, ldc_tte); 58802531Snarayan 58812531Snarayan sfmmu_tteload(kas.a_hat, &ldc_tte, tmpaddr, 58822531Snarayan NULL, HAT_LOAD_LOCK); 58832531Snarayan 58842531Snarayan cookie_size -= pg_size; 58852531Snarayan cookie_addr += pg_size; 58862531Snarayan tmpaddr += pg_size; 58872531Snarayan } 58882531Snarayan } 58892531Snarayan } 58902531Snarayan 58911991Sheppo if (mtype == LDC_SHADOW_MAP) { 58921991Sheppo if (*vaddr == NULL) { 58932793Slm66018 memseg->vaddr = kmem_zalloc(exp_size, KM_SLEEP); 58941991Sheppo mhdl->myshadow = B_TRUE; 58951991Sheppo 58961991Sheppo D1(ldcp->id, "ldc_mem_map: (0x%llx) allocated " 58972531Snarayan "shadow page va=0x%llx\n", ldcp->id, memseg->vaddr); 58981991Sheppo } else { 58991991Sheppo /* 59002531Snarayan * Use client supplied memory for memseg->vaddr 59011991Sheppo * WARNING: assuming that client mem is >= exp_size 59021991Sheppo */ 59032531Snarayan memseg->vaddr = *vaddr; 59041991Sheppo } 59052531Snarayan 59062531Snarayan /* Save all page and cookie information */ 59072531Snarayan for (i = 0, tmpaddr = memseg->vaddr; i < npages; i++) { 59082531Snarayan memseg->pages[i].raddr = va_to_pa(tmpaddr); 59092531Snarayan memseg->pages[i].size = pg_size; 59102531Snarayan tmpaddr += pg_size; 59112531Snarayan } 59122531Snarayan 59132531Snarayan } 59142531Snarayan 59152531Snarayan /* save all cookies */ 59162531Snarayan bcopy(cookie, memseg->cookies, ccount * sizeof (ldc_mem_cookie_t)); 59171991Sheppo 59181991Sheppo /* update memseg_t */ 59191991Sheppo memseg->raddr = memseg->pages[0].raddr; 59202531Snarayan memseg->size = (mtype == LDC_SHADOW_MAP) ? exp_size : map_size; 59211991Sheppo memseg->npages = npages; 59221991Sheppo memseg->ncookies = ccount; 59231991Sheppo memseg->next_cookie = 0; 59241991Sheppo 59251991Sheppo /* memory handle = mapped */ 59261991Sheppo mhdl->mtype = mtype; 59272531Snarayan mhdl->perm = perm; 59281991Sheppo mhdl->status = LDC_MAPPED; 59291991Sheppo 59301991Sheppo D1(ldcp->id, "ldc_mem_map: (0x%llx) mapped 0x%llx, ra=0x%llx, " 59311991Sheppo "va=0x%llx, pgs=0x%llx cookies=0x%llx\n", 59321991Sheppo ldcp->id, mhdl, memseg->raddr, memseg->vaddr, 59331991Sheppo memseg->npages, memseg->ncookies); 59341991Sheppo 59352531Snarayan if (mtype == LDC_SHADOW_MAP) 59362531Snarayan base_off = 0; 59371991Sheppo if (raddr) 59382531Snarayan *raddr = (caddr_t)(memseg->raddr | base_off); 59391991Sheppo if (vaddr) 59402531Snarayan *vaddr = (caddr_t)((uintptr_t)memseg->vaddr | base_off); 59411991Sheppo 59421991Sheppo mutex_exit(&ldcp->lock); 59431991Sheppo mutex_exit(&mhdl->lock); 59441991Sheppo return (0); 59451991Sheppo } 59461991Sheppo 59471991Sheppo /* 59481991Sheppo * Unmap a memory segment. Free shadow memory (if any). 59491991Sheppo */ 59501991Sheppo int 59511991Sheppo ldc_mem_unmap(ldc_mem_handle_t mhandle) 59521991Sheppo { 59532531Snarayan int i, rv; 59541991Sheppo ldc_mhdl_t *mhdl = (ldc_mhdl_t *)mhandle; 59551991Sheppo ldc_chan_t *ldcp; 59561991Sheppo ldc_memseg_t *memseg; 59571991Sheppo 59581991Sheppo if (mhdl == 0 || mhdl->status != LDC_MAPPED) { 59591991Sheppo DWARN(DBG_ALL_LDCS, 59601991Sheppo "ldc_mem_unmap: (0x%llx) handle is not mapped\n", 59611991Sheppo mhandle); 59621991Sheppo return (EINVAL); 59631991Sheppo } 59641991Sheppo 59651991Sheppo mutex_enter(&mhdl->lock); 59661991Sheppo 59671991Sheppo ldcp = mhdl->ldcp; 59681991Sheppo memseg = mhdl->memseg; 59691991Sheppo 59701991Sheppo D1(ldcp->id, "ldc_mem_unmap: (0x%llx) unmapping handle 0x%llx\n", 59711991Sheppo ldcp->id, mhdl); 59721991Sheppo 59731991Sheppo /* if we allocated shadow memory - free it */ 59741991Sheppo if (mhdl->mtype == LDC_SHADOW_MAP && mhdl->myshadow) { 59752793Slm66018 kmem_free(memseg->vaddr, memseg->size); 59762531Snarayan } else if (mhdl->mtype == LDC_DIRECT_MAP) { 59772531Snarayan 59782531Snarayan /* unmap in the case of DIRECT_MAP */ 59792531Snarayan hat_unload(kas.a_hat, memseg->vaddr, memseg->size, 59802531Snarayan HAT_UNLOAD_UNLOCK); 59812531Snarayan 59822531Snarayan for (i = 0; i < memseg->npages; i++) { 59832531Snarayan rv = hv_ldc_unmap(memseg->pages[i].raddr); 59842531Snarayan if (rv) { 59852531Snarayan cmn_err(CE_WARN, 59862531Snarayan "ldc_mem_map: (0x%lx) hv unmap err %d\n", 59872531Snarayan ldcp->id, rv); 59882531Snarayan } 59892531Snarayan } 59902531Snarayan 59912531Snarayan vmem_free(heap_arena, (void *)memseg->vaddr, memseg->size); 59921991Sheppo } 59931991Sheppo 59941991Sheppo /* free the allocated memseg and page structures */ 59951991Sheppo kmem_free(memseg->pages, (sizeof (ldc_page_t) * memseg->npages)); 59961991Sheppo kmem_free(memseg->cookies, 59971991Sheppo (sizeof (ldc_mem_cookie_t) * memseg->ncookies)); 59982531Snarayan kmem_cache_free(ldcssp->memseg_cache, memseg); 59991991Sheppo 60001991Sheppo /* uninitialize the memory handle */ 60011991Sheppo mhdl->memseg = NULL; 60021991Sheppo mhdl->status = LDC_UNBOUND; 60031991Sheppo 60041991Sheppo D1(ldcp->id, "ldc_mem_unmap: (0x%llx) unmapped handle 0x%llx\n", 60051991Sheppo ldcp->id, mhdl); 60061991Sheppo 60071991Sheppo mutex_exit(&mhdl->lock); 60081991Sheppo return (0); 60091991Sheppo } 60101991Sheppo 60111991Sheppo /* 60121991Sheppo * Internal entry point for LDC mapped memory entry consistency 60131991Sheppo * semantics. Acquire copies the contents of the remote memory 60141991Sheppo * into the local shadow copy. The release operation copies the local 60151991Sheppo * contents into the remote memory. The offset and size specify the 60161991Sheppo * bounds for the memory range being synchronized. 60171991Sheppo */ 60181991Sheppo static int 60191991Sheppo i_ldc_mem_acquire_release(ldc_mem_handle_t mhandle, uint8_t direction, 60201991Sheppo uint64_t offset, size_t size) 60211991Sheppo { 60221991Sheppo int err; 60231991Sheppo ldc_mhdl_t *mhdl; 60241991Sheppo ldc_chan_t *ldcp; 60251991Sheppo ldc_memseg_t *memseg; 60261991Sheppo caddr_t local_vaddr; 60271991Sheppo size_t copy_size; 60281991Sheppo 60291991Sheppo if (mhandle == NULL) { 60301991Sheppo DWARN(DBG_ALL_LDCS, 60311991Sheppo "i_ldc_mem_acquire_release: invalid memory handle\n"); 60321991Sheppo return (EINVAL); 60331991Sheppo } 60341991Sheppo mhdl = (ldc_mhdl_t *)mhandle; 60351991Sheppo 60361991Sheppo mutex_enter(&mhdl->lock); 60371991Sheppo 60381991Sheppo if (mhdl->status != LDC_MAPPED || mhdl->ldcp == NULL) { 60391991Sheppo DWARN(DBG_ALL_LDCS, 60401991Sheppo "i_ldc_mem_acquire_release: not mapped memory\n"); 60411991Sheppo mutex_exit(&mhdl->lock); 60421991Sheppo return (EINVAL); 60431991Sheppo } 60441991Sheppo 60452531Snarayan /* do nothing for direct map */ 60462531Snarayan if (mhdl->mtype == LDC_DIRECT_MAP) { 60472531Snarayan mutex_exit(&mhdl->lock); 60482531Snarayan return (0); 60492531Snarayan } 60502531Snarayan 60512531Snarayan /* do nothing if COPY_IN+MEM_W and COPY_OUT+MEM_R */ 60522531Snarayan if ((direction == LDC_COPY_IN && (mhdl->perm & LDC_MEM_R) == 0) || 60532531Snarayan (direction == LDC_COPY_OUT && (mhdl->perm & LDC_MEM_W) == 0)) { 60542531Snarayan mutex_exit(&mhdl->lock); 60552531Snarayan return (0); 60562531Snarayan } 60572531Snarayan 60581991Sheppo if (offset >= mhdl->memseg->size || 60591991Sheppo (offset + size) > mhdl->memseg->size) { 60601991Sheppo DWARN(DBG_ALL_LDCS, 60611991Sheppo "i_ldc_mem_acquire_release: memory out of range\n"); 60621991Sheppo mutex_exit(&mhdl->lock); 60631991Sheppo return (EINVAL); 60641991Sheppo } 60651991Sheppo 60661991Sheppo /* get the channel handle and memory segment */ 60671991Sheppo ldcp = mhdl->ldcp; 60681991Sheppo memseg = mhdl->memseg; 60691991Sheppo 60701991Sheppo if (mhdl->mtype == LDC_SHADOW_MAP) { 60711991Sheppo 60721991Sheppo local_vaddr = memseg->vaddr + offset; 60731991Sheppo copy_size = size; 60741991Sheppo 60751991Sheppo /* copy to/from remote from/to local memory */ 60761991Sheppo err = ldc_mem_copy((ldc_handle_t)ldcp, local_vaddr, offset, 60771991Sheppo ©_size, memseg->cookies, memseg->ncookies, 60781991Sheppo direction); 60791991Sheppo if (err || copy_size != size) { 60803010Slm66018 DWARN(ldcp->id, 60811991Sheppo "i_ldc_mem_acquire_release: copy failed\n"); 60821991Sheppo mutex_exit(&mhdl->lock); 60831991Sheppo return (err); 60841991Sheppo } 60851991Sheppo } 60861991Sheppo 60871991Sheppo mutex_exit(&mhdl->lock); 60881991Sheppo 60891991Sheppo return (0); 60901991Sheppo } 60911991Sheppo 60921991Sheppo /* 60931991Sheppo * Ensure that the contents in the remote memory seg are consistent 60941991Sheppo * with the contents if of local segment 60951991Sheppo */ 60961991Sheppo int 60971991Sheppo ldc_mem_acquire(ldc_mem_handle_t mhandle, uint64_t offset, uint64_t size) 60981991Sheppo { 60991991Sheppo return (i_ldc_mem_acquire_release(mhandle, LDC_COPY_IN, offset, size)); 61001991Sheppo } 61011991Sheppo 61021991Sheppo 61031991Sheppo /* 61041991Sheppo * Ensure that the contents in the local memory seg are consistent 61051991Sheppo * with the contents if of remote segment 61061991Sheppo */ 61071991Sheppo int 61081991Sheppo ldc_mem_release(ldc_mem_handle_t mhandle, uint64_t offset, uint64_t size) 61091991Sheppo { 61101991Sheppo return (i_ldc_mem_acquire_release(mhandle, LDC_COPY_OUT, offset, size)); 61111991Sheppo } 61121991Sheppo 61131991Sheppo /* 61141991Sheppo * Allocate a descriptor ring. The size of each each descriptor 61151991Sheppo * must be 8-byte aligned and the entire ring should be a multiple 61161991Sheppo * of MMU_PAGESIZE. 61171991Sheppo */ 61181991Sheppo int 61191991Sheppo ldc_mem_dring_create(uint32_t len, uint32_t dsize, ldc_dring_handle_t *dhandle) 61201991Sheppo { 61211991Sheppo ldc_dring_t *dringp; 61221991Sheppo size_t size = (dsize * len); 61231991Sheppo 61241991Sheppo D1(DBG_ALL_LDCS, "ldc_mem_dring_create: len=0x%x, size=0x%x\n", 61251991Sheppo len, dsize); 61261991Sheppo 61271991Sheppo if (dhandle == NULL) { 61281991Sheppo DWARN(DBG_ALL_LDCS, "ldc_mem_dring_create: invalid dhandle\n"); 61291991Sheppo return (EINVAL); 61301991Sheppo } 61311991Sheppo 61321991Sheppo if (len == 0) { 61331991Sheppo DWARN(DBG_ALL_LDCS, "ldc_mem_dring_create: invalid length\n"); 61341991Sheppo return (EINVAL); 61351991Sheppo } 61361991Sheppo 61371991Sheppo /* descriptor size should be 8-byte aligned */ 61381991Sheppo if (dsize == 0 || (dsize & 0x7)) { 61391991Sheppo DWARN(DBG_ALL_LDCS, "ldc_mem_dring_create: invalid size\n"); 61401991Sheppo return (EINVAL); 61411991Sheppo } 61421991Sheppo 61431991Sheppo *dhandle = 0; 61441991Sheppo 61451991Sheppo /* Allocate a desc ring structure */ 61461991Sheppo dringp = kmem_zalloc(sizeof (ldc_dring_t), KM_SLEEP); 61471991Sheppo 61481991Sheppo /* Initialize dring */ 61491991Sheppo dringp->length = len; 61501991Sheppo dringp->dsize = dsize; 61511991Sheppo 61521991Sheppo /* round off to multiple of pagesize */ 61531991Sheppo dringp->size = (size & MMU_PAGEMASK); 61541991Sheppo if (size & MMU_PAGEOFFSET) 61551991Sheppo dringp->size += MMU_PAGESIZE; 61561991Sheppo 61571991Sheppo dringp->status = LDC_UNBOUND; 61581991Sheppo 61591991Sheppo /* allocate descriptor ring memory */ 61602793Slm66018 dringp->base = kmem_zalloc(dringp->size, KM_SLEEP); 61611991Sheppo 61621991Sheppo /* initialize the desc ring lock */ 61631991Sheppo mutex_init(&dringp->lock, NULL, MUTEX_DRIVER, NULL); 61641991Sheppo 61651991Sheppo /* Add descriptor ring to the head of global list */ 61661991Sheppo mutex_enter(&ldcssp->lock); 61671991Sheppo dringp->next = ldcssp->dring_list; 61681991Sheppo ldcssp->dring_list = dringp; 61691991Sheppo mutex_exit(&ldcssp->lock); 61701991Sheppo 61711991Sheppo *dhandle = (ldc_dring_handle_t)dringp; 61721991Sheppo 61731991Sheppo D1(DBG_ALL_LDCS, "ldc_mem_dring_create: dring allocated\n"); 61741991Sheppo 61751991Sheppo return (0); 61761991Sheppo } 61771991Sheppo 61781991Sheppo 61791991Sheppo /* 61801991Sheppo * Destroy a descriptor ring. 61811991Sheppo */ 61821991Sheppo int 61831991Sheppo ldc_mem_dring_destroy(ldc_dring_handle_t dhandle) 61841991Sheppo { 61851991Sheppo ldc_dring_t *dringp; 61861991Sheppo ldc_dring_t *tmp_dringp; 61871991Sheppo 61881991Sheppo D1(DBG_ALL_LDCS, "ldc_mem_dring_destroy: entered\n"); 61891991Sheppo 61901991Sheppo if (dhandle == NULL) { 61911991Sheppo DWARN(DBG_ALL_LDCS, 61921991Sheppo "ldc_mem_dring_destroy: invalid desc ring handle\n"); 61931991Sheppo return (EINVAL); 61941991Sheppo } 61951991Sheppo dringp = (ldc_dring_t *)dhandle; 61961991Sheppo 61971991Sheppo if (dringp->status == LDC_BOUND) { 61981991Sheppo DWARN(DBG_ALL_LDCS, 61991991Sheppo "ldc_mem_dring_destroy: desc ring is bound\n"); 62001991Sheppo return (EACCES); 62011991Sheppo } 62021991Sheppo 62031991Sheppo mutex_enter(&dringp->lock); 62041991Sheppo mutex_enter(&ldcssp->lock); 62051991Sheppo 62061991Sheppo /* remove from linked list - if not bound */ 62071991Sheppo tmp_dringp = ldcssp->dring_list; 62081991Sheppo if (tmp_dringp == dringp) { 62091991Sheppo ldcssp->dring_list = dringp->next; 62101991Sheppo dringp->next = NULL; 62111991Sheppo 62121991Sheppo } else { 62131991Sheppo while (tmp_dringp != NULL) { 62141991Sheppo if (tmp_dringp->next == dringp) { 62151991Sheppo tmp_dringp->next = dringp->next; 62161991Sheppo dringp->next = NULL; 62171991Sheppo break; 62181991Sheppo } 62191991Sheppo tmp_dringp = tmp_dringp->next; 62201991Sheppo } 62211991Sheppo if (tmp_dringp == NULL) { 62221991Sheppo DWARN(DBG_ALL_LDCS, 62231991Sheppo "ldc_mem_dring_destroy: invalid descriptor\n"); 62241991Sheppo mutex_exit(&ldcssp->lock); 62251991Sheppo mutex_exit(&dringp->lock); 62261991Sheppo return (EINVAL); 62271991Sheppo } 62281991Sheppo } 62291991Sheppo 62301991Sheppo mutex_exit(&ldcssp->lock); 62311991Sheppo 62321991Sheppo /* free the descriptor ring */ 62332793Slm66018 kmem_free(dringp->base, dringp->size); 62341991Sheppo 62351991Sheppo mutex_exit(&dringp->lock); 62361991Sheppo 62371991Sheppo /* destroy dring lock */ 62381991Sheppo mutex_destroy(&dringp->lock); 62391991Sheppo 62401991Sheppo /* free desc ring object */ 62411991Sheppo kmem_free(dringp, sizeof (ldc_dring_t)); 62421991Sheppo 62431991Sheppo return (0); 62441991Sheppo } 62451991Sheppo 62461991Sheppo /* 62471991Sheppo * Bind a previously allocated dring to a channel. The channel should 62481991Sheppo * be OPEN in order to bind the ring to the channel. Returns back a 62491991Sheppo * descriptor ring cookie. The descriptor ring is exported for remote 62501991Sheppo * access by the client at the other end of the channel. An entry for 62511991Sheppo * dring pages is stored in map table (via call to ldc_mem_bind_handle). 62521991Sheppo */ 62531991Sheppo int 62541991Sheppo ldc_mem_dring_bind(ldc_handle_t handle, ldc_dring_handle_t dhandle, 62551991Sheppo uint8_t mtype, uint8_t perm, ldc_mem_cookie_t *cookie, uint32_t *ccount) 62561991Sheppo { 62571991Sheppo int err; 62581991Sheppo ldc_chan_t *ldcp; 62591991Sheppo ldc_dring_t *dringp; 62601991Sheppo ldc_mem_handle_t mhandle; 62611991Sheppo 62621991Sheppo /* check to see if channel is initalized */ 62631991Sheppo if (handle == NULL) { 62641991Sheppo DWARN(DBG_ALL_LDCS, 62651991Sheppo "ldc_mem_dring_bind: invalid channel handle\n"); 62661991Sheppo return (EINVAL); 62671991Sheppo } 62681991Sheppo ldcp = (ldc_chan_t *)handle; 62691991Sheppo 62701991Sheppo if (dhandle == NULL) { 62711991Sheppo DWARN(DBG_ALL_LDCS, 62721991Sheppo "ldc_mem_dring_bind: invalid desc ring handle\n"); 62731991Sheppo return (EINVAL); 62741991Sheppo } 62751991Sheppo dringp = (ldc_dring_t *)dhandle; 62761991Sheppo 62771991Sheppo if (cookie == NULL) { 62781991Sheppo DWARN(ldcp->id, 62791991Sheppo "ldc_mem_dring_bind: invalid cookie arg\n"); 62801991Sheppo return (EINVAL); 62811991Sheppo } 62821991Sheppo 62831991Sheppo mutex_enter(&dringp->lock); 62841991Sheppo 62851991Sheppo if (dringp->status == LDC_BOUND) { 62861991Sheppo DWARN(DBG_ALL_LDCS, 62871991Sheppo "ldc_mem_dring_bind: (0x%llx) descriptor ring is bound\n", 62881991Sheppo ldcp->id); 62891991Sheppo mutex_exit(&dringp->lock); 62901991Sheppo return (EINVAL); 62911991Sheppo } 62921991Sheppo 62931991Sheppo if ((perm & LDC_MEM_RW) == 0) { 62941991Sheppo DWARN(DBG_ALL_LDCS, 62951991Sheppo "ldc_mem_dring_bind: invalid permissions\n"); 62961991Sheppo mutex_exit(&dringp->lock); 62971991Sheppo return (EINVAL); 62981991Sheppo } 62991991Sheppo 63001991Sheppo if ((mtype & (LDC_SHADOW_MAP|LDC_DIRECT_MAP|LDC_IO_MAP)) == 0) { 63011991Sheppo DWARN(DBG_ALL_LDCS, "ldc_mem_dring_bind: invalid type\n"); 63021991Sheppo mutex_exit(&dringp->lock); 63031991Sheppo return (EINVAL); 63041991Sheppo } 63051991Sheppo 63061991Sheppo dringp->ldcp = ldcp; 63071991Sheppo 63081991Sheppo /* create an memory handle */ 63091991Sheppo err = ldc_mem_alloc_handle(handle, &mhandle); 63101991Sheppo if (err || mhandle == NULL) { 63111991Sheppo DWARN(DBG_ALL_LDCS, 63121991Sheppo "ldc_mem_dring_bind: (0x%llx) error allocating mhandle\n", 63131991Sheppo ldcp->id); 63141991Sheppo mutex_exit(&dringp->lock); 63151991Sheppo return (err); 63161991Sheppo } 63171991Sheppo dringp->mhdl = mhandle; 63181991Sheppo 63191991Sheppo /* bind the descriptor ring to channel */ 63201991Sheppo err = ldc_mem_bind_handle(mhandle, dringp->base, dringp->size, 63211991Sheppo mtype, perm, cookie, ccount); 63221991Sheppo if (err) { 63231991Sheppo DWARN(ldcp->id, 63241991Sheppo "ldc_mem_dring_bind: (0x%llx) error binding mhandle\n", 63251991Sheppo ldcp->id); 63261991Sheppo mutex_exit(&dringp->lock); 63271991Sheppo return (err); 63281991Sheppo } 63291991Sheppo 63301991Sheppo /* 63311991Sheppo * For now return error if we get more than one cookie 63321991Sheppo * FUTURE: Return multiple cookies .. 63331991Sheppo */ 63341991Sheppo if (*ccount > 1) { 63351991Sheppo (void) ldc_mem_unbind_handle(mhandle); 63361991Sheppo (void) ldc_mem_free_handle(mhandle); 63371991Sheppo 63381991Sheppo dringp->ldcp = NULL; 63391991Sheppo dringp->mhdl = NULL; 63401991Sheppo *ccount = 0; 63411991Sheppo 63421991Sheppo mutex_exit(&dringp->lock); 63431991Sheppo return (EAGAIN); 63441991Sheppo } 63451991Sheppo 63461991Sheppo /* Add descriptor ring to channel's exported dring list */ 63471991Sheppo mutex_enter(&ldcp->exp_dlist_lock); 63481991Sheppo dringp->ch_next = ldcp->exp_dring_list; 63491991Sheppo ldcp->exp_dring_list = dringp; 63501991Sheppo mutex_exit(&ldcp->exp_dlist_lock); 63511991Sheppo 63521991Sheppo dringp->status = LDC_BOUND; 63531991Sheppo 63541991Sheppo mutex_exit(&dringp->lock); 63551991Sheppo 63561991Sheppo return (0); 63571991Sheppo } 63581991Sheppo 63591991Sheppo /* 63601991Sheppo * Return the next cookie associated with the specified dring handle 63611991Sheppo */ 63621991Sheppo int 63631991Sheppo ldc_mem_dring_nextcookie(ldc_dring_handle_t dhandle, ldc_mem_cookie_t *cookie) 63641991Sheppo { 63651991Sheppo int rv = 0; 63661991Sheppo ldc_dring_t *dringp; 63671991Sheppo ldc_chan_t *ldcp; 63681991Sheppo 63691991Sheppo if (dhandle == NULL) { 63701991Sheppo DWARN(DBG_ALL_LDCS, 63711991Sheppo "ldc_mem_dring_nextcookie: invalid desc ring handle\n"); 63721991Sheppo return (EINVAL); 63731991Sheppo } 63741991Sheppo dringp = (ldc_dring_t *)dhandle; 63751991Sheppo mutex_enter(&dringp->lock); 63761991Sheppo 63771991Sheppo if (dringp->status != LDC_BOUND) { 63781991Sheppo DWARN(DBG_ALL_LDCS, 63791991Sheppo "ldc_mem_dring_nextcookie: descriptor ring 0x%llx " 63801991Sheppo "is not bound\n", dringp); 63811991Sheppo mutex_exit(&dringp->lock); 63821991Sheppo return (EINVAL); 63831991Sheppo } 63841991Sheppo 63851991Sheppo ldcp = dringp->ldcp; 63861991Sheppo 63871991Sheppo if (cookie == NULL) { 63881991Sheppo DWARN(ldcp->id, 63891991Sheppo "ldc_mem_dring_nextcookie:(0x%llx) invalid cookie arg\n", 63901991Sheppo ldcp->id); 63911991Sheppo mutex_exit(&dringp->lock); 63921991Sheppo return (EINVAL); 63931991Sheppo } 63941991Sheppo 63951991Sheppo rv = ldc_mem_nextcookie((ldc_mem_handle_t)dringp->mhdl, cookie); 63961991Sheppo mutex_exit(&dringp->lock); 63971991Sheppo 63981991Sheppo return (rv); 63991991Sheppo } 64001991Sheppo /* 64011991Sheppo * Unbind a previously bound dring from a channel. 64021991Sheppo */ 64031991Sheppo int 64041991Sheppo ldc_mem_dring_unbind(ldc_dring_handle_t dhandle) 64051991Sheppo { 64061991Sheppo ldc_dring_t *dringp; 64071991Sheppo ldc_dring_t *tmp_dringp; 64081991Sheppo ldc_chan_t *ldcp; 64091991Sheppo 64101991Sheppo if (dhandle == NULL) { 64111991Sheppo DWARN(DBG_ALL_LDCS, 64121991Sheppo "ldc_mem_dring_unbind: invalid desc ring handle\n"); 64131991Sheppo return (EINVAL); 64141991Sheppo } 64151991Sheppo dringp = (ldc_dring_t *)dhandle; 64161991Sheppo 64171991Sheppo mutex_enter(&dringp->lock); 64181991Sheppo 64191991Sheppo if (dringp->status == LDC_UNBOUND) { 64201991Sheppo DWARN(DBG_ALL_LDCS, 64211991Sheppo "ldc_mem_dring_bind: descriptor ring 0x%llx is unbound\n", 64221991Sheppo dringp); 64231991Sheppo mutex_exit(&dringp->lock); 64241991Sheppo return (EINVAL); 64251991Sheppo } 64261991Sheppo ldcp = dringp->ldcp; 64271991Sheppo 64281991Sheppo mutex_enter(&ldcp->exp_dlist_lock); 64291991Sheppo 64301991Sheppo tmp_dringp = ldcp->exp_dring_list; 64311991Sheppo if (tmp_dringp == dringp) { 64321991Sheppo ldcp->exp_dring_list = dringp->ch_next; 64331991Sheppo dringp->ch_next = NULL; 64341991Sheppo 64351991Sheppo } else { 64361991Sheppo while (tmp_dringp != NULL) { 64371991Sheppo if (tmp_dringp->ch_next == dringp) { 64381991Sheppo tmp_dringp->ch_next = dringp->ch_next; 64391991Sheppo dringp->ch_next = NULL; 64401991Sheppo break; 64411991Sheppo } 64421991Sheppo tmp_dringp = tmp_dringp->ch_next; 64431991Sheppo } 64441991Sheppo if (tmp_dringp == NULL) { 64451991Sheppo DWARN(DBG_ALL_LDCS, 64461991Sheppo "ldc_mem_dring_unbind: invalid descriptor\n"); 64471991Sheppo mutex_exit(&ldcp->exp_dlist_lock); 64481991Sheppo mutex_exit(&dringp->lock); 64491991Sheppo return (EINVAL); 64501991Sheppo } 64511991Sheppo } 64521991Sheppo 64531991Sheppo mutex_exit(&ldcp->exp_dlist_lock); 64541991Sheppo 64551991Sheppo (void) ldc_mem_unbind_handle((ldc_mem_handle_t)dringp->mhdl); 64561991Sheppo (void) ldc_mem_free_handle((ldc_mem_handle_t)dringp->mhdl); 64571991Sheppo 64581991Sheppo dringp->ldcp = NULL; 64591991Sheppo dringp->mhdl = NULL; 64601991Sheppo dringp->status = LDC_UNBOUND; 64611991Sheppo 64621991Sheppo mutex_exit(&dringp->lock); 64631991Sheppo 64641991Sheppo return (0); 64651991Sheppo } 64661991Sheppo 64671991Sheppo /* 64681991Sheppo * Get information about the dring. The base address of the descriptor 64691991Sheppo * ring along with the type and permission are returned back. 64701991Sheppo */ 64711991Sheppo int 64721991Sheppo ldc_mem_dring_info(ldc_dring_handle_t dhandle, ldc_mem_info_t *minfo) 64731991Sheppo { 64741991Sheppo ldc_dring_t *dringp; 64751991Sheppo int rv; 64761991Sheppo 64771991Sheppo if (dhandle == NULL) { 64781991Sheppo DWARN(DBG_ALL_LDCS, 64791991Sheppo "ldc_mem_dring_info: invalid desc ring handle\n"); 64801991Sheppo return (EINVAL); 64811991Sheppo } 64821991Sheppo dringp = (ldc_dring_t *)dhandle; 64831991Sheppo 64841991Sheppo mutex_enter(&dringp->lock); 64851991Sheppo 64861991Sheppo if (dringp->mhdl) { 64871991Sheppo rv = ldc_mem_info(dringp->mhdl, minfo); 64881991Sheppo if (rv) { 64891991Sheppo DWARN(DBG_ALL_LDCS, 64901991Sheppo "ldc_mem_dring_info: error reading mem info\n"); 64911991Sheppo mutex_exit(&dringp->lock); 64921991Sheppo return (rv); 64931991Sheppo } 64941991Sheppo } else { 64951991Sheppo minfo->vaddr = dringp->base; 64961991Sheppo minfo->raddr = NULL; 64971991Sheppo minfo->status = dringp->status; 64981991Sheppo } 64991991Sheppo 65001991Sheppo mutex_exit(&dringp->lock); 65011991Sheppo 65021991Sheppo return (0); 65031991Sheppo } 65041991Sheppo 65051991Sheppo /* 65061991Sheppo * Map an exported descriptor ring into the local address space. If the 65071991Sheppo * descriptor ring was exported for direct map access, a HV call is made 65081991Sheppo * to allocate a RA range. If the map is done via a shadow copy, local 65091991Sheppo * shadow memory is allocated. 65101991Sheppo */ 65111991Sheppo int 65121991Sheppo ldc_mem_dring_map(ldc_handle_t handle, ldc_mem_cookie_t *cookie, 65131991Sheppo uint32_t ccount, uint32_t len, uint32_t dsize, uint8_t mtype, 65141991Sheppo ldc_dring_handle_t *dhandle) 65151991Sheppo { 65161991Sheppo int err; 65171991Sheppo ldc_chan_t *ldcp = (ldc_chan_t *)handle; 65181991Sheppo ldc_mem_handle_t mhandle; 65191991Sheppo ldc_dring_t *dringp; 65201991Sheppo size_t dring_size; 65211991Sheppo 65221991Sheppo if (dhandle == NULL) { 65231991Sheppo DWARN(DBG_ALL_LDCS, 65241991Sheppo "ldc_mem_dring_map: invalid dhandle\n"); 65251991Sheppo return (EINVAL); 65261991Sheppo } 65271991Sheppo 65281991Sheppo /* check to see if channel is initalized */ 65291991Sheppo if (handle == NULL) { 65301991Sheppo DWARN(DBG_ALL_LDCS, 65311991Sheppo "ldc_mem_dring_map: invalid channel handle\n"); 65321991Sheppo return (EINVAL); 65331991Sheppo } 65341991Sheppo ldcp = (ldc_chan_t *)handle; 65351991Sheppo 65361991Sheppo if (cookie == NULL) { 65371991Sheppo DWARN(ldcp->id, 65381991Sheppo "ldc_mem_dring_map: (0x%llx) invalid cookie\n", 65391991Sheppo ldcp->id); 65401991Sheppo return (EINVAL); 65411991Sheppo } 65421991Sheppo 65431991Sheppo /* FUTURE: For now we support only one cookie per dring */ 65441991Sheppo ASSERT(ccount == 1); 65451991Sheppo 65461991Sheppo if (cookie->size < (dsize * len)) { 65471991Sheppo DWARN(ldcp->id, 65481991Sheppo "ldc_mem_dring_map: (0x%llx) invalid dsize/len\n", 65491991Sheppo ldcp->id); 65501991Sheppo return (EINVAL); 65511991Sheppo } 65521991Sheppo 65531991Sheppo *dhandle = 0; 65541991Sheppo 65551991Sheppo /* Allocate an dring structure */ 65561991Sheppo dringp = kmem_zalloc(sizeof (ldc_dring_t), KM_SLEEP); 65571991Sheppo 65581991Sheppo D1(ldcp->id, 65591991Sheppo "ldc_mem_dring_map: 0x%x,0x%x,0x%x,0x%llx,0x%llx\n", 65601991Sheppo mtype, len, dsize, cookie->addr, cookie->size); 65611991Sheppo 65621991Sheppo /* Initialize dring */ 65631991Sheppo dringp->length = len; 65641991Sheppo dringp->dsize = dsize; 65651991Sheppo 65661991Sheppo /* round of to multiple of page size */ 65671991Sheppo dring_size = len * dsize; 65681991Sheppo dringp->size = (dring_size & MMU_PAGEMASK); 65691991Sheppo if (dring_size & MMU_PAGEOFFSET) 65701991Sheppo dringp->size += MMU_PAGESIZE; 65711991Sheppo 65721991Sheppo dringp->ldcp = ldcp; 65731991Sheppo 65741991Sheppo /* create an memory handle */ 65751991Sheppo err = ldc_mem_alloc_handle(handle, &mhandle); 65761991Sheppo if (err || mhandle == NULL) { 65771991Sheppo DWARN(DBG_ALL_LDCS, 65781991Sheppo "ldc_mem_dring_map: cannot alloc hdl err=%d\n", 65791991Sheppo err); 65801991Sheppo kmem_free(dringp, sizeof (ldc_dring_t)); 65811991Sheppo return (ENOMEM); 65821991Sheppo } 65831991Sheppo 65841991Sheppo dringp->mhdl = mhandle; 65851991Sheppo dringp->base = NULL; 65861991Sheppo 65871991Sheppo /* map the dring into local memory */ 65882531Snarayan err = ldc_mem_map(mhandle, cookie, ccount, mtype, LDC_MEM_RW, 65891991Sheppo &(dringp->base), NULL); 65901991Sheppo if (err || dringp->base == NULL) { 65911991Sheppo cmn_err(CE_WARN, 65921991Sheppo "ldc_mem_dring_map: cannot map desc ring err=%d\n", err); 65931991Sheppo (void) ldc_mem_free_handle(mhandle); 65941991Sheppo kmem_free(dringp, sizeof (ldc_dring_t)); 65951991Sheppo return (ENOMEM); 65961991Sheppo } 65971991Sheppo 65981991Sheppo /* initialize the desc ring lock */ 65991991Sheppo mutex_init(&dringp->lock, NULL, MUTEX_DRIVER, NULL); 66001991Sheppo 66011991Sheppo /* Add descriptor ring to channel's imported dring list */ 66021991Sheppo mutex_enter(&ldcp->imp_dlist_lock); 66031991Sheppo dringp->ch_next = ldcp->imp_dring_list; 66041991Sheppo ldcp->imp_dring_list = dringp; 66051991Sheppo mutex_exit(&ldcp->imp_dlist_lock); 66061991Sheppo 66071991Sheppo dringp->status = LDC_MAPPED; 66081991Sheppo 66091991Sheppo *dhandle = (ldc_dring_handle_t)dringp; 66101991Sheppo 66111991Sheppo return (0); 66121991Sheppo } 66131991Sheppo 66141991Sheppo /* 66151991Sheppo * Unmap a descriptor ring. Free shadow memory (if any). 66161991Sheppo */ 66171991Sheppo int 66181991Sheppo ldc_mem_dring_unmap(ldc_dring_handle_t dhandle) 66191991Sheppo { 66201991Sheppo ldc_dring_t *dringp; 66211991Sheppo ldc_dring_t *tmp_dringp; 66221991Sheppo ldc_chan_t *ldcp; 66231991Sheppo 66241991Sheppo if (dhandle == NULL) { 66251991Sheppo DWARN(DBG_ALL_LDCS, 66261991Sheppo "ldc_mem_dring_unmap: invalid desc ring handle\n"); 66271991Sheppo return (EINVAL); 66281991Sheppo } 66291991Sheppo dringp = (ldc_dring_t *)dhandle; 66301991Sheppo 66311991Sheppo if (dringp->status != LDC_MAPPED) { 66321991Sheppo DWARN(DBG_ALL_LDCS, 66331991Sheppo "ldc_mem_dring_unmap: not a mapped desc ring\n"); 66341991Sheppo return (EINVAL); 66351991Sheppo } 66361991Sheppo 66371991Sheppo mutex_enter(&dringp->lock); 66381991Sheppo 66391991Sheppo ldcp = dringp->ldcp; 66401991Sheppo 66411991Sheppo mutex_enter(&ldcp->imp_dlist_lock); 66421991Sheppo 66431991Sheppo /* find and unlink the desc ring from channel import list */ 66441991Sheppo tmp_dringp = ldcp->imp_dring_list; 66451991Sheppo if (tmp_dringp == dringp) { 66461991Sheppo ldcp->imp_dring_list = dringp->ch_next; 66471991Sheppo dringp->ch_next = NULL; 66481991Sheppo 66491991Sheppo } else { 66501991Sheppo while (tmp_dringp != NULL) { 66511991Sheppo if (tmp_dringp->ch_next == dringp) { 66521991Sheppo tmp_dringp->ch_next = dringp->ch_next; 66531991Sheppo dringp->ch_next = NULL; 66541991Sheppo break; 66551991Sheppo } 66561991Sheppo tmp_dringp = tmp_dringp->ch_next; 66571991Sheppo } 66581991Sheppo if (tmp_dringp == NULL) { 66591991Sheppo DWARN(DBG_ALL_LDCS, 66601991Sheppo "ldc_mem_dring_unmap: invalid descriptor\n"); 66611991Sheppo mutex_exit(&ldcp->imp_dlist_lock); 66621991Sheppo mutex_exit(&dringp->lock); 66631991Sheppo return (EINVAL); 66641991Sheppo } 66651991Sheppo } 66661991Sheppo 66671991Sheppo mutex_exit(&ldcp->imp_dlist_lock); 66681991Sheppo 66691991Sheppo /* do a LDC memory handle unmap and free */ 66701991Sheppo (void) ldc_mem_unmap(dringp->mhdl); 66711991Sheppo (void) ldc_mem_free_handle((ldc_mem_handle_t)dringp->mhdl); 66721991Sheppo 66731991Sheppo dringp->status = 0; 66741991Sheppo dringp->ldcp = NULL; 66751991Sheppo 66761991Sheppo mutex_exit(&dringp->lock); 66771991Sheppo 66781991Sheppo /* destroy dring lock */ 66791991Sheppo mutex_destroy(&dringp->lock); 66801991Sheppo 66811991Sheppo /* free desc ring object */ 66821991Sheppo kmem_free(dringp, sizeof (ldc_dring_t)); 66831991Sheppo 66841991Sheppo return (0); 66851991Sheppo } 66861991Sheppo 66871991Sheppo /* 66881991Sheppo * Internal entry point for descriptor ring access entry consistency 66891991Sheppo * semantics. Acquire copies the contents of the remote descriptor ring 66901991Sheppo * into the local shadow copy. The release operation copies the local 66911991Sheppo * contents into the remote dring. The start and end locations specify 66921991Sheppo * bounds for the entries being synchronized. 66931991Sheppo */ 66941991Sheppo static int 66951991Sheppo i_ldc_dring_acquire_release(ldc_dring_handle_t dhandle, 66961991Sheppo uint8_t direction, uint64_t start, uint64_t end) 66971991Sheppo { 66981991Sheppo int err; 66991991Sheppo ldc_dring_t *dringp; 67001991Sheppo ldc_chan_t *ldcp; 67011991Sheppo uint64_t soff; 67021991Sheppo size_t copy_size; 67031991Sheppo 67041991Sheppo if (dhandle == NULL) { 67051991Sheppo DWARN(DBG_ALL_LDCS, 67061991Sheppo "i_ldc_dring_acquire_release: invalid desc ring handle\n"); 67071991Sheppo return (EINVAL); 67081991Sheppo } 67091991Sheppo dringp = (ldc_dring_t *)dhandle; 67101991Sheppo mutex_enter(&dringp->lock); 67111991Sheppo 67121991Sheppo if (dringp->status != LDC_MAPPED || dringp->ldcp == NULL) { 67131991Sheppo DWARN(DBG_ALL_LDCS, 67141991Sheppo "i_ldc_dring_acquire_release: not a mapped desc ring\n"); 67151991Sheppo mutex_exit(&dringp->lock); 67161991Sheppo return (EINVAL); 67171991Sheppo } 67181991Sheppo 67191991Sheppo if (start >= dringp->length || end >= dringp->length) { 67201991Sheppo DWARN(DBG_ALL_LDCS, 67211991Sheppo "i_ldc_dring_acquire_release: index out of range\n"); 67221991Sheppo mutex_exit(&dringp->lock); 67231991Sheppo return (EINVAL); 67241991Sheppo } 67251991Sheppo 67261991Sheppo /* get the channel handle */ 67271991Sheppo ldcp = dringp->ldcp; 67281991Sheppo 67291991Sheppo copy_size = (start <= end) ? (((end - start) + 1) * dringp->dsize) : 67304690Snarayan ((dringp->length - start) * dringp->dsize); 67311991Sheppo 67321991Sheppo /* Calculate the relative offset for the first desc */ 67331991Sheppo soff = (start * dringp->dsize); 67341991Sheppo 67351991Sheppo /* copy to/from remote from/to local memory */ 67361991Sheppo D1(ldcp->id, "i_ldc_dring_acquire_release: c1 off=0x%llx sz=0x%llx\n", 67371991Sheppo soff, copy_size); 67381991Sheppo err = i_ldc_mem_acquire_release((ldc_mem_handle_t)dringp->mhdl, 67391991Sheppo direction, soff, copy_size); 67401991Sheppo if (err) { 67411991Sheppo DWARN(ldcp->id, 67421991Sheppo "i_ldc_dring_acquire_release: copy failed\n"); 67431991Sheppo mutex_exit(&dringp->lock); 67441991Sheppo return (err); 67451991Sheppo } 67461991Sheppo 67471991Sheppo /* do the balance */ 67481991Sheppo if (start > end) { 67491991Sheppo copy_size = ((end + 1) * dringp->dsize); 67501991Sheppo soff = 0; 67511991Sheppo 67521991Sheppo /* copy to/from remote from/to local memory */ 67531991Sheppo D1(ldcp->id, "i_ldc_dring_acquire_release: c2 " 67541991Sheppo "off=0x%llx sz=0x%llx\n", soff, copy_size); 67551991Sheppo err = i_ldc_mem_acquire_release((ldc_mem_handle_t)dringp->mhdl, 67561991Sheppo direction, soff, copy_size); 67571991Sheppo if (err) { 67581991Sheppo DWARN(ldcp->id, 67591991Sheppo "i_ldc_dring_acquire_release: copy failed\n"); 67601991Sheppo mutex_exit(&dringp->lock); 67611991Sheppo return (err); 67621991Sheppo } 67631991Sheppo } 67641991Sheppo 67651991Sheppo mutex_exit(&dringp->lock); 67661991Sheppo 67671991Sheppo return (0); 67681991Sheppo } 67691991Sheppo 67701991Sheppo /* 67711991Sheppo * Ensure that the contents in the local dring are consistent 67721991Sheppo * with the contents if of remote dring 67731991Sheppo */ 67741991Sheppo int 67751991Sheppo ldc_mem_dring_acquire(ldc_dring_handle_t dhandle, uint64_t start, uint64_t end) 67761991Sheppo { 67771991Sheppo return (i_ldc_dring_acquire_release(dhandle, LDC_COPY_IN, start, end)); 67781991Sheppo } 67791991Sheppo 67801991Sheppo /* 67811991Sheppo * Ensure that the contents in the remote dring are consistent 67821991Sheppo * with the contents if of local dring 67831991Sheppo */ 67841991Sheppo int 67851991Sheppo ldc_mem_dring_release(ldc_dring_handle_t dhandle, uint64_t start, uint64_t end) 67861991Sheppo { 67871991Sheppo return (i_ldc_dring_acquire_release(dhandle, LDC_COPY_OUT, start, end)); 67881991Sheppo } 67891991Sheppo 67901991Sheppo 67911991Sheppo /* ------------------------------------------------------------------------- */ 6792