xref: /dpdk/drivers/net/r8169/r8169_rxtx.c (revision 63d37ff9a453370a82a28ca8194f38b09aeb8191)
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