17bd3a2e2SSriharsha Basavapatna /* 27bd3a2e2SSriharsha Basavapatna * CDDL HEADER START 37bd3a2e2SSriharsha Basavapatna * 47bd3a2e2SSriharsha Basavapatna * The contents of this file are subject to the terms of the 57bd3a2e2SSriharsha Basavapatna * Common Development and Distribution License (the "License"). 67bd3a2e2SSriharsha Basavapatna * You may not use this file except in compliance with the License. 77bd3a2e2SSriharsha Basavapatna * 87bd3a2e2SSriharsha Basavapatna * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97bd3a2e2SSriharsha Basavapatna * or http://www.opensolaris.org/os/licensing. 107bd3a2e2SSriharsha Basavapatna * See the License for the specific language governing permissions 117bd3a2e2SSriharsha Basavapatna * and limitations under the License. 127bd3a2e2SSriharsha Basavapatna * 137bd3a2e2SSriharsha Basavapatna * When distributing Covered Code, include this CDDL HEADER in each 147bd3a2e2SSriharsha Basavapatna * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157bd3a2e2SSriharsha Basavapatna * If applicable, add the following below this CDDL HEADER, with the 167bd3a2e2SSriharsha Basavapatna * fields enclosed by brackets "[]" replaced with your own identifying 177bd3a2e2SSriharsha Basavapatna * information: Portions Copyright [yyyy] [name of copyright owner] 187bd3a2e2SSriharsha Basavapatna * 197bd3a2e2SSriharsha Basavapatna * CDDL HEADER END 207bd3a2e2SSriharsha Basavapatna */ 217bd3a2e2SSriharsha Basavapatna 227bd3a2e2SSriharsha Basavapatna /* 238e512277SWENTAO YANG * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 247bd3a2e2SSriharsha Basavapatna */ 258e512277SWENTAO YANG 267bd3a2e2SSriharsha Basavapatna #include <sys/types.h> 277bd3a2e2SSriharsha Basavapatna #include <sys/errno.h> 287bd3a2e2SSriharsha Basavapatna #include <sys/sysmacros.h> 297bd3a2e2SSriharsha Basavapatna #include <sys/param.h> 307bd3a2e2SSriharsha Basavapatna #include <sys/machsystm.h> 317bd3a2e2SSriharsha Basavapatna #include <sys/stream.h> 327bd3a2e2SSriharsha Basavapatna #include <sys/strsubr.h> 337bd3a2e2SSriharsha Basavapatna #include <sys/kmem.h> 347bd3a2e2SSriharsha Basavapatna #include <sys/strsun.h> 357bd3a2e2SSriharsha Basavapatna #include <sys/callb.h> 367bd3a2e2SSriharsha Basavapatna #include <sys/sdt.h> 377bd3a2e2SSriharsha Basavapatna #include <sys/mach_descrip.h> 387bd3a2e2SSriharsha Basavapatna #include <sys/mdeg.h> 397bd3a2e2SSriharsha Basavapatna #include <net/if.h> 407bd3a2e2SSriharsha Basavapatna #include <sys/vsw.h> 417bd3a2e2SSriharsha Basavapatna #include <sys/vio_mailbox.h> 427bd3a2e2SSriharsha Basavapatna #include <sys/vio_common.h> 437bd3a2e2SSriharsha Basavapatna #include <sys/vnet_common.h> 447bd3a2e2SSriharsha Basavapatna #include <sys/vnet_mailbox.h> 457bd3a2e2SSriharsha Basavapatna #include <sys/vio_util.h> 467bd3a2e2SSriharsha Basavapatna 477bd3a2e2SSriharsha Basavapatna /* 487bd3a2e2SSriharsha Basavapatna * This file contains the implementation of RxDringData transfer mode of VIO 497bd3a2e2SSriharsha Basavapatna * Protocol in vsw. The functions in this file are invoked from vsw_ldc.c 507bd3a2e2SSriharsha Basavapatna * after RxDringData mode is negotiated with the peer during attribute phase of 517bd3a2e2SSriharsha Basavapatna * handshake. This file contains functions that setup the transmit and receive 527bd3a2e2SSriharsha Basavapatna * descriptor rings, and associated resources in RxDringData mode. It also 537bd3a2e2SSriharsha Basavapatna * contains the transmit and receive data processing functions that are invoked 547bd3a2e2SSriharsha Basavapatna * in RxDringData mode. The data processing routines in this file have the 557bd3a2e2SSriharsha Basavapatna * suffix '_shm' to indicate the shared memory mechanism used in RxDringData 567bd3a2e2SSriharsha Basavapatna * mode. 577bd3a2e2SSriharsha Basavapatna */ 587bd3a2e2SSriharsha Basavapatna 597bd3a2e2SSriharsha Basavapatna /* Functions exported to vsw_ldc.c */ 607bd3a2e2SSriharsha Basavapatna vio_dring_reg_msg_t *vsw_create_rx_dring_info(vsw_ldc_t *); 617bd3a2e2SSriharsha Basavapatna void vsw_destroy_rx_dring(vsw_ldc_t *ldcp); 627bd3a2e2SSriharsha Basavapatna dring_info_t *vsw_map_tx_dring(vsw_ldc_t *ldcp, void *pkt); 637bd3a2e2SSriharsha Basavapatna void vsw_unmap_tx_dring(vsw_ldc_t *ldcp); 647bd3a2e2SSriharsha Basavapatna int vsw_dringsend_shm(vsw_ldc_t *, mblk_t *); 657bd3a2e2SSriharsha Basavapatna void vsw_ldc_rcv_worker(void *arg); 667bd3a2e2SSriharsha Basavapatna void vsw_stop_rcv_thread(vsw_ldc_t *ldcp); 677bd3a2e2SSriharsha Basavapatna void vsw_process_dringdata_shm(void *, void *); 687bd3a2e2SSriharsha Basavapatna 697bd3a2e2SSriharsha Basavapatna /* Internal functions */ 707bd3a2e2SSriharsha Basavapatna static dring_info_t *vsw_create_rx_dring(vsw_ldc_t *); 717bd3a2e2SSriharsha Basavapatna static int vsw_setup_rx_dring(vsw_ldc_t *ldcp, dring_info_t *dp); 727bd3a2e2SSriharsha Basavapatna static void vsw_process_dringdata_info_shm(vsw_ldc_t *ldcp, 737bd3a2e2SSriharsha Basavapatna vio_dring_msg_t *msg); 747bd3a2e2SSriharsha Basavapatna static void vsw_process_dringdata_ack_shm(vsw_ldc_t *ldcp, 757bd3a2e2SSriharsha Basavapatna vio_dring_msg_t *msg); 767bd3a2e2SSriharsha Basavapatna static void vsw_ldc_rcv_shm(vsw_ldc_t *ldcp); 777bd3a2e2SSriharsha Basavapatna static int vsw_receive_packet(vsw_ldc_t *ldcp, mblk_t **bp); 787bd3a2e2SSriharsha Basavapatna static int vsw_send_msg_shm(vsw_ldc_t *ldcp, void *msgp, int size, 797bd3a2e2SSriharsha Basavapatna boolean_t handle_reset); 807bd3a2e2SSriharsha Basavapatna 817bd3a2e2SSriharsha Basavapatna /* Functions imported from vsw_ldc.c */ 827bd3a2e2SSriharsha Basavapatna extern void vsw_process_pkt(void *); 837bd3a2e2SSriharsha Basavapatna extern void vsw_destroy_rxpools(void *); 847bd3a2e2SSriharsha Basavapatna extern dring_info_t *vsw_map_dring_cmn(vsw_ldc_t *ldcp, 857bd3a2e2SSriharsha Basavapatna vio_dring_reg_msg_t *dring_pkt); 867bd3a2e2SSriharsha Basavapatna extern void vsw_process_conn_evt(vsw_ldc_t *, uint16_t); 877bd3a2e2SSriharsha Basavapatna extern mblk_t *vsw_vlan_frame_pretag(void *arg, int type, mblk_t *mp); 887bd3a2e2SSriharsha Basavapatna 897bd3a2e2SSriharsha Basavapatna /* Tunables */ 907bd3a2e2SSriharsha Basavapatna extern int vsw_wretries; 917bd3a2e2SSriharsha Basavapatna extern int vsw_recv_delay; 927bd3a2e2SSriharsha Basavapatna extern int vsw_recv_retries; 937bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_chain_len; 947bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_num_descriptors; 957bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_nrbufs_factor; 967bd3a2e2SSriharsha Basavapatna 977bd3a2e2SSriharsha Basavapatna #define VSW_SWITCH_FRAMES(vswp, ldcp, bp, bpt, count, total_count) \ 987bd3a2e2SSriharsha Basavapatna { \ 997bd3a2e2SSriharsha Basavapatna DTRACE_PROBE2(vsw_rx_pkts, vsw_ldc_t *, (ldcp), int, (count)); \ 1007bd3a2e2SSriharsha Basavapatna (vswp)->vsw_switch_frame((vswp), (bp), VSW_VNETPORT, \ 1017bd3a2e2SSriharsha Basavapatna (ldcp)->ldc_port, NULL); \ 1027bd3a2e2SSriharsha Basavapatna (bp) = (bpt) = NULL; \ 1037bd3a2e2SSriharsha Basavapatna (count) = 0; \ 1047bd3a2e2SSriharsha Basavapatna } 1057bd3a2e2SSriharsha Basavapatna 1067bd3a2e2SSriharsha Basavapatna vio_dring_reg_msg_t * 1077bd3a2e2SSriharsha Basavapatna vsw_create_rx_dring_info(vsw_ldc_t *ldcp) 1087bd3a2e2SSriharsha Basavapatna { 1097bd3a2e2SSriharsha Basavapatna vio_dring_reg_msg_t *mp; 1107bd3a2e2SSriharsha Basavapatna vio_dring_reg_ext_msg_t *emsg; 1117bd3a2e2SSriharsha Basavapatna dring_info_t *dp; 1127bd3a2e2SSriharsha Basavapatna uint8_t *buf; 1137bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 1147bd3a2e2SSriharsha Basavapatna 1157bd3a2e2SSriharsha Basavapatna D1(vswp, "%s enter\n", __func__); 1167bd3a2e2SSriharsha Basavapatna 1177bd3a2e2SSriharsha Basavapatna /* 1187bd3a2e2SSriharsha Basavapatna * If we can't create a dring, obviously no point sending 1197bd3a2e2SSriharsha Basavapatna * a message. 1207bd3a2e2SSriharsha Basavapatna */ 1217bd3a2e2SSriharsha Basavapatna if ((dp = vsw_create_rx_dring(ldcp)) == NULL) 1227bd3a2e2SSriharsha Basavapatna return (NULL); 1237bd3a2e2SSriharsha Basavapatna 1247bd3a2e2SSriharsha Basavapatna mp = kmem_zalloc(VNET_DRING_REG_EXT_MSG_SIZE(dp->data_ncookies), 1257bd3a2e2SSriharsha Basavapatna KM_SLEEP); 1267bd3a2e2SSriharsha Basavapatna 1277bd3a2e2SSriharsha Basavapatna mp->tag.vio_msgtype = VIO_TYPE_CTRL; 1287bd3a2e2SSriharsha Basavapatna mp->tag.vio_subtype = VIO_SUBTYPE_INFO; 1297bd3a2e2SSriharsha Basavapatna mp->tag.vio_subtype_env = VIO_DRING_REG; 1307bd3a2e2SSriharsha Basavapatna mp->tag.vio_sid = ldcp->local_session; 1317bd3a2e2SSriharsha Basavapatna 1327bd3a2e2SSriharsha Basavapatna /* payload */ 1337bd3a2e2SSriharsha Basavapatna mp->num_descriptors = dp->num_descriptors; 1347bd3a2e2SSriharsha Basavapatna mp->descriptor_size = dp->descriptor_size; 1357bd3a2e2SSriharsha Basavapatna mp->options = dp->options; 1367bd3a2e2SSriharsha Basavapatna mp->ncookies = dp->dring_ncookies; 1377bd3a2e2SSriharsha Basavapatna bcopy(&dp->dring_cookie[0], &mp->cookie[0], 1387bd3a2e2SSriharsha Basavapatna sizeof (ldc_mem_cookie_t)); 1397bd3a2e2SSriharsha Basavapatna 1407bd3a2e2SSriharsha Basavapatna mp->dring_ident = 0; 1417bd3a2e2SSriharsha Basavapatna 1427bd3a2e2SSriharsha Basavapatna buf = (uint8_t *)mp->cookie; 1437bd3a2e2SSriharsha Basavapatna 1447bd3a2e2SSriharsha Basavapatna /* skip over dring cookies */ 1457bd3a2e2SSriharsha Basavapatna ASSERT(mp->ncookies == 1); 1467bd3a2e2SSriharsha Basavapatna buf += (mp->ncookies * sizeof (ldc_mem_cookie_t)); 1477bd3a2e2SSriharsha Basavapatna 1487bd3a2e2SSriharsha Basavapatna emsg = (vio_dring_reg_ext_msg_t *)buf; 1497bd3a2e2SSriharsha Basavapatna 1507bd3a2e2SSriharsha Basavapatna /* copy data_ncookies in the msg */ 1517bd3a2e2SSriharsha Basavapatna emsg->data_ncookies = dp->data_ncookies; 1527bd3a2e2SSriharsha Basavapatna 1537bd3a2e2SSriharsha Basavapatna /* copy data area size in the msg */ 1547bd3a2e2SSriharsha Basavapatna emsg->data_area_size = dp->data_sz; 1557bd3a2e2SSriharsha Basavapatna 1567bd3a2e2SSriharsha Basavapatna /* copy data area cookies in the msg */ 1577bd3a2e2SSriharsha Basavapatna bcopy(dp->data_cookie, (ldc_mem_cookie_t *)emsg->data_cookie, 1587bd3a2e2SSriharsha Basavapatna sizeof (ldc_mem_cookie_t) * dp->data_ncookies); 1597bd3a2e2SSriharsha Basavapatna 1607bd3a2e2SSriharsha Basavapatna D1(vswp, "%s exit\n", __func__); 1617bd3a2e2SSriharsha Basavapatna 1627bd3a2e2SSriharsha Basavapatna return (mp); 1637bd3a2e2SSriharsha Basavapatna } 1647bd3a2e2SSriharsha Basavapatna 1657bd3a2e2SSriharsha Basavapatna /* 1667bd3a2e2SSriharsha Basavapatna * Allocate receive resources for the channel. The resources consist of a 1677bd3a2e2SSriharsha Basavapatna * receive descriptor ring and an associated receive buffer area. 1687bd3a2e2SSriharsha Basavapatna */ 1697bd3a2e2SSriharsha Basavapatna static dring_info_t * 1707bd3a2e2SSriharsha Basavapatna vsw_create_rx_dring(vsw_ldc_t *ldcp) 1717bd3a2e2SSriharsha Basavapatna { 1727bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 1737bd3a2e2SSriharsha Basavapatna ldc_mem_info_t minfo; 1747bd3a2e2SSriharsha Basavapatna dring_info_t *dp; 1757bd3a2e2SSriharsha Basavapatna 1767bd3a2e2SSriharsha Basavapatna dp = (dring_info_t *)kmem_zalloc(sizeof (dring_info_t), KM_SLEEP); 1777bd3a2e2SSriharsha Basavapatna mutex_init(&dp->dlock, NULL, MUTEX_DRIVER, NULL); 1787bd3a2e2SSriharsha Basavapatna ldcp->lane_out.dringp = dp; 1797bd3a2e2SSriharsha Basavapatna 1807bd3a2e2SSriharsha Basavapatna /* Create the receive descriptor ring */ 1817bd3a2e2SSriharsha Basavapatna if ((ldc_mem_dring_create(vsw_num_descriptors, 1827bd3a2e2SSriharsha Basavapatna sizeof (vnet_rx_dringdata_desc_t), &dp->dring_handle)) != 0) { 1837bd3a2e2SSriharsha Basavapatna DERR(vswp, "vsw_create_rx_dring(%lld): ldc dring create " 1847bd3a2e2SSriharsha Basavapatna "failed", ldcp->ldc_id); 1857bd3a2e2SSriharsha Basavapatna goto fail; 1867bd3a2e2SSriharsha Basavapatna } 1877bd3a2e2SSriharsha Basavapatna 1887bd3a2e2SSriharsha Basavapatna ASSERT(dp->dring_handle != NULL); 1897bd3a2e2SSriharsha Basavapatna 1907bd3a2e2SSriharsha Basavapatna /* Get the addr of descriptor ring */ 1917bd3a2e2SSriharsha Basavapatna if ((ldc_mem_dring_info(dp->dring_handle, &minfo)) != 0) { 1927bd3a2e2SSriharsha Basavapatna DERR(vswp, "vsw_create_rx_dring(%lld): dring info failed\n", 1937bd3a2e2SSriharsha Basavapatna ldcp->ldc_id); 1947bd3a2e2SSriharsha Basavapatna goto fail; 1957bd3a2e2SSriharsha Basavapatna } else { 1967bd3a2e2SSriharsha Basavapatna ASSERT(minfo.vaddr != 0); 1977bd3a2e2SSriharsha Basavapatna dp->pub_addr = minfo.vaddr; 1987bd3a2e2SSriharsha Basavapatna } 1997bd3a2e2SSriharsha Basavapatna 2007bd3a2e2SSriharsha Basavapatna dp->num_descriptors = vsw_num_descriptors; 2017bd3a2e2SSriharsha Basavapatna dp->descriptor_size = sizeof (vnet_rx_dringdata_desc_t); 2027bd3a2e2SSriharsha Basavapatna dp->options = VIO_RX_DRING_DATA; 2037bd3a2e2SSriharsha Basavapatna dp->dring_ncookies = 1; /* guaranteed by ldc */ 204*34f94fbcSWENTAO YANG dp->num_bufs = VSW_RXDRING_NRBUFS; 2057bd3a2e2SSriharsha Basavapatna 2067bd3a2e2SSriharsha Basavapatna /* 2077bd3a2e2SSriharsha Basavapatna * Allocate a table that maps descriptor to its associated buffer; 2087bd3a2e2SSriharsha Basavapatna * used while receiving to validate that the peer has not changed the 2097bd3a2e2SSriharsha Basavapatna * buffer offset provided in the descriptor. 2107bd3a2e2SSriharsha Basavapatna */ 2117bd3a2e2SSriharsha Basavapatna dp->rxdp_to_vmp = kmem_zalloc(dp->num_descriptors * sizeof (uintptr_t), 2127bd3a2e2SSriharsha Basavapatna KM_SLEEP); 2137bd3a2e2SSriharsha Basavapatna 2147bd3a2e2SSriharsha Basavapatna /* Setup the descriptor ring */ 2157bd3a2e2SSriharsha Basavapatna if (vsw_setup_rx_dring(ldcp, dp)) { 2167bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s: unable to setup ring", __func__); 2177bd3a2e2SSriharsha Basavapatna goto fail; 2187bd3a2e2SSriharsha Basavapatna } 2197bd3a2e2SSriharsha Basavapatna 2207bd3a2e2SSriharsha Basavapatna /* 2217bd3a2e2SSriharsha Basavapatna * The descriptors and the associated buffers are all ready; 2227bd3a2e2SSriharsha Basavapatna * now bind descriptor ring to the channel. 2237bd3a2e2SSriharsha Basavapatna */ 2247bd3a2e2SSriharsha Basavapatna if ((ldc_mem_dring_bind(ldcp->ldc_handle, dp->dring_handle, 2257bd3a2e2SSriharsha Basavapatna LDC_DIRECT_MAP | LDC_SHADOW_MAP, LDC_MEM_RW, 2267bd3a2e2SSriharsha Basavapatna &dp->dring_cookie[0], &dp->dring_ncookies)) != 0) { 2277bd3a2e2SSriharsha Basavapatna DERR(vswp, "vsw_create_rx_dring: unable to bind to channel " 2287bd3a2e2SSriharsha Basavapatna "%lld", ldcp->ldc_id); 2297bd3a2e2SSriharsha Basavapatna goto fail; 2307bd3a2e2SSriharsha Basavapatna } 2317bd3a2e2SSriharsha Basavapatna 2327bd3a2e2SSriharsha Basavapatna /* haven't used any descriptors yet */ 2337bd3a2e2SSriharsha Basavapatna dp->end_idx = 0; 2347bd3a2e2SSriharsha Basavapatna dp->last_ack_recv = -1; 2357bd3a2e2SSriharsha Basavapatna dp->next_rxi = 0; 2367bd3a2e2SSriharsha Basavapatna return (dp); 2377bd3a2e2SSriharsha Basavapatna 2387bd3a2e2SSriharsha Basavapatna fail: 2397bd3a2e2SSriharsha Basavapatna vsw_destroy_rx_dring(ldcp); 2407bd3a2e2SSriharsha Basavapatna return (NULL); 2417bd3a2e2SSriharsha Basavapatna } 2427bd3a2e2SSriharsha Basavapatna 2437bd3a2e2SSriharsha Basavapatna /* 2447bd3a2e2SSriharsha Basavapatna * Setup the descriptors in the rx dring. 2457bd3a2e2SSriharsha Basavapatna * Returns 0 on success, 1 on failure. 2467bd3a2e2SSriharsha Basavapatna */ 2477bd3a2e2SSriharsha Basavapatna static int 2487bd3a2e2SSriharsha Basavapatna vsw_setup_rx_dring(vsw_ldc_t *ldcp, dring_info_t *dp) 2497bd3a2e2SSriharsha Basavapatna { 2508e512277SWENTAO YANG int i, j; 2517bd3a2e2SSriharsha Basavapatna int rv; 2527bd3a2e2SSriharsha Basavapatna size_t data_sz; 2537bd3a2e2SSriharsha Basavapatna vio_mblk_t *vmp; 2547bd3a2e2SSriharsha Basavapatna vio_mblk_t **rxdp_to_vmp; 2557bd3a2e2SSriharsha Basavapatna vnet_rx_dringdata_desc_t *rxdp; 2567bd3a2e2SSriharsha Basavapatna vnet_rx_dringdata_desc_t *pub_addr; 2577bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 2587bd3a2e2SSriharsha Basavapatna uint32_t ncookies = 0; 2597bd3a2e2SSriharsha Basavapatna static char *name = "vsw_setup_rx_dring"; 2607bd3a2e2SSriharsha Basavapatna void *data_addr = NULL; 2617bd3a2e2SSriharsha Basavapatna 2627bd3a2e2SSriharsha Basavapatna /* 2637bd3a2e2SSriharsha Basavapatna * Allocate a single large buffer that serves as the rx buffer area. 2647bd3a2e2SSriharsha Basavapatna * We allocate a ldc memory handle and export the buffer area as shared 2657bd3a2e2SSriharsha Basavapatna * memory. We send the ldc memcookie for this buffer space to the peer, 2667bd3a2e2SSriharsha Basavapatna * as part of dring registration phase during handshake. We manage this 2677bd3a2e2SSriharsha Basavapatna * buffer area as individual buffers of max_frame_size and provide 2687bd3a2e2SSriharsha Basavapatna * specific buffer offsets in each descriptor to the peer. Note that 2697bd3a2e2SSriharsha Basavapatna * the factor used to compute the # of buffers (above) must be > 1 to 2707bd3a2e2SSriharsha Basavapatna * ensure that there are more buffers than the # of descriptors. This 2717bd3a2e2SSriharsha Basavapatna * is needed because, while the shared memory buffers are sent up our 2727bd3a2e2SSriharsha Basavapatna * stack during receive, the sender needs additional buffers that can 2737bd3a2e2SSriharsha Basavapatna * be used for further transmits. This also means there is no one to 2747bd3a2e2SSriharsha Basavapatna * one correspondence between the descriptor index and buffer offset. 2757bd3a2e2SSriharsha Basavapatna * The sender has to read the buffer offset in the descriptor and use 2767bd3a2e2SSriharsha Basavapatna * the specified offset to copy the tx data into the shared buffer. We 2777bd3a2e2SSriharsha Basavapatna * (receiver) manage the individual buffers and their state (see 2787bd3a2e2SSriharsha Basavapatna * VIO_MBLK_STATEs in vio_util.h). 2797bd3a2e2SSriharsha Basavapatna */ 280*34f94fbcSWENTAO YANG data_sz = RXDRING_DBLK_SZ(vswp->max_frame_size); 2817bd3a2e2SSriharsha Basavapatna 2827bd3a2e2SSriharsha Basavapatna dp->desc_data_sz = data_sz; 2837bd3a2e2SSriharsha Basavapatna dp->data_sz = (dp->num_bufs * data_sz); 2847bd3a2e2SSriharsha Basavapatna data_addr = kmem_zalloc(dp->data_sz, KM_SLEEP); 2857bd3a2e2SSriharsha Basavapatna dp->data_addr = data_addr; 2867bd3a2e2SSriharsha Basavapatna 2877bd3a2e2SSriharsha Basavapatna D2(vswp, "%s: allocated %lld bytes at 0x%llx\n", name, 2887bd3a2e2SSriharsha Basavapatna dp->data_sz, dp->data_addr); 2897bd3a2e2SSriharsha Basavapatna 2907bd3a2e2SSriharsha Basavapatna /* Allocate a ldc memhandle for the entire rx data area */ 2917bd3a2e2SSriharsha Basavapatna rv = ldc_mem_alloc_handle(ldcp->ldc_handle, &dp->data_handle); 2927bd3a2e2SSriharsha Basavapatna if (rv != 0) { 2937bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s: alloc mem handle failed", name); 2947bd3a2e2SSriharsha Basavapatna goto fail; 2957bd3a2e2SSriharsha Basavapatna } 2967bd3a2e2SSriharsha Basavapatna 2977bd3a2e2SSriharsha Basavapatna /* Allocate memory for the data cookies */ 2987bd3a2e2SSriharsha Basavapatna dp->data_cookie = kmem_zalloc(VNET_DATA_AREA_COOKIES * 2997bd3a2e2SSriharsha Basavapatna sizeof (ldc_mem_cookie_t), KM_SLEEP); 3007bd3a2e2SSriharsha Basavapatna 3017bd3a2e2SSriharsha Basavapatna /* 3027bd3a2e2SSriharsha Basavapatna * Bind ldc memhandle to the corresponding rx data area. 3037bd3a2e2SSriharsha Basavapatna */ 3047bd3a2e2SSriharsha Basavapatna rv = ldc_mem_bind_handle(dp->data_handle, (caddr_t)data_addr, 3057bd3a2e2SSriharsha Basavapatna dp->data_sz, LDC_DIRECT_MAP, LDC_MEM_W, 3067bd3a2e2SSriharsha Basavapatna dp->data_cookie, &ncookies); 3077bd3a2e2SSriharsha Basavapatna if (rv != 0) { 3087bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s(%lld): ldc_mem_bind_handle failed " 3097bd3a2e2SSriharsha Basavapatna "(rv %d)", name, ldcp->ldc_id, rv); 3107bd3a2e2SSriharsha Basavapatna goto fail; 3117bd3a2e2SSriharsha Basavapatna } 3127bd3a2e2SSriharsha Basavapatna if ((ncookies == 0) || (ncookies > VNET_DATA_AREA_COOKIES)) { 3137bd3a2e2SSriharsha Basavapatna goto fail; 3147bd3a2e2SSriharsha Basavapatna } 3157bd3a2e2SSriharsha Basavapatna dp->data_ncookies = ncookies; 3167bd3a2e2SSriharsha Basavapatna 3178e512277SWENTAO YANG for (j = 1; j < ncookies; j++) { 3188e512277SWENTAO YANG rv = ldc_mem_nextcookie(dp->data_handle, 3198e512277SWENTAO YANG &(dp->data_cookie[j])); 3208e512277SWENTAO YANG if (rv != 0) { 3218e512277SWENTAO YANG DERR(vswp, "%s: ldc_mem_nextcookie " 3228e512277SWENTAO YANG "failed rv (%d)", name, rv); 3238e512277SWENTAO YANG goto fail; 3248e512277SWENTAO YANG } 3258e512277SWENTAO YANG } 3268e512277SWENTAO YANG 3277bd3a2e2SSriharsha Basavapatna /* 3287bd3a2e2SSriharsha Basavapatna * Successful in binding the handle to rx data area. Now setup mblks 3297bd3a2e2SSriharsha Basavapatna * around each data buffer and setup the descriptors to point to these 3307bd3a2e2SSriharsha Basavapatna * rx data buffers. We associate each descriptor with a buffer 3317bd3a2e2SSriharsha Basavapatna * by specifying the buffer offset in the descriptor. When the peer 3327bd3a2e2SSriharsha Basavapatna * needs to transmit data, this offset is read by the peer to determine 3337bd3a2e2SSriharsha Basavapatna * the buffer in the mapped buffer area where the data to be 3347bd3a2e2SSriharsha Basavapatna * transmitted should be copied, for a specific descriptor. 3357bd3a2e2SSriharsha Basavapatna */ 3367bd3a2e2SSriharsha Basavapatna rv = vio_create_mblks(dp->num_bufs, data_sz, (uint8_t *)data_addr, 3377bd3a2e2SSriharsha Basavapatna &dp->rx_vmp); 3387bd3a2e2SSriharsha Basavapatna if (rv != 0) { 3397bd3a2e2SSriharsha Basavapatna goto fail; 3407bd3a2e2SSriharsha Basavapatna } 3417bd3a2e2SSriharsha Basavapatna 3427bd3a2e2SSriharsha Basavapatna pub_addr = dp->pub_addr; 3437bd3a2e2SSriharsha Basavapatna rxdp_to_vmp = dp->rxdp_to_vmp; 3447bd3a2e2SSriharsha Basavapatna for (i = 0; i < dp->num_descriptors; i++) { 3457bd3a2e2SSriharsha Basavapatna rxdp = &pub_addr[i]; 3467bd3a2e2SSriharsha Basavapatna /* allocate an mblk around this data buffer */ 3477bd3a2e2SSriharsha Basavapatna vmp = vio_allocb(dp->rx_vmp); 3487bd3a2e2SSriharsha Basavapatna ASSERT(vmp != NULL); 3497bd3a2e2SSriharsha Basavapatna rxdp->data_buf_offset = VIO_MBLK_DATA_OFF(vmp) + VNET_IPALIGN; 3507bd3a2e2SSriharsha Basavapatna rxdp->dstate = VIO_DESC_FREE; 3517bd3a2e2SSriharsha Basavapatna rxdp_to_vmp[i] = vmp; 3527bd3a2e2SSriharsha Basavapatna } 3537bd3a2e2SSriharsha Basavapatna 3547bd3a2e2SSriharsha Basavapatna return (0); 3557bd3a2e2SSriharsha Basavapatna 3567bd3a2e2SSriharsha Basavapatna fail: 3577bd3a2e2SSriharsha Basavapatna /* return failure; caller will cleanup */ 3587bd3a2e2SSriharsha Basavapatna return (1); 3597bd3a2e2SSriharsha Basavapatna } 3607bd3a2e2SSriharsha Basavapatna 3617bd3a2e2SSriharsha Basavapatna /* 3627bd3a2e2SSriharsha Basavapatna * Free receive resources for the channel. 3637bd3a2e2SSriharsha Basavapatna */ 3647bd3a2e2SSriharsha Basavapatna void 3657bd3a2e2SSriharsha Basavapatna vsw_destroy_rx_dring(vsw_ldc_t *ldcp) 3667bd3a2e2SSriharsha Basavapatna { 3677bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 3687bd3a2e2SSriharsha Basavapatna lane_t *lp = &ldcp->lane_out; 3697bd3a2e2SSriharsha Basavapatna dring_info_t *dp; 3707bd3a2e2SSriharsha Basavapatna 3717bd3a2e2SSriharsha Basavapatna dp = lp->dringp; 3727bd3a2e2SSriharsha Basavapatna if (dp == NULL) { 3737bd3a2e2SSriharsha Basavapatna return; 3747bd3a2e2SSriharsha Basavapatna } 3757bd3a2e2SSriharsha Basavapatna 3767bd3a2e2SSriharsha Basavapatna mutex_enter(&dp->dlock); 3777bd3a2e2SSriharsha Basavapatna 3787bd3a2e2SSriharsha Basavapatna if (dp->rx_vmp != NULL) { 3797bd3a2e2SSriharsha Basavapatna vio_clobber_pool(dp->rx_vmp); 3807bd3a2e2SSriharsha Basavapatna /* 3817bd3a2e2SSriharsha Basavapatna * If we can't destroy the rx pool for this channel, dispatch a 3827bd3a2e2SSriharsha Basavapatna * task to retry and clean up those rx pools. Note that we 3837bd3a2e2SSriharsha Basavapatna * don't need to wait for the task to complete. If the vsw 3847bd3a2e2SSriharsha Basavapatna * device itself gets detached (vsw_detach()), it will wait for 3857bd3a2e2SSriharsha Basavapatna * the task to complete implicitly in ddi_taskq_destroy(). 3867bd3a2e2SSriharsha Basavapatna */ 3877bd3a2e2SSriharsha Basavapatna if (vio_destroy_mblks(dp->rx_vmp) != 0) { 3887bd3a2e2SSriharsha Basavapatna (void) ddi_taskq_dispatch(vswp->rxp_taskq, 3897bd3a2e2SSriharsha Basavapatna vsw_destroy_rxpools, dp->rx_vmp, DDI_SLEEP); 3907bd3a2e2SSriharsha Basavapatna } 3917bd3a2e2SSriharsha Basavapatna } 3927bd3a2e2SSriharsha Basavapatna 3937bd3a2e2SSriharsha Basavapatna /* Free rx data area cookies */ 3947bd3a2e2SSriharsha Basavapatna if (dp->data_cookie != NULL) { 3957bd3a2e2SSriharsha Basavapatna kmem_free(dp->data_cookie, VNET_DATA_AREA_COOKIES * 3967bd3a2e2SSriharsha Basavapatna sizeof (ldc_mem_cookie_t)); 3977bd3a2e2SSriharsha Basavapatna dp->data_cookie = NULL; 3987bd3a2e2SSriharsha Basavapatna } 3997bd3a2e2SSriharsha Basavapatna 4007bd3a2e2SSriharsha Basavapatna /* Unbind rx data area memhandle */ 4017bd3a2e2SSriharsha Basavapatna if (dp->data_ncookies != 0) { 4027bd3a2e2SSriharsha Basavapatna (void) ldc_mem_unbind_handle(dp->data_handle); 4037bd3a2e2SSriharsha Basavapatna dp->data_ncookies = 0; 4047bd3a2e2SSriharsha Basavapatna } 4057bd3a2e2SSriharsha Basavapatna 4067bd3a2e2SSriharsha Basavapatna /* Free rx data area memhandle */ 4077bd3a2e2SSriharsha Basavapatna if (dp->data_handle) { 4087bd3a2e2SSriharsha Basavapatna (void) ldc_mem_free_handle(dp->data_handle); 4097bd3a2e2SSriharsha Basavapatna dp->data_handle = 0; 4107bd3a2e2SSriharsha Basavapatna } 4117bd3a2e2SSriharsha Basavapatna 4127bd3a2e2SSriharsha Basavapatna /* Now free the rx data area itself */ 4137bd3a2e2SSriharsha Basavapatna if (dp->data_addr != NULL) { 4147bd3a2e2SSriharsha Basavapatna kmem_free(dp->data_addr, dp->data_sz); 4157bd3a2e2SSriharsha Basavapatna } 4167bd3a2e2SSriharsha Basavapatna 4177bd3a2e2SSriharsha Basavapatna /* Finally, free the receive descriptor ring */ 4187bd3a2e2SSriharsha Basavapatna if (dp->dring_handle != NULL) { 4197bd3a2e2SSriharsha Basavapatna (void) ldc_mem_dring_unbind(dp->dring_handle); 4207bd3a2e2SSriharsha Basavapatna (void) ldc_mem_dring_destroy(dp->dring_handle); 4217bd3a2e2SSriharsha Basavapatna } 4227bd3a2e2SSriharsha Basavapatna 4237bd3a2e2SSriharsha Basavapatna if (dp->rxdp_to_vmp != NULL) { 4247bd3a2e2SSriharsha Basavapatna kmem_free(dp->rxdp_to_vmp, 4257bd3a2e2SSriharsha Basavapatna dp->num_descriptors * sizeof (uintptr_t)); 4267bd3a2e2SSriharsha Basavapatna dp->rxdp_to_vmp = NULL; 4277bd3a2e2SSriharsha Basavapatna } 4287bd3a2e2SSriharsha Basavapatna 4297bd3a2e2SSriharsha Basavapatna mutex_exit(&dp->dlock); 4307bd3a2e2SSriharsha Basavapatna mutex_destroy(&dp->dlock); 4317bd3a2e2SSriharsha Basavapatna mutex_destroy(&dp->restart_lock); 4327bd3a2e2SSriharsha Basavapatna kmem_free(dp, sizeof (dring_info_t)); 4337bd3a2e2SSriharsha Basavapatna lp->dringp = NULL; 4347bd3a2e2SSriharsha Basavapatna } 4357bd3a2e2SSriharsha Basavapatna 4367bd3a2e2SSriharsha Basavapatna /* 4377bd3a2e2SSriharsha Basavapatna * Map the receive descriptor ring exported by the peer, as our transmit 4387bd3a2e2SSriharsha Basavapatna * descriptor ring. 4397bd3a2e2SSriharsha Basavapatna */ 4407bd3a2e2SSriharsha Basavapatna dring_info_t * 4417bd3a2e2SSriharsha Basavapatna vsw_map_tx_dring(vsw_ldc_t *ldcp, void *pkt) 4427bd3a2e2SSriharsha Basavapatna { 4437bd3a2e2SSriharsha Basavapatna int i; 4447bd3a2e2SSriharsha Basavapatna int rv; 4457bd3a2e2SSriharsha Basavapatna dring_info_t *dp; 4467bd3a2e2SSriharsha Basavapatna vnet_rx_dringdata_desc_t *txdp; 4477bd3a2e2SSriharsha Basavapatna on_trap_data_t otd; 4487bd3a2e2SSriharsha Basavapatna vio_dring_reg_msg_t *dring_pkt = pkt; 4497bd3a2e2SSriharsha Basavapatna 4507bd3a2e2SSriharsha Basavapatna dp = vsw_map_dring_cmn(ldcp, dring_pkt); 4517bd3a2e2SSriharsha Basavapatna if (dp == NULL) { 4527bd3a2e2SSriharsha Basavapatna return (NULL); 4537bd3a2e2SSriharsha Basavapatna } 4547bd3a2e2SSriharsha Basavapatna 4557bd3a2e2SSriharsha Basavapatna /* RxDringData mode specific initializations */ 4567bd3a2e2SSriharsha Basavapatna mutex_init(&dp->txlock, NULL, MUTEX_DRIVER, NULL); 4577bd3a2e2SSriharsha Basavapatna mutex_init(&dp->restart_lock, NULL, MUTEX_DRIVER, NULL); 4580e263307SWENTAO YANG dp->next_txi = dp->restart_peer_txi = 0; 4597bd3a2e2SSriharsha Basavapatna dp->restart_reqd = B_TRUE; 4607bd3a2e2SSriharsha Basavapatna ldcp->dringdata_msgid = 0; 4617bd3a2e2SSriharsha Basavapatna ldcp->lane_in.dringp = dp; 4627bd3a2e2SSriharsha Basavapatna 4637bd3a2e2SSriharsha Basavapatna /* 4647bd3a2e2SSriharsha Basavapatna * Mark the descriptor state as 'done'. This is implementation specific 4657bd3a2e2SSriharsha Basavapatna * and not required by the protocol. In our implementation, we only 4667bd3a2e2SSriharsha Basavapatna * need the descripor to be in 'done' state to be used by the transmit 4677bd3a2e2SSriharsha Basavapatna * function and the peer is not aware of it. As the protocol requires 4687bd3a2e2SSriharsha Basavapatna * that during initial registration the exporting end point mark the 4697bd3a2e2SSriharsha Basavapatna * dstate as 'free', we change it 'done' here. After this, the dstate 4707bd3a2e2SSriharsha Basavapatna * in our implementation will keep moving between 'ready', set by our 4717bd3a2e2SSriharsha Basavapatna * transmit function; and and 'done', set by the peer (per protocol) 4727bd3a2e2SSriharsha Basavapatna * after receiving data. 4737bd3a2e2SSriharsha Basavapatna * Setup on_trap() protection before accessing dring shared memory area. 4747bd3a2e2SSriharsha Basavapatna */ 4757bd3a2e2SSriharsha Basavapatna rv = LDC_ON_TRAP(&otd); 4767bd3a2e2SSriharsha Basavapatna if (rv != 0) { 4777bd3a2e2SSriharsha Basavapatna /* 4787bd3a2e2SSriharsha Basavapatna * Data access fault occured down the code path below while 4797bd3a2e2SSriharsha Basavapatna * accessing the descriptors. Return failure. 4807bd3a2e2SSriharsha Basavapatna */ 4817bd3a2e2SSriharsha Basavapatna goto fail; 4827bd3a2e2SSriharsha Basavapatna } 4837bd3a2e2SSriharsha Basavapatna 4847bd3a2e2SSriharsha Basavapatna txdp = (vnet_rx_dringdata_desc_t *)dp->pub_addr; 4857bd3a2e2SSriharsha Basavapatna for (i = 0; i < dp->num_descriptors; i++) { 4867bd3a2e2SSriharsha Basavapatna txdp[i].dstate = VIO_DESC_DONE; 4877bd3a2e2SSriharsha Basavapatna } 4887bd3a2e2SSriharsha Basavapatna 4897bd3a2e2SSriharsha Basavapatna (void) LDC_NO_TRAP(); 4907bd3a2e2SSriharsha Basavapatna 4917bd3a2e2SSriharsha Basavapatna return (dp); 4927bd3a2e2SSriharsha Basavapatna 4937bd3a2e2SSriharsha Basavapatna fail: 4947bd3a2e2SSriharsha Basavapatna if (dp->dring_handle != NULL) { 4957bd3a2e2SSriharsha Basavapatna (void) ldc_mem_dring_unmap(dp->dring_handle); 4967bd3a2e2SSriharsha Basavapatna } 4977bd3a2e2SSriharsha Basavapatna kmem_free(dp, sizeof (*dp)); 4987bd3a2e2SSriharsha Basavapatna return (NULL); 4997bd3a2e2SSriharsha Basavapatna } 5007bd3a2e2SSriharsha Basavapatna 5017bd3a2e2SSriharsha Basavapatna /* 5027bd3a2e2SSriharsha Basavapatna * Unmap the transmit descriptor ring. 5037bd3a2e2SSriharsha Basavapatna */ 5047bd3a2e2SSriharsha Basavapatna void 5057bd3a2e2SSriharsha Basavapatna vsw_unmap_tx_dring(vsw_ldc_t *ldcp) 5067bd3a2e2SSriharsha Basavapatna { 5077bd3a2e2SSriharsha Basavapatna lane_t *lp = &ldcp->lane_in; 5087bd3a2e2SSriharsha Basavapatna dring_info_t *dp; 5097bd3a2e2SSriharsha Basavapatna 5107bd3a2e2SSriharsha Basavapatna if ((dp = lp->dringp) == NULL) { 5117bd3a2e2SSriharsha Basavapatna return; 5127bd3a2e2SSriharsha Basavapatna } 5137bd3a2e2SSriharsha Basavapatna 5147bd3a2e2SSriharsha Basavapatna /* Unmap tx data area and free data handle */ 5157bd3a2e2SSriharsha Basavapatna if (dp->data_handle != NULL) { 5167bd3a2e2SSriharsha Basavapatna (void) ldc_mem_unmap(dp->data_handle); 5177bd3a2e2SSriharsha Basavapatna (void) ldc_mem_free_handle(dp->data_handle); 5187bd3a2e2SSriharsha Basavapatna dp->data_handle = NULL; 5197bd3a2e2SSriharsha Basavapatna } 5207bd3a2e2SSriharsha Basavapatna 5217bd3a2e2SSriharsha Basavapatna /* Free tx data area cookies */ 5227bd3a2e2SSriharsha Basavapatna if (dp->data_cookie != NULL) { 5237bd3a2e2SSriharsha Basavapatna kmem_free(dp->data_cookie, dp->data_ncookies * 5247bd3a2e2SSriharsha Basavapatna sizeof (ldc_mem_cookie_t)); 5257bd3a2e2SSriharsha Basavapatna dp->data_cookie = NULL; 5267bd3a2e2SSriharsha Basavapatna dp->data_ncookies = 0; 5277bd3a2e2SSriharsha Basavapatna } 5287bd3a2e2SSriharsha Basavapatna 5297bd3a2e2SSriharsha Basavapatna /* Unmap peer's dring */ 5307bd3a2e2SSriharsha Basavapatna if (dp->dring_handle != NULL) { 5317bd3a2e2SSriharsha Basavapatna (void) ldc_mem_dring_unmap(dp->dring_handle); 5327bd3a2e2SSriharsha Basavapatna dp->dring_handle = NULL; 5337bd3a2e2SSriharsha Basavapatna } 5347bd3a2e2SSriharsha Basavapatna 5357bd3a2e2SSriharsha Basavapatna mutex_destroy(&dp->txlock); 5367bd3a2e2SSriharsha Basavapatna kmem_free(dp, sizeof (dring_info_t)); 5377bd3a2e2SSriharsha Basavapatna lp->dringp = NULL; 5387bd3a2e2SSriharsha Basavapatna } 5397bd3a2e2SSriharsha Basavapatna 5407bd3a2e2SSriharsha Basavapatna /* 5417bd3a2e2SSriharsha Basavapatna * A per LDC worker thread to process the rx dring and receive packets. This 5427bd3a2e2SSriharsha Basavapatna * thread is woken up by the LDC interrupt handler when a dring data info 5437bd3a2e2SSriharsha Basavapatna * message is received. 5447bd3a2e2SSriharsha Basavapatna */ 5457bd3a2e2SSriharsha Basavapatna void 5467bd3a2e2SSriharsha Basavapatna vsw_ldc_rcv_worker(void *arg) 5477bd3a2e2SSriharsha Basavapatna { 5487bd3a2e2SSriharsha Basavapatna callb_cpr_t cprinfo; 5497bd3a2e2SSriharsha Basavapatna vsw_ldc_t *ldcp = (vsw_ldc_t *)arg; 5507bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 5517bd3a2e2SSriharsha Basavapatna 5527bd3a2e2SSriharsha Basavapatna D1(vswp, "%s(%lld):enter\n", __func__, ldcp->ldc_id); 5537bd3a2e2SSriharsha Basavapatna CALLB_CPR_INIT(&cprinfo, &ldcp->rcv_thr_lock, callb_generic_cpr, 5547bd3a2e2SSriharsha Basavapatna "vsw_rcv_thread"); 5557bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->rcv_thr_lock); 5567bd3a2e2SSriharsha Basavapatna while (!(ldcp->rcv_thr_flags & VSW_WTHR_STOP)) { 5577bd3a2e2SSriharsha Basavapatna 5587bd3a2e2SSriharsha Basavapatna CALLB_CPR_SAFE_BEGIN(&cprinfo); 5597bd3a2e2SSriharsha Basavapatna /* 5607bd3a2e2SSriharsha Basavapatna * Wait until the data is received or a stop 5617bd3a2e2SSriharsha Basavapatna * request is received. 5627bd3a2e2SSriharsha Basavapatna */ 5637bd3a2e2SSriharsha Basavapatna while (!(ldcp->rcv_thr_flags & 5647bd3a2e2SSriharsha Basavapatna (VSW_WTHR_DATARCVD | VSW_WTHR_STOP))) { 5657bd3a2e2SSriharsha Basavapatna cv_wait(&ldcp->rcv_thr_cv, &ldcp->rcv_thr_lock); 5667bd3a2e2SSriharsha Basavapatna } 5677bd3a2e2SSriharsha Basavapatna CALLB_CPR_SAFE_END(&cprinfo, &ldcp->rcv_thr_lock) 5687bd3a2e2SSriharsha Basavapatna 5697bd3a2e2SSriharsha Basavapatna /* 5707bd3a2e2SSriharsha Basavapatna * First process the stop request. 5717bd3a2e2SSriharsha Basavapatna */ 5727bd3a2e2SSriharsha Basavapatna if (ldcp->rcv_thr_flags & VSW_WTHR_STOP) { 5737bd3a2e2SSriharsha Basavapatna D2(vswp, "%s(%lld):Rx thread stopped\n", 5747bd3a2e2SSriharsha Basavapatna __func__, ldcp->ldc_id); 5757bd3a2e2SSriharsha Basavapatna break; 5767bd3a2e2SSriharsha Basavapatna } 5777bd3a2e2SSriharsha Basavapatna ldcp->rcv_thr_flags &= ~VSW_WTHR_DATARCVD; 5787bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->rcv_thr_lock); 5797bd3a2e2SSriharsha Basavapatna D1(vswp, "%s(%lld):calling vsw_process_pkt\n", 5807bd3a2e2SSriharsha Basavapatna __func__, ldcp->ldc_id); 5817bd3a2e2SSriharsha Basavapatna vsw_ldc_rcv_shm(ldcp); 5827bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->rcv_thr_lock); 5837bd3a2e2SSriharsha Basavapatna } 5847bd3a2e2SSriharsha Basavapatna 5857bd3a2e2SSriharsha Basavapatna /* 5867bd3a2e2SSriharsha Basavapatna * Update the run status and wakeup the thread that 5877bd3a2e2SSriharsha Basavapatna * has sent the stop request. 5887bd3a2e2SSriharsha Basavapatna */ 5897bd3a2e2SSriharsha Basavapatna ldcp->rcv_thr_flags &= ~VSW_WTHR_STOP; 5907bd3a2e2SSriharsha Basavapatna ldcp->rcv_thread = NULL; 5917bd3a2e2SSriharsha Basavapatna CALLB_CPR_EXIT(&cprinfo); 5927bd3a2e2SSriharsha Basavapatna D1(vswp, "%s(%lld):exit\n", __func__, ldcp->ldc_id); 5937bd3a2e2SSriharsha Basavapatna thread_exit(); 5947bd3a2e2SSriharsha Basavapatna } 5957bd3a2e2SSriharsha Basavapatna 5967bd3a2e2SSriharsha Basavapatna /* 5977bd3a2e2SSriharsha Basavapatna * Process the rx descriptor ring in the context of receive worker 5987bd3a2e2SSriharsha Basavapatna * thread and switch the received packets to their destinations. 5997bd3a2e2SSriharsha Basavapatna */ 6007bd3a2e2SSriharsha Basavapatna static void 6017bd3a2e2SSriharsha Basavapatna vsw_ldc_rcv_shm(vsw_ldc_t *ldcp) 6027bd3a2e2SSriharsha Basavapatna { 6037bd3a2e2SSriharsha Basavapatna int rv; 6047bd3a2e2SSriharsha Basavapatna uint32_t end_ix; 6057bd3a2e2SSriharsha Basavapatna vio_dring_msg_t msg; 6067bd3a2e2SSriharsha Basavapatna vio_dring_msg_t *msgp = &msg; 6077bd3a2e2SSriharsha Basavapatna int count = 0; 6087bd3a2e2SSriharsha Basavapatna int total_count = 0; 6097bd3a2e2SSriharsha Basavapatna uint32_t retries = 0; 6107bd3a2e2SSriharsha Basavapatna mblk_t *bp = NULL; 6117bd3a2e2SSriharsha Basavapatna mblk_t *bpt = NULL; 6127bd3a2e2SSriharsha Basavapatna mblk_t *mp = NULL; 6137bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 6147bd3a2e2SSriharsha Basavapatna lane_t *lp = &ldcp->lane_out; 6157bd3a2e2SSriharsha Basavapatna dring_info_t *dp = lp->dringp; 6167bd3a2e2SSriharsha Basavapatna 6177bd3a2e2SSriharsha Basavapatna do { 6187bd3a2e2SSriharsha Basavapatna again: 6197bd3a2e2SSriharsha Basavapatna rv = vsw_receive_packet(ldcp, &mp); 6207bd3a2e2SSriharsha Basavapatna if (rv != 0) { 6217bd3a2e2SSriharsha Basavapatna if (rv == EINVAL) { 6227bd3a2e2SSriharsha Basavapatna /* Invalid descriptor error; get next */ 6237bd3a2e2SSriharsha Basavapatna continue; 6247bd3a2e2SSriharsha Basavapatna } 6257bd3a2e2SSriharsha Basavapatna if (rv != EAGAIN) { 6267bd3a2e2SSriharsha Basavapatna break; 6277bd3a2e2SSriharsha Basavapatna } 6287bd3a2e2SSriharsha Basavapatna 6297bd3a2e2SSriharsha Basavapatna /* Descriptor not ready for processsing */ 6307bd3a2e2SSriharsha Basavapatna if (retries == vsw_recv_retries) { 6317bd3a2e2SSriharsha Basavapatna DTRACE_PROBE1(vsw_noready_rxds, 6327bd3a2e2SSriharsha Basavapatna vsw_ldc_t *, ldcp); 6337bd3a2e2SSriharsha Basavapatna break; 6347bd3a2e2SSriharsha Basavapatna } 6357bd3a2e2SSriharsha Basavapatna 6367bd3a2e2SSriharsha Basavapatna /* Switch packets received so far before retrying */ 6377bd3a2e2SSriharsha Basavapatna if (bp != NULL) { 6387bd3a2e2SSriharsha Basavapatna VSW_SWITCH_FRAMES(vswp, ldcp, bp, bpt, count, 6397bd3a2e2SSriharsha Basavapatna total_count); 6407bd3a2e2SSriharsha Basavapatna } 6417bd3a2e2SSriharsha Basavapatna retries++; 6427bd3a2e2SSriharsha Basavapatna drv_usecwait(vsw_recv_delay); 6437bd3a2e2SSriharsha Basavapatna goto again; 6447bd3a2e2SSriharsha Basavapatna } 6457bd3a2e2SSriharsha Basavapatna retries = 0; 6467bd3a2e2SSriharsha Basavapatna 6477bd3a2e2SSriharsha Basavapatna /* Build a chain of received packets */ 6487bd3a2e2SSriharsha Basavapatna if (bp == NULL) { 6497bd3a2e2SSriharsha Basavapatna /* first pkt */ 6507bd3a2e2SSriharsha Basavapatna bp = mp; 6517bd3a2e2SSriharsha Basavapatna bpt = bp; 6527bd3a2e2SSriharsha Basavapatna bpt->b_next = NULL; 6537bd3a2e2SSriharsha Basavapatna } else { 6547bd3a2e2SSriharsha Basavapatna mp->b_next = NULL; 6557bd3a2e2SSriharsha Basavapatna bpt->b_next = mp; 6567bd3a2e2SSriharsha Basavapatna bpt = mp; 6577bd3a2e2SSriharsha Basavapatna } 6587bd3a2e2SSriharsha Basavapatna 6597bd3a2e2SSriharsha Basavapatna total_count++; 6607bd3a2e2SSriharsha Basavapatna count++; 6617bd3a2e2SSriharsha Basavapatna 6627bd3a2e2SSriharsha Basavapatna /* 6637bd3a2e2SSriharsha Basavapatna * If we have gathered vsw_chain_len (tunable) 6647bd3a2e2SSriharsha Basavapatna * # of packets in the chain, switch them. 6657bd3a2e2SSriharsha Basavapatna */ 6667bd3a2e2SSriharsha Basavapatna if (count == vsw_chain_len) { 6677bd3a2e2SSriharsha Basavapatna VSW_SWITCH_FRAMES(vswp, ldcp, bp, bpt, count, 6687bd3a2e2SSriharsha Basavapatna total_count); 6697bd3a2e2SSriharsha Basavapatna } 6707bd3a2e2SSriharsha Basavapatna 6717bd3a2e2SSriharsha Basavapatna /* 6727bd3a2e2SSriharsha Basavapatna * Stop further processing if we processed the entire dring 6737bd3a2e2SSriharsha Basavapatna * once; otherwise continue. 6747bd3a2e2SSriharsha Basavapatna */ 6757bd3a2e2SSriharsha Basavapatna } while (total_count < dp->num_bufs); 6767bd3a2e2SSriharsha Basavapatna 6777bd3a2e2SSriharsha Basavapatna DTRACE_PROBE2(vsw_rx_total_count, vsw_ldc_t *, ldcp, 6787bd3a2e2SSriharsha Basavapatna int, (total_count)); 6797bd3a2e2SSriharsha Basavapatna if (bp != NULL) { 6807bd3a2e2SSriharsha Basavapatna VSW_SWITCH_FRAMES(vswp, ldcp, bp, bpt, count, 6817bd3a2e2SSriharsha Basavapatna total_count); 6827bd3a2e2SSriharsha Basavapatna } 6837bd3a2e2SSriharsha Basavapatna 6847bd3a2e2SSriharsha Basavapatna /* Send stopped signal to peer (sender) */ 6857bd3a2e2SSriharsha Basavapatna end_ix = lp->dringp->next_rxi; 6867bd3a2e2SSriharsha Basavapatna DECR_RXI(dp, end_ix); 6877bd3a2e2SSriharsha Basavapatna msgp->tag.vio_msgtype = VIO_TYPE_DATA; 6887bd3a2e2SSriharsha Basavapatna msgp->tag.vio_subtype = VIO_SUBTYPE_ACK; 6897bd3a2e2SSriharsha Basavapatna msgp->tag.vio_subtype_env = VIO_DRING_DATA; 6907bd3a2e2SSriharsha Basavapatna msgp->dring_ident = ldcp->lane_in.dringp->ident; 6917bd3a2e2SSriharsha Basavapatna msgp->tag.vio_sid = ldcp->local_session; 6927bd3a2e2SSriharsha Basavapatna msgp->dring_process_state = VIO_DP_STOPPED; 6937bd3a2e2SSriharsha Basavapatna msgp->start_idx = VNET_START_IDX_UNSPEC; 6947bd3a2e2SSriharsha Basavapatna msgp->end_idx = end_ix; 6957bd3a2e2SSriharsha Basavapatna 6967bd3a2e2SSriharsha Basavapatna (void) vsw_send_msg_shm(ldcp, (void *)msgp, 6977bd3a2e2SSriharsha Basavapatna sizeof (vio_dring_msg_t), B_TRUE); 6987bd3a2e2SSriharsha Basavapatna 6997bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.dring_data_acks_sent++; 7007bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.dring_stopped_acks_sent++; 7017bd3a2e2SSriharsha Basavapatna } 7027bd3a2e2SSriharsha Basavapatna 7037bd3a2e2SSriharsha Basavapatna /* 7047bd3a2e2SSriharsha Basavapatna * Process the next index in the rx dring and receive the associated packet. 7057bd3a2e2SSriharsha Basavapatna * 7067bd3a2e2SSriharsha Basavapatna * Returns: 7077bd3a2e2SSriharsha Basavapatna * bp: Success: The received packet. 7087bd3a2e2SSriharsha Basavapatna * Failure: NULL 7097bd3a2e2SSriharsha Basavapatna * retval: 7107bd3a2e2SSriharsha Basavapatna * Success: 0 7117bd3a2e2SSriharsha Basavapatna * Failure: EAGAIN: Descriptor not ready 7127bd3a2e2SSriharsha Basavapatna * EIO: Descriptor contents invalid. 7137bd3a2e2SSriharsha Basavapatna */ 7147bd3a2e2SSriharsha Basavapatna static int 7157bd3a2e2SSriharsha Basavapatna vsw_receive_packet(vsw_ldc_t *ldcp, mblk_t **bp) 7167bd3a2e2SSriharsha Basavapatna { 7177bd3a2e2SSriharsha Basavapatna uint32_t rxi; 7187bd3a2e2SSriharsha Basavapatna vio_mblk_t *vmp; 7197bd3a2e2SSriharsha Basavapatna vio_mblk_t *new_vmp; 7207bd3a2e2SSriharsha Basavapatna struct ether_header *ehp; 7217bd3a2e2SSriharsha Basavapatna vnet_rx_dringdata_desc_t *rxdp; 7227bd3a2e2SSriharsha Basavapatna int err = 0; 7237bd3a2e2SSriharsha Basavapatna uint_t nbytes = 0; 7247bd3a2e2SSriharsha Basavapatna mblk_t *mp = NULL; 7257bd3a2e2SSriharsha Basavapatna mblk_t *dmp = NULL; 7267bd3a2e2SSriharsha Basavapatna vgen_stats_t *statsp = &ldcp->ldc_stats; 7277bd3a2e2SSriharsha Basavapatna dring_info_t *dp = ldcp->lane_out.dringp; 7287bd3a2e2SSriharsha Basavapatna vnet_rx_dringdata_desc_t *pub_addr = dp->pub_addr; 7297bd3a2e2SSriharsha Basavapatna 7307bd3a2e2SSriharsha Basavapatna rxi = dp->next_rxi; 7317bd3a2e2SSriharsha Basavapatna rxdp = &(pub_addr[rxi]); 7327bd3a2e2SSriharsha Basavapatna vmp = dp->rxdp_to_vmp[rxi]; 7337bd3a2e2SSriharsha Basavapatna 7347bd3a2e2SSriharsha Basavapatna if (rxdp->dstate != VIO_DESC_READY) { 7357bd3a2e2SSriharsha Basavapatna /* 7367bd3a2e2SSriharsha Basavapatna * Descriptor is not ready. 7377bd3a2e2SSriharsha Basavapatna */ 7387bd3a2e2SSriharsha Basavapatna return (EAGAIN); 7397bd3a2e2SSriharsha Basavapatna } 7407bd3a2e2SSriharsha Basavapatna 7417bd3a2e2SSriharsha Basavapatna /* 7427bd3a2e2SSriharsha Basavapatna * Ensure load ordering of dstate and nbytes. 7437bd3a2e2SSriharsha Basavapatna */ 7447bd3a2e2SSriharsha Basavapatna MEMBAR_CONSUMER(); 7457bd3a2e2SSriharsha Basavapatna 7467bd3a2e2SSriharsha Basavapatna if ((rxdp->nbytes < ETHERMIN) || 7477bd3a2e2SSriharsha Basavapatna (rxdp->nbytes > ldcp->lane_in.mtu) || 7487bd3a2e2SSriharsha Basavapatna (rxdp->data_buf_offset != 7497bd3a2e2SSriharsha Basavapatna (VIO_MBLK_DATA_OFF(vmp) + VNET_IPALIGN))) { 7507bd3a2e2SSriharsha Basavapatna /* 7517bd3a2e2SSriharsha Basavapatna * Descriptor contents invalid. 7527bd3a2e2SSriharsha Basavapatna */ 7537bd3a2e2SSriharsha Basavapatna statsp->ierrors++; 7547bd3a2e2SSriharsha Basavapatna rxdp->dstate = VIO_DESC_DONE; 7557bd3a2e2SSriharsha Basavapatna err = EIO; 7567bd3a2e2SSriharsha Basavapatna goto done; 7577bd3a2e2SSriharsha Basavapatna } 7587bd3a2e2SSriharsha Basavapatna 7597bd3a2e2SSriharsha Basavapatna /* 7607bd3a2e2SSriharsha Basavapatna * Now allocate a new buffer for this descriptor before sending up the 7617bd3a2e2SSriharsha Basavapatna * buffer being processed. If that fails, stop processing; as we are 7627bd3a2e2SSriharsha Basavapatna * out of receive buffers. 7637bd3a2e2SSriharsha Basavapatna */ 7647bd3a2e2SSriharsha Basavapatna new_vmp = vio_allocb(dp->rx_vmp); 7657bd3a2e2SSriharsha Basavapatna 7667bd3a2e2SSriharsha Basavapatna /* 7677bd3a2e2SSriharsha Basavapatna * Process the current buffer being received. 7687bd3a2e2SSriharsha Basavapatna */ 7697bd3a2e2SSriharsha Basavapatna nbytes = rxdp->nbytes; 7707bd3a2e2SSriharsha Basavapatna mp = vmp->mp; 7717bd3a2e2SSriharsha Basavapatna 7727bd3a2e2SSriharsha Basavapatna if (new_vmp == NULL) { 7737bd3a2e2SSriharsha Basavapatna /* 7747bd3a2e2SSriharsha Basavapatna * We failed to get a new mapped buffer that is needed to 7757bd3a2e2SSriharsha Basavapatna * refill the descriptor. In that case, leave the current 7767bd3a2e2SSriharsha Basavapatna * buffer bound to the descriptor; allocate an mblk dynamically 7777bd3a2e2SSriharsha Basavapatna * and copy the contents of the buffer to the mblk. Then send 7787bd3a2e2SSriharsha Basavapatna * up this mblk. This way the sender has the same buffer as 7797bd3a2e2SSriharsha Basavapatna * before that can be used to send new data. 7807bd3a2e2SSriharsha Basavapatna */ 7817bd3a2e2SSriharsha Basavapatna statsp->norcvbuf++; 7827bd3a2e2SSriharsha Basavapatna dmp = allocb(nbytes + VNET_IPALIGN, BPRI_MED); 7837bd3a2e2SSriharsha Basavapatna bcopy(mp->b_rptr + VNET_IPALIGN, 7847bd3a2e2SSriharsha Basavapatna dmp->b_rptr + VNET_IPALIGN, nbytes); 7857bd3a2e2SSriharsha Basavapatna mp = dmp; 7867bd3a2e2SSriharsha Basavapatna } else { 7877bd3a2e2SSriharsha Basavapatna /* Mark the status of the current rbuf */ 7887bd3a2e2SSriharsha Basavapatna vmp->state = VIO_MBLK_HAS_DATA; 7897bd3a2e2SSriharsha Basavapatna 7907bd3a2e2SSriharsha Basavapatna /* Set the offset of the new buffer in the descriptor */ 7917bd3a2e2SSriharsha Basavapatna rxdp->data_buf_offset = 7927bd3a2e2SSriharsha Basavapatna VIO_MBLK_DATA_OFF(new_vmp) + VNET_IPALIGN; 7937bd3a2e2SSriharsha Basavapatna dp->rxdp_to_vmp[rxi] = new_vmp; 7947bd3a2e2SSriharsha Basavapatna } 7957bd3a2e2SSriharsha Basavapatna mp->b_rptr += VNET_IPALIGN; 7967bd3a2e2SSriharsha Basavapatna mp->b_wptr = mp->b_rptr + nbytes; 7977bd3a2e2SSriharsha Basavapatna 7987bd3a2e2SSriharsha Basavapatna /* 7997bd3a2e2SSriharsha Basavapatna * Ensure store ordering of data_buf_offset and dstate; so that the 8007bd3a2e2SSriharsha Basavapatna * peer sees the right data_buf_offset after it checks that the dstate 8017bd3a2e2SSriharsha Basavapatna * is DONE. 8027bd3a2e2SSriharsha Basavapatna */ 8037bd3a2e2SSriharsha Basavapatna MEMBAR_PRODUCER(); 8047bd3a2e2SSriharsha Basavapatna 8057bd3a2e2SSriharsha Basavapatna /* Now mark the descriptor 'done' */ 8067bd3a2e2SSriharsha Basavapatna rxdp->dstate = VIO_DESC_DONE; 8077bd3a2e2SSriharsha Basavapatna 8087bd3a2e2SSriharsha Basavapatna /* Update stats */ 8097bd3a2e2SSriharsha Basavapatna statsp->ipackets++; 8107bd3a2e2SSriharsha Basavapatna statsp->rbytes += rxdp->nbytes; 8117bd3a2e2SSriharsha Basavapatna ehp = (struct ether_header *)mp->b_rptr; 8127bd3a2e2SSriharsha Basavapatna if (IS_BROADCAST(ehp)) 8137bd3a2e2SSriharsha Basavapatna statsp->brdcstrcv++; 8147bd3a2e2SSriharsha Basavapatna else if (IS_MULTICAST(ehp)) 8157bd3a2e2SSriharsha Basavapatna statsp->multircv++; 8167bd3a2e2SSriharsha Basavapatna done: 8177bd3a2e2SSriharsha Basavapatna /* Update the next index to be processed */ 8187bd3a2e2SSriharsha Basavapatna INCR_RXI(dp, rxi); 8197bd3a2e2SSriharsha Basavapatna 8207bd3a2e2SSriharsha Basavapatna /* Save the new recv index */ 8217bd3a2e2SSriharsha Basavapatna dp->next_rxi = rxi; 8227bd3a2e2SSriharsha Basavapatna 8237bd3a2e2SSriharsha Basavapatna /* Return the packet received */ 8247bd3a2e2SSriharsha Basavapatna *bp = mp; 8257bd3a2e2SSriharsha Basavapatna return (err); 8267bd3a2e2SSriharsha Basavapatna } 8277bd3a2e2SSriharsha Basavapatna 8287bd3a2e2SSriharsha Basavapatna void 8297bd3a2e2SSriharsha Basavapatna vsw_stop_rcv_thread(vsw_ldc_t *ldcp) 8307bd3a2e2SSriharsha Basavapatna { 8317bd3a2e2SSriharsha Basavapatna kt_did_t tid = 0; 8327bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 8337bd3a2e2SSriharsha Basavapatna 8347bd3a2e2SSriharsha Basavapatna D1(vswp, "%s(%lld):enter\n", __func__, ldcp->ldc_id); 8357bd3a2e2SSriharsha Basavapatna /* 8367bd3a2e2SSriharsha Basavapatna * Send a stop request by setting the stop flag and 8377bd3a2e2SSriharsha Basavapatna * wait until the rcv process thread stops. 8387bd3a2e2SSriharsha Basavapatna */ 8397bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->rcv_thr_lock); 8407bd3a2e2SSriharsha Basavapatna if (ldcp->rcv_thread != NULL) { 8417bd3a2e2SSriharsha Basavapatna tid = ldcp->rcv_thread->t_did; 8427bd3a2e2SSriharsha Basavapatna ldcp->rcv_thr_flags |= VSW_WTHR_STOP; 8437bd3a2e2SSriharsha Basavapatna cv_signal(&ldcp->rcv_thr_cv); 8447bd3a2e2SSriharsha Basavapatna } 8457bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->rcv_thr_lock); 8467bd3a2e2SSriharsha Basavapatna 8477bd3a2e2SSriharsha Basavapatna if (tid != 0) { 8487bd3a2e2SSriharsha Basavapatna thread_join(tid); 8497bd3a2e2SSriharsha Basavapatna } 8507bd3a2e2SSriharsha Basavapatna D1(vswp, "%s(%lld):exit\n", __func__, ldcp->ldc_id); 8517bd3a2e2SSriharsha Basavapatna } 8527bd3a2e2SSriharsha Basavapatna 8537bd3a2e2SSriharsha Basavapatna int 8547bd3a2e2SSriharsha Basavapatna vsw_dringsend_shm(vsw_ldc_t *ldcp, mblk_t *mp) 8557bd3a2e2SSriharsha Basavapatna { 8567bd3a2e2SSriharsha Basavapatna uint32_t next_txi; 8577bd3a2e2SSriharsha Basavapatna uint32_t txi; 8587bd3a2e2SSriharsha Basavapatna vnet_rx_dringdata_desc_t *txdp; 8597bd3a2e2SSriharsha Basavapatna struct ether_header *ehp; 8607bd3a2e2SSriharsha Basavapatna size_t mblksz; 8617bd3a2e2SSriharsha Basavapatna caddr_t dst; 8627bd3a2e2SSriharsha Basavapatna mblk_t *bp; 8637bd3a2e2SSriharsha Basavapatna size_t size; 8647bd3a2e2SSriharsha Basavapatna on_trap_data_t otd; 8657bd3a2e2SSriharsha Basavapatna uint32_t buf_offset; 8667bd3a2e2SSriharsha Basavapatna vnet_rx_dringdata_desc_t *pub_addr; 8677bd3a2e2SSriharsha Basavapatna vio_dring_msg_t msg; 8687bd3a2e2SSriharsha Basavapatna vio_dring_msg_t *msgp = &msg; 8697bd3a2e2SSriharsha Basavapatna int rv = 0; 8707bd3a2e2SSriharsha Basavapatna boolean_t resched_peer = B_FALSE; 8717bd3a2e2SSriharsha Basavapatna boolean_t is_bcast = B_FALSE; 8727bd3a2e2SSriharsha Basavapatna boolean_t is_mcast = B_FALSE; 8737bd3a2e2SSriharsha Basavapatna vgen_stats_t *statsp = &ldcp->ldc_stats; 8747bd3a2e2SSriharsha Basavapatna lane_t *lane_in = &ldcp->lane_in; 8757bd3a2e2SSriharsha Basavapatna lane_t *lane_out = &ldcp->lane_out; 8767bd3a2e2SSriharsha Basavapatna dring_info_t *dp = lane_in->dringp; 8777bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 8787bd3a2e2SSriharsha Basavapatna 8797bd3a2e2SSriharsha Basavapatna if ((!(lane_in->lstate & VSW_LANE_ACTIVE)) || 8807bd3a2e2SSriharsha Basavapatna (ldcp->ldc_status != LDC_UP) || (ldcp->ldc_handle == NULL)) { 8817bd3a2e2SSriharsha Basavapatna DWARN(vswp, "%s(%lld) status(%d) lstate(0x%llx), dropping " 8827bd3a2e2SSriharsha Basavapatna "packet\n", __func__, ldcp->ldc_id, ldcp->ldc_status, 8837bd3a2e2SSriharsha Basavapatna lane_in->lstate); 8847bd3a2e2SSriharsha Basavapatna statsp->oerrors++; 8857bd3a2e2SSriharsha Basavapatna return (LDC_TX_FAILURE); 8867bd3a2e2SSriharsha Basavapatna } 8877bd3a2e2SSriharsha Basavapatna 8887bd3a2e2SSriharsha Basavapatna if (dp == NULL) { 8897bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s(%lld): no dring for outbound lane on" 8907bd3a2e2SSriharsha Basavapatna " channel %d", __func__, ldcp->ldc_id, ldcp->ldc_id); 8917bd3a2e2SSriharsha Basavapatna statsp->oerrors++; 8927bd3a2e2SSriharsha Basavapatna return (LDC_TX_FAILURE); 8937bd3a2e2SSriharsha Basavapatna } 8947bd3a2e2SSriharsha Basavapatna pub_addr = dp->pub_addr; 8957bd3a2e2SSriharsha Basavapatna 8967bd3a2e2SSriharsha Basavapatna size = msgsize(mp); 8977bd3a2e2SSriharsha Basavapatna 8987bd3a2e2SSriharsha Basavapatna /* 8997bd3a2e2SSriharsha Basavapatna * Note: In RxDringData mode, lane_in is associated with transmit and 9007bd3a2e2SSriharsha Basavapatna * lane_out is associated with receive. However, we still keep the 9017bd3a2e2SSriharsha Basavapatna * negotiated mtu in lane_out (our exported attributes). 9027bd3a2e2SSriharsha Basavapatna */ 9037bd3a2e2SSriharsha Basavapatna if (size > (size_t)lane_out->mtu) { 9047bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s(%lld) invalid size (%ld)\n", __func__, 9057bd3a2e2SSriharsha Basavapatna ldcp->ldc_id, size); 9067bd3a2e2SSriharsha Basavapatna statsp->oerrors++; 9077bd3a2e2SSriharsha Basavapatna return (LDC_TX_FAILURE); 9087bd3a2e2SSriharsha Basavapatna } 9097bd3a2e2SSriharsha Basavapatna 9107bd3a2e2SSriharsha Basavapatna if (size < ETHERMIN) 9117bd3a2e2SSriharsha Basavapatna size = ETHERMIN; 9127bd3a2e2SSriharsha Basavapatna 9137bd3a2e2SSriharsha Basavapatna ehp = (struct ether_header *)mp->b_rptr; 9147bd3a2e2SSriharsha Basavapatna is_bcast = IS_BROADCAST(ehp); 9157bd3a2e2SSriharsha Basavapatna is_mcast = IS_MULTICAST(ehp); 9167bd3a2e2SSriharsha Basavapatna 9177bd3a2e2SSriharsha Basavapatna /* 9187bd3a2e2SSriharsha Basavapatna * Setup on_trap() protection before accessing shared memory areas 9197bd3a2e2SSriharsha Basavapatna * (descriptor and data buffer). Note that we enable this protection a 9207bd3a2e2SSriharsha Basavapatna * little early and turn it off slightly later, than keeping it enabled 9217bd3a2e2SSriharsha Basavapatna * strictly at the points in code below where the descriptor and data 9227bd3a2e2SSriharsha Basavapatna * buffer are accessed. This is done for performance reasons: 9237bd3a2e2SSriharsha Basavapatna * (a) to avoid calling the trap protection code while holding mutex. 9247bd3a2e2SSriharsha Basavapatna * (b) to avoid multiple on/off steps for descriptor and data accesses. 9257bd3a2e2SSriharsha Basavapatna */ 9267bd3a2e2SSriharsha Basavapatna rv = LDC_ON_TRAP(&otd); 9277bd3a2e2SSriharsha Basavapatna if (rv != 0) { 9287bd3a2e2SSriharsha Basavapatna /* 9297bd3a2e2SSriharsha Basavapatna * Data access fault occured down the code path below while 9307bd3a2e2SSriharsha Basavapatna * accessing either the descriptor or the data buffer. Release 9317bd3a2e2SSriharsha Basavapatna * any locks that we might have acquired in the code below and 9327bd3a2e2SSriharsha Basavapatna * return failure. 9337bd3a2e2SSriharsha Basavapatna */ 9347bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s(%lld) data access fault occured\n", 9357bd3a2e2SSriharsha Basavapatna __func__, ldcp->ldc_id); 9367bd3a2e2SSriharsha Basavapatna statsp->oerrors++; 9377bd3a2e2SSriharsha Basavapatna if (mutex_owned(&dp->txlock)) { 9387bd3a2e2SSriharsha Basavapatna mutex_exit(&dp->txlock); 9397bd3a2e2SSriharsha Basavapatna } 9407bd3a2e2SSriharsha Basavapatna if (mutex_owned(&dp->restart_lock)) { 9417bd3a2e2SSriharsha Basavapatna mutex_exit(&dp->restart_lock); 9427bd3a2e2SSriharsha Basavapatna } 9437bd3a2e2SSriharsha Basavapatna goto dringsend_shm_exit; 9447bd3a2e2SSriharsha Basavapatna } 9457bd3a2e2SSriharsha Basavapatna 9467bd3a2e2SSriharsha Basavapatna /* 9477bd3a2e2SSriharsha Basavapatna * Allocate a descriptor 9487bd3a2e2SSriharsha Basavapatna */ 9497bd3a2e2SSriharsha Basavapatna mutex_enter(&dp->txlock); 9507bd3a2e2SSriharsha Basavapatna txi = next_txi = dp->next_txi; 9517bd3a2e2SSriharsha Basavapatna INCR_TXI(dp, next_txi); 9520e263307SWENTAO YANG txdp = &(pub_addr[txi]); 9530e263307SWENTAO YANG if (txdp->dstate != VIO_DESC_DONE) { /* out of descriptors */ 9547bd3a2e2SSriharsha Basavapatna statsp->tx_no_desc++; 9557bd3a2e2SSriharsha Basavapatna mutex_exit(&dp->txlock); 9567bd3a2e2SSriharsha Basavapatna (void) LDC_NO_TRAP(); 9577bd3a2e2SSriharsha Basavapatna return (LDC_TX_NORESOURCES); 9580e263307SWENTAO YANG } else { 9590e263307SWENTAO YANG txdp->dstate = VIO_DESC_INITIALIZING; 9607bd3a2e2SSriharsha Basavapatna } 9617bd3a2e2SSriharsha Basavapatna 9627bd3a2e2SSriharsha Basavapatna /* Update descriptor ring index */ 9637bd3a2e2SSriharsha Basavapatna dp->next_txi = next_txi; 9647bd3a2e2SSriharsha Basavapatna mutex_exit(&dp->txlock); 9657bd3a2e2SSriharsha Basavapatna 9667bd3a2e2SSriharsha Basavapatna /* Ensure load ordering of dstate (above) and data_buf_offset. */ 9677bd3a2e2SSriharsha Basavapatna MEMBAR_CONSUMER(); 9687bd3a2e2SSriharsha Basavapatna 9697bd3a2e2SSriharsha Basavapatna /* Get the offset of the buffer to be used */ 9707bd3a2e2SSriharsha Basavapatna buf_offset = txdp->data_buf_offset; 9717bd3a2e2SSriharsha Basavapatna 9727bd3a2e2SSriharsha Basavapatna /* Access the buffer using the offset */ 9737bd3a2e2SSriharsha Basavapatna dst = (caddr_t)dp->data_addr + buf_offset; 9747bd3a2e2SSriharsha Basavapatna 9757bd3a2e2SSriharsha Basavapatna /* Copy data into mapped transmit buffer */ 9767bd3a2e2SSriharsha Basavapatna for (bp = mp; bp != NULL; bp = bp->b_cont) { 9777bd3a2e2SSriharsha Basavapatna mblksz = MBLKL(bp); 9787bd3a2e2SSriharsha Basavapatna bcopy(bp->b_rptr, dst, mblksz); 9797bd3a2e2SSriharsha Basavapatna dst += mblksz; 9807bd3a2e2SSriharsha Basavapatna } 9817bd3a2e2SSriharsha Basavapatna 9827bd3a2e2SSriharsha Basavapatna /* Set the size of data in the descriptor */ 9837bd3a2e2SSriharsha Basavapatna txdp->nbytes = size; 9847bd3a2e2SSriharsha Basavapatna 9857bd3a2e2SSriharsha Basavapatna /* 9867bd3a2e2SSriharsha Basavapatna * Ensure store ordering of nbytes and dstate (below); so that the peer 9877bd3a2e2SSriharsha Basavapatna * sees the right nbytes value after it checks that the dstate is READY. 9887bd3a2e2SSriharsha Basavapatna */ 9897bd3a2e2SSriharsha Basavapatna MEMBAR_PRODUCER(); 9907bd3a2e2SSriharsha Basavapatna 9917bd3a2e2SSriharsha Basavapatna mutex_enter(&dp->restart_lock); 9927bd3a2e2SSriharsha Basavapatna 9930e263307SWENTAO YANG ASSERT(txdp->dstate == VIO_DESC_INITIALIZING); 9940e263307SWENTAO YANG 9957bd3a2e2SSriharsha Basavapatna /* Mark the descriptor ready */ 9967bd3a2e2SSriharsha Basavapatna txdp->dstate = VIO_DESC_READY; 9977bd3a2e2SSriharsha Basavapatna 9987bd3a2e2SSriharsha Basavapatna /* Check if peer needs wake up (handled below) */ 9990e263307SWENTAO YANG if (dp->restart_reqd == B_TRUE && dp->restart_peer_txi == txi) { 10007bd3a2e2SSriharsha Basavapatna dp->restart_reqd = B_FALSE; 10017bd3a2e2SSriharsha Basavapatna resched_peer = B_TRUE; 10027bd3a2e2SSriharsha Basavapatna } 10037bd3a2e2SSriharsha Basavapatna 10047bd3a2e2SSriharsha Basavapatna /* Update tx stats */ 10057bd3a2e2SSriharsha Basavapatna statsp->opackets++; 10067bd3a2e2SSriharsha Basavapatna statsp->obytes += size; 10077bd3a2e2SSriharsha Basavapatna if (is_bcast) 10087bd3a2e2SSriharsha Basavapatna statsp->brdcstxmt++; 10097bd3a2e2SSriharsha Basavapatna else if (is_mcast) 10107bd3a2e2SSriharsha Basavapatna statsp->multixmt++; 10117bd3a2e2SSriharsha Basavapatna 10127bd3a2e2SSriharsha Basavapatna mutex_exit(&dp->restart_lock); 10137bd3a2e2SSriharsha Basavapatna 10147bd3a2e2SSriharsha Basavapatna /* 10157bd3a2e2SSriharsha Basavapatna * We are done accessing shared memory; clear trap protection. 10167bd3a2e2SSriharsha Basavapatna */ 10177bd3a2e2SSriharsha Basavapatna (void) LDC_NO_TRAP(); 10187bd3a2e2SSriharsha Basavapatna 10197bd3a2e2SSriharsha Basavapatna /* 10207bd3a2e2SSriharsha Basavapatna * Need to wake up the peer ? 10217bd3a2e2SSriharsha Basavapatna */ 10227bd3a2e2SSriharsha Basavapatna if (resched_peer == B_TRUE) { 10237bd3a2e2SSriharsha Basavapatna msgp->tag.vio_msgtype = VIO_TYPE_DATA; 10247bd3a2e2SSriharsha Basavapatna msgp->tag.vio_subtype = VIO_SUBTYPE_INFO; 10257bd3a2e2SSriharsha Basavapatna msgp->tag.vio_subtype_env = VIO_DRING_DATA; 10267bd3a2e2SSriharsha Basavapatna msgp->tag.vio_sid = ldcp->local_session; 10277bd3a2e2SSriharsha Basavapatna msgp->dring_ident = lane_out->dringp->ident; 10287bd3a2e2SSriharsha Basavapatna msgp->start_idx = txi; 10297bd3a2e2SSriharsha Basavapatna msgp->end_idx = -1; 10307bd3a2e2SSriharsha Basavapatna 10317bd3a2e2SSriharsha Basavapatna rv = vsw_send_msg_shm(ldcp, (void *)msgp, sizeof (*msgp), 10327bd3a2e2SSriharsha Basavapatna B_FALSE); 10337bd3a2e2SSriharsha Basavapatna if (rv != 0) { 10347bd3a2e2SSriharsha Basavapatna /* error: drop the packet */ 10357bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s(%lld) failed sending dringdata msg\n", 10367bd3a2e2SSriharsha Basavapatna __func__, ldcp->ldc_id); 10377bd3a2e2SSriharsha Basavapatna mutex_enter(&dp->restart_lock); 10387bd3a2e2SSriharsha Basavapatna statsp->oerrors++; 10397bd3a2e2SSriharsha Basavapatna dp->restart_reqd = B_TRUE; 10407bd3a2e2SSriharsha Basavapatna mutex_exit(&dp->restart_lock); 10417bd3a2e2SSriharsha Basavapatna } 10427bd3a2e2SSriharsha Basavapatna statsp->dring_data_msgs_sent++; 10437bd3a2e2SSriharsha Basavapatna } 10447bd3a2e2SSriharsha Basavapatna 10457bd3a2e2SSriharsha Basavapatna dringsend_shm_exit: 10467bd3a2e2SSriharsha Basavapatna if (rv == ECONNRESET || rv == EACCES) { 10477bd3a2e2SSriharsha Basavapatna vsw_process_conn_evt(ldcp, VSW_CONN_RESET); 10487bd3a2e2SSriharsha Basavapatna } 10497bd3a2e2SSriharsha Basavapatna return (LDC_TX_SUCCESS); 10507bd3a2e2SSriharsha Basavapatna } 10517bd3a2e2SSriharsha Basavapatna 10527bd3a2e2SSriharsha Basavapatna void 10537bd3a2e2SSriharsha Basavapatna vsw_process_dringdata_shm(void *arg, void *dpkt) 10547bd3a2e2SSriharsha Basavapatna { 10557bd3a2e2SSriharsha Basavapatna vsw_ldc_t *ldcp = arg; 10567bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 10577bd3a2e2SSriharsha Basavapatna vio_dring_msg_t *dring_pkt = dpkt; 10587bd3a2e2SSriharsha Basavapatna 10597bd3a2e2SSriharsha Basavapatna switch (dring_pkt->tag.vio_subtype) { 10607bd3a2e2SSriharsha Basavapatna case VIO_SUBTYPE_INFO: 10617bd3a2e2SSriharsha Basavapatna D2(vswp, "%s(%lld): VIO_SUBTYPE_INFO", __func__, ldcp->ldc_id); 10627bd3a2e2SSriharsha Basavapatna vsw_process_dringdata_info_shm(ldcp, dring_pkt); 10637bd3a2e2SSriharsha Basavapatna break; 10647bd3a2e2SSriharsha Basavapatna 10657bd3a2e2SSriharsha Basavapatna case VIO_SUBTYPE_ACK: 10667bd3a2e2SSriharsha Basavapatna D2(vswp, "%s(%lld): VIO_SUBTYPE_ACK", __func__, ldcp->ldc_id); 10677bd3a2e2SSriharsha Basavapatna vsw_process_dringdata_ack_shm(ldcp, dring_pkt); 10687bd3a2e2SSriharsha Basavapatna break; 10697bd3a2e2SSriharsha Basavapatna 10707bd3a2e2SSriharsha Basavapatna case VIO_SUBTYPE_NACK: 10717bd3a2e2SSriharsha Basavapatna DWARN(vswp, "%s(%lld): VIO_SUBTYPE_NACK", 10727bd3a2e2SSriharsha Basavapatna __func__, ldcp->ldc_id); 10737bd3a2e2SSriharsha Basavapatna /* 10747bd3a2e2SSriharsha Basavapatna * Something is badly wrong if we are getting NACK's 10757bd3a2e2SSriharsha Basavapatna * for our data pkts. So reset the channel. 10767bd3a2e2SSriharsha Basavapatna */ 10777bd3a2e2SSriharsha Basavapatna vsw_process_conn_evt(ldcp, VSW_CONN_RESTART); 10787bd3a2e2SSriharsha Basavapatna break; 10797bd3a2e2SSriharsha Basavapatna 10807bd3a2e2SSriharsha Basavapatna default: 10817bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s(%lld): Unknown vio_subtype %x\n", __func__, 10827bd3a2e2SSriharsha Basavapatna ldcp->ldc_id, dring_pkt->tag.vio_subtype); 10837bd3a2e2SSriharsha Basavapatna } 10847bd3a2e2SSriharsha Basavapatna } 10857bd3a2e2SSriharsha Basavapatna 10867bd3a2e2SSriharsha Basavapatna static void 10877bd3a2e2SSriharsha Basavapatna vsw_process_dringdata_info_shm(vsw_ldc_t *ldcp, vio_dring_msg_t *msg) 10887bd3a2e2SSriharsha Basavapatna { 10897bd3a2e2SSriharsha Basavapatna dring_info_t *dp = ldcp->lane_in.dringp; 10907bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 10917bd3a2e2SSriharsha Basavapatna vgen_stats_t *statsp = &ldcp->ldc_stats; 10927bd3a2e2SSriharsha Basavapatna 10937bd3a2e2SSriharsha Basavapatna if (dp->ident != msg->dring_ident) { 10947bd3a2e2SSriharsha Basavapatna /* drop the message */ 10957bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s(%lld): Invalid dring ident 0x%llx", 10967bd3a2e2SSriharsha Basavapatna __func__, ldcp->ldc_id, msg->dring_ident); 10977bd3a2e2SSriharsha Basavapatna return; 10987bd3a2e2SSriharsha Basavapatna } 10997bd3a2e2SSriharsha Basavapatna 11007bd3a2e2SSriharsha Basavapatna statsp->dring_data_msgs_rcvd++; 11017bd3a2e2SSriharsha Basavapatna 11027bd3a2e2SSriharsha Basavapatna /* 11037bd3a2e2SSriharsha Basavapatna * Wake up the rcv worker thread to process the rx dring. 11047bd3a2e2SSriharsha Basavapatna */ 11057bd3a2e2SSriharsha Basavapatna ASSERT(MUTEX_HELD(&ldcp->ldc_cblock)); 11067bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->ldc_cblock); 11077bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->rcv_thr_lock); 11087bd3a2e2SSriharsha Basavapatna if (!(ldcp->rcv_thr_flags & VSW_WTHR_DATARCVD)) { 11097bd3a2e2SSriharsha Basavapatna ldcp->rcv_thr_flags |= VSW_WTHR_DATARCVD; 11107bd3a2e2SSriharsha Basavapatna cv_signal(&ldcp->rcv_thr_cv); 11117bd3a2e2SSriharsha Basavapatna } 11127bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->rcv_thr_lock); 11137bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->ldc_cblock); 11147bd3a2e2SSriharsha Basavapatna } 11157bd3a2e2SSriharsha Basavapatna 11167bd3a2e2SSriharsha Basavapatna static void 11177bd3a2e2SSriharsha Basavapatna vsw_process_dringdata_ack_shm(vsw_ldc_t *ldcp, vio_dring_msg_t *msg) 11187bd3a2e2SSriharsha Basavapatna { 11197bd3a2e2SSriharsha Basavapatna dring_info_t *dp; 11207bd3a2e2SSriharsha Basavapatna uint32_t start; 11217bd3a2e2SSriharsha Basavapatna int32_t end; 11227bd3a2e2SSriharsha Basavapatna int rv; 11237bd3a2e2SSriharsha Basavapatna on_trap_data_t otd; 11247bd3a2e2SSriharsha Basavapatna uint32_t txi; 11257bd3a2e2SSriharsha Basavapatna vnet_rx_dringdata_desc_t *txdp; 11267bd3a2e2SSriharsha Basavapatna vnet_rx_dringdata_desc_t *pub_addr; 11277bd3a2e2SSriharsha Basavapatna boolean_t ready_txd = B_FALSE; 11287bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 11297bd3a2e2SSriharsha Basavapatna vgen_stats_t *statsp = &ldcp->ldc_stats; 11307bd3a2e2SSriharsha Basavapatna 11317bd3a2e2SSriharsha Basavapatna dp = ldcp->lane_in.dringp; 11327bd3a2e2SSriharsha Basavapatna start = msg->start_idx; 11337bd3a2e2SSriharsha Basavapatna end = msg->end_idx; 11347bd3a2e2SSriharsha Basavapatna pub_addr = dp->pub_addr; 11357bd3a2e2SSriharsha Basavapatna 11367bd3a2e2SSriharsha Basavapatna /* 11377bd3a2e2SSriharsha Basavapatna * In RxDringData mode (v1.6), start index of -1 can be used by the 11387bd3a2e2SSriharsha Basavapatna * peer to indicate that it is unspecified. However, the end index 11397bd3a2e2SSriharsha Basavapatna * must be set correctly indicating the last descriptor index processed. 11407bd3a2e2SSriharsha Basavapatna */ 11417bd3a2e2SSriharsha Basavapatna if (((start != VNET_START_IDX_UNSPEC) && !(CHECK_TXI(dp, start))) || 11427bd3a2e2SSriharsha Basavapatna !(CHECK_TXI(dp, end))) { 11437bd3a2e2SSriharsha Basavapatna /* drop the message if invalid index */ 11447bd3a2e2SSriharsha Basavapatna DWARN(vswp, "%s(%lld): Invalid Tx ack start(%d) or end(%d)\n", 11457bd3a2e2SSriharsha Basavapatna __func__, ldcp->ldc_id, start, end); 11467bd3a2e2SSriharsha Basavapatna return; 11477bd3a2e2SSriharsha Basavapatna } 11487bd3a2e2SSriharsha Basavapatna 11497bd3a2e2SSriharsha Basavapatna /* Validate dring_ident */ 11507bd3a2e2SSriharsha Basavapatna if (msg->dring_ident != ldcp->lane_out.dringp->ident) { 11517bd3a2e2SSriharsha Basavapatna /* invalid dring_ident, drop the msg */ 11527bd3a2e2SSriharsha Basavapatna DWARN(vswp, "%s(%lld): Invalid dring ident 0x%x\n", 11537bd3a2e2SSriharsha Basavapatna __func__, ldcp->ldc_id, msg->dring_ident); 11547bd3a2e2SSriharsha Basavapatna return; 11557bd3a2e2SSriharsha Basavapatna } 11567bd3a2e2SSriharsha Basavapatna statsp->dring_data_acks_rcvd++; 11577bd3a2e2SSriharsha Basavapatna 11587bd3a2e2SSriharsha Basavapatna if (msg->dring_process_state != VIO_DP_STOPPED) { 11597bd3a2e2SSriharsha Basavapatna /* 11607bd3a2e2SSriharsha Basavapatna * Receiver continued processing 11617bd3a2e2SSriharsha Basavapatna * dring after sending us the ack. 11627bd3a2e2SSriharsha Basavapatna */ 11637bd3a2e2SSriharsha Basavapatna return; 11647bd3a2e2SSriharsha Basavapatna } 11657bd3a2e2SSriharsha Basavapatna 11667bd3a2e2SSriharsha Basavapatna statsp->dring_stopped_acks_rcvd++; 11677bd3a2e2SSriharsha Basavapatna 11687bd3a2e2SSriharsha Basavapatna /* 11697bd3a2e2SSriharsha Basavapatna * Setup on_trap() protection before accessing dring shared memory area. 11707bd3a2e2SSriharsha Basavapatna */ 11717bd3a2e2SSriharsha Basavapatna rv = LDC_ON_TRAP(&otd); 11727bd3a2e2SSriharsha Basavapatna if (rv != 0) { 11737bd3a2e2SSriharsha Basavapatna /* 11747bd3a2e2SSriharsha Basavapatna * Data access fault occured down the code path below while 11757bd3a2e2SSriharsha Basavapatna * accessing the descriptors. Release any locks that we might 11767bd3a2e2SSriharsha Basavapatna * have acquired in the code below and return failure. 11777bd3a2e2SSriharsha Basavapatna */ 11787bd3a2e2SSriharsha Basavapatna if (mutex_owned(&dp->restart_lock)) { 11797bd3a2e2SSriharsha Basavapatna mutex_exit(&dp->restart_lock); 11807bd3a2e2SSriharsha Basavapatna } 11817bd3a2e2SSriharsha Basavapatna return; 11827bd3a2e2SSriharsha Basavapatna } 11837bd3a2e2SSriharsha Basavapatna 11847bd3a2e2SSriharsha Basavapatna /* 11857bd3a2e2SSriharsha Basavapatna * Determine if there are any pending tx descriptors ready to be 11867bd3a2e2SSriharsha Basavapatna * processed by the receiver(peer) and if so, send a message to the 11877bd3a2e2SSriharsha Basavapatna * peer to restart receiving. 11887bd3a2e2SSriharsha Basavapatna */ 11897bd3a2e2SSriharsha Basavapatna mutex_enter(&dp->restart_lock); 11907bd3a2e2SSriharsha Basavapatna 11917bd3a2e2SSriharsha Basavapatna ready_txd = B_FALSE; 11927bd3a2e2SSriharsha Basavapatna txi = end; 11937bd3a2e2SSriharsha Basavapatna INCR_TXI(dp, txi); 11947bd3a2e2SSriharsha Basavapatna txdp = &pub_addr[txi]; 11957bd3a2e2SSriharsha Basavapatna if (txdp->dstate == VIO_DESC_READY) { 11967bd3a2e2SSriharsha Basavapatna ready_txd = B_TRUE; 11977bd3a2e2SSriharsha Basavapatna } 11987bd3a2e2SSriharsha Basavapatna 11997bd3a2e2SSriharsha Basavapatna /* 12007bd3a2e2SSriharsha Basavapatna * We are done accessing shared memory; clear trap protection. 12017bd3a2e2SSriharsha Basavapatna */ 12027bd3a2e2SSriharsha Basavapatna (void) LDC_NO_TRAP(); 12037bd3a2e2SSriharsha Basavapatna 12047bd3a2e2SSriharsha Basavapatna if (ready_txd == B_FALSE) { 12057bd3a2e2SSriharsha Basavapatna /* 12067bd3a2e2SSriharsha Basavapatna * No ready tx descriptors. Set the flag to send a message to 12077bd3a2e2SSriharsha Basavapatna * the peer when tx descriptors are ready in transmit routine. 12087bd3a2e2SSriharsha Basavapatna */ 12097bd3a2e2SSriharsha Basavapatna dp->restart_reqd = B_TRUE; 12100e263307SWENTAO YANG dp->restart_peer_txi = txi; 12117bd3a2e2SSriharsha Basavapatna mutex_exit(&dp->restart_lock); 12127bd3a2e2SSriharsha Basavapatna return; 12137bd3a2e2SSriharsha Basavapatna } 12147bd3a2e2SSriharsha Basavapatna 12157bd3a2e2SSriharsha Basavapatna /* 12167bd3a2e2SSriharsha Basavapatna * We have some tx descriptors ready to be processed by the receiver. 12177bd3a2e2SSriharsha Basavapatna * Send a dring data message to the peer to restart processing. 12187bd3a2e2SSriharsha Basavapatna */ 12197bd3a2e2SSriharsha Basavapatna dp->restart_reqd = B_FALSE; 12207bd3a2e2SSriharsha Basavapatna mutex_exit(&dp->restart_lock); 12217bd3a2e2SSriharsha Basavapatna 12227bd3a2e2SSriharsha Basavapatna msg->tag.vio_msgtype = VIO_TYPE_DATA; 12237bd3a2e2SSriharsha Basavapatna msg->tag.vio_subtype = VIO_SUBTYPE_INFO; 12247bd3a2e2SSriharsha Basavapatna msg->tag.vio_subtype_env = VIO_DRING_DATA; 12257bd3a2e2SSriharsha Basavapatna msg->tag.vio_sid = ldcp->local_session; 12267bd3a2e2SSriharsha Basavapatna msg->dring_ident = ldcp->lane_out.dringp->ident; 12277bd3a2e2SSriharsha Basavapatna msg->start_idx = txi; 12287bd3a2e2SSriharsha Basavapatna msg->end_idx = -1; 12297bd3a2e2SSriharsha Basavapatna rv = vsw_send_msg_shm(ldcp, (void *)msg, 12307bd3a2e2SSriharsha Basavapatna sizeof (vio_dring_msg_t), B_FALSE); 12317bd3a2e2SSriharsha Basavapatna statsp->dring_data_msgs_sent++; 12327bd3a2e2SSriharsha Basavapatna if (rv != 0) { 12337bd3a2e2SSriharsha Basavapatna mutex_enter(&dp->restart_lock); 12347bd3a2e2SSriharsha Basavapatna dp->restart_reqd = B_TRUE; 12357bd3a2e2SSriharsha Basavapatna mutex_exit(&dp->restart_lock); 12367bd3a2e2SSriharsha Basavapatna } 12377bd3a2e2SSriharsha Basavapatna 12387bd3a2e2SSriharsha Basavapatna if (rv == ECONNRESET) { 12397bd3a2e2SSriharsha Basavapatna vsw_process_conn_evt(ldcp, VSW_CONN_RESET); 12407bd3a2e2SSriharsha Basavapatna } 12417bd3a2e2SSriharsha Basavapatna } 12427bd3a2e2SSriharsha Basavapatna 12437bd3a2e2SSriharsha Basavapatna /* 12447bd3a2e2SSriharsha Basavapatna * Send dring data msgs (info/ack/nack) over LDC. 12457bd3a2e2SSriharsha Basavapatna */ 12467bd3a2e2SSriharsha Basavapatna int 12477bd3a2e2SSriharsha Basavapatna vsw_send_msg_shm(vsw_ldc_t *ldcp, void *msgp, int size, boolean_t handle_reset) 12487bd3a2e2SSriharsha Basavapatna { 12497bd3a2e2SSriharsha Basavapatna int rv; 12507bd3a2e2SSriharsha Basavapatna int retries = vsw_wretries; 12517bd3a2e2SSriharsha Basavapatna size_t msglen = size; 12527bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 12537bd3a2e2SSriharsha Basavapatna vio_dring_msg_t *dmsg = (vio_dring_msg_t *)msgp; 12547bd3a2e2SSriharsha Basavapatna 12557bd3a2e2SSriharsha Basavapatna D1(vswp, "vsw_send_msg (%lld) enter : sending %d bytes", 12567bd3a2e2SSriharsha Basavapatna ldcp->ldc_id, size); 12577bd3a2e2SSriharsha Basavapatna 12587bd3a2e2SSriharsha Basavapatna dmsg->seq_num = atomic_inc_32_nv(&ldcp->dringdata_msgid); 12597bd3a2e2SSriharsha Basavapatna 12607bd3a2e2SSriharsha Basavapatna do { 12617bd3a2e2SSriharsha Basavapatna msglen = size; 12627bd3a2e2SSriharsha Basavapatna rv = ldc_write(ldcp->ldc_handle, (caddr_t)msgp, &msglen); 12637bd3a2e2SSriharsha Basavapatna } while (rv == EWOULDBLOCK && --retries > 0); 12647bd3a2e2SSriharsha Basavapatna 12657bd3a2e2SSriharsha Basavapatna if ((rv != 0) || (msglen != size)) { 12667bd3a2e2SSriharsha Basavapatna DERR(vswp, "vsw_send_msg_shm:ldc_write failed: " 12677bd3a2e2SSriharsha Basavapatna "chan(%lld) rv(%d) size (%d) msglen(%d)\n", 12687bd3a2e2SSriharsha Basavapatna ldcp->ldc_id, rv, size, msglen); 12697bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.oerrors++; 12707bd3a2e2SSriharsha Basavapatna } 12717bd3a2e2SSriharsha Basavapatna 12727bd3a2e2SSriharsha Basavapatna /* 12737bd3a2e2SSriharsha Basavapatna * If channel has been reset we either handle it here or 12747bd3a2e2SSriharsha Basavapatna * simply report back that it has been reset and let caller 12757bd3a2e2SSriharsha Basavapatna * decide what to do. 12767bd3a2e2SSriharsha Basavapatna */ 12777bd3a2e2SSriharsha Basavapatna if (rv == ECONNRESET) { 12787bd3a2e2SSriharsha Basavapatna DWARN(vswp, "%s (%lld) channel reset", __func__, ldcp->ldc_id); 12797bd3a2e2SSriharsha Basavapatna 12807bd3a2e2SSriharsha Basavapatna if (handle_reset) { 12817bd3a2e2SSriharsha Basavapatna vsw_process_conn_evt(ldcp, VSW_CONN_RESET); 12827bd3a2e2SSriharsha Basavapatna } 12837bd3a2e2SSriharsha Basavapatna } 12847bd3a2e2SSriharsha Basavapatna 12857bd3a2e2SSriharsha Basavapatna return (rv); 12867bd3a2e2SSriharsha Basavapatna } 1287