11bbe869eSHoward Wang /* SPDX-License-Identifier: BSD-3-Clause 21bbe869eSHoward Wang * Copyright(c) 2024 Realtek Corporation. All rights reserved 31bbe869eSHoward Wang */ 41bbe869eSHoward Wang 51bbe869eSHoward Wang #include <stdio.h> 62f198f0aSHoward Wang #include <errno.h> 71bbe869eSHoward Wang #include <stdint.h> 81bbe869eSHoward Wang 91bbe869eSHoward Wang #include <rte_eal.h> 101bbe869eSHoward Wang 111bbe869eSHoward Wang #include <rte_common.h> 122f198f0aSHoward Wang #include <rte_interrupts.h> 132f198f0aSHoward Wang #include <rte_byteorder.h> 142f198f0aSHoward Wang #include <rte_debug.h> 151bbe869eSHoward Wang #include <rte_pci.h> 161bbe869eSHoward Wang #include <bus_pci_driver.h> 172f198f0aSHoward Wang #include <rte_ether.h> 181bbe869eSHoward Wang #include <ethdev_driver.h> 191bbe869eSHoward Wang #include <ethdev_pci.h> 202f198f0aSHoward Wang #include <rte_memory.h> 212f198f0aSHoward Wang #include <rte_malloc.h> 221bbe869eSHoward Wang #include <dev_driver.h> 231bbe869eSHoward Wang 241bbe869eSHoward Wang #include "r8169_ethdev.h" 252f198f0aSHoward Wang #include "r8169_hw.h" 262f198f0aSHoward Wang #include "r8169_logs.h" 271bbe869eSHoward Wang 28*63d37ff9SHoward Wang /* Bit mask to indicate what bits required for building TX context */ 29*63d37ff9SHoward Wang #define RTL_TX_OFFLOAD_MASK (RTE_MBUF_F_TX_IPV6 | \ 30*63d37ff9SHoward Wang RTE_MBUF_F_TX_IPV4 | \ 31*63d37ff9SHoward Wang RTE_MBUF_F_TX_VLAN | \ 32*63d37ff9SHoward Wang RTE_MBUF_F_TX_IP_CKSUM | \ 33*63d37ff9SHoward Wang RTE_MBUF_F_TX_L4_MASK | \ 34*63d37ff9SHoward Wang RTE_MBUF_F_TX_TCP_SEG) 35*63d37ff9SHoward Wang 36*63d37ff9SHoward Wang #define MIN_PATCH_LENGTH 47 37*63d37ff9SHoward Wang #define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ 38*63d37ff9SHoward Wang 39*63d37ff9SHoward Wang /* Struct TxDesc in kernel r8169 */ 40*63d37ff9SHoward Wang struct rtl_tx_desc { 41*63d37ff9SHoward Wang u32 opts1; 42*63d37ff9SHoward Wang u32 opts2; 43*63d37ff9SHoward Wang u64 addr; 44*63d37ff9SHoward Wang u32 reserved0; 45*63d37ff9SHoward Wang u32 reserved1; 46*63d37ff9SHoward Wang u32 reserved2; 47*63d37ff9SHoward Wang u32 reserved3; 48*63d37ff9SHoward Wang }; 49*63d37ff9SHoward Wang 502f198f0aSHoward Wang /* Struct RxDesc in kernel r8169 */ 512f198f0aSHoward Wang struct rtl_rx_desc { 522f198f0aSHoward Wang u32 opts1; 532f198f0aSHoward Wang u32 opts2; 542f198f0aSHoward Wang u64 addr; 552f198f0aSHoward Wang }; 562f198f0aSHoward Wang 57*63d37ff9SHoward Wang /* Structure associated with each descriptor of the TX ring of a TX queue. */ 58*63d37ff9SHoward Wang struct rtl_tx_entry { 59*63d37ff9SHoward Wang struct rte_mbuf *mbuf; 60*63d37ff9SHoward Wang }; 61*63d37ff9SHoward Wang 622f198f0aSHoward Wang /* Structure associated with each descriptor of the RX ring of a RX queue. */ 632f198f0aSHoward Wang struct rtl_rx_entry { 642f198f0aSHoward Wang struct rte_mbuf *mbuf; 652f198f0aSHoward Wang }; 662f198f0aSHoward Wang 67*63d37ff9SHoward Wang /* Structure associated with each TX queue. */ 68*63d37ff9SHoward Wang struct rtl_tx_queue { 69*63d37ff9SHoward Wang struct rtl_tx_desc *hw_ring; 70*63d37ff9SHoward Wang struct rtl_tx_entry *sw_ring; 71*63d37ff9SHoward Wang struct rtl_hw *hw; 72*63d37ff9SHoward Wang uint64_t hw_ring_phys_addr; 73*63d37ff9SHoward Wang uint16_t nb_tx_desc; 74*63d37ff9SHoward Wang RTE_ATOMIC(uint32_t) tx_tail; 75*63d37ff9SHoward Wang uint16_t tx_head; 76*63d37ff9SHoward Wang uint16_t queue_id; 77*63d37ff9SHoward Wang uint16_t port_id; 78*63d37ff9SHoward Wang uint16_t tx_free_thresh; 79*63d37ff9SHoward Wang uint16_t tx_free; 80*63d37ff9SHoward Wang }; 81*63d37ff9SHoward Wang 822f198f0aSHoward Wang /* Structure associated with each RX queue. */ 832f198f0aSHoward Wang struct rtl_rx_queue { 842f198f0aSHoward Wang struct rte_mempool *mb_pool; 852f198f0aSHoward Wang struct rtl_rx_desc *hw_ring; 862f198f0aSHoward Wang struct rtl_rx_entry *sw_ring; 872f198f0aSHoward Wang struct rte_mbuf *pkt_first_seg; /* First segment of current packet. */ 882f198f0aSHoward Wang struct rte_mbuf *pkt_last_seg; /* Last segment of current packet. */ 892f198f0aSHoward Wang struct rtl_hw *hw; 902f198f0aSHoward Wang uint64_t hw_ring_phys_addr; 912f198f0aSHoward Wang uint64_t offloads; 922f198f0aSHoward Wang uint16_t nb_rx_desc; 932f198f0aSHoward Wang uint16_t rx_tail; 942f198f0aSHoward Wang uint16_t nb_rx_hold; 952f198f0aSHoward Wang uint16_t queue_id; 962f198f0aSHoward Wang uint16_t port_id; 972f198f0aSHoward Wang uint16_t rx_free_thresh; 982f198f0aSHoward Wang }; 992f198f0aSHoward Wang 1002f198f0aSHoward Wang enum _DescStatusBit { 1012f198f0aSHoward Wang DescOwn = (1 << 31), /* Descriptor is owned by NIC. */ 1022f198f0aSHoward Wang RingEnd = (1 << 30), /* End of descriptor ring */ 1032f198f0aSHoward Wang FirstFrag = (1 << 29), /* First segment of a packet */ 1042f198f0aSHoward Wang LastFrag = (1 << 28), /* Final segment of a packet */ 1052f198f0aSHoward Wang 1062f198f0aSHoward Wang DescOwn_V3 = DescOwn, /* Descriptor is owned by NIC. */ 1072f198f0aSHoward Wang RingEnd_V3 = RingEnd, /* End of descriptor ring */ 1082f198f0aSHoward Wang FirstFrag_V3 = (1 << 25), /* First segment of a packet */ 1092f198f0aSHoward Wang LastFrag_V3 = (1 << 24), /* Final segment of a packet */ 1102f198f0aSHoward Wang 1112f198f0aSHoward Wang /* TX private */ 1122f198f0aSHoward Wang /*------ offset 0 of TX descriptor ------*/ 1132f198f0aSHoward Wang LargeSend = (1 << 27), /* TCP Large Send Offload (TSO) */ 1142f198f0aSHoward Wang GiantSendv4 = (1 << 26), /* TCP Giant Send Offload V4 (GSOv4) */ 1152f198f0aSHoward Wang GiantSendv6 = (1 << 25), /* TCP Giant Send Offload V6 (GSOv6) */ 1162f198f0aSHoward Wang LargeSend_DP = (1 << 16), /* TCP Large Send Offload (TSO) */ 1172f198f0aSHoward Wang MSSShift = 16, /* MSS value position */ 1182f198f0aSHoward Wang MSSMask = 0x7FFU, /* MSS value 11 bits */ 1192f198f0aSHoward Wang TxIPCS = (1 << 18), /* Calculate IP checksum */ 1202f198f0aSHoward Wang TxUDPCS = (1 << 17), /* Calculate UDP/IP checksum */ 1212f198f0aSHoward Wang TxTCPCS = (1 << 16), /* Calculate TCP/IP checksum */ 1222f198f0aSHoward Wang TxVlanTag = (1 << 17), /* Add VLAN tag */ 1232f198f0aSHoward Wang 1242f198f0aSHoward Wang /*@@@@@@ offset 4 of TX descriptor => bits for RTL8169 only begin @@@@@@*/ 1252f198f0aSHoward Wang TxUDPCS_C = (1 << 31), /* Calculate UDP/IP checksum */ 1262f198f0aSHoward Wang TxTCPCS_C = (1 << 30), /* Calculate TCP/IP checksum */ 1272f198f0aSHoward Wang TxIPCS_C = (1 << 29), /* Calculate IP checksum */ 1282f198f0aSHoward Wang TxIPV6F_C = (1 << 28), /* Indicate it is an IPv6 packet */ 1292f198f0aSHoward Wang /*@@@@@@ offset 4 of tx descriptor => bits for RTL8169 only end @@@@@@*/ 1302f198f0aSHoward Wang 1312f198f0aSHoward Wang /* RX private */ 1322f198f0aSHoward Wang /* ------ offset 0 of RX descriptor ------ */ 1332f198f0aSHoward Wang PID1 = (1 << 18), /* Protocol ID bit 1/2 */ 1342f198f0aSHoward Wang PID0 = (1 << 17), /* Protocol ID bit 2/2 */ 1352f198f0aSHoward Wang 1362f198f0aSHoward Wang #define RxProtoUDP PID1 1372f198f0aSHoward Wang #define RxProtoTCP PID0 1382f198f0aSHoward Wang #define RxProtoIP (PID1 | PID0) 1392f198f0aSHoward Wang #define RxProtoMask RxProtoIP 1402f198f0aSHoward Wang 1412f198f0aSHoward Wang RxIPF = (1 << 16), /* IP checksum failed */ 1422f198f0aSHoward Wang RxUDPF = (1 << 15), /* UDP/IP checksum failed */ 1432f198f0aSHoward Wang RxTCPF = (1 << 14), /* TCP/IP checksum failed */ 1442f198f0aSHoward Wang RxVlanTag = (1 << 16), /* VLAN tag available */ 1452f198f0aSHoward Wang 1462f198f0aSHoward Wang /*@@@@@@ offset 0 of RX descriptor => bits for RTL8169 only begin @@@@@@*/ 1472f198f0aSHoward Wang RxUDPT = (1 << 18), 1482f198f0aSHoward Wang RxTCPT = (1 << 17), 1492f198f0aSHoward Wang /*@@@@@@ offset 0 of RX descriptor => bits for RTL8169 only end @@@@@@*/ 1502f198f0aSHoward Wang 1512f198f0aSHoward Wang /*@@@@@@ offset 4 of RX descriptor => bits for RTL8169 only begin @@@@@@*/ 1522f198f0aSHoward Wang RxV6F = (1 << 31), 1532f198f0aSHoward Wang RxV4F = (1 << 30), 1542f198f0aSHoward Wang /*@@@@@@ offset 4 of RX descriptor => bits for RTL8169 only end @@@@@@*/ 1552f198f0aSHoward Wang 1562f198f0aSHoward Wang PID1_v3 = (1 << 29), /* Protocol ID bit 1/2 */ 1572f198f0aSHoward Wang PID0_v3 = (1 << 28), /* Protocol ID bit 2/2 */ 1582f198f0aSHoward Wang 1592f198f0aSHoward Wang #define RxProtoUDP_v3 PID1_v3 1602f198f0aSHoward Wang #define RxProtoTCP_v3 PID0_v3 1612f198f0aSHoward Wang #define RxProtoIP_v3 (PID1_v3 | PID0_v3) 1622f198f0aSHoward Wang #define RxProtoMask_v3 RxProtoIP_v3 1632f198f0aSHoward Wang 1642f198f0aSHoward Wang RxIPF_v3 = (1 << 26), /* IP checksum failed */ 1652f198f0aSHoward Wang RxUDPF_v3 = (1 << 25), /* UDP/IP checksum failed */ 1662f198f0aSHoward Wang RxTCPF_v3 = (1 << 24), /* TCP/IP checksum failed */ 1672f198f0aSHoward Wang RxSCTPF_v3 = (1 << 23), /* TCP/IP checksum failed */ 1682f198f0aSHoward Wang RxVlanTag_v3 = (RxVlanTag), /* VLAN tag available */ 1692f198f0aSHoward Wang 1702f198f0aSHoward Wang /*@@@@@@ offset 0 of RX descriptor => bits for RTL8169 only begin @@@@@@*/ 1712f198f0aSHoward Wang RxUDPT_v3 = (1 << 29), 1722f198f0aSHoward Wang RxTCPT_v3 = (1 << 28), 1732f198f0aSHoward Wang RxSCTP_v3 = (1 << 27), 1742f198f0aSHoward Wang /*@@@@@@ offset 0 of RX descriptor => bits for RTL8169 only end @@@@@@*/ 1752f198f0aSHoward Wang 1762f198f0aSHoward Wang /*@@@@@@ offset 4 of RX descriptor => bits for RTL8169 only begin @@@@@@*/ 1772f198f0aSHoward Wang RxV6F_v3 = RxV6F, 1782f198f0aSHoward Wang RxV4F_v3 = RxV4F, 1792f198f0aSHoward Wang /*@@@@@@ offset 4 of RX descriptor => bits for RTL8169 only end @@@@@@*/ 1802f198f0aSHoward Wang }; 181*63d37ff9SHoward Wang 182*63d37ff9SHoward Wang #define GTTCPHO_SHIFT 18 183*63d37ff9SHoward Wang #define GTTCPHO_MAX 0x70U 184*63d37ff9SHoward Wang #define GTPKTSIZE_MAX 0x3ffffU 185*63d37ff9SHoward Wang #define TCPHO_SHIFT 18 186*63d37ff9SHoward Wang #define TCPHO_MAX 0x3ffU 187*63d37ff9SHoward Wang #define LSOPKTSIZE_MAX 0xffffU 188*63d37ff9SHoward Wang #define MSS_MAX 0x07ffu /* MSS value */ 189*63d37ff9SHoward Wang 1901bbe869eSHoward Wang /* ---------------------------------RX---------------------------------- */ 1912f198f0aSHoward Wang 1922f198f0aSHoward Wang static void 1932f198f0aSHoward Wang rtl_rx_queue_release_mbufs(struct rtl_rx_queue *rxq) 1941bbe869eSHoward Wang { 1952f198f0aSHoward Wang int i; 1962f198f0aSHoward Wang 1972f198f0aSHoward Wang PMD_INIT_FUNC_TRACE(); 1982f198f0aSHoward Wang 1992f198f0aSHoward Wang if (rxq != NULL) { 2002f198f0aSHoward Wang if (rxq->sw_ring != NULL) { 2012f198f0aSHoward Wang for (i = 0; i < rxq->nb_rx_desc; i++) { 2022f198f0aSHoward Wang if (rxq->sw_ring[i].mbuf != NULL) { 2032f198f0aSHoward Wang rte_pktmbuf_free_seg(rxq->sw_ring[i].mbuf); 2042f198f0aSHoward Wang rxq->sw_ring[i].mbuf = NULL; 2052f198f0aSHoward Wang } 2062f198f0aSHoward Wang } 2072f198f0aSHoward Wang } 2082f198f0aSHoward Wang } 2092f198f0aSHoward Wang } 2102f198f0aSHoward Wang 2112f198f0aSHoward Wang void 2122f198f0aSHoward Wang rtl_rx_queue_release(struct rte_eth_dev *dev, uint16_t rx_queue_id) 2132f198f0aSHoward Wang { 2142f198f0aSHoward Wang struct rtl_rx_queue *rxq = dev->data->rx_queues[rx_queue_id]; 2152f198f0aSHoward Wang 2162f198f0aSHoward Wang PMD_INIT_FUNC_TRACE(); 2172f198f0aSHoward Wang 2182f198f0aSHoward Wang if (rxq != NULL) { 2192f198f0aSHoward Wang rtl_rx_queue_release_mbufs(rxq); 2202f198f0aSHoward Wang rte_free(rxq->sw_ring); 2212f198f0aSHoward Wang rte_free(rxq); 2222f198f0aSHoward Wang } 2232f198f0aSHoward Wang } 2242f198f0aSHoward Wang 2252f198f0aSHoward Wang void 2262f198f0aSHoward Wang rtl_rxq_info_get(struct rte_eth_dev *dev, uint16_t queue_id, 2272f198f0aSHoward Wang struct rte_eth_rxq_info *qinfo) 2282f198f0aSHoward Wang { 2292f198f0aSHoward Wang struct rtl_rx_queue *rxq; 2302f198f0aSHoward Wang 2312f198f0aSHoward Wang rxq = dev->data->rx_queues[queue_id]; 2322f198f0aSHoward Wang 2332f198f0aSHoward Wang qinfo->mp = rxq->mb_pool; 2342f198f0aSHoward Wang qinfo->scattered_rx = dev->data->scattered_rx; 2352f198f0aSHoward Wang qinfo->nb_desc = rxq->nb_rx_desc; 2362f198f0aSHoward Wang 2372f198f0aSHoward Wang qinfo->conf.rx_free_thresh = rxq->rx_free_thresh; 2382f198f0aSHoward Wang qinfo->conf.offloads = rxq->offloads; 2392f198f0aSHoward Wang } 2402f198f0aSHoward Wang 2412f198f0aSHoward Wang static void 2422f198f0aSHoward Wang rtl_reset_rx_queue(struct rtl_rx_queue *rxq) 2432f198f0aSHoward Wang { 2442f198f0aSHoward Wang static const struct rtl_rx_desc zero_rxd = {0}; 2452f198f0aSHoward Wang int i; 2462f198f0aSHoward Wang 2472f198f0aSHoward Wang for (i = 0; i < rxq->nb_rx_desc; i++) 2482f198f0aSHoward Wang rxq->hw_ring[i] = zero_rxd; 2492f198f0aSHoward Wang 2502f198f0aSHoward Wang rxq->hw_ring[rxq->nb_rx_desc - 1].opts1 = rte_cpu_to_le_32(RingEnd); 2512f198f0aSHoward Wang rxq->rx_tail = 0; 2522f198f0aSHoward Wang rxq->pkt_first_seg = NULL; 2532f198f0aSHoward Wang rxq->pkt_last_seg = NULL; 2542f198f0aSHoward Wang } 2552f198f0aSHoward Wang 2562f198f0aSHoward Wang uint64_t 2572f198f0aSHoward Wang rtl_get_rx_port_offloads(void) 2582f198f0aSHoward Wang { 2592f198f0aSHoward Wang uint64_t offloads; 2602f198f0aSHoward Wang 2612f198f0aSHoward Wang offloads = RTE_ETH_RX_OFFLOAD_IPV4_CKSUM | 2622f198f0aSHoward Wang RTE_ETH_RX_OFFLOAD_UDP_CKSUM | 2632f198f0aSHoward Wang RTE_ETH_RX_OFFLOAD_TCP_CKSUM | 2642f198f0aSHoward Wang RTE_ETH_RX_OFFLOAD_SCATTER | 2652f198f0aSHoward Wang RTE_ETH_RX_OFFLOAD_VLAN_STRIP; 2662f198f0aSHoward Wang 2672f198f0aSHoward Wang return offloads; 2682f198f0aSHoward Wang } 2692f198f0aSHoward Wang 2702f198f0aSHoward Wang int 2712f198f0aSHoward Wang rtl_rx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_idx, 2722f198f0aSHoward Wang uint16_t nb_rx_desc, unsigned int socket_id, 2732f198f0aSHoward Wang const struct rte_eth_rxconf *rx_conf, 2742f198f0aSHoward Wang struct rte_mempool *mb_pool) 2752f198f0aSHoward Wang { 2762f198f0aSHoward Wang struct rtl_rx_queue *rxq; 2772f198f0aSHoward Wang const struct rte_memzone *mz; 2782f198f0aSHoward Wang struct rtl_adapter *adapter = RTL_DEV_PRIVATE(dev); 2792f198f0aSHoward Wang struct rtl_hw *hw = &adapter->hw; 2802f198f0aSHoward Wang uint32_t size; 2812f198f0aSHoward Wang 2822f198f0aSHoward Wang PMD_INIT_FUNC_TRACE(); 2832f198f0aSHoward Wang 2842f198f0aSHoward Wang /* 2852f198f0aSHoward Wang * If this queue existed already, free the associated memory. The 2862f198f0aSHoward Wang * queue cannot be reused in case we need to allocate memory on 2872f198f0aSHoward Wang * different socket than was previously used. 2882f198f0aSHoward Wang */ 2892f198f0aSHoward Wang if (dev->data->rx_queues[queue_idx] != NULL) { 2902f198f0aSHoward Wang rtl_rx_queue_release(dev, queue_idx); 2912f198f0aSHoward Wang dev->data->rx_queues[queue_idx] = NULL; 2922f198f0aSHoward Wang } 2932f198f0aSHoward Wang 2942f198f0aSHoward Wang /* First allocate the rx queue data structure */ 2952f198f0aSHoward Wang rxq = rte_zmalloc_socket("r8169 RX queue", sizeof(struct rtl_rx_queue), 2962f198f0aSHoward Wang RTE_CACHE_LINE_SIZE, socket_id); 2972f198f0aSHoward Wang 2982f198f0aSHoward Wang if (rxq == NULL) { 2992f198f0aSHoward Wang PMD_INIT_LOG(ERR, "Cannot allocate Rx queue structure"); 3002f198f0aSHoward Wang return -ENOMEM; 3012f198f0aSHoward Wang } 3022f198f0aSHoward Wang 3032f198f0aSHoward Wang /* Setup queue */ 3042f198f0aSHoward Wang rxq->mb_pool = mb_pool; 3052f198f0aSHoward Wang rxq->nb_rx_desc = nb_rx_desc; 3062f198f0aSHoward Wang rxq->port_id = dev->data->port_id; 3072f198f0aSHoward Wang rxq->queue_id = queue_idx; 3082f198f0aSHoward Wang rxq->rx_free_thresh = rx_conf->rx_free_thresh; 3092f198f0aSHoward Wang 3102f198f0aSHoward Wang /* Allocate memory for the software ring */ 3112f198f0aSHoward Wang rxq->sw_ring = rte_calloc("r8169 sw rx ring", nb_rx_desc, 3122f198f0aSHoward Wang sizeof(struct rtl_rx_entry), RTE_CACHE_LINE_SIZE); 3132f198f0aSHoward Wang 3142f198f0aSHoward Wang if (rxq->sw_ring == NULL) { 3152f198f0aSHoward Wang PMD_INIT_LOG(ERR, 3162f198f0aSHoward Wang "Port %d: Cannot allocate software ring for queue %d", 3172f198f0aSHoward Wang rxq->port_id, rxq->queue_id); 3182f198f0aSHoward Wang rte_free(rxq); 3192f198f0aSHoward Wang return -ENOMEM; 3202f198f0aSHoward Wang } 3212f198f0aSHoward Wang 3222f198f0aSHoward Wang /* 3232f198f0aSHoward Wang * Allocate RX ring hardware descriptors. A memzone large enough to 3242f198f0aSHoward Wang * handle the maximum ring size is allocated in order to allow for 3252f198f0aSHoward Wang * resizing in later calls to the queue setup function. 3262f198f0aSHoward Wang */ 3272f198f0aSHoward Wang size = sizeof(struct rtl_rx_desc) * (nb_rx_desc + 1); 3282f198f0aSHoward Wang mz = rte_eth_dma_zone_reserve(dev, "rx_ring", queue_idx, size, 3292f198f0aSHoward Wang RTL_RING_ALIGN, socket_id); 3302f198f0aSHoward Wang if (mz == NULL) { 3312f198f0aSHoward Wang PMD_INIT_LOG(ERR, 3322f198f0aSHoward Wang "Port %d: Cannot allocate software ring for queue %d", 3332f198f0aSHoward Wang rxq->port_id, rxq->queue_id); 3342f198f0aSHoward Wang rtl_rx_queue_release(dev, rxq->queue_id); 3352f198f0aSHoward Wang return -ENOMEM; 3362f198f0aSHoward Wang } 3372f198f0aSHoward Wang 3382f198f0aSHoward Wang rxq->hw = hw; 3392f198f0aSHoward Wang rxq->hw_ring = mz->addr; 3402f198f0aSHoward Wang rxq->hw_ring_phys_addr = mz->iova; 3412f198f0aSHoward Wang rxq->offloads = rx_conf->offloads | dev->data->dev_conf.rxmode.offloads; 3422f198f0aSHoward Wang 3432f198f0aSHoward Wang rtl_reset_rx_queue(rxq); 3442f198f0aSHoward Wang 3452f198f0aSHoward Wang dev->data->rx_queues[queue_idx] = rxq; 3462f198f0aSHoward Wang 3471bbe869eSHoward Wang return 0; 3481bbe869eSHoward Wang } 3491bbe869eSHoward Wang 3502f198f0aSHoward Wang static int 3512f198f0aSHoward Wang rtl_alloc_rx_queue_mbufs(struct rtl_rx_queue *rxq) 3521bbe869eSHoward Wang { 3532f198f0aSHoward Wang struct rtl_rx_entry *rxe = rxq->sw_ring; 3542f198f0aSHoward Wang struct rtl_hw *hw = rxq->hw; 3552f198f0aSHoward Wang struct rtl_rx_desc *rxd; 3562f198f0aSHoward Wang int i; 3572f198f0aSHoward Wang uint64_t dma_addr; 3582f198f0aSHoward Wang 3592f198f0aSHoward Wang rxd = &rxq->hw_ring[0]; 3602f198f0aSHoward Wang 3612f198f0aSHoward Wang /* Initialize software ring entries */ 3622f198f0aSHoward Wang for (i = 0; i < rxq->nb_rx_desc; i++) { 3632f198f0aSHoward Wang struct rte_mbuf *mbuf = rte_mbuf_raw_alloc(rxq->mb_pool); 3642f198f0aSHoward Wang 3652f198f0aSHoward Wang if (mbuf == NULL) { 3662f198f0aSHoward Wang PMD_INIT_LOG(ERR, "RX mbuf alloc failed queue_id=%hu", 3672f198f0aSHoward Wang rxq->queue_id); 3682f198f0aSHoward Wang return -ENOMEM; 3692f198f0aSHoward Wang } 3702f198f0aSHoward Wang 3712f198f0aSHoward Wang dma_addr = rte_cpu_to_le_64(rte_mbuf_data_iova_default(mbuf)); 3722f198f0aSHoward Wang 3732f198f0aSHoward Wang rxd = &rxq->hw_ring[i]; 3742f198f0aSHoward Wang rxd->addr = dma_addr; 3752f198f0aSHoward Wang rxd->opts2 = 0; 3762f198f0aSHoward Wang rte_wmb(); 3772f198f0aSHoward Wang rxd->opts1 = rte_cpu_to_le_32(DescOwn | hw->rx_buf_sz); 3782f198f0aSHoward Wang rxe[i].mbuf = mbuf; 3792f198f0aSHoward Wang } 3802f198f0aSHoward Wang 3812f198f0aSHoward Wang /* Mark as last desc */ 3822f198f0aSHoward Wang rxd->opts1 |= rte_cpu_to_le_32(RingEnd); 3832f198f0aSHoward Wang 3841bbe869eSHoward Wang return 0; 3851bbe869eSHoward Wang } 3861bbe869eSHoward Wang 3872f198f0aSHoward Wang static int 3882f198f0aSHoward Wang rtl_hw_set_features(struct rtl_hw *hw, uint64_t offloads) 3892f198f0aSHoward Wang { 3902f198f0aSHoward Wang u16 cp_cmd; 3912f198f0aSHoward Wang u32 rx_config; 3922f198f0aSHoward Wang 3932f198f0aSHoward Wang rx_config = RTL_R32(hw, RxConfig); 3942f198f0aSHoward Wang if (offloads & RTE_ETH_RX_OFFLOAD_VLAN_STRIP) 3952f198f0aSHoward Wang rx_config |= (EnableInnerVlan | EnableOuterVlan); 3962f198f0aSHoward Wang else 3972f198f0aSHoward Wang rx_config &= ~(EnableInnerVlan | EnableOuterVlan); 3982f198f0aSHoward Wang 3992f198f0aSHoward Wang RTL_W32(hw, RxConfig, rx_config); 4002f198f0aSHoward Wang 4012f198f0aSHoward Wang cp_cmd = RTL_R16(hw, CPlusCmd); 4022f198f0aSHoward Wang 4032f198f0aSHoward Wang if (offloads & RTE_ETH_RX_OFFLOAD_CHECKSUM) 4042f198f0aSHoward Wang cp_cmd |= RxChkSum; 4052f198f0aSHoward Wang else 4062f198f0aSHoward Wang cp_cmd &= ~RxChkSum; 4072f198f0aSHoward Wang 4082f198f0aSHoward Wang RTL_W16(hw, CPlusCmd, cp_cmd); 4092f198f0aSHoward Wang 4102f198f0aSHoward Wang return 0; 4112f198f0aSHoward Wang } 4122f198f0aSHoward Wang 4132f198f0aSHoward Wang static void 4142f198f0aSHoward Wang rtl_hw_set_rx_packet_filter(struct rtl_hw *hw) 4152f198f0aSHoward Wang { 4162f198f0aSHoward Wang int rx_mode; 4172f198f0aSHoward Wang 4182f198f0aSHoward Wang hw->hw_ops.hw_init_rxcfg(hw); 4192f198f0aSHoward Wang 4202f198f0aSHoward Wang rx_mode = AcceptBroadcast | AcceptMyPhys; 4212f198f0aSHoward Wang RTL_W32(hw, RxConfig, rx_mode | (RTL_R32(hw, RxConfig))); 4222f198f0aSHoward Wang } 4232f198f0aSHoward Wang 4242f198f0aSHoward Wang int 4252f198f0aSHoward Wang rtl_rx_init(struct rte_eth_dev *dev) 4262f198f0aSHoward Wang { 4272f198f0aSHoward Wang struct rtl_adapter *adapter = RTL_DEV_PRIVATE(dev); 4282f198f0aSHoward Wang struct rtl_hw *hw = &adapter->hw; 4292f198f0aSHoward Wang struct rtl_rx_queue *rxq; 4302f198f0aSHoward Wang int ret; 4312f198f0aSHoward Wang u32 max_rx_pkt_size; 4322f198f0aSHoward Wang 4332f198f0aSHoward Wang rxq = dev->data->rx_queues[0]; 4342f198f0aSHoward Wang 4352f198f0aSHoward Wang if (rxq->mb_pool == NULL) { 4362f198f0aSHoward Wang PMD_INIT_LOG(ERR, "r8169 rx queue pool not setup!"); 4372f198f0aSHoward Wang return -ENOMEM; 4382f198f0aSHoward Wang } 4392f198f0aSHoward Wang 4402f198f0aSHoward Wang RTL_W32(hw, RxDescAddrLow, ((u64)rxq->hw_ring_phys_addr & DMA_BIT_MASK(32))); 4412f198f0aSHoward Wang RTL_W32(hw, RxDescAddrHigh, ((u64)rxq->hw_ring_phys_addr >> 32)); 4422f198f0aSHoward Wang 4432f198f0aSHoward Wang dev->rx_pkt_burst = rtl_recv_pkts; 4442f198f0aSHoward Wang hw->rx_buf_sz = rte_pktmbuf_data_room_size(rxq->mb_pool) - RTE_PKTMBUF_HEADROOM; 4452f198f0aSHoward Wang 4462f198f0aSHoward Wang max_rx_pkt_size = dev->data->mtu + RTL_ETH_OVERHEAD; 4472f198f0aSHoward Wang 4482f198f0aSHoward Wang if (dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_SCATTER || 4492f198f0aSHoward Wang max_rx_pkt_size > hw->rx_buf_sz) { 4502f198f0aSHoward Wang if (!dev->data->scattered_rx) 4512f198f0aSHoward Wang PMD_INIT_LOG(DEBUG, "forcing scatter mode"); 4522f198f0aSHoward Wang dev->rx_pkt_burst = rtl_recv_scattered_pkts; 4532f198f0aSHoward Wang dev->data->scattered_rx = 1; 4542f198f0aSHoward Wang } 4552f198f0aSHoward Wang 4562f198f0aSHoward Wang RTL_W16(hw, RxMaxSize, max_rx_pkt_size); 4572f198f0aSHoward Wang 4582f198f0aSHoward Wang ret = rtl_alloc_rx_queue_mbufs(rxq); 4592f198f0aSHoward Wang if (ret) { 4602f198f0aSHoward Wang PMD_INIT_LOG(ERR, "r8169 rx mbuf alloc failed!"); 4612f198f0aSHoward Wang return ret; 4622f198f0aSHoward Wang } 4632f198f0aSHoward Wang 4642f198f0aSHoward Wang rtl_enable_cfg9346_write(hw); 4652f198f0aSHoward Wang 4662f198f0aSHoward Wang /* RX accept type and csum vlan offload */ 4672f198f0aSHoward Wang rtl_hw_set_features(hw, rxq->offloads); 4682f198f0aSHoward Wang 4692f198f0aSHoward Wang rtl_disable_rxdvgate(hw); 4702f198f0aSHoward Wang 4712f198f0aSHoward Wang /* Set Rx packet filter */ 4722f198f0aSHoward Wang rtl_hw_set_rx_packet_filter(hw); 4732f198f0aSHoward Wang 4742f198f0aSHoward Wang rtl_disable_cfg9346_write(hw); 4752f198f0aSHoward Wang 4762f198f0aSHoward Wang RTL_W8(hw, ChipCmd, RTL_R8(hw, ChipCmd) | CmdRxEnb); 4772f198f0aSHoward Wang 4782f198f0aSHoward Wang dev->data->rx_queue_state[0] = RTE_ETH_QUEUE_STATE_STARTED; 4792f198f0aSHoward Wang 4802f198f0aSHoward Wang return 0; 4812f198f0aSHoward Wang } 4822f198f0aSHoward Wang 4832f198f0aSHoward Wang static inline void 4842f198f0aSHoward Wang rtl_mark_to_asic(struct rtl_rx_desc *rxd, u32 size) 4852f198f0aSHoward Wang { 4862f198f0aSHoward Wang u32 eor = rte_le_to_cpu_32(rxd->opts1) & RingEnd; 4872f198f0aSHoward Wang 4882f198f0aSHoward Wang rxd->opts1 = rte_cpu_to_le_32(DescOwn | eor | size); 4892f198f0aSHoward Wang } 4902f198f0aSHoward Wang 4912f198f0aSHoward Wang static inline uint64_t 4922f198f0aSHoward Wang rtl_rx_desc_error_to_pkt_flags(struct rtl_rx_queue *rxq, uint32_t opts1, 4932f198f0aSHoward Wang uint32_t opts2) 4942f198f0aSHoward Wang { 4952f198f0aSHoward Wang uint64_t pkt_flags = 0; 4962f198f0aSHoward Wang 4972f198f0aSHoward Wang if (!(rxq->offloads & RTE_ETH_RX_OFFLOAD_CHECKSUM)) 4982f198f0aSHoward Wang goto exit; 4992f198f0aSHoward Wang 5002f198f0aSHoward Wang /* RX csum offload for RTL8169*/ 5012f198f0aSHoward Wang if (((opts2 & RxV4F) && !(opts1 & RxIPF)) || (opts2 & RxV6F)) { 5022f198f0aSHoward Wang pkt_flags |= RTE_MBUF_F_RX_IP_CKSUM_GOOD; 5032f198f0aSHoward Wang if (((opts1 & RxTCPT) && !(opts1 & RxTCPF)) || 5042f198f0aSHoward Wang ((opts1 & RxUDPT) && !(opts1 & RxUDPF))) 5052f198f0aSHoward Wang pkt_flags |= RTE_MBUF_F_RX_L4_CKSUM_GOOD; 5062f198f0aSHoward Wang } 5072f198f0aSHoward Wang 5082f198f0aSHoward Wang exit: 5092f198f0aSHoward Wang return pkt_flags; 5102f198f0aSHoward Wang } 5112f198f0aSHoward Wang 5122f198f0aSHoward Wang /* PMD receive function */ 5132f198f0aSHoward Wang uint16_t 5142f198f0aSHoward Wang rtl_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts) 5152f198f0aSHoward Wang { 5162f198f0aSHoward Wang struct rtl_rx_queue *rxq = (struct rtl_rx_queue *)rx_queue; 5172f198f0aSHoward Wang struct rte_eth_dev *dev = &rte_eth_devices[rxq->port_id]; 5182f198f0aSHoward Wang struct rtl_hw *hw = rxq->hw; 5192f198f0aSHoward Wang struct rtl_rx_desc *rxd; 5202f198f0aSHoward Wang struct rtl_rx_desc *hw_ring; 5212f198f0aSHoward Wang struct rtl_rx_entry *rxe; 5222f198f0aSHoward Wang struct rtl_rx_entry *sw_ring = rxq->sw_ring; 5232f198f0aSHoward Wang struct rte_mbuf *new_mb; 5242f198f0aSHoward Wang struct rte_mbuf *rmb; 5252f198f0aSHoward Wang struct rtl_adapter *adapter = RTL_DEV_PRIVATE(dev); 5262f198f0aSHoward Wang struct rtl_sw_stats *stats = &adapter->sw_stats; 5272f198f0aSHoward Wang uint16_t nb_rx = 0; 5282f198f0aSHoward Wang uint16_t nb_hold = 0; 5292f198f0aSHoward Wang uint16_t tail = rxq->rx_tail; 5302f198f0aSHoward Wang const uint16_t nb_rx_desc = rxq->nb_rx_desc; 5312f198f0aSHoward Wang uint32_t opts1; 5322f198f0aSHoward Wang uint32_t opts2; 5332f198f0aSHoward Wang uint16_t pkt_len = 0; 5342f198f0aSHoward Wang uint64_t dma_addr; 5352f198f0aSHoward Wang 5362f198f0aSHoward Wang hw_ring = rxq->hw_ring; 5372f198f0aSHoward Wang 5382f198f0aSHoward Wang RTE_ASSERT(RTL_R8(hw, ChipCmd) & CmdRxEnb); 5392f198f0aSHoward Wang 5402f198f0aSHoward Wang while (nb_rx < nb_pkts) { 5412f198f0aSHoward Wang rxd = &hw_ring[tail]; 5422f198f0aSHoward Wang 5432f198f0aSHoward Wang opts1 = rte_le_to_cpu_32(rxd->opts1); 5442f198f0aSHoward Wang if (opts1 & DescOwn) 5452f198f0aSHoward Wang break; 5462f198f0aSHoward Wang 5472f198f0aSHoward Wang /* 5482f198f0aSHoward Wang * This barrier is needed to keep us from reading 5492f198f0aSHoward Wang * any other fields out of the Rx descriptor until 5502f198f0aSHoward Wang * we know the status of DescOwn. 5512f198f0aSHoward Wang */ 5522f198f0aSHoward Wang rte_rmb(); 5532f198f0aSHoward Wang 5542f198f0aSHoward Wang if (unlikely(opts1 & RxRES)) { 5552f198f0aSHoward Wang stats->rx_errors++; 5562f198f0aSHoward Wang rtl_mark_to_asic(rxd, hw->rx_buf_sz); 5572f198f0aSHoward Wang nb_hold++; 5582f198f0aSHoward Wang tail = (tail + 1) % nb_rx_desc; 5592f198f0aSHoward Wang } else { 5602f198f0aSHoward Wang opts2 = rte_le_to_cpu_32(rxd->opts2); 5612f198f0aSHoward Wang 5622f198f0aSHoward Wang new_mb = rte_mbuf_raw_alloc(rxq->mb_pool); 5632f198f0aSHoward Wang if (new_mb == NULL) { 5642f198f0aSHoward Wang PMD_RX_LOG(DEBUG, "RX mbuf alloc failed port_id=%u " 5652f198f0aSHoward Wang "queue_id=%u", 5662f198f0aSHoward Wang (uint32_t)rxq->port_id, (uint32_t)rxq->queue_id); 5672f198f0aSHoward Wang dev->data->rx_mbuf_alloc_failed++; 5682f198f0aSHoward Wang break; 5692f198f0aSHoward Wang } 5702f198f0aSHoward Wang 5712f198f0aSHoward Wang nb_hold++; 5722f198f0aSHoward Wang rxe = &sw_ring[tail]; 5732f198f0aSHoward Wang 5742f198f0aSHoward Wang rmb = rxe->mbuf; 5752f198f0aSHoward Wang 5762f198f0aSHoward Wang tail = (tail + 1) % nb_rx_desc; 5772f198f0aSHoward Wang 5782f198f0aSHoward Wang /* Prefetch next mbufs */ 5792f198f0aSHoward Wang rte_prefetch0(sw_ring[tail].mbuf); 5802f198f0aSHoward Wang 5812f198f0aSHoward Wang /* 5822f198f0aSHoward Wang * When next RX descriptor is on a cache-line boundary, 5832f198f0aSHoward Wang * prefetch the next 4 RX descriptors and the next 8 pointers 5842f198f0aSHoward Wang * to mbufs. 5852f198f0aSHoward Wang */ 5862f198f0aSHoward Wang if ((tail & 0x3) == 0) { 5872f198f0aSHoward Wang rte_prefetch0(&sw_ring[tail]); 5882f198f0aSHoward Wang rte_prefetch0(&hw_ring[tail]); 5892f198f0aSHoward Wang } 5902f198f0aSHoward Wang 5912f198f0aSHoward Wang /* Refill the RX desc */ 5922f198f0aSHoward Wang rxe->mbuf = new_mb; 5932f198f0aSHoward Wang dma_addr = rte_cpu_to_le_64(rte_mbuf_data_iova_default(new_mb)); 5942f198f0aSHoward Wang 5952f198f0aSHoward Wang /* Setup RX descriptor */ 5962f198f0aSHoward Wang rxd->addr = dma_addr; 5972f198f0aSHoward Wang rxd->opts2 = 0; 5982f198f0aSHoward Wang rte_wmb(); 5992f198f0aSHoward Wang rtl_mark_to_asic(rxd, hw->rx_buf_sz); 6002f198f0aSHoward Wang 6012f198f0aSHoward Wang pkt_len = opts1 & 0x00003fff; 6022f198f0aSHoward Wang pkt_len -= RTE_ETHER_CRC_LEN; 6032f198f0aSHoward Wang 6042f198f0aSHoward Wang rmb->data_off = RTE_PKTMBUF_HEADROOM; 6052f198f0aSHoward Wang rte_prefetch1((char *)rmb->buf_addr + rmb->data_off); 6062f198f0aSHoward Wang rmb->nb_segs = 1; 6072f198f0aSHoward Wang rmb->next = NULL; 6082f198f0aSHoward Wang rmb->pkt_len = pkt_len; 6092f198f0aSHoward Wang rmb->data_len = pkt_len; 6102f198f0aSHoward Wang rmb->port = rxq->port_id; 6112f198f0aSHoward Wang 6122f198f0aSHoward Wang if (opts2 & RxVlanTag) 6132f198f0aSHoward Wang rmb->vlan_tci = rte_bswap16(opts2 & 0xffff); 6142f198f0aSHoward Wang 6152f198f0aSHoward Wang rmb->ol_flags = rtl_rx_desc_error_to_pkt_flags(rxq, opts1, opts2); 6162f198f0aSHoward Wang 6172f198f0aSHoward Wang /* 6182f198f0aSHoward Wang * Store the mbuf address into the next entry of the array 6192f198f0aSHoward Wang * of returned packets. 6202f198f0aSHoward Wang */ 6212f198f0aSHoward Wang rx_pkts[nb_rx++] = rmb; 6222f198f0aSHoward Wang 6232f198f0aSHoward Wang stats->rx_bytes += pkt_len; 6242f198f0aSHoward Wang stats->rx_packets++; 6252f198f0aSHoward Wang } 6262f198f0aSHoward Wang } 6272f198f0aSHoward Wang 6282f198f0aSHoward Wang rxq->rx_tail = tail; 6292f198f0aSHoward Wang 6302f198f0aSHoward Wang nb_hold = (uint16_t)(nb_hold + rxq->nb_rx_hold); 6312f198f0aSHoward Wang if (nb_hold > rxq->rx_free_thresh) { 6322f198f0aSHoward Wang rte_wmb(); 6332f198f0aSHoward Wang 6342f198f0aSHoward Wang /* Clear RDU */ 6352f198f0aSHoward Wang RTL_W32(hw, ISR0_8125, (RxOK | RxErr | RxDescUnavail)); 6362f198f0aSHoward Wang 6372f198f0aSHoward Wang nb_hold = 0; 6382f198f0aSHoward Wang } 6392f198f0aSHoward Wang 6402f198f0aSHoward Wang rxq->nb_rx_hold = nb_hold; 6412f198f0aSHoward Wang 6422f198f0aSHoward Wang return nb_rx; 6432f198f0aSHoward Wang } 6442f198f0aSHoward Wang 6452f198f0aSHoward Wang /* PMD receive function for scattered pkts */ 6462f198f0aSHoward Wang uint16_t 6472f198f0aSHoward Wang rtl_recv_scattered_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, 6482f198f0aSHoward Wang uint16_t nb_pkts) 6492f198f0aSHoward Wang { 6502f198f0aSHoward Wang struct rtl_rx_queue *rxq = (struct rtl_rx_queue *)rx_queue; 6512f198f0aSHoward Wang struct rte_eth_dev *dev = &rte_eth_devices[rxq->port_id]; 6522f198f0aSHoward Wang struct rtl_hw *hw = rxq->hw; 6532f198f0aSHoward Wang struct rtl_rx_desc *rxd; 6542f198f0aSHoward Wang struct rtl_rx_desc *hw_ring; 6552f198f0aSHoward Wang struct rtl_rx_entry *rxe; 6562f198f0aSHoward Wang struct rtl_rx_entry *sw_ring = rxq->sw_ring; 6572f198f0aSHoward Wang struct rte_mbuf *first_seg; 6582f198f0aSHoward Wang struct rte_mbuf *last_seg; 6592f198f0aSHoward Wang struct rte_mbuf *new_mb; 6602f198f0aSHoward Wang struct rte_mbuf *rmb; 6612f198f0aSHoward Wang struct rtl_adapter *adapter = RTL_DEV_PRIVATE(dev); 6622f198f0aSHoward Wang struct rtl_sw_stats *stats = &adapter->sw_stats; 6632f198f0aSHoward Wang uint16_t nb_rx = 0; 6642f198f0aSHoward Wang uint16_t nb_hold = 0; 6652f198f0aSHoward Wang uint16_t data_len = 0; 6662f198f0aSHoward Wang uint16_t tail = rxq->rx_tail; 6672f198f0aSHoward Wang const uint16_t nb_rx_desc = rxq->nb_rx_desc; 6682f198f0aSHoward Wang uint32_t opts1; 6692f198f0aSHoward Wang uint32_t opts2; 6702f198f0aSHoward Wang uint64_t dma_addr; 6712f198f0aSHoward Wang 6722f198f0aSHoward Wang hw_ring = rxq->hw_ring; 6732f198f0aSHoward Wang 6742f198f0aSHoward Wang /* 6752f198f0aSHoward Wang * Retrieve RX context of current packet, if any. 6762f198f0aSHoward Wang */ 6772f198f0aSHoward Wang first_seg = rxq->pkt_first_seg; 6782f198f0aSHoward Wang last_seg = rxq->pkt_last_seg; 6792f198f0aSHoward Wang 6802f198f0aSHoward Wang RTE_ASSERT(RTL_R8(hw, ChipCmd) & CmdRxEnb); 6812f198f0aSHoward Wang 6822f198f0aSHoward Wang while (nb_rx < nb_pkts) { 6832f198f0aSHoward Wang next_desc: 6842f198f0aSHoward Wang rxd = &hw_ring[tail]; 6852f198f0aSHoward Wang 6862f198f0aSHoward Wang opts1 = rte_le_to_cpu_32(rxd->opts1); 6872f198f0aSHoward Wang if (opts1 & DescOwn) 6882f198f0aSHoward Wang break; 6892f198f0aSHoward Wang 6902f198f0aSHoward Wang /* 6912f198f0aSHoward Wang * This barrier is needed to keep us from reading 6922f198f0aSHoward Wang * any other fields out of the Rx descriptor until 6932f198f0aSHoward Wang * we know the status of DescOwn 6942f198f0aSHoward Wang */ 6952f198f0aSHoward Wang rte_rmb(); 6962f198f0aSHoward Wang 6972f198f0aSHoward Wang if (unlikely(opts1 & RxRES)) { 6982f198f0aSHoward Wang stats->rx_errors++; 6992f198f0aSHoward Wang rtl_mark_to_asic(rxd, hw->rx_buf_sz); 7002f198f0aSHoward Wang nb_hold++; 7012f198f0aSHoward Wang tail = (tail + 1) % nb_rx_desc; 7022f198f0aSHoward Wang } else { 7032f198f0aSHoward Wang opts2 = rte_le_to_cpu_32(rxd->opts2); 7042f198f0aSHoward Wang 7052f198f0aSHoward Wang new_mb = rte_mbuf_raw_alloc(rxq->mb_pool); 7062f198f0aSHoward Wang if (new_mb == NULL) { 7072f198f0aSHoward Wang PMD_RX_LOG(DEBUG, "RX mbuf alloc failed port_id=%u " 7082f198f0aSHoward Wang "queue_id=%u", 7092f198f0aSHoward Wang (uint32_t)rxq->port_id, (uint32_t)rxq->queue_id); 7102f198f0aSHoward Wang dev->data->rx_mbuf_alloc_failed++; 7112f198f0aSHoward Wang break; 7122f198f0aSHoward Wang } 7132f198f0aSHoward Wang 7142f198f0aSHoward Wang nb_hold++; 7152f198f0aSHoward Wang rxe = &sw_ring[tail]; 7162f198f0aSHoward Wang 7172f198f0aSHoward Wang rmb = rxe->mbuf; 7182f198f0aSHoward Wang 7192f198f0aSHoward Wang /* Prefetch next mbufs */ 7202f198f0aSHoward Wang tail = (tail + 1) % nb_rx_desc; 7212f198f0aSHoward Wang rte_prefetch0(sw_ring[tail].mbuf); 7222f198f0aSHoward Wang 7232f198f0aSHoward Wang /* 7242f198f0aSHoward Wang * When next RX descriptor is on a cache-line boundary, 7252f198f0aSHoward Wang * prefetch the next 4 RX descriptors and the next 8 pointers 7262f198f0aSHoward Wang * to mbufs. 7272f198f0aSHoward Wang */ 7282f198f0aSHoward Wang if ((tail & 0x3) == 0) { 7292f198f0aSHoward Wang rte_prefetch0(&sw_ring[tail]); 7302f198f0aSHoward Wang rte_prefetch0(&hw_ring[tail]); 7312f198f0aSHoward Wang } 7322f198f0aSHoward Wang 7332f198f0aSHoward Wang /* Refill the RX desc */ 7342f198f0aSHoward Wang rxe->mbuf = new_mb; 7352f198f0aSHoward Wang dma_addr = rte_cpu_to_le_64(rte_mbuf_data_iova_default(new_mb)); 7362f198f0aSHoward Wang 7372f198f0aSHoward Wang /* Setup RX descriptor */ 7382f198f0aSHoward Wang rxd->addr = dma_addr; 7392f198f0aSHoward Wang rxd->opts2 = 0; 7402f198f0aSHoward Wang rte_wmb(); 7412f198f0aSHoward Wang rtl_mark_to_asic(rxd, hw->rx_buf_sz); 7422f198f0aSHoward Wang 7432f198f0aSHoward Wang data_len = opts1 & 0x00003fff; 7442f198f0aSHoward Wang rmb->data_len = data_len; 7452f198f0aSHoward Wang rmb->data_off = RTE_PKTMBUF_HEADROOM; 7462f198f0aSHoward Wang 7472f198f0aSHoward Wang /* 7482f198f0aSHoward Wang * If this is the first buffer of the received packet, 7492f198f0aSHoward Wang * set the pointer to the first mbuf of the packet and 7502f198f0aSHoward Wang * initialize its context. 7512f198f0aSHoward Wang * Otherwise, update the total length and the number of segments 7522f198f0aSHoward Wang * of the current scattered packet, and update the pointer to 7532f198f0aSHoward Wang * the last mbuf of the current packet. 7542f198f0aSHoward Wang */ 7552f198f0aSHoward Wang if (first_seg == NULL) { 7562f198f0aSHoward Wang first_seg = rmb; 7572f198f0aSHoward Wang first_seg->pkt_len = data_len; 7582f198f0aSHoward Wang first_seg->nb_segs = 1; 7592f198f0aSHoward Wang } else { 7602f198f0aSHoward Wang first_seg->pkt_len += data_len; 7612f198f0aSHoward Wang first_seg->nb_segs++; 7622f198f0aSHoward Wang last_seg->next = rmb; 7632f198f0aSHoward Wang } 7642f198f0aSHoward Wang 7652f198f0aSHoward Wang /* 7662f198f0aSHoward Wang * If this is not the last buffer of the received packet, 7672f198f0aSHoward Wang * update the pointer to the last mbuf of the current scattered 7682f198f0aSHoward Wang * packet and continue to parse the RX ring. 7692f198f0aSHoward Wang */ 7702f198f0aSHoward Wang if (!(opts1 & LastFrag)) { 7712f198f0aSHoward Wang last_seg = rmb; 7722f198f0aSHoward Wang goto next_desc; 7732f198f0aSHoward Wang } 7742f198f0aSHoward Wang 7752f198f0aSHoward Wang /* 7762f198f0aSHoward Wang * This is the last buffer of the received packet. 7772f198f0aSHoward Wang */ 7782f198f0aSHoward Wang rmb->next = NULL; 7792f198f0aSHoward Wang 7802f198f0aSHoward Wang first_seg->pkt_len -= RTE_ETHER_CRC_LEN; 7812f198f0aSHoward Wang if (data_len <= RTE_ETHER_CRC_LEN) { 7822f198f0aSHoward Wang rte_pktmbuf_free_seg(rmb); 7832f198f0aSHoward Wang first_seg->nb_segs--; 7842f198f0aSHoward Wang last_seg->data_len = last_seg->data_len - 7852f198f0aSHoward Wang (RTE_ETHER_CRC_LEN - data_len); 7862f198f0aSHoward Wang last_seg->next = NULL; 7872f198f0aSHoward Wang } else { 7882f198f0aSHoward Wang rmb->data_len = data_len - RTE_ETHER_CRC_LEN; 7892f198f0aSHoward Wang } 7902f198f0aSHoward Wang 7912f198f0aSHoward Wang first_seg->port = rxq->port_id; 7922f198f0aSHoward Wang 7932f198f0aSHoward Wang if (opts2 & RxVlanTag) 7942f198f0aSHoward Wang first_seg->vlan_tci = rte_bswap16(opts2 & 0xffff); 7952f198f0aSHoward Wang 7962f198f0aSHoward Wang first_seg->ol_flags = rtl_rx_desc_error_to_pkt_flags(rxq, opts1, opts2); 7972f198f0aSHoward Wang 7982f198f0aSHoward Wang rte_prefetch1((char *)first_seg->buf_addr + first_seg->data_off); 7992f198f0aSHoward Wang 8002f198f0aSHoward Wang /* 8012f198f0aSHoward Wang * Store the mbuf address into the next entry of the array 8022f198f0aSHoward Wang * of returned packets. 8032f198f0aSHoward Wang */ 8042f198f0aSHoward Wang rx_pkts[nb_rx++] = first_seg; 8052f198f0aSHoward Wang 8062f198f0aSHoward Wang stats->rx_bytes += first_seg->pkt_len; 8072f198f0aSHoward Wang stats->rx_packets++; 8082f198f0aSHoward Wang 8092f198f0aSHoward Wang /* 8102f198f0aSHoward Wang * Setup receipt context for a new packet. 8112f198f0aSHoward Wang */ 8122f198f0aSHoward Wang first_seg = NULL; 8132f198f0aSHoward Wang } 8142f198f0aSHoward Wang } 8152f198f0aSHoward Wang 8162f198f0aSHoward Wang /* 8172f198f0aSHoward Wang * Record index of the next RX descriptor to probe. 8182f198f0aSHoward Wang */ 8192f198f0aSHoward Wang rxq->rx_tail = tail; 8202f198f0aSHoward Wang 8212f198f0aSHoward Wang /* 8222f198f0aSHoward Wang * Save receive context. 8232f198f0aSHoward Wang */ 8242f198f0aSHoward Wang rxq->pkt_first_seg = first_seg; 8252f198f0aSHoward Wang rxq->pkt_last_seg = last_seg; 8262f198f0aSHoward Wang 8272f198f0aSHoward Wang nb_hold = (uint16_t)(nb_hold + rxq->nb_rx_hold); 8282f198f0aSHoward Wang if (nb_hold > rxq->rx_free_thresh) { 8292f198f0aSHoward Wang rte_wmb(); 8302f198f0aSHoward Wang 8312f198f0aSHoward Wang /* Clear RDU */ 8322f198f0aSHoward Wang RTL_W32(hw, ISR0_8125, (RxOK | RxErr | RxDescUnavail)); 8332f198f0aSHoward Wang 8342f198f0aSHoward Wang nb_hold = 0; 8352f198f0aSHoward Wang } 8362f198f0aSHoward Wang 8372f198f0aSHoward Wang rxq->nb_rx_hold = nb_hold; 8382f198f0aSHoward Wang 8392f198f0aSHoward Wang return nb_rx; 8402f198f0aSHoward Wang } 8412f198f0aSHoward Wang 8421bbe869eSHoward Wang /* ---------------------------------TX---------------------------------- */ 843*63d37ff9SHoward Wang static void 844*63d37ff9SHoward Wang rtl_tx_queue_release_mbufs(struct rtl_tx_queue *txq) 8451bbe869eSHoward Wang { 846*63d37ff9SHoward Wang int i; 847*63d37ff9SHoward Wang 848*63d37ff9SHoward Wang PMD_INIT_FUNC_TRACE(); 849*63d37ff9SHoward Wang 850*63d37ff9SHoward Wang if (txq != NULL) { 851*63d37ff9SHoward Wang if (txq->sw_ring != NULL) { 852*63d37ff9SHoward Wang for (i = 0; i < txq->nb_tx_desc; i++) { 853*63d37ff9SHoward Wang if (txq->sw_ring[i].mbuf != NULL) { 854*63d37ff9SHoward Wang rte_pktmbuf_free_seg(txq->sw_ring[i].mbuf); 855*63d37ff9SHoward Wang txq->sw_ring[i].mbuf = NULL; 856*63d37ff9SHoward Wang } 857*63d37ff9SHoward Wang } 858*63d37ff9SHoward Wang } 859*63d37ff9SHoward Wang } 860*63d37ff9SHoward Wang } 861*63d37ff9SHoward Wang 862*63d37ff9SHoward Wang void 863*63d37ff9SHoward Wang rtl_tx_queue_release(struct rte_eth_dev *dev, uint16_t tx_queue_id) 864*63d37ff9SHoward Wang { 865*63d37ff9SHoward Wang struct rtl_tx_queue *txq = dev->data->tx_queues[tx_queue_id]; 866*63d37ff9SHoward Wang 867*63d37ff9SHoward Wang PMD_INIT_FUNC_TRACE(); 868*63d37ff9SHoward Wang 869*63d37ff9SHoward Wang if (txq != NULL) { 870*63d37ff9SHoward Wang rtl_tx_queue_release_mbufs(txq); 871*63d37ff9SHoward Wang rte_free(txq->sw_ring); 872*63d37ff9SHoward Wang rte_free(txq); 873*63d37ff9SHoward Wang } 874*63d37ff9SHoward Wang } 875*63d37ff9SHoward Wang 876*63d37ff9SHoward Wang void 877*63d37ff9SHoward Wang rtl_txq_info_get(struct rte_eth_dev *dev, uint16_t queue_id, 878*63d37ff9SHoward Wang struct rte_eth_txq_info *qinfo) 879*63d37ff9SHoward Wang { 880*63d37ff9SHoward Wang struct rtl_tx_queue *txq; 881*63d37ff9SHoward Wang 882*63d37ff9SHoward Wang txq = dev->data->tx_queues[queue_id]; 883*63d37ff9SHoward Wang 884*63d37ff9SHoward Wang qinfo->nb_desc = txq->nb_tx_desc; 885*63d37ff9SHoward Wang } 886*63d37ff9SHoward Wang 887*63d37ff9SHoward Wang static void 888*63d37ff9SHoward Wang rtl_reset_tx_queue(struct rtl_tx_queue *txq) 889*63d37ff9SHoward Wang { 890*63d37ff9SHoward Wang static const struct rtl_tx_desc zero_txd = {0}; 891*63d37ff9SHoward Wang int i; 892*63d37ff9SHoward Wang 893*63d37ff9SHoward Wang for (i = 0; i < txq->nb_tx_desc; i++) 894*63d37ff9SHoward Wang txq->hw_ring[i] = zero_txd; 895*63d37ff9SHoward Wang 896*63d37ff9SHoward Wang txq->hw_ring[txq->nb_tx_desc - 1].opts1 = rte_cpu_to_le_32(RingEnd); 897*63d37ff9SHoward Wang 898*63d37ff9SHoward Wang txq->tx_tail = 0; 899*63d37ff9SHoward Wang txq->tx_head = 0; 900*63d37ff9SHoward Wang txq->tx_free = txq->nb_tx_desc - 1; 901*63d37ff9SHoward Wang } 902*63d37ff9SHoward Wang 903*63d37ff9SHoward Wang uint64_t 904*63d37ff9SHoward Wang rtl_get_tx_port_offloads(void) 905*63d37ff9SHoward Wang { 906*63d37ff9SHoward Wang uint64_t tx_offload_capa; 907*63d37ff9SHoward Wang 908*63d37ff9SHoward Wang tx_offload_capa = RTE_ETH_TX_OFFLOAD_VLAN_INSERT | 909*63d37ff9SHoward Wang RTE_ETH_TX_OFFLOAD_IPV4_CKSUM | 910*63d37ff9SHoward Wang RTE_ETH_TX_OFFLOAD_UDP_CKSUM | 911*63d37ff9SHoward Wang RTE_ETH_TX_OFFLOAD_TCP_CKSUM | 912*63d37ff9SHoward Wang RTE_ETH_TX_OFFLOAD_TCP_TSO | 913*63d37ff9SHoward Wang RTE_ETH_TX_OFFLOAD_MULTI_SEGS; 914*63d37ff9SHoward Wang 915*63d37ff9SHoward Wang return tx_offload_capa; 916*63d37ff9SHoward Wang } 917*63d37ff9SHoward Wang 918*63d37ff9SHoward Wang int 919*63d37ff9SHoward Wang rtl_tx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_idx, 920*63d37ff9SHoward Wang uint16_t nb_tx_desc, unsigned int socket_id, 921*63d37ff9SHoward Wang const struct rte_eth_txconf *tx_conf) 922*63d37ff9SHoward Wang { 923*63d37ff9SHoward Wang struct rtl_tx_queue *txq; 924*63d37ff9SHoward Wang const struct rte_memzone *mz; 925*63d37ff9SHoward Wang struct rtl_adapter *adapter = RTL_DEV_PRIVATE(dev); 926*63d37ff9SHoward Wang struct rtl_hw *hw = &adapter->hw; 927*63d37ff9SHoward Wang u32 size; 928*63d37ff9SHoward Wang 929*63d37ff9SHoward Wang PMD_INIT_FUNC_TRACE(); 930*63d37ff9SHoward Wang 931*63d37ff9SHoward Wang /* 932*63d37ff9SHoward Wang * If this queue existed already, free the associated memory. The 933*63d37ff9SHoward Wang * queue cannot be reused in case we need to allocate memory on 934*63d37ff9SHoward Wang * different socket than was previously used. 935*63d37ff9SHoward Wang */ 936*63d37ff9SHoward Wang if (dev->data->tx_queues[queue_idx] != NULL) { 937*63d37ff9SHoward Wang rtl_tx_queue_release(dev, queue_idx); 938*63d37ff9SHoward Wang dev->data->tx_queues[queue_idx] = NULL; 939*63d37ff9SHoward Wang } 940*63d37ff9SHoward Wang 941*63d37ff9SHoward Wang txq = rte_zmalloc_socket("r8169 TX queue", sizeof(struct rtl_tx_queue), 942*63d37ff9SHoward Wang RTE_CACHE_LINE_SIZE, socket_id); 943*63d37ff9SHoward Wang 944*63d37ff9SHoward Wang if (txq == NULL) { 945*63d37ff9SHoward Wang PMD_INIT_LOG(ERR, "Cannot allocate Tx queue structure"); 946*63d37ff9SHoward Wang return -ENOMEM; 947*63d37ff9SHoward Wang } 948*63d37ff9SHoward Wang 949*63d37ff9SHoward Wang /* Setup queue */ 950*63d37ff9SHoward Wang txq->nb_tx_desc = nb_tx_desc; 951*63d37ff9SHoward Wang txq->port_id = dev->data->port_id; 952*63d37ff9SHoward Wang txq->queue_id = queue_idx; 953*63d37ff9SHoward Wang txq->tx_free_thresh = tx_conf->tx_free_thresh; 954*63d37ff9SHoward Wang 955*63d37ff9SHoward Wang /* Allocate memory for the software ring */ 956*63d37ff9SHoward Wang txq->sw_ring = rte_calloc("r8169 sw tx ring", nb_tx_desc, 957*63d37ff9SHoward Wang sizeof(struct rtl_tx_entry), RTE_CACHE_LINE_SIZE); 958*63d37ff9SHoward Wang 959*63d37ff9SHoward Wang if (txq->sw_ring == NULL) { 960*63d37ff9SHoward Wang PMD_INIT_LOG(ERR, 961*63d37ff9SHoward Wang "Port %d: Cannot allocate software ring for queue %d", 962*63d37ff9SHoward Wang txq->port_id, txq->queue_id); 963*63d37ff9SHoward Wang rte_free(txq); 964*63d37ff9SHoward Wang return -ENOMEM; 965*63d37ff9SHoward Wang } 966*63d37ff9SHoward Wang 967*63d37ff9SHoward Wang /* 968*63d37ff9SHoward Wang * Allocate TX ring hardware descriptors. A memzone large enough to 969*63d37ff9SHoward Wang * handle the maximum ring size is allocated in order to allow for 970*63d37ff9SHoward Wang * resizing in later calls to the queue setup function. 971*63d37ff9SHoward Wang */ 972*63d37ff9SHoward Wang size = sizeof(struct rtl_tx_desc) * (nb_tx_desc + 1); 973*63d37ff9SHoward Wang mz = rte_eth_dma_zone_reserve(dev, "tx_ring", queue_idx, size, 974*63d37ff9SHoward Wang RTL_RING_ALIGN, socket_id); 975*63d37ff9SHoward Wang if (mz == NULL) { 976*63d37ff9SHoward Wang PMD_INIT_LOG(ERR, 977*63d37ff9SHoward Wang "Port %d: Cannot allocate hardware ring for queue %d", 978*63d37ff9SHoward Wang txq->port_id, txq->queue_id); 979*63d37ff9SHoward Wang rtl_tx_queue_release(dev, txq->queue_id); 980*63d37ff9SHoward Wang return -ENOMEM; 981*63d37ff9SHoward Wang } 982*63d37ff9SHoward Wang 983*63d37ff9SHoward Wang txq->hw = hw; 984*63d37ff9SHoward Wang txq->hw_ring = mz->addr; 985*63d37ff9SHoward Wang txq->hw_ring_phys_addr = mz->iova; 986*63d37ff9SHoward Wang 987*63d37ff9SHoward Wang rtl_reset_tx_queue(txq); 988*63d37ff9SHoward Wang 989*63d37ff9SHoward Wang /* EnableTxNoClose */ 990*63d37ff9SHoward Wang hw->NextHwDesCloPtr0 = 0; 991*63d37ff9SHoward Wang hw->BeginHwDesCloPtr0 = 0; 992*63d37ff9SHoward Wang 993*63d37ff9SHoward Wang dev->data->tx_queues[queue_idx] = txq; 994*63d37ff9SHoward Wang 9951bbe869eSHoward Wang return 0; 9961bbe869eSHoward Wang } 9971bbe869eSHoward Wang 998*63d37ff9SHoward Wang int 999*63d37ff9SHoward Wang rtl_tx_init(struct rte_eth_dev *dev) 10001bbe869eSHoward Wang { 1001*63d37ff9SHoward Wang struct rtl_adapter *adapter = RTL_DEV_PRIVATE(dev); 1002*63d37ff9SHoward Wang struct rtl_hw *hw = &adapter->hw; 1003*63d37ff9SHoward Wang struct rtl_tx_queue *txq; 1004*63d37ff9SHoward Wang 1005*63d37ff9SHoward Wang txq = dev->data->tx_queues[0]; 1006*63d37ff9SHoward Wang 1007*63d37ff9SHoward Wang RTL_W32(hw, TxDescStartAddrLow, 1008*63d37ff9SHoward Wang ((u64)txq->hw_ring_phys_addr & DMA_BIT_MASK(32))); 1009*63d37ff9SHoward Wang RTL_W32(hw, TxDescStartAddrHigh, ((u64)txq->hw_ring_phys_addr >> 32)); 1010*63d37ff9SHoward Wang 1011*63d37ff9SHoward Wang rtl_enable_cfg9346_write(hw); 1012*63d37ff9SHoward Wang 1013*63d37ff9SHoward Wang /* Set TDFNR: TX Desc Fetch NumbeR */ 1014*63d37ff9SHoward Wang switch (hw->mcfg) { 1015*63d37ff9SHoward Wang case CFG_METHOD_48 ... CFG_METHOD_57: 1016*63d37ff9SHoward Wang case CFG_METHOD_69 ... CFG_METHOD_71: 1017*63d37ff9SHoward Wang RTL_W8(hw, TDFNR, 0x10); 1018*63d37ff9SHoward Wang break; 1019*63d37ff9SHoward Wang } 1020*63d37ff9SHoward Wang 1021*63d37ff9SHoward Wang rtl_disable_cfg9346_write(hw); 1022*63d37ff9SHoward Wang 1023*63d37ff9SHoward Wang RTL_W8(hw, ChipCmd, RTL_R8(hw, ChipCmd) | CmdTxEnb); 1024*63d37ff9SHoward Wang 1025*63d37ff9SHoward Wang dev->data->tx_queue_state[0] = RTE_ETH_QUEUE_STATE_STARTED; 1026*63d37ff9SHoward Wang 10271bbe869eSHoward Wang return 0; 10281bbe869eSHoward Wang } 10292f198f0aSHoward Wang 1030*63d37ff9SHoward Wang static inline uint32_t 1031*63d37ff9SHoward Wang rtl_tx_vlan_tag(struct rte_mbuf *tx_pkt, uint64_t ol_flags) 1032*63d37ff9SHoward Wang { 1033*63d37ff9SHoward Wang return (ol_flags & RTE_MBUF_F_TX_VLAN) ? 1034*63d37ff9SHoward Wang (TxVlanTag | rte_bswap16(tx_pkt->vlan_tci)) : 1035*63d37ff9SHoward Wang 0; 1036*63d37ff9SHoward Wang } 1037*63d37ff9SHoward Wang 1038*63d37ff9SHoward Wang static inline int 1039*63d37ff9SHoward Wang rtl_tso_setup(struct rte_mbuf *tx_pkt, uint64_t ol_flags, u32 *opts) 1040*63d37ff9SHoward Wang { 1041*63d37ff9SHoward Wang uint32_t mss; 1042*63d37ff9SHoward Wang uint64_t l4_offset; 1043*63d37ff9SHoward Wang 1044*63d37ff9SHoward Wang /* Check if TCP segmentation required for this packet */ 1045*63d37ff9SHoward Wang if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) { 1046*63d37ff9SHoward Wang mss = tx_pkt->tso_segsz; 1047*63d37ff9SHoward Wang l4_offset = tx_pkt->l2_len + tx_pkt->l3_len; 1048*63d37ff9SHoward Wang if (l4_offset <= GTTCPHO_MAX) { 1049*63d37ff9SHoward Wang /* Implies IP cksum in IPv4 */ 1050*63d37ff9SHoward Wang if (ol_flags & RTE_MBUF_F_TX_IP_CKSUM) 1051*63d37ff9SHoward Wang opts[0] |= GiantSendv4; 1052*63d37ff9SHoward Wang else 1053*63d37ff9SHoward Wang opts[0] |= GiantSendv6; 1054*63d37ff9SHoward Wang 1055*63d37ff9SHoward Wang opts[0] |= l4_offset << GTTCPHO_SHIFT; 1056*63d37ff9SHoward Wang opts[1] |= RTE_MIN(mss, MSS_MAX) << 18; 1057*63d37ff9SHoward Wang 1058*63d37ff9SHoward Wang return 1; 1059*63d37ff9SHoward Wang } 1060*63d37ff9SHoward Wang } 1061*63d37ff9SHoward Wang 1062*63d37ff9SHoward Wang return 0; 1063*63d37ff9SHoward Wang } 1064*63d37ff9SHoward Wang 1065*63d37ff9SHoward Wang static inline void 1066*63d37ff9SHoward Wang rtl_setup_csum_offload(struct rte_mbuf *tx_pkt, uint64_t ol_flags, 1067*63d37ff9SHoward Wang uint32_t *opts) 1068*63d37ff9SHoward Wang { 1069*63d37ff9SHoward Wang uint32_t csum_cmd = 0; 1070*63d37ff9SHoward Wang uint64_t l4_offset; 1071*63d37ff9SHoward Wang 1072*63d37ff9SHoward Wang if (ol_flags & RTE_MBUF_F_TX_IP_CKSUM) 1073*63d37ff9SHoward Wang csum_cmd |= TxIPCS_C; 1074*63d37ff9SHoward Wang 1075*63d37ff9SHoward Wang switch (ol_flags & RTE_MBUF_F_TX_L4_MASK) { 1076*63d37ff9SHoward Wang case RTE_MBUF_F_TX_UDP_CKSUM: 1077*63d37ff9SHoward Wang csum_cmd |= TxUDPCS_C; 1078*63d37ff9SHoward Wang break; 1079*63d37ff9SHoward Wang case RTE_MBUF_F_TX_TCP_CKSUM: 1080*63d37ff9SHoward Wang csum_cmd |= TxTCPCS_C; 1081*63d37ff9SHoward Wang break; 1082*63d37ff9SHoward Wang } 1083*63d37ff9SHoward Wang 1084*63d37ff9SHoward Wang if (csum_cmd != 0) { 1085*63d37ff9SHoward Wang if (ol_flags & RTE_MBUF_F_TX_IPV6) { 1086*63d37ff9SHoward Wang l4_offset = tx_pkt->l2_len + tx_pkt->l3_len; 1087*63d37ff9SHoward Wang csum_cmd |= TxIPV6F_C; 1088*63d37ff9SHoward Wang csum_cmd |= l4_offset << TCPHO_SHIFT; 1089*63d37ff9SHoward Wang } else { 1090*63d37ff9SHoward Wang csum_cmd |= TxIPCS_C; 1091*63d37ff9SHoward Wang } 1092*63d37ff9SHoward Wang opts[1] |= csum_cmd; 1093*63d37ff9SHoward Wang } 1094*63d37ff9SHoward Wang } 1095*63d37ff9SHoward Wang 1096*63d37ff9SHoward Wang static uint32_t 1097*63d37ff9SHoward Wang rtl8125_get_patch_pad_len(struct rte_mbuf *tx_pkt) 1098*63d37ff9SHoward Wang { 1099*63d37ff9SHoward Wang uint16_t dest_port; 1100*63d37ff9SHoward Wang uint32_t pad_len = 0; 1101*63d37ff9SHoward Wang int udp_hdr_len = sizeof(struct rte_udp_hdr); 1102*63d37ff9SHoward Wang int trans_data_len, l4_offset; 1103*63d37ff9SHoward Wang struct rte_udp_hdr *udp_hdr; 1104*63d37ff9SHoward Wang 1105*63d37ff9SHoward Wang if (!(tx_pkt->l4_len && tx_pkt->data_len < 175)) 1106*63d37ff9SHoward Wang goto no_padding; 1107*63d37ff9SHoward Wang 1108*63d37ff9SHoward Wang l4_offset = tx_pkt->l2_len + tx_pkt->l3_len; 1109*63d37ff9SHoward Wang trans_data_len = tx_pkt->data_len - l4_offset; 1110*63d37ff9SHoward Wang 1111*63d37ff9SHoward Wang if (trans_data_len > 3 && trans_data_len < MIN_PATCH_LENGTH) { 1112*63d37ff9SHoward Wang udp_hdr = rte_pktmbuf_mtod_offset(tx_pkt, struct rte_udp_hdr *, l4_offset); 1113*63d37ff9SHoward Wang dest_port = ntohs(udp_hdr->dst_port); 1114*63d37ff9SHoward Wang if (dest_port == 0x13f || dest_port == 0x140) { 1115*63d37ff9SHoward Wang pad_len = MIN_PATCH_LENGTH - trans_data_len; 1116*63d37ff9SHoward Wang goto out; 1117*63d37ff9SHoward Wang } 1118*63d37ff9SHoward Wang } 1119*63d37ff9SHoward Wang 1120*63d37ff9SHoward Wang if (trans_data_len < udp_hdr_len) 1121*63d37ff9SHoward Wang pad_len = udp_hdr_len - trans_data_len; 1122*63d37ff9SHoward Wang 1123*63d37ff9SHoward Wang out: 1124*63d37ff9SHoward Wang if ((tx_pkt->data_len + pad_len) < ETH_ZLEN) 1125*63d37ff9SHoward Wang pad_len = ETH_ZLEN - tx_pkt->data_len; 1126*63d37ff9SHoward Wang 1127*63d37ff9SHoward Wang return pad_len; 1128*63d37ff9SHoward Wang 1129*63d37ff9SHoward Wang no_padding: 1130*63d37ff9SHoward Wang 1131*63d37ff9SHoward Wang return 0; 1132*63d37ff9SHoward Wang } 1133*63d37ff9SHoward Wang 1134*63d37ff9SHoward Wang static void 1135*63d37ff9SHoward Wang rtl8125_ptp_patch(struct rte_mbuf *tx_pkt) 1136*63d37ff9SHoward Wang { 1137*63d37ff9SHoward Wang uint32_t pad_len; 1138*63d37ff9SHoward Wang char *padding; 1139*63d37ff9SHoward Wang 1140*63d37ff9SHoward Wang if (tx_pkt->packet_type & RTE_PTYPE_L4_UDP) { 1141*63d37ff9SHoward Wang pad_len = rtl8125_get_patch_pad_len(tx_pkt); 1142*63d37ff9SHoward Wang if (pad_len > 0) { 1143*63d37ff9SHoward Wang padding = rte_pktmbuf_append(tx_pkt, pad_len); 1144*63d37ff9SHoward Wang if (unlikely(padding == NULL)) 1145*63d37ff9SHoward Wang PMD_DRV_LOG(ERR, "Not enough mbuf trailing space."); 1146*63d37ff9SHoward Wang memset(padding, 0, pad_len); 1147*63d37ff9SHoward Wang } 1148*63d37ff9SHoward Wang } 1149*63d37ff9SHoward Wang } 1150*63d37ff9SHoward Wang 1151*63d37ff9SHoward Wang static inline void 1152*63d37ff9SHoward Wang rtl_xmit_pkt(struct rtl_hw *hw, struct rtl_tx_queue *txq, 1153*63d37ff9SHoward Wang struct rte_mbuf *tx_pkt) 1154*63d37ff9SHoward Wang { 1155*63d37ff9SHoward Wang struct rte_mbuf *m_seg; 1156*63d37ff9SHoward Wang struct rte_eth_dev *dev = &rte_eth_devices[txq->port_id]; 1157*63d37ff9SHoward Wang struct rtl_adapter *adapter = RTL_DEV_PRIVATE(dev); 1158*63d37ff9SHoward Wang struct rtl_sw_stats *stats = &adapter->sw_stats; 1159*63d37ff9SHoward Wang struct rtl_tx_desc *txd; 1160*63d37ff9SHoward Wang struct rtl_tx_entry *txe = NULL; 1161*63d37ff9SHoward Wang uint16_t desc_count = 0; 1162*63d37ff9SHoward Wang const uint16_t nb_tx_desc = txq->nb_tx_desc; 1163*63d37ff9SHoward Wang uint16_t tail; 1164*63d37ff9SHoward Wang u32 len; 1165*63d37ff9SHoward Wang u32 opts[2] = {0}; 1166*63d37ff9SHoward Wang u32 opts1; 1167*63d37ff9SHoward Wang u32 opts2; 1168*63d37ff9SHoward Wang int large_send; 1169*63d37ff9SHoward Wang uint64_t buf_dma_addr; 1170*63d37ff9SHoward Wang uint64_t ol_flags; 1171*63d37ff9SHoward Wang uint64_t tx_ol_flags; 1172*63d37ff9SHoward Wang 1173*63d37ff9SHoward Wang /* Like cur_tx */ 1174*63d37ff9SHoward Wang tail = (uint16_t)(txq->tx_tail % nb_tx_desc); 1175*63d37ff9SHoward Wang 1176*63d37ff9SHoward Wang /* If hardware offload required */ 1177*63d37ff9SHoward Wang ol_flags = tx_pkt->ol_flags; 1178*63d37ff9SHoward Wang tx_ol_flags = ol_flags & RTL_TX_OFFLOAD_MASK; 1179*63d37ff9SHoward Wang 1180*63d37ff9SHoward Wang opts[0] = DescOwn; 1181*63d37ff9SHoward Wang opts[1] = rtl_tx_vlan_tag(tx_pkt, tx_ol_flags); 1182*63d37ff9SHoward Wang 1183*63d37ff9SHoward Wang large_send = rtl_tso_setup(tx_pkt, tx_ol_flags, opts); 1184*63d37ff9SHoward Wang 1185*63d37ff9SHoward Wang /* No TSO */ 1186*63d37ff9SHoward Wang if (large_send == 0) { 1187*63d37ff9SHoward Wang rtl_setup_csum_offload(tx_pkt, tx_ol_flags, opts); 1188*63d37ff9SHoward Wang 1189*63d37ff9SHoward Wang switch (hw->mcfg) { 1190*63d37ff9SHoward Wang case CFG_METHOD_48 ... CFG_METHOD_53: 1191*63d37ff9SHoward Wang rtl8125_ptp_patch(tx_pkt); 1192*63d37ff9SHoward Wang break; 1193*63d37ff9SHoward Wang } 1194*63d37ff9SHoward Wang } 1195*63d37ff9SHoward Wang 1196*63d37ff9SHoward Wang for (m_seg = tx_pkt; m_seg; m_seg = m_seg->next) { 1197*63d37ff9SHoward Wang opts1 = opts[0]; 1198*63d37ff9SHoward Wang opts2 = opts[1]; 1199*63d37ff9SHoward Wang 1200*63d37ff9SHoward Wang len = m_seg->data_len; 1201*63d37ff9SHoward Wang 1202*63d37ff9SHoward Wang if (len == 0) 1203*63d37ff9SHoward Wang break; 1204*63d37ff9SHoward Wang 1205*63d37ff9SHoward Wang txd = &txq->hw_ring[tail]; 1206*63d37ff9SHoward Wang 1207*63d37ff9SHoward Wang buf_dma_addr = rte_mbuf_data_iova(m_seg); 1208*63d37ff9SHoward Wang txd->addr = rte_cpu_to_le_64(buf_dma_addr); 1209*63d37ff9SHoward Wang 1210*63d37ff9SHoward Wang opts1 |= len; 1211*63d37ff9SHoward Wang if (m_seg == tx_pkt) 1212*63d37ff9SHoward Wang opts1 |= FirstFrag; 1213*63d37ff9SHoward Wang if (!m_seg->next) 1214*63d37ff9SHoward Wang opts1 |= LastFrag; 1215*63d37ff9SHoward Wang if (tail == nb_tx_desc - 1) 1216*63d37ff9SHoward Wang opts1 |= RingEnd; 1217*63d37ff9SHoward Wang 1218*63d37ff9SHoward Wang /* Store mbuf for freeing later */ 1219*63d37ff9SHoward Wang txe = &txq->sw_ring[tail]; 1220*63d37ff9SHoward Wang 1221*63d37ff9SHoward Wang if (txe->mbuf) 1222*63d37ff9SHoward Wang rte_pktmbuf_free_seg(txe->mbuf); 1223*63d37ff9SHoward Wang 1224*63d37ff9SHoward Wang txe->mbuf = m_seg; 1225*63d37ff9SHoward Wang 1226*63d37ff9SHoward Wang txd->opts2 = rte_cpu_to_le_32(opts2); 1227*63d37ff9SHoward Wang rte_wmb(); 1228*63d37ff9SHoward Wang txd->opts1 = rte_cpu_to_le_32(opts1); 1229*63d37ff9SHoward Wang 1230*63d37ff9SHoward Wang tail = (tail + 1) % nb_tx_desc; 1231*63d37ff9SHoward Wang 1232*63d37ff9SHoward Wang desc_count++; 1233*63d37ff9SHoward Wang 1234*63d37ff9SHoward Wang stats->tx_bytes += len; 1235*63d37ff9SHoward Wang } 1236*63d37ff9SHoward Wang 1237*63d37ff9SHoward Wang txq->tx_tail += desc_count; 1238*63d37ff9SHoward Wang txq->tx_free -= desc_count; 1239*63d37ff9SHoward Wang 1240*63d37ff9SHoward Wang stats->tx_packets++; 1241*63d37ff9SHoward Wang } 1242*63d37ff9SHoward Wang 1243*63d37ff9SHoward Wang static inline u32 1244*63d37ff9SHoward Wang rtl_fast_mod_mask(const u32 input, const u32 mask) 1245*63d37ff9SHoward Wang { 1246*63d37ff9SHoward Wang return input > mask ? input & mask : input; 1247*63d37ff9SHoward Wang } 1248*63d37ff9SHoward Wang 1249*63d37ff9SHoward Wang static u32 1250*63d37ff9SHoward Wang rtl_get_hw_clo_ptr(struct rtl_hw *hw) 1251*63d37ff9SHoward Wang { 1252*63d37ff9SHoward Wang switch (hw->HwSuppTxNoCloseVer) { 1253*63d37ff9SHoward Wang case 3: 1254*63d37ff9SHoward Wang return RTL_R16(hw, hw->hw_clo_ptr_reg); 1255*63d37ff9SHoward Wang case 4: 1256*63d37ff9SHoward Wang case 5: 1257*63d37ff9SHoward Wang case 6: 1258*63d37ff9SHoward Wang return RTL_R32(hw, hw->hw_clo_ptr_reg); 1259*63d37ff9SHoward Wang default: 1260*63d37ff9SHoward Wang return 0; 1261*63d37ff9SHoward Wang } 1262*63d37ff9SHoward Wang } 1263*63d37ff9SHoward Wang 1264*63d37ff9SHoward Wang static u32 1265*63d37ff9SHoward Wang rtl_get_opts1(struct rtl_tx_desc *txd) 1266*63d37ff9SHoward Wang { 1267*63d37ff9SHoward Wang rte_smp_rmb(); 1268*63d37ff9SHoward Wang 1269*63d37ff9SHoward Wang return rte_le_to_cpu_32(txd->opts1); 1270*63d37ff9SHoward Wang } 1271*63d37ff9SHoward Wang 1272*63d37ff9SHoward Wang static void 1273*63d37ff9SHoward Wang rtl_tx_clean(struct rtl_hw *hw, struct rtl_tx_queue *txq) 1274*63d37ff9SHoward Wang { 1275*63d37ff9SHoward Wang struct rtl_tx_entry *sw_ring = txq->sw_ring; 1276*63d37ff9SHoward Wang struct rtl_tx_entry *txe; 1277*63d37ff9SHoward Wang struct rtl_tx_desc *txd; 1278*63d37ff9SHoward Wang const uint8_t enable_tx_no_close = hw->EnableTxNoClose; 1279*63d37ff9SHoward Wang const uint16_t nb_tx_desc = txq->nb_tx_desc; 1280*63d37ff9SHoward Wang uint16_t head = txq->tx_head; 1281*63d37ff9SHoward Wang uint16_t desc_freed = 0; 1282*63d37ff9SHoward Wang uint32_t tx_left; 1283*63d37ff9SHoward Wang uint32_t tx_desc_closed, next_hw_desc_clo_ptr0; 1284*63d37ff9SHoward Wang 1285*63d37ff9SHoward Wang if (txq == NULL) 1286*63d37ff9SHoward Wang return; 1287*63d37ff9SHoward Wang 1288*63d37ff9SHoward Wang if (enable_tx_no_close) { 1289*63d37ff9SHoward Wang next_hw_desc_clo_ptr0 = rtl_get_hw_clo_ptr(hw); 1290*63d37ff9SHoward Wang hw->NextHwDesCloPtr0 = next_hw_desc_clo_ptr0; 1291*63d37ff9SHoward Wang tx_desc_closed = rtl_fast_mod_mask(next_hw_desc_clo_ptr0 - 1292*63d37ff9SHoward Wang hw->BeginHwDesCloPtr0, hw->MaxTxDescPtrMask); 1293*63d37ff9SHoward Wang tx_left = RTE_MIN(((rte_atomic_load_explicit(&txq->tx_tail, 1294*63d37ff9SHoward Wang rte_memory_order_relaxed) % nb_tx_desc) - head), 1295*63d37ff9SHoward Wang tx_desc_closed); 1296*63d37ff9SHoward Wang hw->BeginHwDesCloPtr0 += tx_left; 1297*63d37ff9SHoward Wang } else { 1298*63d37ff9SHoward Wang tx_left = (rte_atomic_load_explicit(&txq->tx_tail, 1299*63d37ff9SHoward Wang rte_memory_order_relaxed) % nb_tx_desc) - head; 1300*63d37ff9SHoward Wang } 1301*63d37ff9SHoward Wang 1302*63d37ff9SHoward Wang while (tx_left > 0) { 1303*63d37ff9SHoward Wang txd = &txq->hw_ring[head]; 1304*63d37ff9SHoward Wang 1305*63d37ff9SHoward Wang if (!enable_tx_no_close && (rtl_get_opts1(txd) & DescOwn)) 1306*63d37ff9SHoward Wang break; 1307*63d37ff9SHoward Wang 1308*63d37ff9SHoward Wang txe = &sw_ring[head]; 1309*63d37ff9SHoward Wang if (txe->mbuf) { 1310*63d37ff9SHoward Wang rte_pktmbuf_free_seg(txe->mbuf); 1311*63d37ff9SHoward Wang txe->mbuf = NULL; 1312*63d37ff9SHoward Wang } 1313*63d37ff9SHoward Wang 1314*63d37ff9SHoward Wang head = (head + 1) % nb_tx_desc; 1315*63d37ff9SHoward Wang desc_freed++; 1316*63d37ff9SHoward Wang tx_left--; 1317*63d37ff9SHoward Wang } 1318*63d37ff9SHoward Wang txq->tx_free += desc_freed; 1319*63d37ff9SHoward Wang txq->tx_head = head; 1320*63d37ff9SHoward Wang } 1321*63d37ff9SHoward Wang 1322*63d37ff9SHoward Wang int 1323*63d37ff9SHoward Wang rtl_tx_done_cleanup(void *tx_queue, uint32_t free_cnt) 1324*63d37ff9SHoward Wang { 1325*63d37ff9SHoward Wang struct rtl_tx_queue *txq = tx_queue; 1326*63d37ff9SHoward Wang struct rtl_hw *hw = txq->hw; 1327*63d37ff9SHoward Wang struct rtl_tx_entry *sw_ring = txq->sw_ring; 1328*63d37ff9SHoward Wang struct rtl_tx_entry *txe; 1329*63d37ff9SHoward Wang struct rtl_tx_desc *txd; 1330*63d37ff9SHoward Wang const uint8_t enable_tx_no_close = hw->EnableTxNoClose; 1331*63d37ff9SHoward Wang const uint16_t nb_tx_desc = txq->nb_tx_desc; 1332*63d37ff9SHoward Wang uint16_t head = txq->tx_head; 1333*63d37ff9SHoward Wang uint16_t desc_freed = 0; 1334*63d37ff9SHoward Wang uint32_t tx_left; 1335*63d37ff9SHoward Wang uint32_t count = 0; 1336*63d37ff9SHoward Wang uint32_t status; 1337*63d37ff9SHoward Wang uint32_t tx_desc_closed, next_hw_desc_clo_ptr0; 1338*63d37ff9SHoward Wang 1339*63d37ff9SHoward Wang if (txq == NULL) 1340*63d37ff9SHoward Wang return -ENODEV; 1341*63d37ff9SHoward Wang 1342*63d37ff9SHoward Wang if (enable_tx_no_close) { 1343*63d37ff9SHoward Wang next_hw_desc_clo_ptr0 = rtl_get_hw_clo_ptr(hw); 1344*63d37ff9SHoward Wang hw->NextHwDesCloPtr0 = next_hw_desc_clo_ptr0; 1345*63d37ff9SHoward Wang tx_desc_closed = rtl_fast_mod_mask(next_hw_desc_clo_ptr0 - 1346*63d37ff9SHoward Wang hw->BeginHwDesCloPtr0, hw->MaxTxDescPtrMask); 1347*63d37ff9SHoward Wang tx_left = RTE_MIN(((rte_atomic_load_explicit(&txq->tx_tail, 1348*63d37ff9SHoward Wang rte_memory_order_relaxed) % nb_tx_desc) - head), 1349*63d37ff9SHoward Wang tx_desc_closed); 1350*63d37ff9SHoward Wang hw->BeginHwDesCloPtr0 += tx_left; 1351*63d37ff9SHoward Wang } else { 1352*63d37ff9SHoward Wang tx_left = (rte_atomic_load_explicit(&txq->tx_tail, 1353*63d37ff9SHoward Wang rte_memory_order_relaxed) % nb_tx_desc) - head; 1354*63d37ff9SHoward Wang } 1355*63d37ff9SHoward Wang 1356*63d37ff9SHoward Wang while (tx_left > 0) { 1357*63d37ff9SHoward Wang txd = &txq->hw_ring[head]; 1358*63d37ff9SHoward Wang 1359*63d37ff9SHoward Wang status = rtl_get_opts1(txd); 1360*63d37ff9SHoward Wang 1361*63d37ff9SHoward Wang if (!enable_tx_no_close && (status & DescOwn)) 1362*63d37ff9SHoward Wang break; 1363*63d37ff9SHoward Wang 1364*63d37ff9SHoward Wang txe = &sw_ring[head]; 1365*63d37ff9SHoward Wang if (txe->mbuf) { 1366*63d37ff9SHoward Wang rte_pktmbuf_free_seg(txe->mbuf); 1367*63d37ff9SHoward Wang txe->mbuf = NULL; 1368*63d37ff9SHoward Wang } 1369*63d37ff9SHoward Wang 1370*63d37ff9SHoward Wang head = (head + 1) % nb_tx_desc; 1371*63d37ff9SHoward Wang 1372*63d37ff9SHoward Wang desc_freed++; 1373*63d37ff9SHoward Wang tx_left--; 1374*63d37ff9SHoward Wang 1375*63d37ff9SHoward Wang if (status & LastFrag) { 1376*63d37ff9SHoward Wang count++; 1377*63d37ff9SHoward Wang if (count == free_cnt) 1378*63d37ff9SHoward Wang break; 1379*63d37ff9SHoward Wang } 1380*63d37ff9SHoward Wang } 1381*63d37ff9SHoward Wang 1382*63d37ff9SHoward Wang txq->tx_free += desc_freed; 1383*63d37ff9SHoward Wang txq->tx_head = head; 1384*63d37ff9SHoward Wang 1385*63d37ff9SHoward Wang return count; 1386*63d37ff9SHoward Wang } 1387*63d37ff9SHoward Wang 1388*63d37ff9SHoward Wang static void 1389*63d37ff9SHoward Wang rtl_doorbell(struct rtl_hw *hw, struct rtl_tx_queue *txq) 1390*63d37ff9SHoward Wang { 1391*63d37ff9SHoward Wang if (hw->EnableTxNoClose) 1392*63d37ff9SHoward Wang if (hw->HwSuppTxNoCloseVer > 3) 1393*63d37ff9SHoward Wang RTL_W32(hw, hw->sw_tail_ptr_reg, txq->tx_tail); 1394*63d37ff9SHoward Wang else 1395*63d37ff9SHoward Wang RTL_W16(hw, hw->sw_tail_ptr_reg, txq->tx_tail); 1396*63d37ff9SHoward Wang else 1397*63d37ff9SHoward Wang RTL_W16(hw, TPPOLL_8125, BIT_0); 1398*63d37ff9SHoward Wang } 1399*63d37ff9SHoward Wang 1400*63d37ff9SHoward Wang /* PMD transmit function */ 1401*63d37ff9SHoward Wang uint16_t 1402*63d37ff9SHoward Wang rtl_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) 1403*63d37ff9SHoward Wang { 1404*63d37ff9SHoward Wang struct rtl_tx_queue *txq = tx_queue; 1405*63d37ff9SHoward Wang struct rtl_hw *hw = txq->hw; 1406*63d37ff9SHoward Wang struct rte_mbuf *tx_pkt; 1407*63d37ff9SHoward Wang uint16_t nb_tx; 1408*63d37ff9SHoward Wang 1409*63d37ff9SHoward Wang RTE_ASSERT(RTL_R8(hw, ChipCmd) & CmdTxEnb); 1410*63d37ff9SHoward Wang 1411*63d37ff9SHoward Wang PMD_TX_LOG(DEBUG, 1412*63d37ff9SHoward Wang "port %d txq %d pkts: %d tx_free=%d tx_tail=%d tx_head=%d", 1413*63d37ff9SHoward Wang txq->port_id, txq->queue_id, nb_pkts, txq->tx_free, 1414*63d37ff9SHoward Wang txq->tx_tail, txq->tx_head); 1415*63d37ff9SHoward Wang 1416*63d37ff9SHoward Wang for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) { 1417*63d37ff9SHoward Wang tx_pkt = *tx_pkts++; 1418*63d37ff9SHoward Wang 1419*63d37ff9SHoward Wang if (txq->tx_free < tx_pkt->nb_segs) 1420*63d37ff9SHoward Wang break; 1421*63d37ff9SHoward Wang 1422*63d37ff9SHoward Wang /* Check mbuf is valid */ 1423*63d37ff9SHoward Wang if (tx_pkt->nb_segs == 0 || tx_pkt->pkt_len == 0 || 1424*63d37ff9SHoward Wang (tx_pkt->nb_segs > 1 && tx_pkt->next == NULL)) 1425*63d37ff9SHoward Wang break; 1426*63d37ff9SHoward Wang 1427*63d37ff9SHoward Wang rtl_xmit_pkt(hw, txq, tx_pkt); 1428*63d37ff9SHoward Wang } 1429*63d37ff9SHoward Wang 1430*63d37ff9SHoward Wang rte_wmb(); 1431*63d37ff9SHoward Wang 1432*63d37ff9SHoward Wang if (nb_tx > 0) 1433*63d37ff9SHoward Wang rtl_doorbell(hw, txq); 1434*63d37ff9SHoward Wang 1435*63d37ff9SHoward Wang PMD_TX_LOG(DEBUG, "%s %d transmitted", __func__, nb_tx); 1436*63d37ff9SHoward Wang 1437*63d37ff9SHoward Wang rtl_tx_clean(hw, txq); 1438*63d37ff9SHoward Wang 1439*63d37ff9SHoward Wang return nb_tx; 1440*63d37ff9SHoward Wang } 1441*63d37ff9SHoward Wang 14422f198f0aSHoward Wang int 14432f198f0aSHoward Wang rtl_stop_queues(struct rte_eth_dev *dev) 14442f198f0aSHoward Wang { 1445*63d37ff9SHoward Wang struct rtl_tx_queue *txq; 14462f198f0aSHoward Wang struct rtl_rx_queue *rxq; 14472f198f0aSHoward Wang 14482f198f0aSHoward Wang PMD_INIT_FUNC_TRACE(); 14492f198f0aSHoward Wang 1450*63d37ff9SHoward Wang txq = dev->data->tx_queues[0]; 1451*63d37ff9SHoward Wang 1452*63d37ff9SHoward Wang rtl_tx_queue_release_mbufs(txq); 1453*63d37ff9SHoward Wang rtl_reset_tx_queue(txq); 1454*63d37ff9SHoward Wang dev->data->tx_queue_state[0] = RTE_ETH_QUEUE_STATE_STOPPED; 1455*63d37ff9SHoward Wang 14562f198f0aSHoward Wang rxq = dev->data->rx_queues[0]; 14572f198f0aSHoward Wang 14582f198f0aSHoward Wang rtl_rx_queue_release_mbufs(rxq); 14592f198f0aSHoward Wang rtl_reset_rx_queue(rxq); 14602f198f0aSHoward Wang dev->data->rx_queue_state[0] = RTE_ETH_QUEUE_STATE_STOPPED; 14612f198f0aSHoward Wang 14622f198f0aSHoward Wang return 0; 14632f198f0aSHoward Wang } 14642f198f0aSHoward Wang 14652f198f0aSHoward Wang void 14662f198f0aSHoward Wang rtl_free_queues(struct rte_eth_dev *dev) 14672f198f0aSHoward Wang { 14682f198f0aSHoward Wang PMD_INIT_FUNC_TRACE(); 14692f198f0aSHoward Wang 14702f198f0aSHoward Wang rte_eth_dma_zone_free(dev, "rx_ring", 0); 14712f198f0aSHoward Wang rtl_rx_queue_release(dev, 0); 14722f198f0aSHoward Wang dev->data->rx_queues[0] = 0; 14732f198f0aSHoward Wang dev->data->nb_rx_queues = 0; 1474*63d37ff9SHoward Wang 1475*63d37ff9SHoward Wang rte_eth_dma_zone_free(dev, "tx_ring", 0); 1476*63d37ff9SHoward Wang rtl_tx_queue_release(dev, 0); 1477*63d37ff9SHoward Wang dev->data->tx_queues[0] = 0; 1478*63d37ff9SHoward Wang dev->data->nb_tx_queues = 0; 14792f198f0aSHoward Wang } 1480