xref: /dpdk/drivers/net/sfc/sfc_tx.c (revision c6a1d9b5abcec20ab8018c1093cc230a708a814c)
1a8ad8cf8SIvan Malov /*-
2a8ad8cf8SIvan Malov  * Copyright (c) 2016 Solarflare Communications Inc.
3a8ad8cf8SIvan Malov  * All rights reserved.
4a8ad8cf8SIvan Malov  *
5a8ad8cf8SIvan Malov  * This software was jointly developed between OKTET Labs (under contract
6a8ad8cf8SIvan Malov  * for Solarflare) and Solarflare Communications, Inc.
7a8ad8cf8SIvan Malov  *
8a8ad8cf8SIvan Malov  * Redistribution and use in source and binary forms, with or without
9a8ad8cf8SIvan Malov  * modification, are permitted provided that the following conditions are met:
10a8ad8cf8SIvan Malov  *
11a8ad8cf8SIvan Malov  * 1. Redistributions of source code must retain the above copyright notice,
12a8ad8cf8SIvan Malov  *    this list of conditions and the following disclaimer.
13a8ad8cf8SIvan Malov  * 2. Redistributions in binary form must reproduce the above copyright notice,
14a8ad8cf8SIvan Malov  *    this list of conditions and the following disclaimer in the documentation
15a8ad8cf8SIvan Malov  *    and/or other materials provided with the distribution.
16a8ad8cf8SIvan Malov  *
17a8ad8cf8SIvan Malov  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18a8ad8cf8SIvan Malov  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19a8ad8cf8SIvan Malov  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20a8ad8cf8SIvan Malov  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21a8ad8cf8SIvan Malov  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22a8ad8cf8SIvan Malov  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23a8ad8cf8SIvan Malov  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24a8ad8cf8SIvan Malov  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25a8ad8cf8SIvan Malov  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26a8ad8cf8SIvan Malov  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27a8ad8cf8SIvan Malov  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28a8ad8cf8SIvan Malov  */
29a8ad8cf8SIvan Malov 
30a8ad8cf8SIvan Malov #include "sfc.h"
31fed9aeb4SIvan Malov #include "sfc_debug.h"
32a8ad8cf8SIvan Malov #include "sfc_log.h"
33a8ad8cf8SIvan Malov #include "sfc_ev.h"
34a8ad8cf8SIvan Malov #include "sfc_tx.h"
35428c7dddSIvan Malov #include "sfc_tweak.h"
36a8ad8cf8SIvan Malov 
37fed9aeb4SIvan Malov /*
38fed9aeb4SIvan Malov  * Maximum number of TX queue flush attempts in case of
39fed9aeb4SIvan Malov  * failure or flush timeout
40fed9aeb4SIvan Malov  */
41fed9aeb4SIvan Malov #define SFC_TX_QFLUSH_ATTEMPTS		(3)
42fed9aeb4SIvan Malov 
43fed9aeb4SIvan Malov /*
44fed9aeb4SIvan Malov  * Time to wait between event queue polling attempts when waiting for TX
45fed9aeb4SIvan Malov  * queue flush done or flush failed events
46fed9aeb4SIvan Malov  */
47fed9aeb4SIvan Malov #define SFC_TX_QFLUSH_POLL_WAIT_MS	(1)
48fed9aeb4SIvan Malov 
49fed9aeb4SIvan Malov /*
50fed9aeb4SIvan Malov  * Maximum number of event queue polling attempts when waiting for TX queue
51fed9aeb4SIvan Malov  * flush done or flush failed events; it defines TX queue flush attempt timeout
52fed9aeb4SIvan Malov  * together with SFC_TX_QFLUSH_POLL_WAIT_MS
53fed9aeb4SIvan Malov  */
54fed9aeb4SIvan Malov #define SFC_TX_QFLUSH_POLL_ATTEMPTS	(2000)
55fed9aeb4SIvan Malov 
56a8ad8cf8SIvan Malov static int
5721f6411cSIvan Malov sfc_tx_qcheck_conf(struct sfc_adapter *sa, uint16_t nb_tx_desc,
58b1b7ad93SIvan Malov 		   const struct rte_eth_txconf *tx_conf)
59b1b7ad93SIvan Malov {
60b1b7ad93SIvan Malov 	unsigned int flags = tx_conf->txq_flags;
61b1b7ad93SIvan Malov 	int rc = 0;
62b1b7ad93SIvan Malov 
63b1b7ad93SIvan Malov 	if (tx_conf->tx_rs_thresh != 0) {
64b1b7ad93SIvan Malov 		sfc_err(sa, "RS bit in transmit descriptor is not supported");
65b1b7ad93SIvan Malov 		rc = EINVAL;
66b1b7ad93SIvan Malov 	}
67b1b7ad93SIvan Malov 
6821f6411cSIvan Malov 	if (tx_conf->tx_free_thresh > EFX_TXQ_LIMIT(nb_tx_desc)) {
69b1b7ad93SIvan Malov 		sfc_err(sa,
7021f6411cSIvan Malov 			"TxQ free threshold too large: %u vs maximum %u",
7121f6411cSIvan Malov 			tx_conf->tx_free_thresh, EFX_TXQ_LIMIT(nb_tx_desc));
72b1b7ad93SIvan Malov 		rc = EINVAL;
73b1b7ad93SIvan Malov 	}
74b1b7ad93SIvan Malov 
75b1b7ad93SIvan Malov 	if (tx_conf->tx_thresh.pthresh != 0 ||
76b1b7ad93SIvan Malov 	    tx_conf->tx_thresh.hthresh != 0 ||
77b1b7ad93SIvan Malov 	    tx_conf->tx_thresh.wthresh != 0) {
78b1b7ad93SIvan Malov 		sfc_err(sa,
79b1b7ad93SIvan Malov 			"prefetch/host/writeback thresholds are not supported");
80b1b7ad93SIvan Malov 		rc = EINVAL;
81b1b7ad93SIvan Malov 	}
82b1b7ad93SIvan Malov 
83b1b7ad93SIvan Malov 	if ((flags & ETH_TXQ_FLAGS_NOVLANOFFL) == 0) {
84b1b7ad93SIvan Malov 		sfc_err(sa, "VLAN offload is not supported");
85b1b7ad93SIvan Malov 		rc = EINVAL;
86b1b7ad93SIvan Malov 	}
87b1b7ad93SIvan Malov 
88b1b7ad93SIvan Malov 	if ((flags & ETH_TXQ_FLAGS_NOXSUMSCTP) == 0) {
89b1b7ad93SIvan Malov 		sfc_err(sa, "SCTP offload is not supported");
90b1b7ad93SIvan Malov 		rc = EINVAL;
91b1b7ad93SIvan Malov 	}
92b1b7ad93SIvan Malov 
93b1b7ad93SIvan Malov 	/* We either perform both TCP and UDP offload, or no offload at all */
94b1b7ad93SIvan Malov 	if (((flags & ETH_TXQ_FLAGS_NOXSUMTCP) == 0) !=
95b1b7ad93SIvan Malov 	    ((flags & ETH_TXQ_FLAGS_NOXSUMUDP) == 0)) {
96b1b7ad93SIvan Malov 		sfc_err(sa, "TCP and UDP offloads can't be set independently");
97b1b7ad93SIvan Malov 		rc = EINVAL;
98b1b7ad93SIvan Malov 	}
99b1b7ad93SIvan Malov 
100b1b7ad93SIvan Malov 	return rc;
101b1b7ad93SIvan Malov }
102b1b7ad93SIvan Malov 
103fed9aeb4SIvan Malov void
104fed9aeb4SIvan Malov sfc_tx_qflush_done(struct sfc_txq *txq)
105fed9aeb4SIvan Malov {
106fed9aeb4SIvan Malov 	txq->state |= SFC_TXQ_FLUSHED;
107fed9aeb4SIvan Malov 	txq->state &= ~SFC_TXQ_FLUSHING;
108fed9aeb4SIvan Malov }
109fed9aeb4SIvan Malov 
110fed9aeb4SIvan Malov static void
111fed9aeb4SIvan Malov sfc_tx_reap(struct sfc_txq *txq)
112fed9aeb4SIvan Malov {
113fed9aeb4SIvan Malov 	unsigned int    completed;
114fed9aeb4SIvan Malov 
115fed9aeb4SIvan Malov 
116fed9aeb4SIvan Malov 	sfc_ev_qpoll(txq->evq);
117fed9aeb4SIvan Malov 
118fed9aeb4SIvan Malov 	for (completed = txq->completed;
119fed9aeb4SIvan Malov 	     completed != txq->pending; completed++) {
120fed9aeb4SIvan Malov 		struct sfc_tx_sw_desc *txd;
121fed9aeb4SIvan Malov 
122fed9aeb4SIvan Malov 		txd = &txq->sw_ring[completed & txq->ptr_mask];
123fed9aeb4SIvan Malov 
124fed9aeb4SIvan Malov 		if (txd->mbuf != NULL) {
125fed9aeb4SIvan Malov 			rte_pktmbuf_free(txd->mbuf);
126fed9aeb4SIvan Malov 			txd->mbuf = NULL;
127fed9aeb4SIvan Malov 		}
128fed9aeb4SIvan Malov 	}
129fed9aeb4SIvan Malov 
130fed9aeb4SIvan Malov 	txq->completed = completed;
131fed9aeb4SIvan Malov }
132fed9aeb4SIvan Malov 
133b1b7ad93SIvan Malov int
134b1b7ad93SIvan Malov sfc_tx_qinit(struct sfc_adapter *sa, unsigned int sw_index,
135b1b7ad93SIvan Malov 	     uint16_t nb_tx_desc, unsigned int socket_id,
136b1b7ad93SIvan Malov 	     const struct rte_eth_txconf *tx_conf)
137b1b7ad93SIvan Malov {
138b1b7ad93SIvan Malov 	struct sfc_txq_info *txq_info;
139b1b7ad93SIvan Malov 	struct sfc_evq *evq;
140b1b7ad93SIvan Malov 	struct sfc_txq *txq;
141b1b7ad93SIvan Malov 	unsigned int evq_index = sfc_evq_index_by_txq_sw_index(sa, sw_index);
142b1b7ad93SIvan Malov 	int rc = 0;
143b1b7ad93SIvan Malov 
144b1b7ad93SIvan Malov 	sfc_log_init(sa, "TxQ = %u", sw_index);
145b1b7ad93SIvan Malov 
14621f6411cSIvan Malov 	rc = sfc_tx_qcheck_conf(sa, nb_tx_desc, tx_conf);
147b1b7ad93SIvan Malov 	if (rc != 0)
148b1b7ad93SIvan Malov 		goto fail_bad_conf;
149b1b7ad93SIvan Malov 
150b1b7ad93SIvan Malov 	SFC_ASSERT(sw_index < sa->txq_count);
151b1b7ad93SIvan Malov 	txq_info = &sa->txq_info[sw_index];
152b1b7ad93SIvan Malov 
153b1b7ad93SIvan Malov 	SFC_ASSERT(nb_tx_desc <= sa->txq_max_entries);
154b1b7ad93SIvan Malov 	txq_info->entries = nb_tx_desc;
155b1b7ad93SIvan Malov 
156b1b7ad93SIvan Malov 	rc = sfc_ev_qinit(sa, evq_index, txq_info->entries, socket_id);
157b1b7ad93SIvan Malov 	if (rc != 0)
158b1b7ad93SIvan Malov 		goto fail_ev_qinit;
159b1b7ad93SIvan Malov 
160b1b7ad93SIvan Malov 	evq = sa->evq_info[evq_index].evq;
161b1b7ad93SIvan Malov 
162b1b7ad93SIvan Malov 	rc = ENOMEM;
163b1b7ad93SIvan Malov 	txq = rte_zmalloc_socket("sfc-txq", sizeof(*txq), 0, socket_id);
164b1b7ad93SIvan Malov 	if (txq == NULL)
165b1b7ad93SIvan Malov 		goto fail_txq_alloc;
166b1b7ad93SIvan Malov 
167b1b7ad93SIvan Malov 	rc = sfc_dma_alloc(sa, "txq", sw_index, EFX_TXQ_SIZE(txq_info->entries),
168b1b7ad93SIvan Malov 			   socket_id, &txq->mem);
169b1b7ad93SIvan Malov 	if (rc != 0)
170b1b7ad93SIvan Malov 		goto fail_dma_alloc;
171b1b7ad93SIvan Malov 
172b1b7ad93SIvan Malov 	rc = ENOMEM;
173b1b7ad93SIvan Malov 	txq->pend_desc = rte_calloc_socket("sfc-txq-pend-desc",
174b1b7ad93SIvan Malov 					   EFX_TXQ_LIMIT(txq_info->entries),
175b1b7ad93SIvan Malov 					   sizeof(efx_desc_t), 0, socket_id);
176b1b7ad93SIvan Malov 	if (txq->pend_desc == NULL)
177b1b7ad93SIvan Malov 		goto fail_pend_desc_alloc;
178b1b7ad93SIvan Malov 
179b1b7ad93SIvan Malov 	rc = ENOMEM;
180b1b7ad93SIvan Malov 	txq->sw_ring = rte_calloc_socket("sfc-txq-desc", txq_info->entries,
181b1b7ad93SIvan Malov 					 sizeof(*txq->sw_ring), 0, socket_id);
182b1b7ad93SIvan Malov 	if (txq->sw_ring == NULL)
183b1b7ad93SIvan Malov 		goto fail_desc_alloc;
184b1b7ad93SIvan Malov 
185b1b7ad93SIvan Malov 	txq->state = SFC_TXQ_INITIALIZED;
186b1b7ad93SIvan Malov 	txq->ptr_mask = txq_info->entries - 1;
18721f6411cSIvan Malov 	txq->free_thresh = (tx_conf->tx_free_thresh) ? tx_conf->tx_free_thresh :
18821f6411cSIvan Malov 						     SFC_TX_DEFAULT_FREE_THRESH;
189b1b7ad93SIvan Malov 	txq->hw_index = sw_index;
190b1b7ad93SIvan Malov 	txq->flags = tx_conf->txq_flags;
191b1b7ad93SIvan Malov 	txq->evq = evq;
192b1b7ad93SIvan Malov 
193b1b7ad93SIvan Malov 	evq->txq = txq;
194b1b7ad93SIvan Malov 
195b1b7ad93SIvan Malov 	txq_info->txq = txq;
196*c6a1d9b5SIvan Malov 	txq_info->deferred_start = (tx_conf->tx_deferred_start != 0);
197b1b7ad93SIvan Malov 
198b1b7ad93SIvan Malov 	return 0;
199b1b7ad93SIvan Malov 
200b1b7ad93SIvan Malov fail_desc_alloc:
201b1b7ad93SIvan Malov 	rte_free(txq->pend_desc);
202b1b7ad93SIvan Malov 
203b1b7ad93SIvan Malov fail_pend_desc_alloc:
204b1b7ad93SIvan Malov 	sfc_dma_free(sa, &txq->mem);
205b1b7ad93SIvan Malov 
206b1b7ad93SIvan Malov fail_dma_alloc:
207b1b7ad93SIvan Malov 	rte_free(txq);
208b1b7ad93SIvan Malov 
209b1b7ad93SIvan Malov fail_txq_alloc:
210b1b7ad93SIvan Malov 	sfc_ev_qfini(sa, evq_index);
211b1b7ad93SIvan Malov 
212b1b7ad93SIvan Malov fail_ev_qinit:
213b1b7ad93SIvan Malov 	txq_info->entries = 0;
214b1b7ad93SIvan Malov 
215b1b7ad93SIvan Malov fail_bad_conf:
216b1b7ad93SIvan Malov 	sfc_log_init(sa, "failed (TxQ = %u, rc = %d)", sw_index, rc);
217b1b7ad93SIvan Malov 	return rc;
218b1b7ad93SIvan Malov }
219b1b7ad93SIvan Malov 
220b1b7ad93SIvan Malov void
221b1b7ad93SIvan Malov sfc_tx_qfini(struct sfc_adapter *sa, unsigned int sw_index)
222b1b7ad93SIvan Malov {
223b1b7ad93SIvan Malov 	struct sfc_txq_info *txq_info;
224b1b7ad93SIvan Malov 	struct sfc_txq *txq;
225b1b7ad93SIvan Malov 
226b1b7ad93SIvan Malov 	sfc_log_init(sa, "TxQ = %u", sw_index);
227b1b7ad93SIvan Malov 
228b1b7ad93SIvan Malov 	SFC_ASSERT(sw_index < sa->txq_count);
229b1b7ad93SIvan Malov 	txq_info = &sa->txq_info[sw_index];
230b1b7ad93SIvan Malov 
231b1b7ad93SIvan Malov 	txq = txq_info->txq;
232b1b7ad93SIvan Malov 	SFC_ASSERT(txq != NULL);
233b1b7ad93SIvan Malov 	SFC_ASSERT(txq->state == SFC_TXQ_INITIALIZED);
234b1b7ad93SIvan Malov 
235b1b7ad93SIvan Malov 	txq_info->txq = NULL;
236b1b7ad93SIvan Malov 	txq_info->entries = 0;
237b1b7ad93SIvan Malov 
238b1b7ad93SIvan Malov 	rte_free(txq->sw_ring);
239b1b7ad93SIvan Malov 	rte_free(txq->pend_desc);
240b1b7ad93SIvan Malov 	sfc_dma_free(sa, &txq->mem);
241b1b7ad93SIvan Malov 	rte_free(txq);
242b1b7ad93SIvan Malov }
243b1b7ad93SIvan Malov 
244b1b7ad93SIvan Malov static int
245a8ad8cf8SIvan Malov sfc_tx_qinit_info(struct sfc_adapter *sa, unsigned int sw_index)
246a8ad8cf8SIvan Malov {
247a8ad8cf8SIvan Malov 	sfc_log_init(sa, "TxQ = %u", sw_index);
248a8ad8cf8SIvan Malov 
249a8ad8cf8SIvan Malov 	return 0;
250a8ad8cf8SIvan Malov }
251a8ad8cf8SIvan Malov 
252dbf0f627SIvan Malov static int
253dbf0f627SIvan Malov sfc_tx_check_mode(struct sfc_adapter *sa, const struct rte_eth_txmode *txmode)
254dbf0f627SIvan Malov {
255dbf0f627SIvan Malov 	int rc = 0;
256dbf0f627SIvan Malov 
257dbf0f627SIvan Malov 	switch (txmode->mq_mode) {
258dbf0f627SIvan Malov 	case ETH_MQ_TX_NONE:
259dbf0f627SIvan Malov 		break;
260dbf0f627SIvan Malov 	default:
261dbf0f627SIvan Malov 		sfc_err(sa, "Tx multi-queue mode %u not supported",
262dbf0f627SIvan Malov 			txmode->mq_mode);
263dbf0f627SIvan Malov 		rc = EINVAL;
264dbf0f627SIvan Malov 	}
265dbf0f627SIvan Malov 
266dbf0f627SIvan Malov 	/*
267dbf0f627SIvan Malov 	 * These features are claimed to be i40e-specific,
268dbf0f627SIvan Malov 	 * but it does make sense to double-check their absence
269dbf0f627SIvan Malov 	 */
270dbf0f627SIvan Malov 	if (txmode->hw_vlan_reject_tagged) {
271dbf0f627SIvan Malov 		sfc_err(sa, "Rejecting tagged packets not supported");
272dbf0f627SIvan Malov 		rc = EINVAL;
273dbf0f627SIvan Malov 	}
274dbf0f627SIvan Malov 
275dbf0f627SIvan Malov 	if (txmode->hw_vlan_reject_untagged) {
276dbf0f627SIvan Malov 		sfc_err(sa, "Rejecting untagged packets not supported");
277dbf0f627SIvan Malov 		rc = EINVAL;
278dbf0f627SIvan Malov 	}
279dbf0f627SIvan Malov 
280dbf0f627SIvan Malov 	if (txmode->hw_vlan_insert_pvid) {
281dbf0f627SIvan Malov 		sfc_err(sa, "Port-based VLAN insertion not supported");
282dbf0f627SIvan Malov 		rc = EINVAL;
283dbf0f627SIvan Malov 	}
284dbf0f627SIvan Malov 
285dbf0f627SIvan Malov 	return rc;
286dbf0f627SIvan Malov }
287dbf0f627SIvan Malov 
288a8ad8cf8SIvan Malov int
289a8ad8cf8SIvan Malov sfc_tx_init(struct sfc_adapter *sa)
290a8ad8cf8SIvan Malov {
291dbf0f627SIvan Malov 	const struct rte_eth_conf *dev_conf = &sa->eth_dev->data->dev_conf;
292a8ad8cf8SIvan Malov 	unsigned int sw_index;
293a8ad8cf8SIvan Malov 	int rc = 0;
294a8ad8cf8SIvan Malov 
295dbf0f627SIvan Malov 	rc = sfc_tx_check_mode(sa, &dev_conf->txmode);
296dbf0f627SIvan Malov 	if (rc != 0)
297dbf0f627SIvan Malov 		goto fail_check_mode;
298dbf0f627SIvan Malov 
299a8ad8cf8SIvan Malov 	sa->txq_count = sa->eth_dev->data->nb_tx_queues;
300a8ad8cf8SIvan Malov 
301a8ad8cf8SIvan Malov 	sa->txq_info = rte_calloc_socket("sfc-txqs", sa->txq_count,
302a8ad8cf8SIvan Malov 					 sizeof(sa->txq_info[0]), 0,
303a8ad8cf8SIvan Malov 					 sa->socket_id);
304a8ad8cf8SIvan Malov 	if (sa->txq_info == NULL)
305a8ad8cf8SIvan Malov 		goto fail_txqs_alloc;
306a8ad8cf8SIvan Malov 
307a8ad8cf8SIvan Malov 	for (sw_index = 0; sw_index < sa->txq_count; ++sw_index) {
308a8ad8cf8SIvan Malov 		rc = sfc_tx_qinit_info(sa, sw_index);
309a8ad8cf8SIvan Malov 		if (rc != 0)
310a8ad8cf8SIvan Malov 			goto fail_tx_qinit_info;
311a8ad8cf8SIvan Malov 	}
312a8ad8cf8SIvan Malov 
313a8ad8cf8SIvan Malov 	return 0;
314a8ad8cf8SIvan Malov 
315a8ad8cf8SIvan Malov fail_tx_qinit_info:
316a8ad8cf8SIvan Malov 	rte_free(sa->txq_info);
317a8ad8cf8SIvan Malov 	sa->txq_info = NULL;
318a8ad8cf8SIvan Malov 
319a8ad8cf8SIvan Malov fail_txqs_alloc:
320a8ad8cf8SIvan Malov 	sa->txq_count = 0;
321a8ad8cf8SIvan Malov 
322dbf0f627SIvan Malov fail_check_mode:
323a8ad8cf8SIvan Malov 	sfc_log_init(sa, "failed (rc = %d)", rc);
324a8ad8cf8SIvan Malov 	return rc;
325a8ad8cf8SIvan Malov }
326a8ad8cf8SIvan Malov 
327a8ad8cf8SIvan Malov void
328a8ad8cf8SIvan Malov sfc_tx_fini(struct sfc_adapter *sa)
329a8ad8cf8SIvan Malov {
330b1b7ad93SIvan Malov 	int sw_index;
331b1b7ad93SIvan Malov 
332b1b7ad93SIvan Malov 	sw_index = sa->txq_count;
333b1b7ad93SIvan Malov 	while (--sw_index >= 0) {
334b1b7ad93SIvan Malov 		if (sa->txq_info[sw_index].txq != NULL)
335b1b7ad93SIvan Malov 			sfc_tx_qfini(sa, sw_index);
336b1b7ad93SIvan Malov 	}
337b1b7ad93SIvan Malov 
338a8ad8cf8SIvan Malov 	rte_free(sa->txq_info);
339a8ad8cf8SIvan Malov 	sa->txq_info = NULL;
340a8ad8cf8SIvan Malov 	sa->txq_count = 0;
341a8ad8cf8SIvan Malov }
342fed9aeb4SIvan Malov 
343fed9aeb4SIvan Malov int
344fed9aeb4SIvan Malov sfc_tx_qstart(struct sfc_adapter *sa, unsigned int sw_index)
345fed9aeb4SIvan Malov {
346fed9aeb4SIvan Malov 	struct rte_eth_dev_data *dev_data;
347fed9aeb4SIvan Malov 	struct sfc_txq_info *txq_info;
348fed9aeb4SIvan Malov 	struct sfc_txq *txq;
349fed9aeb4SIvan Malov 	struct sfc_evq *evq;
350fed9aeb4SIvan Malov 	uint16_t flags;
351fed9aeb4SIvan Malov 	unsigned int desc_index;
352fed9aeb4SIvan Malov 	int rc = 0;
353fed9aeb4SIvan Malov 
354fed9aeb4SIvan Malov 	sfc_log_init(sa, "TxQ = %u", sw_index);
355fed9aeb4SIvan Malov 
356fed9aeb4SIvan Malov 	SFC_ASSERT(sw_index < sa->txq_count);
357fed9aeb4SIvan Malov 	txq_info = &sa->txq_info[sw_index];
358fed9aeb4SIvan Malov 
359fed9aeb4SIvan Malov 	txq = txq_info->txq;
360fed9aeb4SIvan Malov 
361fed9aeb4SIvan Malov 	SFC_ASSERT(txq->state == SFC_TXQ_INITIALIZED);
362fed9aeb4SIvan Malov 
363fed9aeb4SIvan Malov 	evq = txq->evq;
364fed9aeb4SIvan Malov 
365fed9aeb4SIvan Malov 	rc = sfc_ev_qstart(sa, evq->evq_index);
366fed9aeb4SIvan Malov 	if (rc != 0)
367fed9aeb4SIvan Malov 		goto fail_ev_qstart;
368fed9aeb4SIvan Malov 
369fed9aeb4SIvan Malov 	/*
370fed9aeb4SIvan Malov 	 * It seems that DPDK has no controls regarding IPv4 offloads,
371fed9aeb4SIvan Malov 	 * hence, we always enable it here
372fed9aeb4SIvan Malov 	 */
373fed9aeb4SIvan Malov 	if ((txq->flags & ETH_TXQ_FLAGS_NOXSUMTCP) ||
374fed9aeb4SIvan Malov 	    (txq->flags & ETH_TXQ_FLAGS_NOXSUMUDP))
375fed9aeb4SIvan Malov 		flags = EFX_TXQ_CKSUM_IPV4;
376fed9aeb4SIvan Malov 	else
377fed9aeb4SIvan Malov 		flags = EFX_TXQ_CKSUM_IPV4 | EFX_TXQ_CKSUM_TCPUDP;
378fed9aeb4SIvan Malov 
379fed9aeb4SIvan Malov 	rc = efx_tx_qcreate(sa->nic, sw_index, 0, &txq->mem,
380fed9aeb4SIvan Malov 			    txq_info->entries, 0 /* not used on EF10 */,
381fed9aeb4SIvan Malov 			    flags, evq->common,
382fed9aeb4SIvan Malov 			    &txq->common, &desc_index);
383fed9aeb4SIvan Malov 	if (rc != 0)
384fed9aeb4SIvan Malov 		goto fail_tx_qcreate;
385fed9aeb4SIvan Malov 
386fed9aeb4SIvan Malov 	txq->added = txq->pending = txq->completed = desc_index;
387fed9aeb4SIvan Malov 
388fed9aeb4SIvan Malov 	efx_tx_qenable(txq->common);
389fed9aeb4SIvan Malov 
390fed9aeb4SIvan Malov 	txq->state |= (SFC_TXQ_STARTED | SFC_TXQ_RUNNING);
391fed9aeb4SIvan Malov 
392fed9aeb4SIvan Malov 	/*
393fed9aeb4SIvan Malov 	 * It seems to be used by DPDK for debug purposes only ('rte_ether')
394fed9aeb4SIvan Malov 	 */
395fed9aeb4SIvan Malov 	dev_data = sa->eth_dev->data;
396fed9aeb4SIvan Malov 	dev_data->tx_queue_state[sw_index] = RTE_ETH_QUEUE_STATE_STARTED;
397fed9aeb4SIvan Malov 
398fed9aeb4SIvan Malov 	return 0;
399fed9aeb4SIvan Malov 
400fed9aeb4SIvan Malov fail_tx_qcreate:
401fed9aeb4SIvan Malov 	sfc_ev_qstop(sa, evq->evq_index);
402fed9aeb4SIvan Malov 
403fed9aeb4SIvan Malov fail_ev_qstart:
404fed9aeb4SIvan Malov 	return rc;
405fed9aeb4SIvan Malov }
406fed9aeb4SIvan Malov 
407fed9aeb4SIvan Malov void
408fed9aeb4SIvan Malov sfc_tx_qstop(struct sfc_adapter *sa, unsigned int sw_index)
409fed9aeb4SIvan Malov {
410fed9aeb4SIvan Malov 	struct rte_eth_dev_data *dev_data;
411fed9aeb4SIvan Malov 	struct sfc_txq_info *txq_info;
412fed9aeb4SIvan Malov 	struct sfc_txq *txq;
413fed9aeb4SIvan Malov 	unsigned int retry_count;
414fed9aeb4SIvan Malov 	unsigned int wait_count;
415fed9aeb4SIvan Malov 	unsigned int txds;
416fed9aeb4SIvan Malov 
417fed9aeb4SIvan Malov 	sfc_log_init(sa, "TxQ = %u", sw_index);
418fed9aeb4SIvan Malov 
419fed9aeb4SIvan Malov 	SFC_ASSERT(sw_index < sa->txq_count);
420fed9aeb4SIvan Malov 	txq_info = &sa->txq_info[sw_index];
421fed9aeb4SIvan Malov 
422fed9aeb4SIvan Malov 	txq = txq_info->txq;
423fed9aeb4SIvan Malov 
424*c6a1d9b5SIvan Malov 	if (txq->state == SFC_TXQ_INITIALIZED)
425*c6a1d9b5SIvan Malov 		return;
426*c6a1d9b5SIvan Malov 
427fed9aeb4SIvan Malov 	SFC_ASSERT(txq->state & SFC_TXQ_STARTED);
428fed9aeb4SIvan Malov 
429fed9aeb4SIvan Malov 	txq->state &= ~SFC_TXQ_RUNNING;
430fed9aeb4SIvan Malov 
431fed9aeb4SIvan Malov 	/*
432fed9aeb4SIvan Malov 	 * Retry TX queue flushing in case of flush failed or
433fed9aeb4SIvan Malov 	 * timeout; in the worst case it can delay for 6 seconds
434fed9aeb4SIvan Malov 	 */
435fed9aeb4SIvan Malov 	for (retry_count = 0;
436fed9aeb4SIvan Malov 	     ((txq->state & SFC_TXQ_FLUSHED) == 0) &&
437fed9aeb4SIvan Malov 	     (retry_count < SFC_TX_QFLUSH_ATTEMPTS);
438fed9aeb4SIvan Malov 	     ++retry_count) {
439fed9aeb4SIvan Malov 		if (efx_tx_qflush(txq->common) != 0) {
440fed9aeb4SIvan Malov 			txq->state |= SFC_TXQ_FLUSHING;
441fed9aeb4SIvan Malov 			break;
442fed9aeb4SIvan Malov 		}
443fed9aeb4SIvan Malov 
444fed9aeb4SIvan Malov 		/*
445fed9aeb4SIvan Malov 		 * Wait for TX queue flush done or flush failed event at least
446fed9aeb4SIvan Malov 		 * SFC_TX_QFLUSH_POLL_WAIT_MS milliseconds and not more
447fed9aeb4SIvan Malov 		 * than 2 seconds (SFC_TX_QFLUSH_POLL_WAIT_MS multiplied
448fed9aeb4SIvan Malov 		 * by SFC_TX_QFLUSH_POLL_ATTEMPTS)
449fed9aeb4SIvan Malov 		 */
450fed9aeb4SIvan Malov 		wait_count = 0;
451fed9aeb4SIvan Malov 		do {
452fed9aeb4SIvan Malov 			rte_delay_ms(SFC_TX_QFLUSH_POLL_WAIT_MS);
453fed9aeb4SIvan Malov 			sfc_ev_qpoll(txq->evq);
454fed9aeb4SIvan Malov 		} while ((txq->state & SFC_TXQ_FLUSHING) &&
455fed9aeb4SIvan Malov 			 wait_count++ < SFC_TX_QFLUSH_POLL_ATTEMPTS);
456fed9aeb4SIvan Malov 
457fed9aeb4SIvan Malov 		if (txq->state & SFC_TXQ_FLUSHING)
458fed9aeb4SIvan Malov 			sfc_err(sa, "TxQ %u flush timed out", sw_index);
459fed9aeb4SIvan Malov 
460fed9aeb4SIvan Malov 		if (txq->state & SFC_TXQ_FLUSHED)
461fed9aeb4SIvan Malov 			sfc_info(sa, "TxQ %u flushed", sw_index);
462fed9aeb4SIvan Malov 	}
463fed9aeb4SIvan Malov 
464fed9aeb4SIvan Malov 	sfc_tx_reap(txq);
465fed9aeb4SIvan Malov 
466fed9aeb4SIvan Malov 	for (txds = 0; txds < txq_info->entries; txds++) {
467fed9aeb4SIvan Malov 		if (txq->sw_ring[txds].mbuf != NULL) {
468fed9aeb4SIvan Malov 			rte_pktmbuf_free(txq->sw_ring[txds].mbuf);
469fed9aeb4SIvan Malov 			txq->sw_ring[txds].mbuf = NULL;
470fed9aeb4SIvan Malov 		}
471fed9aeb4SIvan Malov 	}
472fed9aeb4SIvan Malov 
473fed9aeb4SIvan Malov 	txq->state = SFC_TXQ_INITIALIZED;
474fed9aeb4SIvan Malov 
475fed9aeb4SIvan Malov 	efx_tx_qdestroy(txq->common);
476fed9aeb4SIvan Malov 
477fed9aeb4SIvan Malov 	sfc_ev_qstop(sa, txq->evq->evq_index);
478fed9aeb4SIvan Malov 
479fed9aeb4SIvan Malov 	/*
480fed9aeb4SIvan Malov 	 * It seems to be used by DPDK for debug purposes only ('rte_ether')
481fed9aeb4SIvan Malov 	 */
482fed9aeb4SIvan Malov 	dev_data = sa->eth_dev->data;
483fed9aeb4SIvan Malov 	dev_data->tx_queue_state[sw_index] = RTE_ETH_QUEUE_STATE_STOPPED;
484fed9aeb4SIvan Malov }
485fed9aeb4SIvan Malov 
486fed9aeb4SIvan Malov int
487fed9aeb4SIvan Malov sfc_tx_start(struct sfc_adapter *sa)
488fed9aeb4SIvan Malov {
489fed9aeb4SIvan Malov 	unsigned int sw_index;
490fed9aeb4SIvan Malov 	int rc = 0;
491fed9aeb4SIvan Malov 
492fed9aeb4SIvan Malov 	sfc_log_init(sa, "txq_count = %u", sa->txq_count);
493fed9aeb4SIvan Malov 
494fed9aeb4SIvan Malov 	rc = efx_tx_init(sa->nic);
495fed9aeb4SIvan Malov 	if (rc != 0)
496fed9aeb4SIvan Malov 		goto fail_efx_tx_init;
497fed9aeb4SIvan Malov 
498fed9aeb4SIvan Malov 	for (sw_index = 0; sw_index < sa->txq_count; ++sw_index) {
499*c6a1d9b5SIvan Malov 		if (!(sa->txq_info[sw_index].deferred_start) ||
500*c6a1d9b5SIvan Malov 		    sa->txq_info[sw_index].deferred_started) {
501fed9aeb4SIvan Malov 			rc = sfc_tx_qstart(sa, sw_index);
502fed9aeb4SIvan Malov 			if (rc != 0)
503fed9aeb4SIvan Malov 				goto fail_tx_qstart;
504fed9aeb4SIvan Malov 		}
505*c6a1d9b5SIvan Malov 	}
506fed9aeb4SIvan Malov 
507fed9aeb4SIvan Malov 	return 0;
508fed9aeb4SIvan Malov 
509fed9aeb4SIvan Malov fail_tx_qstart:
510fed9aeb4SIvan Malov 	while (sw_index-- > 0)
511fed9aeb4SIvan Malov 		sfc_tx_qstop(sa, sw_index);
512fed9aeb4SIvan Malov 
513fed9aeb4SIvan Malov 	efx_tx_fini(sa->nic);
514fed9aeb4SIvan Malov 
515fed9aeb4SIvan Malov fail_efx_tx_init:
516fed9aeb4SIvan Malov 	sfc_log_init(sa, "failed (rc = %d)", rc);
517fed9aeb4SIvan Malov 	return rc;
518fed9aeb4SIvan Malov }
519fed9aeb4SIvan Malov 
520fed9aeb4SIvan Malov void
521fed9aeb4SIvan Malov sfc_tx_stop(struct sfc_adapter *sa)
522fed9aeb4SIvan Malov {
523fed9aeb4SIvan Malov 	unsigned int sw_index;
524fed9aeb4SIvan Malov 
525fed9aeb4SIvan Malov 	sfc_log_init(sa, "txq_count = %u", sa->txq_count);
526fed9aeb4SIvan Malov 
527fed9aeb4SIvan Malov 	sw_index = sa->txq_count;
528fed9aeb4SIvan Malov 	while (sw_index-- > 0) {
529fed9aeb4SIvan Malov 		if (sa->txq_info[sw_index].txq != NULL)
530fed9aeb4SIvan Malov 			sfc_tx_qstop(sa, sw_index);
531fed9aeb4SIvan Malov 	}
532fed9aeb4SIvan Malov 
533fed9aeb4SIvan Malov 	efx_tx_fini(sa->nic);
534fed9aeb4SIvan Malov }
535428c7dddSIvan Malov 
536428c7dddSIvan Malov uint16_t
537428c7dddSIvan Malov sfc_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
538428c7dddSIvan Malov {
539428c7dddSIvan Malov 	struct sfc_txq *txq = (struct sfc_txq *)tx_queue;
540428c7dddSIvan Malov 	unsigned int added = txq->added;
541428c7dddSIvan Malov 	unsigned int pushed = added;
542428c7dddSIvan Malov 	unsigned int pkts_sent = 0;
543428c7dddSIvan Malov 	efx_desc_t *pend = &txq->pend_desc[0];
544428c7dddSIvan Malov 	const unsigned int hard_max_fill = EFX_TXQ_LIMIT(txq->ptr_mask + 1);
54521f6411cSIvan Malov 	const unsigned int soft_max_fill = hard_max_fill - txq->free_thresh;
546428c7dddSIvan Malov 	unsigned int fill_level = added - txq->completed;
547428c7dddSIvan Malov 	boolean_t reap_done;
548428c7dddSIvan Malov 	int rc __rte_unused;
549428c7dddSIvan Malov 	struct rte_mbuf **pktp;
550428c7dddSIvan Malov 
551428c7dddSIvan Malov 	if (unlikely((txq->state & SFC_TXQ_RUNNING) == 0))
552428c7dddSIvan Malov 		goto done;
553428c7dddSIvan Malov 
554428c7dddSIvan Malov 	/*
555428c7dddSIvan Malov 	 * If insufficient space for a single packet is present,
556428c7dddSIvan Malov 	 * we should reap; otherwise, we shouldn't do that all the time
557428c7dddSIvan Malov 	 * to avoid latency increase
558428c7dddSIvan Malov 	 */
559428c7dddSIvan Malov 	reap_done = (fill_level > soft_max_fill);
560428c7dddSIvan Malov 
561428c7dddSIvan Malov 	if (reap_done) {
562428c7dddSIvan Malov 		sfc_tx_reap(txq);
563428c7dddSIvan Malov 		/*
564428c7dddSIvan Malov 		 * Recalculate fill level since 'txq->completed'
565428c7dddSIvan Malov 		 * might have changed on reap
566428c7dddSIvan Malov 		 */
567428c7dddSIvan Malov 		fill_level = added - txq->completed;
568428c7dddSIvan Malov 	}
569428c7dddSIvan Malov 
570428c7dddSIvan Malov 	for (pkts_sent = 0, pktp = &tx_pkts[0];
571428c7dddSIvan Malov 	     (pkts_sent < nb_pkts) && (fill_level <= soft_max_fill);
572428c7dddSIvan Malov 	     pkts_sent++, pktp++) {
573428c7dddSIvan Malov 		struct rte_mbuf		*m_seg = *pktp;
574428c7dddSIvan Malov 		size_t			pkt_len = m_seg->pkt_len;
575428c7dddSIvan Malov 		unsigned int		pkt_descs = 0;
576428c7dddSIvan Malov 
577428c7dddSIvan Malov 		for (; m_seg != NULL; m_seg = m_seg->next) {
578428c7dddSIvan Malov 			efsys_dma_addr_t	next_frag;
579428c7dddSIvan Malov 			size_t			seg_len;
580428c7dddSIvan Malov 
581428c7dddSIvan Malov 			seg_len = m_seg->data_len;
582428c7dddSIvan Malov 			next_frag = rte_mbuf_data_dma_addr(m_seg);
583428c7dddSIvan Malov 
584428c7dddSIvan Malov 			do {
585428c7dddSIvan Malov 				efsys_dma_addr_t	frag_addr = next_frag;
586428c7dddSIvan Malov 				size_t			frag_len;
587428c7dddSIvan Malov 
588428c7dddSIvan Malov 				next_frag = RTE_ALIGN(frag_addr + 1,
589428c7dddSIvan Malov 						      SFC_TX_SEG_BOUNDARY);
590428c7dddSIvan Malov 				frag_len = MIN(next_frag - frag_addr, seg_len);
591428c7dddSIvan Malov 				seg_len -= frag_len;
592428c7dddSIvan Malov 				pkt_len -= frag_len;
593428c7dddSIvan Malov 
594428c7dddSIvan Malov 				efx_tx_qdesc_dma_create(txq->common,
595428c7dddSIvan Malov 							frag_addr, frag_len,
596428c7dddSIvan Malov 							(pkt_len == 0),
597428c7dddSIvan Malov 							pend++);
598428c7dddSIvan Malov 
599428c7dddSIvan Malov 				pkt_descs++;
600428c7dddSIvan Malov 			} while (seg_len != 0);
601428c7dddSIvan Malov 		}
602428c7dddSIvan Malov 
603428c7dddSIvan Malov 		added += pkt_descs;
604428c7dddSIvan Malov 
605428c7dddSIvan Malov 		fill_level += pkt_descs;
606428c7dddSIvan Malov 		if (unlikely(fill_level > hard_max_fill)) {
607428c7dddSIvan Malov 			/*
608428c7dddSIvan Malov 			 * Our estimation for maximum number of descriptors
609428c7dddSIvan Malov 			 * required to send a packet seems to be wrong.
610428c7dddSIvan Malov 			 * Try to reap (if we haven't yet).
611428c7dddSIvan Malov 			 */
612428c7dddSIvan Malov 			if (!reap_done) {
613428c7dddSIvan Malov 				sfc_tx_reap(txq);
614428c7dddSIvan Malov 				reap_done = B_TRUE;
615428c7dddSIvan Malov 				fill_level = added - txq->completed;
616428c7dddSIvan Malov 				if (fill_level > hard_max_fill) {
617428c7dddSIvan Malov 					pend -= pkt_descs;
618428c7dddSIvan Malov 					break;
619428c7dddSIvan Malov 				}
620428c7dddSIvan Malov 			} else {
621428c7dddSIvan Malov 				pend -= pkt_descs;
622428c7dddSIvan Malov 				break;
623428c7dddSIvan Malov 			}
624428c7dddSIvan Malov 		}
625428c7dddSIvan Malov 
626428c7dddSIvan Malov 		/* Assign mbuf to the last used desc */
627428c7dddSIvan Malov 		txq->sw_ring[(added - 1) & txq->ptr_mask].mbuf = *pktp;
628428c7dddSIvan Malov 	}
629428c7dddSIvan Malov 
630428c7dddSIvan Malov 	if (likely(pkts_sent > 0)) {
631428c7dddSIvan Malov 		rc = efx_tx_qdesc_post(txq->common, txq->pend_desc,
632428c7dddSIvan Malov 				       pend - &txq->pend_desc[0],
633428c7dddSIvan Malov 				       txq->completed, &txq->added);
634428c7dddSIvan Malov 		SFC_ASSERT(rc == 0);
635428c7dddSIvan Malov 
636428c7dddSIvan Malov 		if (likely(pushed != txq->added))
637428c7dddSIvan Malov 			efx_tx_qpush(txq->common, txq->added, pushed);
638428c7dddSIvan Malov 	}
639428c7dddSIvan Malov 
640428c7dddSIvan Malov #if SFC_TX_XMIT_PKTS_REAP_AT_LEAST_ONCE
641428c7dddSIvan Malov 	if (!reap_done)
642428c7dddSIvan Malov 		sfc_tx_reap(txq);
643428c7dddSIvan Malov #endif
644428c7dddSIvan Malov 
645428c7dddSIvan Malov done:
646428c7dddSIvan Malov 	return pkts_sent;
647428c7dddSIvan Malov }
648