xref: /dpdk/lib/port/rte_port_ethdev.c (revision 99a2dd955fba6e4cc23b77d590a033650ced9c45)
1*99a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
2*99a2dd95SBruce Richardson  * Copyright(c) 2010-2014 Intel Corporation
3*99a2dd95SBruce Richardson  */
4*99a2dd95SBruce Richardson #include <string.h>
5*99a2dd95SBruce Richardson #include <stdint.h>
6*99a2dd95SBruce Richardson 
7*99a2dd95SBruce Richardson #include <rte_mbuf.h>
8*99a2dd95SBruce Richardson #include <rte_ethdev.h>
9*99a2dd95SBruce Richardson #include <rte_malloc.h>
10*99a2dd95SBruce Richardson 
11*99a2dd95SBruce Richardson #include "rte_port_ethdev.h"
12*99a2dd95SBruce Richardson 
13*99a2dd95SBruce Richardson /*
14*99a2dd95SBruce Richardson  * Port ETHDEV Reader
15*99a2dd95SBruce Richardson  */
16*99a2dd95SBruce Richardson #ifdef RTE_PORT_STATS_COLLECT
17*99a2dd95SBruce Richardson 
18*99a2dd95SBruce Richardson #define RTE_PORT_ETHDEV_READER_STATS_PKTS_IN_ADD(port, val) \
19*99a2dd95SBruce Richardson 	port->stats.n_pkts_in += val
20*99a2dd95SBruce Richardson #define RTE_PORT_ETHDEV_READER_STATS_PKTS_DROP_ADD(port, val) \
21*99a2dd95SBruce Richardson 	port->stats.n_pkts_drop += val
22*99a2dd95SBruce Richardson 
23*99a2dd95SBruce Richardson #else
24*99a2dd95SBruce Richardson 
25*99a2dd95SBruce Richardson #define RTE_PORT_ETHDEV_READER_STATS_PKTS_IN_ADD(port, val)
26*99a2dd95SBruce Richardson #define RTE_PORT_ETHDEV_READER_STATS_PKTS_DROP_ADD(port, val)
27*99a2dd95SBruce Richardson 
28*99a2dd95SBruce Richardson #endif
29*99a2dd95SBruce Richardson 
30*99a2dd95SBruce Richardson struct rte_port_ethdev_reader {
31*99a2dd95SBruce Richardson 	struct rte_port_in_stats stats;
32*99a2dd95SBruce Richardson 
33*99a2dd95SBruce Richardson 	uint16_t queue_id;
34*99a2dd95SBruce Richardson 	uint16_t port_id;
35*99a2dd95SBruce Richardson };
36*99a2dd95SBruce Richardson 
37*99a2dd95SBruce Richardson static void *
38*99a2dd95SBruce Richardson rte_port_ethdev_reader_create(void *params, int socket_id)
39*99a2dd95SBruce Richardson {
40*99a2dd95SBruce Richardson 	struct rte_port_ethdev_reader_params *conf =
41*99a2dd95SBruce Richardson 			params;
42*99a2dd95SBruce Richardson 	struct rte_port_ethdev_reader *port;
43*99a2dd95SBruce Richardson 
44*99a2dd95SBruce Richardson 	/* Check input parameters */
45*99a2dd95SBruce Richardson 	if (conf == NULL) {
46*99a2dd95SBruce Richardson 		RTE_LOG(ERR, PORT, "%s: params is NULL\n", __func__);
47*99a2dd95SBruce Richardson 		return NULL;
48*99a2dd95SBruce Richardson 	}
49*99a2dd95SBruce Richardson 
50*99a2dd95SBruce Richardson 	/* Memory allocation */
51*99a2dd95SBruce Richardson 	port = rte_zmalloc_socket("PORT", sizeof(*port),
52*99a2dd95SBruce Richardson 			RTE_CACHE_LINE_SIZE, socket_id);
53*99a2dd95SBruce Richardson 	if (port == NULL) {
54*99a2dd95SBruce Richardson 		RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
55*99a2dd95SBruce Richardson 		return NULL;
56*99a2dd95SBruce Richardson 	}
57*99a2dd95SBruce Richardson 
58*99a2dd95SBruce Richardson 	/* Initialization */
59*99a2dd95SBruce Richardson 	port->port_id = conf->port_id;
60*99a2dd95SBruce Richardson 	port->queue_id = conf->queue_id;
61*99a2dd95SBruce Richardson 
62*99a2dd95SBruce Richardson 	return port;
63*99a2dd95SBruce Richardson }
64*99a2dd95SBruce Richardson 
65*99a2dd95SBruce Richardson static int
66*99a2dd95SBruce Richardson rte_port_ethdev_reader_rx(void *port, struct rte_mbuf **pkts, uint32_t n_pkts)
67*99a2dd95SBruce Richardson {
68*99a2dd95SBruce Richardson 	struct rte_port_ethdev_reader *p =
69*99a2dd95SBruce Richardson 		port;
70*99a2dd95SBruce Richardson 	uint16_t rx_pkt_cnt;
71*99a2dd95SBruce Richardson 
72*99a2dd95SBruce Richardson 	rx_pkt_cnt = rte_eth_rx_burst(p->port_id, p->queue_id, pkts, n_pkts);
73*99a2dd95SBruce Richardson 	RTE_PORT_ETHDEV_READER_STATS_PKTS_IN_ADD(p, rx_pkt_cnt);
74*99a2dd95SBruce Richardson 	return rx_pkt_cnt;
75*99a2dd95SBruce Richardson }
76*99a2dd95SBruce Richardson 
77*99a2dd95SBruce Richardson static int
78*99a2dd95SBruce Richardson rte_port_ethdev_reader_free(void *port)
79*99a2dd95SBruce Richardson {
80*99a2dd95SBruce Richardson 	if (port == NULL) {
81*99a2dd95SBruce Richardson 		RTE_LOG(ERR, PORT, "%s: port is NULL\n", __func__);
82*99a2dd95SBruce Richardson 		return -EINVAL;
83*99a2dd95SBruce Richardson 	}
84*99a2dd95SBruce Richardson 
85*99a2dd95SBruce Richardson 	rte_free(port);
86*99a2dd95SBruce Richardson 
87*99a2dd95SBruce Richardson 	return 0;
88*99a2dd95SBruce Richardson }
89*99a2dd95SBruce Richardson 
90*99a2dd95SBruce Richardson static int rte_port_ethdev_reader_stats_read(void *port,
91*99a2dd95SBruce Richardson 		struct rte_port_in_stats *stats, int clear)
92*99a2dd95SBruce Richardson {
93*99a2dd95SBruce Richardson 	struct rte_port_ethdev_reader *p =
94*99a2dd95SBruce Richardson 			port;
95*99a2dd95SBruce Richardson 
96*99a2dd95SBruce Richardson 	if (stats != NULL)
97*99a2dd95SBruce Richardson 		memcpy(stats, &p->stats, sizeof(p->stats));
98*99a2dd95SBruce Richardson 
99*99a2dd95SBruce Richardson 	if (clear)
100*99a2dd95SBruce Richardson 		memset(&p->stats, 0, sizeof(p->stats));
101*99a2dd95SBruce Richardson 
102*99a2dd95SBruce Richardson 	return 0;
103*99a2dd95SBruce Richardson }
104*99a2dd95SBruce Richardson 
105*99a2dd95SBruce Richardson /*
106*99a2dd95SBruce Richardson  * Port ETHDEV Writer
107*99a2dd95SBruce Richardson  */
108*99a2dd95SBruce Richardson #ifdef RTE_PORT_STATS_COLLECT
109*99a2dd95SBruce Richardson 
110*99a2dd95SBruce Richardson #define RTE_PORT_ETHDEV_WRITER_STATS_PKTS_IN_ADD(port, val) \
111*99a2dd95SBruce Richardson 	port->stats.n_pkts_in += val
112*99a2dd95SBruce Richardson #define RTE_PORT_ETHDEV_WRITER_STATS_PKTS_DROP_ADD(port, val) \
113*99a2dd95SBruce Richardson 	port->stats.n_pkts_drop += val
114*99a2dd95SBruce Richardson 
115*99a2dd95SBruce Richardson #else
116*99a2dd95SBruce Richardson 
117*99a2dd95SBruce Richardson #define RTE_PORT_ETHDEV_WRITER_STATS_PKTS_IN_ADD(port, val)
118*99a2dd95SBruce Richardson #define RTE_PORT_ETHDEV_WRITER_STATS_PKTS_DROP_ADD(port, val)
119*99a2dd95SBruce Richardson 
120*99a2dd95SBruce Richardson #endif
121*99a2dd95SBruce Richardson 
122*99a2dd95SBruce Richardson struct rte_port_ethdev_writer {
123*99a2dd95SBruce Richardson 	struct rte_port_out_stats stats;
124*99a2dd95SBruce Richardson 
125*99a2dd95SBruce Richardson 	struct rte_mbuf *tx_buf[2 * RTE_PORT_IN_BURST_SIZE_MAX];
126*99a2dd95SBruce Richardson 	uint32_t tx_burst_sz;
127*99a2dd95SBruce Richardson 	uint16_t tx_buf_count;
128*99a2dd95SBruce Richardson 	uint64_t bsz_mask;
129*99a2dd95SBruce Richardson 	uint16_t queue_id;
130*99a2dd95SBruce Richardson 	uint16_t port_id;
131*99a2dd95SBruce Richardson };
132*99a2dd95SBruce Richardson 
133*99a2dd95SBruce Richardson static void *
134*99a2dd95SBruce Richardson rte_port_ethdev_writer_create(void *params, int socket_id)
135*99a2dd95SBruce Richardson {
136*99a2dd95SBruce Richardson 	struct rte_port_ethdev_writer_params *conf =
137*99a2dd95SBruce Richardson 			params;
138*99a2dd95SBruce Richardson 	struct rte_port_ethdev_writer *port;
139*99a2dd95SBruce Richardson 
140*99a2dd95SBruce Richardson 	/* Check input parameters */
141*99a2dd95SBruce Richardson 	if ((conf == NULL) ||
142*99a2dd95SBruce Richardson 		(conf->tx_burst_sz == 0) ||
143*99a2dd95SBruce Richardson 		(conf->tx_burst_sz > RTE_PORT_IN_BURST_SIZE_MAX) ||
144*99a2dd95SBruce Richardson 		(!rte_is_power_of_2(conf->tx_burst_sz))) {
145*99a2dd95SBruce Richardson 		RTE_LOG(ERR, PORT, "%s: Invalid input parameters\n", __func__);
146*99a2dd95SBruce Richardson 		return NULL;
147*99a2dd95SBruce Richardson 	}
148*99a2dd95SBruce Richardson 
149*99a2dd95SBruce Richardson 	/* Memory allocation */
150*99a2dd95SBruce Richardson 	port = rte_zmalloc_socket("PORT", sizeof(*port),
151*99a2dd95SBruce Richardson 			RTE_CACHE_LINE_SIZE, socket_id);
152*99a2dd95SBruce Richardson 	if (port == NULL) {
153*99a2dd95SBruce Richardson 		RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
154*99a2dd95SBruce Richardson 		return NULL;
155*99a2dd95SBruce Richardson 	}
156*99a2dd95SBruce Richardson 
157*99a2dd95SBruce Richardson 	/* Initialization */
158*99a2dd95SBruce Richardson 	port->port_id = conf->port_id;
159*99a2dd95SBruce Richardson 	port->queue_id = conf->queue_id;
160*99a2dd95SBruce Richardson 	port->tx_burst_sz = conf->tx_burst_sz;
161*99a2dd95SBruce Richardson 	port->tx_buf_count = 0;
162*99a2dd95SBruce Richardson 	port->bsz_mask = 1LLU << (conf->tx_burst_sz - 1);
163*99a2dd95SBruce Richardson 
164*99a2dd95SBruce Richardson 	return port;
165*99a2dd95SBruce Richardson }
166*99a2dd95SBruce Richardson 
167*99a2dd95SBruce Richardson static inline void
168*99a2dd95SBruce Richardson send_burst(struct rte_port_ethdev_writer *p)
169*99a2dd95SBruce Richardson {
170*99a2dd95SBruce Richardson 	uint32_t nb_tx;
171*99a2dd95SBruce Richardson 
172*99a2dd95SBruce Richardson 	nb_tx = rte_eth_tx_burst(p->port_id, p->queue_id,
173*99a2dd95SBruce Richardson 			 p->tx_buf, p->tx_buf_count);
174*99a2dd95SBruce Richardson 
175*99a2dd95SBruce Richardson 	RTE_PORT_ETHDEV_WRITER_STATS_PKTS_DROP_ADD(p, p->tx_buf_count - nb_tx);
176*99a2dd95SBruce Richardson 	for ( ; nb_tx < p->tx_buf_count; nb_tx++)
177*99a2dd95SBruce Richardson 		rte_pktmbuf_free(p->tx_buf[nb_tx]);
178*99a2dd95SBruce Richardson 
179*99a2dd95SBruce Richardson 	p->tx_buf_count = 0;
180*99a2dd95SBruce Richardson }
181*99a2dd95SBruce Richardson 
182*99a2dd95SBruce Richardson static int
183*99a2dd95SBruce Richardson rte_port_ethdev_writer_tx(void *port, struct rte_mbuf *pkt)
184*99a2dd95SBruce Richardson {
185*99a2dd95SBruce Richardson 	struct rte_port_ethdev_writer *p =
186*99a2dd95SBruce Richardson 		port;
187*99a2dd95SBruce Richardson 
188*99a2dd95SBruce Richardson 	p->tx_buf[p->tx_buf_count++] = pkt;
189*99a2dd95SBruce Richardson 	RTE_PORT_ETHDEV_WRITER_STATS_PKTS_IN_ADD(p, 1);
190*99a2dd95SBruce Richardson 	if (p->tx_buf_count >= p->tx_burst_sz)
191*99a2dd95SBruce Richardson 		send_burst(p);
192*99a2dd95SBruce Richardson 
193*99a2dd95SBruce Richardson 	return 0;
194*99a2dd95SBruce Richardson }
195*99a2dd95SBruce Richardson 
196*99a2dd95SBruce Richardson static int
197*99a2dd95SBruce Richardson rte_port_ethdev_writer_tx_bulk(void *port,
198*99a2dd95SBruce Richardson 		struct rte_mbuf **pkts,
199*99a2dd95SBruce Richardson 		uint64_t pkts_mask)
200*99a2dd95SBruce Richardson {
201*99a2dd95SBruce Richardson 	struct rte_port_ethdev_writer *p =
202*99a2dd95SBruce Richardson 		port;
203*99a2dd95SBruce Richardson 	uint64_t bsz_mask = p->bsz_mask;
204*99a2dd95SBruce Richardson 	uint32_t tx_buf_count = p->tx_buf_count;
205*99a2dd95SBruce Richardson 	uint64_t expr = (pkts_mask & (pkts_mask + 1)) |
206*99a2dd95SBruce Richardson 			((pkts_mask & bsz_mask) ^ bsz_mask);
207*99a2dd95SBruce Richardson 
208*99a2dd95SBruce Richardson 	if (expr == 0) {
209*99a2dd95SBruce Richardson 		uint64_t n_pkts = __builtin_popcountll(pkts_mask);
210*99a2dd95SBruce Richardson 		uint32_t n_pkts_ok;
211*99a2dd95SBruce Richardson 
212*99a2dd95SBruce Richardson 		if (tx_buf_count)
213*99a2dd95SBruce Richardson 			send_burst(p);
214*99a2dd95SBruce Richardson 
215*99a2dd95SBruce Richardson 		RTE_PORT_ETHDEV_WRITER_STATS_PKTS_IN_ADD(p, n_pkts);
216*99a2dd95SBruce Richardson 		n_pkts_ok = rte_eth_tx_burst(p->port_id, p->queue_id, pkts,
217*99a2dd95SBruce Richardson 			n_pkts);
218*99a2dd95SBruce Richardson 
219*99a2dd95SBruce Richardson 		RTE_PORT_ETHDEV_WRITER_STATS_PKTS_DROP_ADD(p, n_pkts - n_pkts_ok);
220*99a2dd95SBruce Richardson 		for ( ; n_pkts_ok < n_pkts; n_pkts_ok++) {
221*99a2dd95SBruce Richardson 			struct rte_mbuf *pkt = pkts[n_pkts_ok];
222*99a2dd95SBruce Richardson 
223*99a2dd95SBruce Richardson 			rte_pktmbuf_free(pkt);
224*99a2dd95SBruce Richardson 		}
225*99a2dd95SBruce Richardson 	} else {
226*99a2dd95SBruce Richardson 		for ( ; pkts_mask; ) {
227*99a2dd95SBruce Richardson 			uint32_t pkt_index = __builtin_ctzll(pkts_mask);
228*99a2dd95SBruce Richardson 			uint64_t pkt_mask = 1LLU << pkt_index;
229*99a2dd95SBruce Richardson 			struct rte_mbuf *pkt = pkts[pkt_index];
230*99a2dd95SBruce Richardson 
231*99a2dd95SBruce Richardson 			p->tx_buf[tx_buf_count++] = pkt;
232*99a2dd95SBruce Richardson 			RTE_PORT_ETHDEV_WRITER_STATS_PKTS_IN_ADD(p, 1);
233*99a2dd95SBruce Richardson 			pkts_mask &= ~pkt_mask;
234*99a2dd95SBruce Richardson 		}
235*99a2dd95SBruce Richardson 
236*99a2dd95SBruce Richardson 		p->tx_buf_count = tx_buf_count;
237*99a2dd95SBruce Richardson 		if (tx_buf_count >= p->tx_burst_sz)
238*99a2dd95SBruce Richardson 			send_burst(p);
239*99a2dd95SBruce Richardson 	}
240*99a2dd95SBruce Richardson 
241*99a2dd95SBruce Richardson 	return 0;
242*99a2dd95SBruce Richardson }
243*99a2dd95SBruce Richardson 
244*99a2dd95SBruce Richardson static int
245*99a2dd95SBruce Richardson rte_port_ethdev_writer_flush(void *port)
246*99a2dd95SBruce Richardson {
247*99a2dd95SBruce Richardson 	struct rte_port_ethdev_writer *p =
248*99a2dd95SBruce Richardson 		port;
249*99a2dd95SBruce Richardson 
250*99a2dd95SBruce Richardson 	if (p->tx_buf_count > 0)
251*99a2dd95SBruce Richardson 		send_burst(p);
252*99a2dd95SBruce Richardson 
253*99a2dd95SBruce Richardson 	return 0;
254*99a2dd95SBruce Richardson }
255*99a2dd95SBruce Richardson 
256*99a2dd95SBruce Richardson static int
257*99a2dd95SBruce Richardson rte_port_ethdev_writer_free(void *port)
258*99a2dd95SBruce Richardson {
259*99a2dd95SBruce Richardson 	if (port == NULL) {
260*99a2dd95SBruce Richardson 		RTE_LOG(ERR, PORT, "%s: Port is NULL\n", __func__);
261*99a2dd95SBruce Richardson 		return -EINVAL;
262*99a2dd95SBruce Richardson 	}
263*99a2dd95SBruce Richardson 
264*99a2dd95SBruce Richardson 	rte_port_ethdev_writer_flush(port);
265*99a2dd95SBruce Richardson 	rte_free(port);
266*99a2dd95SBruce Richardson 
267*99a2dd95SBruce Richardson 	return 0;
268*99a2dd95SBruce Richardson }
269*99a2dd95SBruce Richardson 
270*99a2dd95SBruce Richardson static int rte_port_ethdev_writer_stats_read(void *port,
271*99a2dd95SBruce Richardson 		struct rte_port_out_stats *stats, int clear)
272*99a2dd95SBruce Richardson {
273*99a2dd95SBruce Richardson 	struct rte_port_ethdev_writer *p =
274*99a2dd95SBruce Richardson 		port;
275*99a2dd95SBruce Richardson 
276*99a2dd95SBruce Richardson 	if (stats != NULL)
277*99a2dd95SBruce Richardson 		memcpy(stats, &p->stats, sizeof(p->stats));
278*99a2dd95SBruce Richardson 
279*99a2dd95SBruce Richardson 	if (clear)
280*99a2dd95SBruce Richardson 		memset(&p->stats, 0, sizeof(p->stats));
281*99a2dd95SBruce Richardson 
282*99a2dd95SBruce Richardson 	return 0;
283*99a2dd95SBruce Richardson }
284*99a2dd95SBruce Richardson 
285*99a2dd95SBruce Richardson /*
286*99a2dd95SBruce Richardson  * Port ETHDEV Writer Nodrop
287*99a2dd95SBruce Richardson  */
288*99a2dd95SBruce Richardson #ifdef RTE_PORT_STATS_COLLECT
289*99a2dd95SBruce Richardson 
290*99a2dd95SBruce Richardson #define RTE_PORT_ETHDEV_WRITER_NODROP_STATS_PKTS_IN_ADD(port, val) \
291*99a2dd95SBruce Richardson 	port->stats.n_pkts_in += val
292*99a2dd95SBruce Richardson #define RTE_PORT_ETHDEV_WRITER_NODROP_STATS_PKTS_DROP_ADD(port, val) \
293*99a2dd95SBruce Richardson 	port->stats.n_pkts_drop += val
294*99a2dd95SBruce Richardson 
295*99a2dd95SBruce Richardson #else
296*99a2dd95SBruce Richardson 
297*99a2dd95SBruce Richardson #define RTE_PORT_ETHDEV_WRITER_NODROP_STATS_PKTS_IN_ADD(port, val)
298*99a2dd95SBruce Richardson #define RTE_PORT_ETHDEV_WRITER_NODROP_STATS_PKTS_DROP_ADD(port, val)
299*99a2dd95SBruce Richardson 
300*99a2dd95SBruce Richardson #endif
301*99a2dd95SBruce Richardson 
302*99a2dd95SBruce Richardson struct rte_port_ethdev_writer_nodrop {
303*99a2dd95SBruce Richardson 	struct rte_port_out_stats stats;
304*99a2dd95SBruce Richardson 
305*99a2dd95SBruce Richardson 	struct rte_mbuf *tx_buf[2 * RTE_PORT_IN_BURST_SIZE_MAX];
306*99a2dd95SBruce Richardson 	uint32_t tx_burst_sz;
307*99a2dd95SBruce Richardson 	uint16_t tx_buf_count;
308*99a2dd95SBruce Richardson 	uint64_t bsz_mask;
309*99a2dd95SBruce Richardson 	uint64_t n_retries;
310*99a2dd95SBruce Richardson 	uint16_t queue_id;
311*99a2dd95SBruce Richardson 	uint16_t port_id;
312*99a2dd95SBruce Richardson };
313*99a2dd95SBruce Richardson 
314*99a2dd95SBruce Richardson static void *
315*99a2dd95SBruce Richardson rte_port_ethdev_writer_nodrop_create(void *params, int socket_id)
316*99a2dd95SBruce Richardson {
317*99a2dd95SBruce Richardson 	struct rte_port_ethdev_writer_nodrop_params *conf =
318*99a2dd95SBruce Richardson 			params;
319*99a2dd95SBruce Richardson 	struct rte_port_ethdev_writer_nodrop *port;
320*99a2dd95SBruce Richardson 
321*99a2dd95SBruce Richardson 	/* Check input parameters */
322*99a2dd95SBruce Richardson 	if ((conf == NULL) ||
323*99a2dd95SBruce Richardson 		(conf->tx_burst_sz == 0) ||
324*99a2dd95SBruce Richardson 		(conf->tx_burst_sz > RTE_PORT_IN_BURST_SIZE_MAX) ||
325*99a2dd95SBruce Richardson 		(!rte_is_power_of_2(conf->tx_burst_sz))) {
326*99a2dd95SBruce Richardson 		RTE_LOG(ERR, PORT, "%s: Invalid input parameters\n", __func__);
327*99a2dd95SBruce Richardson 		return NULL;
328*99a2dd95SBruce Richardson 	}
329*99a2dd95SBruce Richardson 
330*99a2dd95SBruce Richardson 	/* Memory allocation */
331*99a2dd95SBruce Richardson 	port = rte_zmalloc_socket("PORT", sizeof(*port),
332*99a2dd95SBruce Richardson 			RTE_CACHE_LINE_SIZE, socket_id);
333*99a2dd95SBruce Richardson 	if (port == NULL) {
334*99a2dd95SBruce Richardson 		RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
335*99a2dd95SBruce Richardson 		return NULL;
336*99a2dd95SBruce Richardson 	}
337*99a2dd95SBruce Richardson 
338*99a2dd95SBruce Richardson 	/* Initialization */
339*99a2dd95SBruce Richardson 	port->port_id = conf->port_id;
340*99a2dd95SBruce Richardson 	port->queue_id = conf->queue_id;
341*99a2dd95SBruce Richardson 	port->tx_burst_sz = conf->tx_burst_sz;
342*99a2dd95SBruce Richardson 	port->tx_buf_count = 0;
343*99a2dd95SBruce Richardson 	port->bsz_mask = 1LLU << (conf->tx_burst_sz - 1);
344*99a2dd95SBruce Richardson 
345*99a2dd95SBruce Richardson 	/*
346*99a2dd95SBruce Richardson 	 * When n_retries is 0 it means that we should wait for every packet to
347*99a2dd95SBruce Richardson 	 * send no matter how many retries should it take. To limit number of
348*99a2dd95SBruce Richardson 	 * branches in fast path, we use UINT64_MAX instead of branching.
349*99a2dd95SBruce Richardson 	 */
350*99a2dd95SBruce Richardson 	port->n_retries = (conf->n_retries == 0) ? UINT64_MAX : conf->n_retries;
351*99a2dd95SBruce Richardson 
352*99a2dd95SBruce Richardson 	return port;
353*99a2dd95SBruce Richardson }
354*99a2dd95SBruce Richardson 
355*99a2dd95SBruce Richardson static inline void
356*99a2dd95SBruce Richardson send_burst_nodrop(struct rte_port_ethdev_writer_nodrop *p)
357*99a2dd95SBruce Richardson {
358*99a2dd95SBruce Richardson 	uint32_t nb_tx = 0, i;
359*99a2dd95SBruce Richardson 
360*99a2dd95SBruce Richardson 	nb_tx = rte_eth_tx_burst(p->port_id, p->queue_id, p->tx_buf,
361*99a2dd95SBruce Richardson 			p->tx_buf_count);
362*99a2dd95SBruce Richardson 
363*99a2dd95SBruce Richardson 	/* We sent all the packets in a first try */
364*99a2dd95SBruce Richardson 	if (nb_tx >= p->tx_buf_count) {
365*99a2dd95SBruce Richardson 		p->tx_buf_count = 0;
366*99a2dd95SBruce Richardson 		return;
367*99a2dd95SBruce Richardson 	}
368*99a2dd95SBruce Richardson 
369*99a2dd95SBruce Richardson 	for (i = 0; i < p->n_retries; i++) {
370*99a2dd95SBruce Richardson 		nb_tx += rte_eth_tx_burst(p->port_id, p->queue_id,
371*99a2dd95SBruce Richardson 							 p->tx_buf + nb_tx, p->tx_buf_count - nb_tx);
372*99a2dd95SBruce Richardson 
373*99a2dd95SBruce Richardson 		/* We sent all the packets in more than one try */
374*99a2dd95SBruce Richardson 		if (nb_tx >= p->tx_buf_count) {
375*99a2dd95SBruce Richardson 			p->tx_buf_count = 0;
376*99a2dd95SBruce Richardson 			return;
377*99a2dd95SBruce Richardson 		}
378*99a2dd95SBruce Richardson 	}
379*99a2dd95SBruce Richardson 
380*99a2dd95SBruce Richardson 	/* We didn't send the packets in maximum allowed attempts */
381*99a2dd95SBruce Richardson 	RTE_PORT_ETHDEV_WRITER_NODROP_STATS_PKTS_DROP_ADD(p, p->tx_buf_count - nb_tx);
382*99a2dd95SBruce Richardson 	for ( ; nb_tx < p->tx_buf_count; nb_tx++)
383*99a2dd95SBruce Richardson 		rte_pktmbuf_free(p->tx_buf[nb_tx]);
384*99a2dd95SBruce Richardson 
385*99a2dd95SBruce Richardson 	p->tx_buf_count = 0;
386*99a2dd95SBruce Richardson }
387*99a2dd95SBruce Richardson 
388*99a2dd95SBruce Richardson static int
389*99a2dd95SBruce Richardson rte_port_ethdev_writer_nodrop_tx(void *port, struct rte_mbuf *pkt)
390*99a2dd95SBruce Richardson {
391*99a2dd95SBruce Richardson 	struct rte_port_ethdev_writer_nodrop *p =
392*99a2dd95SBruce Richardson 		port;
393*99a2dd95SBruce Richardson 
394*99a2dd95SBruce Richardson 	p->tx_buf[p->tx_buf_count++] = pkt;
395*99a2dd95SBruce Richardson 	RTE_PORT_ETHDEV_WRITER_NODROP_STATS_PKTS_IN_ADD(p, 1);
396*99a2dd95SBruce Richardson 	if (p->tx_buf_count >= p->tx_burst_sz)
397*99a2dd95SBruce Richardson 		send_burst_nodrop(p);
398*99a2dd95SBruce Richardson 
399*99a2dd95SBruce Richardson 	return 0;
400*99a2dd95SBruce Richardson }
401*99a2dd95SBruce Richardson 
402*99a2dd95SBruce Richardson static int
403*99a2dd95SBruce Richardson rte_port_ethdev_writer_nodrop_tx_bulk(void *port,
404*99a2dd95SBruce Richardson 		struct rte_mbuf **pkts,
405*99a2dd95SBruce Richardson 		uint64_t pkts_mask)
406*99a2dd95SBruce Richardson {
407*99a2dd95SBruce Richardson 	struct rte_port_ethdev_writer_nodrop *p =
408*99a2dd95SBruce Richardson 		port;
409*99a2dd95SBruce Richardson 
410*99a2dd95SBruce Richardson 	uint64_t bsz_mask = p->bsz_mask;
411*99a2dd95SBruce Richardson 	uint32_t tx_buf_count = p->tx_buf_count;
412*99a2dd95SBruce Richardson 	uint64_t expr = (pkts_mask & (pkts_mask + 1)) |
413*99a2dd95SBruce Richardson 			((pkts_mask & bsz_mask) ^ bsz_mask);
414*99a2dd95SBruce Richardson 
415*99a2dd95SBruce Richardson 	if (expr == 0) {
416*99a2dd95SBruce Richardson 		uint64_t n_pkts = __builtin_popcountll(pkts_mask);
417*99a2dd95SBruce Richardson 		uint32_t n_pkts_ok;
418*99a2dd95SBruce Richardson 
419*99a2dd95SBruce Richardson 		if (tx_buf_count)
420*99a2dd95SBruce Richardson 			send_burst_nodrop(p);
421*99a2dd95SBruce Richardson 
422*99a2dd95SBruce Richardson 		RTE_PORT_ETHDEV_WRITER_NODROP_STATS_PKTS_IN_ADD(p, n_pkts);
423*99a2dd95SBruce Richardson 		n_pkts_ok = rte_eth_tx_burst(p->port_id, p->queue_id, pkts,
424*99a2dd95SBruce Richardson 			n_pkts);
425*99a2dd95SBruce Richardson 
426*99a2dd95SBruce Richardson 		if (n_pkts_ok >= n_pkts)
427*99a2dd95SBruce Richardson 			return 0;
428*99a2dd95SBruce Richardson 
429*99a2dd95SBruce Richardson 		/*
430*99a2dd95SBruce Richardson 		 * If we did not manage to send all packets in single burst,
431*99a2dd95SBruce Richardson 		 * move remaining packets to the buffer and call send burst.
432*99a2dd95SBruce Richardson 		 */
433*99a2dd95SBruce Richardson 		for (; n_pkts_ok < n_pkts; n_pkts_ok++) {
434*99a2dd95SBruce Richardson 			struct rte_mbuf *pkt = pkts[n_pkts_ok];
435*99a2dd95SBruce Richardson 			p->tx_buf[p->tx_buf_count++] = pkt;
436*99a2dd95SBruce Richardson 		}
437*99a2dd95SBruce Richardson 		send_burst_nodrop(p);
438*99a2dd95SBruce Richardson 	} else {
439*99a2dd95SBruce Richardson 		for ( ; pkts_mask; ) {
440*99a2dd95SBruce Richardson 			uint32_t pkt_index = __builtin_ctzll(pkts_mask);
441*99a2dd95SBruce Richardson 			uint64_t pkt_mask = 1LLU << pkt_index;
442*99a2dd95SBruce Richardson 			struct rte_mbuf *pkt = pkts[pkt_index];
443*99a2dd95SBruce Richardson 
444*99a2dd95SBruce Richardson 			p->tx_buf[tx_buf_count++] = pkt;
445*99a2dd95SBruce Richardson 			RTE_PORT_ETHDEV_WRITER_NODROP_STATS_PKTS_IN_ADD(p, 1);
446*99a2dd95SBruce Richardson 			pkts_mask &= ~pkt_mask;
447*99a2dd95SBruce Richardson 		}
448*99a2dd95SBruce Richardson 
449*99a2dd95SBruce Richardson 		p->tx_buf_count = tx_buf_count;
450*99a2dd95SBruce Richardson 		if (tx_buf_count >= p->tx_burst_sz)
451*99a2dd95SBruce Richardson 			send_burst_nodrop(p);
452*99a2dd95SBruce Richardson 	}
453*99a2dd95SBruce Richardson 
454*99a2dd95SBruce Richardson 	return 0;
455*99a2dd95SBruce Richardson }
456*99a2dd95SBruce Richardson 
457*99a2dd95SBruce Richardson static int
458*99a2dd95SBruce Richardson rte_port_ethdev_writer_nodrop_flush(void *port)
459*99a2dd95SBruce Richardson {
460*99a2dd95SBruce Richardson 	struct rte_port_ethdev_writer_nodrop *p =
461*99a2dd95SBruce Richardson 		port;
462*99a2dd95SBruce Richardson 
463*99a2dd95SBruce Richardson 	if (p->tx_buf_count > 0)
464*99a2dd95SBruce Richardson 		send_burst_nodrop(p);
465*99a2dd95SBruce Richardson 
466*99a2dd95SBruce Richardson 	return 0;
467*99a2dd95SBruce Richardson }
468*99a2dd95SBruce Richardson 
469*99a2dd95SBruce Richardson static int
470*99a2dd95SBruce Richardson rte_port_ethdev_writer_nodrop_free(void *port)
471*99a2dd95SBruce Richardson {
472*99a2dd95SBruce Richardson 	if (port == NULL) {
473*99a2dd95SBruce Richardson 		RTE_LOG(ERR, PORT, "%s: Port is NULL\n", __func__);
474*99a2dd95SBruce Richardson 		return -EINVAL;
475*99a2dd95SBruce Richardson 	}
476*99a2dd95SBruce Richardson 
477*99a2dd95SBruce Richardson 	rte_port_ethdev_writer_nodrop_flush(port);
478*99a2dd95SBruce Richardson 	rte_free(port);
479*99a2dd95SBruce Richardson 
480*99a2dd95SBruce Richardson 	return 0;
481*99a2dd95SBruce Richardson }
482*99a2dd95SBruce Richardson 
483*99a2dd95SBruce Richardson static int rte_port_ethdev_writer_nodrop_stats_read(void *port,
484*99a2dd95SBruce Richardson 		struct rte_port_out_stats *stats, int clear)
485*99a2dd95SBruce Richardson {
486*99a2dd95SBruce Richardson 	struct rte_port_ethdev_writer_nodrop *p =
487*99a2dd95SBruce Richardson 		port;
488*99a2dd95SBruce Richardson 
489*99a2dd95SBruce Richardson 	if (stats != NULL)
490*99a2dd95SBruce Richardson 		memcpy(stats, &p->stats, sizeof(p->stats));
491*99a2dd95SBruce Richardson 
492*99a2dd95SBruce Richardson 	if (clear)
493*99a2dd95SBruce Richardson 		memset(&p->stats, 0, sizeof(p->stats));
494*99a2dd95SBruce Richardson 
495*99a2dd95SBruce Richardson 	return 0;
496*99a2dd95SBruce Richardson }
497*99a2dd95SBruce Richardson 
498*99a2dd95SBruce Richardson /*
499*99a2dd95SBruce Richardson  * Summary of port operations
500*99a2dd95SBruce Richardson  */
501*99a2dd95SBruce Richardson struct rte_port_in_ops rte_port_ethdev_reader_ops = {
502*99a2dd95SBruce Richardson 	.f_create = rte_port_ethdev_reader_create,
503*99a2dd95SBruce Richardson 	.f_free = rte_port_ethdev_reader_free,
504*99a2dd95SBruce Richardson 	.f_rx = rte_port_ethdev_reader_rx,
505*99a2dd95SBruce Richardson 	.f_stats = rte_port_ethdev_reader_stats_read,
506*99a2dd95SBruce Richardson };
507*99a2dd95SBruce Richardson 
508*99a2dd95SBruce Richardson struct rte_port_out_ops rte_port_ethdev_writer_ops = {
509*99a2dd95SBruce Richardson 	.f_create = rte_port_ethdev_writer_create,
510*99a2dd95SBruce Richardson 	.f_free = rte_port_ethdev_writer_free,
511*99a2dd95SBruce Richardson 	.f_tx = rte_port_ethdev_writer_tx,
512*99a2dd95SBruce Richardson 	.f_tx_bulk = rte_port_ethdev_writer_tx_bulk,
513*99a2dd95SBruce Richardson 	.f_flush = rte_port_ethdev_writer_flush,
514*99a2dd95SBruce Richardson 	.f_stats = rte_port_ethdev_writer_stats_read,
515*99a2dd95SBruce Richardson };
516*99a2dd95SBruce Richardson 
517*99a2dd95SBruce Richardson struct rte_port_out_ops rte_port_ethdev_writer_nodrop_ops = {
518*99a2dd95SBruce Richardson 	.f_create = rte_port_ethdev_writer_nodrop_create,
519*99a2dd95SBruce Richardson 	.f_free = rte_port_ethdev_writer_nodrop_free,
520*99a2dd95SBruce Richardson 	.f_tx = rte_port_ethdev_writer_nodrop_tx,
521*99a2dd95SBruce Richardson 	.f_tx_bulk = rte_port_ethdev_writer_nodrop_tx_bulk,
522*99a2dd95SBruce Richardson 	.f_flush = rte_port_ethdev_writer_nodrop_flush,
523*99a2dd95SBruce Richardson 	.f_stats = rte_port_ethdev_writer_nodrop_stats_read,
524*99a2dd95SBruce Richardson };
525