Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : *
3 : : * Copyright(c) 2019-2021 Xilinx, Inc.
4 : : * Copyright(c) 2016-2019 Solarflare Communications Inc.
5 : : *
6 : : * This software was jointly developed between OKTET Labs (under contract
7 : : * for Solarflare) and Solarflare Communications, Inc.
8 : : */
9 : :
10 : : #include "sfc.h"
11 : : #include "sfc_debug.h"
12 : : #include "sfc_log.h"
13 : : #include "sfc_ev.h"
14 : : #include "sfc_tx.h"
15 : : #include "sfc_tweak.h"
16 : : #include "sfc_kvargs.h"
17 : :
18 : : /*
19 : : * Maximum number of TX queue flush attempts in case of
20 : : * failure or flush timeout
21 : : */
22 : : #define SFC_TX_QFLUSH_ATTEMPTS (3)
23 : :
24 : : /*
25 : : * Time to wait between event queue polling attempts when waiting for TX
26 : : * queue flush done or flush failed events
27 : : */
28 : : #define SFC_TX_QFLUSH_POLL_WAIT_MS (1)
29 : :
30 : : /*
31 : : * Maximum number of event queue polling attempts when waiting for TX queue
32 : : * flush done or flush failed events; it defines TX queue flush attempt timeout
33 : : * together with SFC_TX_QFLUSH_POLL_WAIT_MS
34 : : */
35 : : #define SFC_TX_QFLUSH_POLL_ATTEMPTS (2000)
36 : :
37 : : struct sfc_txq_info *
38 : 0 : sfc_txq_info_by_ethdev_qid(struct sfc_adapter_shared *sas,
39 : : sfc_ethdev_qid_t ethdev_qid)
40 : : {
41 : : sfc_sw_index_t sw_index;
42 : :
43 : : SFC_ASSERT((unsigned int)ethdev_qid < sas->ethdev_txq_count);
44 : : SFC_ASSERT(ethdev_qid != SFC_ETHDEV_QID_INVALID);
45 : :
46 : : sw_index = sfc_txq_sw_index_by_ethdev_tx_qid(sas, ethdev_qid);
47 : 0 : return &sas->txq_info[sw_index];
48 : : }
49 : :
50 : : static uint64_t
51 : 0 : sfc_tx_get_offload_mask(struct sfc_adapter *sa)
52 : : {
53 : 0 : const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
54 : : uint64_t no_caps = 0;
55 : :
56 [ # # ]: 0 : if (!encp->enc_hw_tx_insert_vlan_enabled)
57 : : no_caps |= RTE_ETH_TX_OFFLOAD_VLAN_INSERT;
58 : :
59 [ # # ]: 0 : if (!encp->enc_tunnel_encapsulations_supported)
60 : 0 : no_caps |= RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM;
61 : :
62 [ # # ]: 0 : if (!sa->tso)
63 : 0 : no_caps |= RTE_ETH_TX_OFFLOAD_TCP_TSO;
64 : :
65 [ # # ]: 0 : if (!sa->tso_encap ||
66 [ # # ]: 0 : (encp->enc_tunnel_encapsulations_supported &
67 : : (1u << EFX_TUNNEL_PROTOCOL_VXLAN)) == 0)
68 : 0 : no_caps |= RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO;
69 : :
70 [ # # ]: 0 : if (!sa->tso_encap ||
71 [ # # ]: 0 : (encp->enc_tunnel_encapsulations_supported &
72 : : (1u << EFX_TUNNEL_PROTOCOL_GENEVE)) == 0)
73 : 0 : no_caps |= RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO;
74 : :
75 : 0 : return ~no_caps;
76 : : }
77 : :
78 : : uint64_t
79 : 0 : sfc_tx_get_dev_offload_caps(struct sfc_adapter *sa)
80 : : {
81 : 0 : return sa->priv.dp_tx->dev_offload_capa & sfc_tx_get_offload_mask(sa);
82 : : }
83 : :
84 : : uint64_t
85 : 0 : sfc_tx_get_queue_offload_caps(struct sfc_adapter *sa)
86 : : {
87 : 0 : return sa->priv.dp_tx->queue_offload_capa & sfc_tx_get_offload_mask(sa);
88 : : }
89 : :
90 : : static int
91 : 0 : sfc_tx_qcheck_conf(struct sfc_adapter *sa, unsigned int txq_max_fill_level,
92 : : const struct rte_eth_txconf *tx_conf,
93 : : uint64_t offloads)
94 : : {
95 : : int rc = 0;
96 : :
97 [ # # ]: 0 : if (tx_conf->tx_rs_thresh != 0) {
98 : 0 : sfc_err(sa, "RS bit in transmit descriptor is not supported");
99 : : rc = EINVAL;
100 : : }
101 : :
102 [ # # ]: 0 : if (tx_conf->tx_free_thresh > txq_max_fill_level) {
103 : 0 : sfc_err(sa,
104 : : "TxQ free threshold too large: %u vs maximum %u",
105 : : tx_conf->tx_free_thresh, txq_max_fill_level);
106 : : rc = EINVAL;
107 : : }
108 : :
109 : 0 : if (tx_conf->tx_thresh.pthresh != 0 ||
110 [ # # ]: 0 : tx_conf->tx_thresh.hthresh != 0 ||
111 : : tx_conf->tx_thresh.wthresh != 0) {
112 : 0 : sfc_warn(sa,
113 : : "prefetch/host/writeback thresholds are not supported");
114 : : }
115 : :
116 : : /* We either perform both TCP and UDP offload, or no offload at all */
117 : 0 : if (((offloads & RTE_ETH_TX_OFFLOAD_TCP_CKSUM) == 0) !=
118 [ # # ]: 0 : ((offloads & RTE_ETH_TX_OFFLOAD_UDP_CKSUM) == 0)) {
119 : 0 : sfc_err(sa, "TCP and UDP offloads can't be set independently");
120 : : rc = EINVAL;
121 : : }
122 : :
123 : 0 : return rc;
124 : : }
125 : :
126 : : void
127 : 0 : sfc_tx_qflush_done(struct sfc_txq_info *txq_info)
128 : : {
129 : 0 : txq_info->state |= SFC_TXQ_FLUSHED;
130 : 0 : txq_info->state &= ~SFC_TXQ_FLUSHING;
131 : 0 : }
132 : :
133 : : int
134 : 0 : sfc_tx_qinit(struct sfc_adapter *sa, sfc_sw_index_t sw_index,
135 : : uint16_t nb_tx_desc, unsigned int socket_id,
136 : : const struct rte_eth_txconf *tx_conf)
137 : : {
138 : : struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
139 : : sfc_ethdev_qid_t ethdev_qid;
140 : 0 : const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
141 : : unsigned int txq_entries;
142 : : unsigned int evq_entries;
143 : : unsigned int txq_max_fill_level;
144 : : struct sfc_txq_info *txq_info;
145 : : struct sfc_evq *evq;
146 : : struct sfc_txq *txq;
147 : : int rc = 0;
148 : : struct sfc_dp_tx_qcreate_info info;
149 : : uint64_t offloads;
150 : : struct sfc_dp_tx_hw_limits hw_limits;
151 : :
152 : : ethdev_qid = sfc_ethdev_tx_qid_by_txq_sw_index(sas, sw_index);
153 : :
154 : 0 : sfc_log_init(sa, "TxQ = %d (internal %u)", ethdev_qid, sw_index);
155 : :
156 : : memset(&hw_limits, 0, sizeof(hw_limits));
157 : 0 : hw_limits.txq_max_entries = sa->txq_max_entries;
158 : 0 : hw_limits.txq_min_entries = sa->txq_min_entries;
159 : :
160 : 0 : rc = sa->priv.dp_tx->qsize_up_rings(nb_tx_desc, &hw_limits,
161 : : &txq_entries, &evq_entries,
162 : : &txq_max_fill_level);
163 [ # # ]: 0 : if (rc != 0)
164 : 0 : goto fail_size_up_rings;
165 : : SFC_ASSERT(txq_entries >= sa->txq_min_entries);
166 : : SFC_ASSERT(txq_entries <= sa->txq_max_entries);
167 : : SFC_ASSERT(txq_entries >= nb_tx_desc);
168 : : SFC_ASSERT(txq_max_fill_level <= nb_tx_desc);
169 : :
170 : 0 : offloads = tx_conf->offloads;
171 : : /* Add device level Tx offloads if the queue is an ethdev Tx queue */
172 [ # # ]: 0 : if (ethdev_qid != SFC_ETHDEV_QID_INVALID)
173 : 0 : offloads |= sa->eth_dev->data->dev_conf.txmode.offloads;
174 : :
175 : 0 : rc = sfc_tx_qcheck_conf(sa, txq_max_fill_level, tx_conf, offloads);
176 [ # # ]: 0 : if (rc != 0)
177 : 0 : goto fail_bad_conf;
178 : :
179 : : SFC_ASSERT(sw_index < sfc_sa2shared(sa)->txq_count);
180 : 0 : txq_info = &sfc_sa2shared(sa)->txq_info[sw_index];
181 : :
182 : 0 : txq_info->entries = txq_entries;
183 : :
184 : 0 : rc = sfc_ev_qinit(sa, SFC_EVQ_TYPE_TX, sw_index,
185 : : evq_entries, socket_id, &evq);
186 [ # # ]: 0 : if (rc != 0)
187 : 0 : goto fail_ev_qinit;
188 : :
189 : 0 : txq = &sa->txq_ctrl[sw_index];
190 : 0 : txq->hw_index = sw_index;
191 : 0 : txq->evq = evq;
192 : 0 : txq_info->free_thresh =
193 [ # # ]: 0 : (tx_conf->tx_free_thresh) ? tx_conf->tx_free_thresh :
194 : : SFC_TX_DEFAULT_FREE_THRESH;
195 : 0 : txq_info->offloads = offloads;
196 : :
197 : 0 : rc = sfc_dma_alloc(sa, "txq", sw_index, EFX_NIC_DMA_ADDR_TX_RING,
198 : 0 : efx_txq_size(sa->nic, txq_info->entries),
199 : : socket_id, &txq->mem);
200 [ # # ]: 0 : if (rc != 0)
201 : 0 : goto fail_dma_alloc;
202 : :
203 : : memset(&info, 0, sizeof(info));
204 : 0 : info.max_fill_level = txq_max_fill_level;
205 : 0 : info.free_thresh = txq_info->free_thresh;
206 : 0 : info.offloads = offloads;
207 : 0 : info.txq_entries = txq_info->entries;
208 : 0 : info.dma_desc_size_max = encp->enc_tx_dma_desc_size_max;
209 : 0 : info.txq_hw_ring = txq->mem.esm_base;
210 : 0 : info.evq_entries = evq_entries;
211 : 0 : info.evq_hw_ring = evq->mem.esm_base;
212 : 0 : info.hw_index = txq->hw_index;
213 : 0 : info.mem_bar = sa->mem_bar.esb_base;
214 : 0 : info.vi_window_shift = encp->enc_vi_window_shift;
215 : 0 : info.tso_tcp_header_offset_limit =
216 : 0 : encp->enc_tx_tso_tcp_header_offset_limit;
217 : 0 : info.tso_max_nb_header_descs =
218 : 0 : RTE_MIN(encp->enc_tx_tso_max_header_ndescs,
219 : : (uint32_t)UINT16_MAX);
220 : 0 : info.tso_max_header_len =
221 : 0 : RTE_MIN(encp->enc_tx_tso_max_header_length,
222 : : (uint32_t)UINT16_MAX);
223 : 0 : info.tso_max_nb_payload_descs =
224 : 0 : RTE_MIN(encp->enc_tx_tso_max_payload_ndescs,
225 : : (uint32_t)UINT16_MAX);
226 : 0 : info.tso_max_payload_len = encp->enc_tx_tso_max_payload_length;
227 : 0 : info.tso_max_nb_outgoing_frames = encp->enc_tx_tso_max_nframes;
228 : :
229 : 0 : info.nic_dma_info = &sas->nic_dma_info;
230 : :
231 : 0 : rc = sa->priv.dp_tx->qcreate(sa->eth_dev->data->port_id, sw_index,
232 : 0 : &RTE_ETH_DEV_TO_PCI(sa->eth_dev)->addr,
233 : : socket_id, &info, &txq_info->dp);
234 [ # # ]: 0 : if (rc != 0)
235 : 0 : goto fail_dp_tx_qinit;
236 : :
237 : 0 : evq->dp_txq = txq_info->dp;
238 : :
239 : 0 : txq_info->state = SFC_TXQ_INITIALIZED;
240 : :
241 : 0 : txq_info->deferred_start = (tx_conf->tx_deferred_start != 0);
242 : :
243 : 0 : return 0;
244 : :
245 : : fail_dp_tx_qinit:
246 : 0 : sfc_dma_free(sa, &txq->mem);
247 : :
248 : 0 : fail_dma_alloc:
249 : 0 : sfc_ev_qfini(evq);
250 : :
251 : 0 : fail_ev_qinit:
252 : 0 : txq_info->entries = 0;
253 : :
254 : 0 : fail_bad_conf:
255 : 0 : fail_size_up_rings:
256 : 0 : sfc_log_init(sa, "failed (TxQ = %d (internal %u), rc = %d)", ethdev_qid,
257 : : sw_index, rc);
258 : 0 : return rc;
259 : : }
260 : :
261 : : void
262 [ # # ]: 0 : sfc_tx_qfini(struct sfc_adapter *sa, sfc_sw_index_t sw_index)
263 : : {
264 : : struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
265 : : sfc_ethdev_qid_t ethdev_qid;
266 : : struct sfc_txq_info *txq_info;
267 : : struct sfc_txq *txq;
268 : :
269 : : ethdev_qid = sfc_ethdev_tx_qid_by_txq_sw_index(sas, sw_index);
270 : :
271 : 0 : sfc_log_init(sa, "TxQ = %d (internal %u)", ethdev_qid, sw_index);
272 : :
273 : : SFC_ASSERT(sw_index < sfc_sa2shared(sa)->txq_count);
274 [ # # ]: 0 : if (ethdev_qid != SFC_ETHDEV_QID_INVALID)
275 : 0 : sa->eth_dev->data->tx_queues[ethdev_qid] = NULL;
276 : :
277 : 0 : txq_info = &sfc_sa2shared(sa)->txq_info[sw_index];
278 : :
279 : : SFC_ASSERT(txq_info->state == SFC_TXQ_INITIALIZED);
280 : :
281 : 0 : sa->priv.dp_tx->qdestroy(txq_info->dp);
282 : 0 : txq_info->dp = NULL;
283 : :
284 : 0 : txq_info->state &= ~SFC_TXQ_INITIALIZED;
285 : 0 : txq_info->entries = 0;
286 : :
287 : 0 : txq = &sa->txq_ctrl[sw_index];
288 : :
289 : 0 : sfc_dma_free(sa, &txq->mem);
290 : :
291 : 0 : sfc_ev_qfini(txq->evq);
292 : 0 : txq->evq = NULL;
293 : 0 : }
294 : :
295 : : int
296 [ # # ]: 0 : sfc_tx_qinit_info(struct sfc_adapter *sa, sfc_sw_index_t sw_index)
297 : : {
298 : : struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
299 : : sfc_ethdev_qid_t ethdev_qid;
300 : :
301 : : ethdev_qid = sfc_ethdev_tx_qid_by_txq_sw_index(sas, sw_index);
302 : :
303 : 0 : sfc_log_init(sa, "TxQ = %d (internal %u)", ethdev_qid, sw_index);
304 : :
305 : 0 : return 0;
306 : : }
307 : :
308 : : static int
309 : 0 : sfc_tx_check_mode(struct sfc_adapter *sa, const struct rte_eth_txmode *txmode)
310 : : {
311 : 0 : uint64_t dev_tx_offload_cap = sfc_tx_get_dev_offload_caps(sa);
312 : : int rc = 0;
313 : :
314 [ # # ]: 0 : switch (txmode->mq_mode) {
315 : : case RTE_ETH_MQ_TX_NONE:
316 : : break;
317 : 0 : default:
318 : 0 : sfc_err(sa, "Tx multi-queue mode %u not supported",
319 : : txmode->mq_mode);
320 : : rc = EINVAL;
321 : : }
322 : :
323 [ # # ]: 0 : if ((dev_tx_offload_cap & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE) != 0 &&
324 [ # # ]: 0 : (txmode->offloads & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE) == 0) {
325 : 0 : sfc_err(sa, "There is no FAST_FREE flag in the attempted Tx mode configuration");
326 : 0 : sfc_err(sa, "FAST_FREE is always active as per the current Tx datapath variant");
327 : : rc = EINVAL;
328 : : }
329 : :
330 : : /*
331 : : * These features are claimed to be i40e-specific,
332 : : * but it does make sense to double-check their absence
333 : : */
334 [ # # ]: 0 : if (txmode->hw_vlan_reject_tagged) {
335 : 0 : sfc_err(sa, "Rejecting tagged packets not supported");
336 : : rc = EINVAL;
337 : : }
338 : :
339 [ # # ]: 0 : if (txmode->hw_vlan_reject_untagged) {
340 : 0 : sfc_err(sa, "Rejecting untagged packets not supported");
341 : : rc = EINVAL;
342 : : }
343 : :
344 [ # # ]: 0 : if (txmode->hw_vlan_insert_pvid) {
345 : 0 : sfc_err(sa, "Port-based VLAN insertion not supported");
346 : : rc = EINVAL;
347 : : }
348 : :
349 : 0 : return rc;
350 : : }
351 : :
352 : : /**
353 : : * Destroy excess queues that are no longer needed after reconfiguration
354 : : * or complete close.
355 : : */
356 : : static void
357 : 0 : sfc_tx_fini_queues(struct sfc_adapter *sa, unsigned int nb_tx_queues)
358 : : {
359 : : struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
360 : : sfc_sw_index_t sw_index;
361 : : sfc_ethdev_qid_t ethdev_qid;
362 : :
363 : : SFC_ASSERT(nb_tx_queues <= sas->ethdev_txq_count);
364 : :
365 : : /*
366 : : * Finalize only ethdev queues since other ones are finalized only
367 : : * on device close and they may require additional deinitialization.
368 : : */
369 : 0 : ethdev_qid = sas->ethdev_txq_count;
370 [ # # ]: 0 : while (--ethdev_qid >= (int)nb_tx_queues) {
371 : : struct sfc_txq_info *txq_info;
372 : :
373 : : sw_index = sfc_txq_sw_index_by_ethdev_tx_qid(sas, ethdev_qid);
374 : 0 : txq_info = sfc_txq_info_by_ethdev_qid(sas, ethdev_qid);
375 [ # # ]: 0 : if (txq_info->state & SFC_TXQ_INITIALIZED)
376 : 0 : sfc_tx_qfini(sa, sw_index);
377 : : }
378 : :
379 : 0 : sas->ethdev_txq_count = nb_tx_queues;
380 : 0 : }
381 : :
382 : : int
383 : 0 : sfc_tx_configure(struct sfc_adapter *sa)
384 : : {
385 : : struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
386 : 0 : const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
387 : 0 : const struct rte_eth_conf *dev_conf = &sa->eth_dev->data->dev_conf;
388 : 0 : const unsigned int nb_tx_queues = sa->eth_dev->data->nb_tx_queues;
389 : : const unsigned int nb_rsvd_tx_queues = sfc_nb_txq_reserved(sas);
390 : 0 : const unsigned int nb_txq_total = nb_tx_queues + nb_rsvd_tx_queues;
391 : : bool reconfigure;
392 : : int rc = 0;
393 : :
394 : 0 : sfc_log_init(sa, "nb_tx_queues=%u (old %u)",
395 : : nb_tx_queues, sas->ethdev_txq_count);
396 : :
397 : : /*
398 : : * The datapath implementation assumes absence of boundary
399 : : * limits on Tx DMA descriptors. Addition of these checks on
400 : : * datapath would simply make the datapath slower.
401 : : */
402 [ # # ]: 0 : if (encp->enc_tx_dma_desc_boundary != 0) {
403 : : rc = ENOTSUP;
404 : 0 : goto fail_tx_dma_desc_boundary;
405 : : }
406 : :
407 : 0 : rc = sfc_tx_check_mode(sa, &dev_conf->txmode);
408 [ # # ]: 0 : if (rc != 0)
409 : 0 : goto fail_check_mode;
410 : :
411 [ # # ]: 0 : if (nb_txq_total == sas->txq_count)
412 : 0 : goto done;
413 : :
414 [ # # ]: 0 : if (sas->txq_info == NULL) {
415 : : reconfigure = false;
416 : 0 : sas->txq_info = rte_calloc_socket("sfc-txqs", nb_txq_total,
417 : : sizeof(sas->txq_info[0]), 0,
418 : : sa->socket_id);
419 [ # # ]: 0 : if (sas->txq_info == NULL)
420 : 0 : goto fail_txqs_alloc;
421 : :
422 : : /*
423 : : * Allocate primary process only TxQ control from heap
424 : : * since it should not be shared.
425 : : */
426 : : rc = ENOMEM;
427 : 0 : sa->txq_ctrl = calloc(nb_txq_total, sizeof(sa->txq_ctrl[0]));
428 [ # # ]: 0 : if (sa->txq_ctrl == NULL)
429 : 0 : goto fail_txqs_ctrl_alloc;
430 : : } else {
431 : : struct sfc_txq_info *new_txq_info;
432 : : struct sfc_txq *new_txq_ctrl;
433 : :
434 : : reconfigure = true;
435 : :
436 [ # # ]: 0 : if (nb_tx_queues < sas->ethdev_txq_count)
437 : 0 : sfc_tx_fini_queues(sa, nb_tx_queues);
438 : :
439 : : new_txq_info =
440 : 0 : rte_realloc(sas->txq_info,
441 : : nb_txq_total * sizeof(sas->txq_info[0]), 0);
442 [ # # ]: 0 : if (new_txq_info == NULL && nb_txq_total > 0)
443 : 0 : goto fail_txqs_realloc;
444 : :
445 : 0 : new_txq_ctrl = realloc(sa->txq_ctrl,
446 : : nb_txq_total * sizeof(sa->txq_ctrl[0]));
447 [ # # ]: 0 : if (new_txq_ctrl == NULL && nb_txq_total > 0)
448 : 0 : goto fail_txqs_ctrl_realloc;
449 : :
450 : 0 : sas->txq_info = new_txq_info;
451 : 0 : sa->txq_ctrl = new_txq_ctrl;
452 [ # # ]: 0 : if (nb_txq_total > sas->txq_count) {
453 : 0 : memset(&sas->txq_info[sas->txq_count], 0,
454 : 0 : (nb_txq_total - sas->txq_count) *
455 : : sizeof(sas->txq_info[0]));
456 : 0 : memset(&sa->txq_ctrl[sas->txq_count], 0,
457 : 0 : (nb_txq_total - sas->txq_count) *
458 : : sizeof(sa->txq_ctrl[0]));
459 : : }
460 : : }
461 : :
462 [ # # ]: 0 : while (sas->ethdev_txq_count < nb_tx_queues) {
463 : : sfc_sw_index_t sw_index;
464 : :
465 : : sw_index = sfc_txq_sw_index_by_ethdev_tx_qid(sas,
466 : : sas->ethdev_txq_count);
467 : 0 : rc = sfc_tx_qinit_info(sa, sw_index);
468 [ # # ]: 0 : if (rc != 0)
469 : 0 : goto fail_tx_qinit_info;
470 : :
471 : 0 : sas->ethdev_txq_count++;
472 : : }
473 : :
474 : 0 : sas->txq_count = sas->ethdev_txq_count + nb_rsvd_tx_queues;
475 : :
476 [ # # ]: 0 : if (!reconfigure) {
477 : 0 : rc = sfc_repr_proxy_txq_init(sa);
478 [ # # ]: 0 : if (rc != 0)
479 : 0 : goto fail_repr_proxy_txq_init;
480 : : }
481 : :
482 : 0 : done:
483 : : return 0;
484 : :
485 : : fail_repr_proxy_txq_init:
486 : 0 : fail_tx_qinit_info:
487 : 0 : fail_txqs_ctrl_realloc:
488 : 0 : fail_txqs_realloc:
489 : 0 : fail_txqs_ctrl_alloc:
490 : 0 : fail_txqs_alloc:
491 : 0 : sfc_tx_close(sa);
492 : :
493 : 0 : fail_check_mode:
494 : 0 : fail_tx_dma_desc_boundary:
495 : 0 : sfc_log_init(sa, "failed (rc = %d)", rc);
496 : 0 : return rc;
497 : : }
498 : :
499 : : void
500 : 0 : sfc_tx_close(struct sfc_adapter *sa)
501 : : {
502 : 0 : sfc_tx_fini_queues(sa, 0);
503 : 0 : sfc_repr_proxy_txq_fini(sa);
504 : :
505 : 0 : free(sa->txq_ctrl);
506 : 0 : sa->txq_ctrl = NULL;
507 : :
508 : 0 : rte_free(sfc_sa2shared(sa)->txq_info);
509 : 0 : sfc_sa2shared(sa)->txq_info = NULL;
510 : 0 : }
511 : :
512 : : int
513 : 0 : sfc_tx_qstart(struct sfc_adapter *sa, sfc_sw_index_t sw_index)
514 : : {
515 : : struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
516 : : sfc_ethdev_qid_t ethdev_qid;
517 [ # # ]: 0 : uint64_t offloads_supported = sfc_tx_get_dev_offload_caps(sa) |
518 : 0 : sfc_tx_get_queue_offload_caps(sa);
519 : : struct sfc_txq_info *txq_info;
520 : : struct sfc_txq *txq;
521 : : struct sfc_evq *evq;
522 : : uint16_t flags = 0;
523 : : unsigned int desc_index;
524 : : int rc = 0;
525 : :
526 : : ethdev_qid = sfc_ethdev_tx_qid_by_txq_sw_index(sas, sw_index);
527 : :
528 : 0 : sfc_log_init(sa, "TxQ = %d (internal %u)", ethdev_qid, sw_index);
529 : :
530 : : SFC_ASSERT(sw_index < sas->txq_count);
531 : 0 : txq_info = &sas->txq_info[sw_index];
532 : :
533 : : SFC_ASSERT(txq_info->state == SFC_TXQ_INITIALIZED);
534 : :
535 : 0 : txq = &sa->txq_ctrl[sw_index];
536 : 0 : evq = txq->evq;
537 : :
538 : 0 : rc = sfc_ev_qstart(evq, sfc_evq_sw_index_by_txq_sw_index(sa, sw_index));
539 [ # # ]: 0 : if (rc != 0)
540 : 0 : goto fail_ev_qstart;
541 : :
542 [ # # ]: 0 : if (txq_info->offloads & RTE_ETH_TX_OFFLOAD_IPV4_CKSUM)
543 : : flags |= EFX_TXQ_CKSUM_IPV4;
544 : :
545 [ # # ]: 0 : if (txq_info->offloads & RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM)
546 : 0 : flags |= EFX_TXQ_CKSUM_INNER_IPV4;
547 : :
548 [ # # ]: 0 : if ((txq_info->offloads & RTE_ETH_TX_OFFLOAD_TCP_CKSUM) ||
549 : : (txq_info->offloads & RTE_ETH_TX_OFFLOAD_UDP_CKSUM)) {
550 : 0 : flags |= EFX_TXQ_CKSUM_TCPUDP;
551 : :
552 [ # # ]: 0 : if (offloads_supported & RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM)
553 : 0 : flags |= EFX_TXQ_CKSUM_INNER_TCPUDP;
554 : : }
555 : :
556 [ # # ]: 0 : if (txq_info->offloads & (RTE_ETH_TX_OFFLOAD_TCP_TSO |
557 : : RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO |
558 : : RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO))
559 : 0 : flags |= EFX_TXQ_FATSOV2;
560 : :
561 : 0 : rc = efx_tx_qcreate(sa->nic, txq->hw_index, 0, &txq->mem,
562 : 0 : txq_info->entries, 0 /* not used on EF10 */,
563 : : flags, evq->common,
564 : : &txq->common, &desc_index);
565 [ # # ]: 0 : if (rc != 0) {
566 [ # # # # ]: 0 : if (sa->tso && (rc == ENOSPC))
567 : 0 : sfc_err(sa, "ran out of TSO contexts");
568 : :
569 : 0 : goto fail_tx_qcreate;
570 : : }
571 : :
572 : 0 : efx_tx_qenable(txq->common);
573 : :
574 : 0 : txq_info->state |= SFC_TXQ_STARTED;
575 : :
576 : 0 : rc = sa->priv.dp_tx->qstart(txq_info->dp, evq->read_ptr, desc_index);
577 [ # # ]: 0 : if (rc != 0)
578 : 0 : goto fail_dp_qstart;
579 : :
580 [ # # ]: 0 : if (ethdev_qid != SFC_ETHDEV_QID_INVALID) {
581 : : struct rte_eth_dev_data *dev_data;
582 : :
583 : : /*
584 : : * It sems to be used by DPDK for debug purposes only
585 : : * ('rte_ether').
586 : : */
587 : 0 : dev_data = sa->eth_dev->data;
588 : 0 : dev_data->tx_queue_state[ethdev_qid] =
589 : : RTE_ETH_QUEUE_STATE_STARTED;
590 : : }
591 : :
592 : : return 0;
593 : :
594 : : fail_dp_qstart:
595 : 0 : txq_info->state = SFC_TXQ_INITIALIZED;
596 : 0 : efx_tx_qdestroy(txq->common);
597 : :
598 : 0 : fail_tx_qcreate:
599 : 0 : sfc_ev_qstop(evq);
600 : :
601 : : fail_ev_qstart:
602 : : return rc;
603 : : }
604 : :
605 : : void
606 [ # # ]: 0 : sfc_tx_qstop(struct sfc_adapter *sa, sfc_sw_index_t sw_index)
607 : : {
608 : : struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
609 : : sfc_ethdev_qid_t ethdev_qid;
610 : : struct sfc_txq_info *txq_info;
611 : : struct sfc_txq *txq;
612 : : unsigned int retry_count;
613 : : unsigned int wait_count;
614 : : int rc;
615 : :
616 : : ethdev_qid = sfc_ethdev_tx_qid_by_txq_sw_index(sas, sw_index);
617 : :
618 : 0 : sfc_log_init(sa, "TxQ = %d (internal %u)", ethdev_qid, sw_index);
619 : :
620 : : SFC_ASSERT(sw_index < sas->txq_count);
621 : 0 : txq_info = &sas->txq_info[sw_index];
622 : :
623 [ # # ]: 0 : if (txq_info->state == SFC_TXQ_INITIALIZED)
624 : : return;
625 : :
626 : : SFC_ASSERT(txq_info->state & SFC_TXQ_STARTED);
627 : :
628 : 0 : txq = &sa->txq_ctrl[sw_index];
629 : 0 : sa->priv.dp_tx->qstop(txq_info->dp, &txq->evq->read_ptr);
630 : :
631 : : /*
632 : : * Retry TX queue flushing in case of flush failed or
633 : : * timeout; in the worst case it can delay for 6 seconds
634 : : */
635 : 0 : for (retry_count = 0;
636 [ # # # # ]: 0 : ((txq_info->state & SFC_TXQ_FLUSHED) == 0) &&
637 : : (retry_count < SFC_TX_QFLUSH_ATTEMPTS);
638 : 0 : ++retry_count) {
639 : 0 : rc = efx_tx_qflush(txq->common);
640 [ # # ]: 0 : if (rc != 0) {
641 : 0 : txq_info->state |= (rc == EALREADY) ?
642 [ # # ]: 0 : SFC_TXQ_FLUSHED : SFC_TXQ_FLUSH_FAILED;
643 : 0 : break;
644 : : }
645 : :
646 : : /*
647 : : * Wait for TX queue flush done or flush failed event at least
648 : : * SFC_TX_QFLUSH_POLL_WAIT_MS milliseconds and not more
649 : : * than 2 seconds (SFC_TX_QFLUSH_POLL_WAIT_MS multiplied
650 : : * by SFC_TX_QFLUSH_POLL_ATTEMPTS)
651 : : */
652 : : wait_count = 0;
653 : : do {
654 : : rte_delay_ms(SFC_TX_QFLUSH_POLL_WAIT_MS);
655 : 0 : sfc_ev_qpoll(txq->evq);
656 [ # # ]: 0 : } while ((txq_info->state & SFC_TXQ_FLUSHING) &&
657 [ # # ]: 0 : wait_count++ < SFC_TX_QFLUSH_POLL_ATTEMPTS);
658 : :
659 [ # # ]: 0 : if (txq_info->state & SFC_TXQ_FLUSHING)
660 : 0 : sfc_err(sa, "TxQ %d (internal %u) flush timed out",
661 : : ethdev_qid, sw_index);
662 : :
663 [ # # ]: 0 : if (txq_info->state & SFC_TXQ_FLUSHED)
664 : 0 : sfc_notice(sa, "TxQ %d (internal %u) flushed",
665 : : ethdev_qid, sw_index);
666 : : }
667 : :
668 : 0 : sa->priv.dp_tx->qreap(txq_info->dp);
669 : :
670 : 0 : txq_info->state = SFC_TXQ_INITIALIZED;
671 : :
672 : 0 : efx_tx_qdestroy(txq->common);
673 : :
674 : 0 : sfc_ev_qstop(txq->evq);
675 : :
676 [ # # ]: 0 : if (ethdev_qid != SFC_ETHDEV_QID_INVALID) {
677 : : struct rte_eth_dev_data *dev_data;
678 : :
679 : : /*
680 : : * It seems to be used by DPDK for debug purposes only
681 : : * ('rte_ether')
682 : : */
683 : 0 : dev_data = sa->eth_dev->data;
684 : 0 : dev_data->tx_queue_state[ethdev_qid] =
685 : : RTE_ETH_QUEUE_STATE_STOPPED;
686 : : }
687 : : }
688 : :
689 : : int
690 : 0 : sfc_tx_start(struct sfc_adapter *sa)
691 : : {
692 : : struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
693 : 0 : const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
694 : : sfc_sw_index_t sw_index;
695 : : int rc = 0;
696 : :
697 : 0 : sfc_log_init(sa, "txq_count = %u (internal %u)",
698 : : sas->ethdev_txq_count, sas->txq_count);
699 : :
700 [ # # ]: 0 : if (sa->tso) {
701 [ # # ]: 0 : if (!encp->enc_fw_assisted_tso_v2_enabled &&
702 [ # # ]: 0 : !encp->enc_tso_v3_enabled) {
703 : 0 : sfc_warn(sa, "TSO support was unable to be restored");
704 : 0 : sa->tso = B_FALSE;
705 : 0 : sa->tso_encap = B_FALSE;
706 : : }
707 : : }
708 : :
709 [ # # # # ]: 0 : if (sa->tso_encap && !encp->enc_fw_assisted_tso_v2_encap_enabled &&
710 [ # # ]: 0 : !encp->enc_tso_v3_enabled) {
711 : 0 : sfc_warn(sa, "Encapsulated TSO support was unable to be restored");
712 : 0 : sa->tso_encap = B_FALSE;
713 : : }
714 : :
715 : 0 : rc = efx_tx_init(sa->nic);
716 [ # # ]: 0 : if (rc != 0)
717 : 0 : goto fail_efx_tx_init;
718 : :
719 [ # # ]: 0 : for (sw_index = 0; sw_index < sas->txq_count; ++sw_index) {
720 [ # # ]: 0 : if (sas->txq_info[sw_index].state == SFC_TXQ_INITIALIZED &&
721 [ # # ]: 0 : (!(sas->txq_info[sw_index].deferred_start) ||
722 [ # # ]: 0 : sas->txq_info[sw_index].deferred_started)) {
723 : 0 : rc = sfc_tx_qstart(sa, sw_index);
724 [ # # ]: 0 : if (rc != 0)
725 : 0 : goto fail_tx_qstart;
726 : : }
727 : : }
728 : :
729 : : return 0;
730 : :
731 : : fail_tx_qstart:
732 [ # # ]: 0 : while (sw_index-- > 0)
733 : 0 : sfc_tx_qstop(sa, sw_index);
734 : :
735 : 0 : efx_tx_fini(sa->nic);
736 : :
737 : 0 : fail_efx_tx_init:
738 : 0 : sfc_log_init(sa, "failed (rc = %d)", rc);
739 : 0 : return rc;
740 : : }
741 : :
742 : : void
743 : 0 : sfc_tx_stop(struct sfc_adapter *sa)
744 : : {
745 : : struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
746 : : sfc_sw_index_t sw_index;
747 : :
748 : 0 : sfc_log_init(sa, "txq_count = %u (internal %u)",
749 : : sas->ethdev_txq_count, sas->txq_count);
750 : :
751 : 0 : sw_index = sas->txq_count;
752 [ # # ]: 0 : while (sw_index-- > 0) {
753 [ # # ]: 0 : if (sas->txq_info[sw_index].state & SFC_TXQ_STARTED)
754 : 0 : sfc_tx_qstop(sa, sw_index);
755 : : }
756 : :
757 : 0 : efx_tx_fini(sa->nic);
758 : 0 : }
759 : :
760 : : static void
761 : 0 : sfc_efx_tx_reap(struct sfc_efx_txq *txq)
762 : : {
763 : : unsigned int completed;
764 : :
765 : 0 : sfc_ev_qpoll(txq->evq);
766 : :
767 : 0 : for (completed = txq->completed;
768 [ # # ]: 0 : completed != txq->pending; completed++) {
769 : : struct sfc_efx_tx_sw_desc *txd;
770 : :
771 : 0 : txd = &txq->sw_ring[completed & txq->ptr_mask];
772 : :
773 [ # # ]: 0 : if (txd->mbuf != NULL) {
774 : 0 : rte_pktmbuf_free(txd->mbuf);
775 : 0 : txd->mbuf = NULL;
776 : : }
777 : : }
778 : :
779 : 0 : txq->completed = completed;
780 : 0 : }
781 : :
782 : : /*
783 : : * The function is used to insert or update VLAN tag;
784 : : * the firmware has state of the firmware tag to insert per TxQ
785 : : * (controlled by option descriptors), hence, if the tag of the
786 : : * packet to be sent is different from one remembered by the firmware,
787 : : * the function will update it
788 : : */
789 : : static unsigned int
790 : 0 : sfc_efx_tx_maybe_insert_tag(struct sfc_efx_txq *txq, struct rte_mbuf *m,
791 : : efx_desc_t **pend)
792 : : {
793 [ # # ]: 0 : uint16_t this_tag = ((m->ol_flags & RTE_MBUF_F_TX_VLAN) ?
794 : : m->vlan_tci : 0);
795 : :
796 [ # # ]: 0 : if (this_tag == txq->hw_vlan_tci)
797 : : return 0;
798 : :
799 : : /*
800 : : * The expression inside SFC_ASSERT() is not desired to be checked in
801 : : * a non-debug build because it might be too expensive on the data path
802 : : */
803 : : SFC_ASSERT(efx_nic_cfg_get(txq->evq->sa->nic)->enc_hw_tx_insert_vlan_enabled);
804 : :
805 [ # # ]: 0 : efx_tx_qdesc_vlantci_create(txq->common, rte_cpu_to_be_16(this_tag),
806 : : *pend);
807 : 0 : (*pend)++;
808 : 0 : txq->hw_vlan_tci = this_tag;
809 : :
810 : 0 : return 1;
811 : : }
812 : :
813 : : static uint16_t
814 : 0 : sfc_efx_prepare_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
815 : : uint16_t nb_pkts)
816 : : {
817 : : struct sfc_dp_txq *dp_txq = tx_queue;
818 : : struct sfc_efx_txq *txq = sfc_efx_txq_by_dp_txq(dp_txq);
819 : 0 : const efx_nic_cfg_t *encp = efx_nic_cfg_get(txq->evq->sa->nic);
820 : : uint16_t i;
821 : :
822 [ # # ]: 0 : for (i = 0; i < nb_pkts; i++) {
823 : : int ret;
824 : :
825 : : /*
826 : : * EFX Tx datapath may require extra VLAN descriptor if VLAN
827 : : * insertion offload is requested regardless the offload
828 : : * requested/supported.
829 : : */
830 : 0 : ret = sfc_dp_tx_prepare_pkt(tx_pkts[i], 0, SFC_TSOH_STD_LEN,
831 : 0 : encp->enc_tx_tso_tcp_header_offset_limit,
832 : : txq->max_fill_level, EFX_TX_FATSOV2_OPT_NDESCS,
833 : : 1);
834 [ # # ]: 0 : if (unlikely(ret != 0)) {
835 : 0 : rte_errno = ret;
836 : 0 : break;
837 : : }
838 : : }
839 : :
840 : 0 : return i;
841 : : }
842 : :
843 : : static uint16_t
844 [ # # ]: 0 : sfc_efx_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
845 : : {
846 : : struct sfc_dp_txq *dp_txq = (struct sfc_dp_txq *)tx_queue;
847 : : struct sfc_efx_txq *txq = sfc_efx_txq_by_dp_txq(dp_txq);
848 : 0 : unsigned int added = txq->added;
849 : : unsigned int pushed = added;
850 : : unsigned int pkts_sent = 0;
851 : 0 : efx_desc_t *pend = &txq->pend_desc[0];
852 : 0 : const unsigned int hard_max_fill = txq->max_fill_level;
853 : 0 : const unsigned int soft_max_fill = hard_max_fill - txq->free_thresh;
854 : 0 : unsigned int fill_level = added - txq->completed;
855 : : boolean_t reap_done;
856 : : int rc __rte_unused;
857 : : struct rte_mbuf **pktp;
858 : :
859 [ # # ]: 0 : if (unlikely((txq->flags & SFC_EFX_TXQ_FLAG_RUNNING) == 0))
860 : 0 : goto done;
861 : :
862 : : /*
863 : : * If insufficient space for a single packet is present,
864 : : * we should reap; otherwise, we shouldn't do that all the time
865 : : * to avoid latency increase
866 : : */
867 : 0 : reap_done = (fill_level > soft_max_fill);
868 : :
869 [ # # ]: 0 : if (reap_done) {
870 : 0 : sfc_efx_tx_reap(txq);
871 : : /*
872 : : * Recalculate fill level since 'txq->completed'
873 : : * might have changed on reap
874 : : */
875 : 0 : fill_level = added - txq->completed;
876 : : }
877 : :
878 : : for (pkts_sent = 0, pktp = &tx_pkts[0];
879 [ # # # # ]: 0 : (pkts_sent < nb_pkts) && (fill_level <= soft_max_fill);
880 : 0 : pkts_sent++, pktp++) {
881 : 0 : uint16_t hw_vlan_tci_prev = txq->hw_vlan_tci;
882 : 0 : struct rte_mbuf *m_seg = *pktp;
883 : 0 : size_t pkt_len = m_seg->pkt_len;
884 : 0 : unsigned int pkt_descs = 0;
885 : 0 : size_t in_off = 0;
886 : :
887 : : /*
888 : : * Here VLAN TCI is expected to be zero in case if no
889 : : * RTE_ETH_TX_OFFLOAD_VLAN_INSERT capability is advertised;
890 : : * if the calling app ignores the absence of
891 : : * RTE_ETH_TX_OFFLOAD_VLAN_INSERT and pushes VLAN TCI, then
892 : : * TX_ERROR will occur
893 : : */
894 : 0 : pkt_descs += sfc_efx_tx_maybe_insert_tag(txq, m_seg, &pend);
895 : :
896 [ # # ]: 0 : if (m_seg->ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
897 : : /*
898 : : * We expect correct 'pkt->l[2, 3, 4]_len' values
899 : : * to be set correctly by the caller
900 : : */
901 [ # # ]: 0 : if (sfc_efx_tso_do(txq, added, &m_seg, &in_off, &pend,
902 : : &pkt_descs, &pkt_len) != 0) {
903 : : /* We may have reached this place if packet
904 : : * header linearization is needed but the
905 : : * header length is greater than
906 : : * SFC_TSOH_STD_LEN
907 : : *
908 : : * We will deceive RTE saying that we have sent
909 : : * the packet, but we will actually drop it.
910 : : * Hence, we should revert 'pend' to the
911 : : * previous state (in case we have added
912 : : * VLAN descriptor) and start processing
913 : : * another one packet. But the original
914 : : * mbuf shouldn't be orphaned
915 : : */
916 : 0 : pend -= pkt_descs;
917 : 0 : txq->hw_vlan_tci = hw_vlan_tci_prev;
918 : :
919 : 0 : rte_pktmbuf_free(*pktp);
920 : :
921 : 0 : continue;
922 : : }
923 : :
924 : : /*
925 : : * We've only added 2 FATSOv2 option descriptors
926 : : * and 1 descriptor for the linearized packet header.
927 : : * The outstanding work will be done in the same manner
928 : : * as for the usual non-TSO path
929 : : */
930 : : }
931 : :
932 [ # # ]: 0 : for (; m_seg != NULL; m_seg = m_seg->next) {
933 : : efsys_dma_addr_t next_frag;
934 : : size_t seg_len;
935 : :
936 : 0 : seg_len = m_seg->data_len;
937 : : next_frag = rte_mbuf_data_iova(m_seg);
938 : :
939 : : /*
940 : : * If we've started TSO transaction few steps earlier,
941 : : * we'll skip packet header using an offset in the
942 : : * current segment (which has been set to the
943 : : * first one containing payload)
944 : : */
945 : 0 : seg_len -= in_off;
946 : 0 : next_frag += in_off;
947 : 0 : in_off = 0;
948 : :
949 : : do {
950 : : efsys_dma_addr_t frag_addr = next_frag;
951 : : size_t frag_len;
952 : :
953 : : /*
954 : : * It is assumed here that there is no
955 : : * limitation on address boundary
956 : : * crossing by DMA descriptor.
957 : : */
958 : 0 : frag_len = MIN(seg_len, txq->dma_desc_size_max);
959 : 0 : next_frag += frag_len;
960 : 0 : seg_len -= frag_len;
961 : 0 : pkt_len -= frag_len;
962 : :
963 : 0 : efx_tx_qdesc_dma_create(txq->common,
964 : : frag_addr, frag_len,
965 : : (pkt_len == 0),
966 : : pend++);
967 : :
968 : 0 : pkt_descs++;
969 [ # # ]: 0 : } while (seg_len != 0);
970 : : }
971 : :
972 : 0 : added += pkt_descs;
973 : :
974 : 0 : fill_level += pkt_descs;
975 [ # # ]: 0 : if (unlikely(fill_level > hard_max_fill)) {
976 : : /*
977 : : * Our estimation for maximum number of descriptors
978 : : * required to send a packet seems to be wrong.
979 : : * Try to reap (if we haven't yet).
980 : : */
981 [ # # ]: 0 : if (!reap_done) {
982 : 0 : sfc_efx_tx_reap(txq);
983 : : reap_done = B_TRUE;
984 : 0 : fill_level = added - txq->completed;
985 [ # # ]: 0 : if (fill_level > hard_max_fill) {
986 : 0 : pend -= pkt_descs;
987 : 0 : txq->hw_vlan_tci = hw_vlan_tci_prev;
988 : 0 : break;
989 : : }
990 : : } else {
991 : 0 : pend -= pkt_descs;
992 : 0 : txq->hw_vlan_tci = hw_vlan_tci_prev;
993 : 0 : break;
994 : : }
995 : : }
996 : :
997 : : /* Assign mbuf to the last used desc */
998 : 0 : txq->sw_ring[(added - 1) & txq->ptr_mask].mbuf = *pktp;
999 : : }
1000 : :
1001 [ # # ]: 0 : if (likely(pkts_sent > 0)) {
1002 : 0 : rc = efx_tx_qdesc_post(txq->common, txq->pend_desc,
1003 : 0 : pend - &txq->pend_desc[0],
1004 : : txq->completed, &txq->added);
1005 : : SFC_ASSERT(rc == 0);
1006 : :
1007 [ # # ]: 0 : if (likely(pushed != txq->added)) {
1008 : 0 : efx_tx_qpush(txq->common, txq->added, pushed);
1009 : 0 : txq->dp.dpq.dbells++;
1010 : : }
1011 : : }
1012 : :
1013 : : #if SFC_TX_XMIT_PKTS_REAP_AT_LEAST_ONCE
1014 [ # # ]: 0 : if (!reap_done)
1015 : 0 : sfc_efx_tx_reap(txq);
1016 : : #endif
1017 : :
1018 : 0 : done:
1019 : 0 : return pkts_sent;
1020 : : }
1021 : :
1022 : : const struct sfc_dp_tx *
1023 : 0 : sfc_dp_tx_by_dp_txq(const struct sfc_dp_txq *dp_txq)
1024 : : {
1025 : : const struct sfc_dp_queue *dpq = &dp_txq->dpq;
1026 : : struct rte_eth_dev *eth_dev;
1027 : : struct sfc_adapter_priv *sap;
1028 : :
1029 : : SFC_ASSERT(rte_eth_dev_is_valid_port(dpq->port_id));
1030 : 0 : eth_dev = &rte_eth_devices[dpq->port_id];
1031 : :
1032 : : sap = sfc_adapter_priv_by_eth_dev(eth_dev);
1033 : :
1034 : 0 : return sap->dp_tx;
1035 : : }
1036 : :
1037 : : struct sfc_txq_info *
1038 : 0 : sfc_txq_info_by_dp_txq(const struct sfc_dp_txq *dp_txq)
1039 : : {
1040 : : const struct sfc_dp_queue *dpq = &dp_txq->dpq;
1041 : : struct rte_eth_dev *eth_dev;
1042 : : struct sfc_adapter_shared *sas;
1043 : :
1044 : : SFC_ASSERT(rte_eth_dev_is_valid_port(dpq->port_id));
1045 : 0 : eth_dev = &rte_eth_devices[dpq->port_id];
1046 : :
1047 : : sas = sfc_adapter_shared_by_eth_dev(eth_dev);
1048 : :
1049 : : SFC_ASSERT(dpq->queue_id < sas->txq_count);
1050 : 0 : return &sas->txq_info[dpq->queue_id];
1051 : : }
1052 : :
1053 : : struct sfc_txq *
1054 : 0 : sfc_txq_by_dp_txq(const struct sfc_dp_txq *dp_txq)
1055 : : {
1056 : : const struct sfc_dp_queue *dpq = &dp_txq->dpq;
1057 : : struct rte_eth_dev *eth_dev;
1058 : : struct sfc_adapter *sa;
1059 : :
1060 : : SFC_ASSERT(rte_eth_dev_is_valid_port(dpq->port_id));
1061 : 0 : eth_dev = &rte_eth_devices[dpq->port_id];
1062 : :
1063 : : sa = sfc_adapter_by_eth_dev(eth_dev);
1064 : :
1065 : : SFC_ASSERT(dpq->queue_id < sfc_sa2shared(sa)->txq_count);
1066 : 0 : return &sa->txq_ctrl[dpq->queue_id];
1067 : : }
1068 : :
1069 : : static sfc_dp_tx_qsize_up_rings_t sfc_efx_tx_qsize_up_rings;
1070 : : static int
1071 : 0 : sfc_efx_tx_qsize_up_rings(uint16_t nb_tx_desc,
1072 : : __rte_unused struct sfc_dp_tx_hw_limits *limits,
1073 : : unsigned int *txq_entries,
1074 : : unsigned int *evq_entries,
1075 : : unsigned int *txq_max_fill_level)
1076 : : {
1077 : 0 : *txq_entries = nb_tx_desc;
1078 : 0 : *evq_entries = nb_tx_desc;
1079 : 0 : *txq_max_fill_level = EFX_TXQ_LIMIT(*txq_entries);
1080 : 0 : return 0;
1081 : : }
1082 : :
1083 : : static sfc_dp_tx_qcreate_t sfc_efx_tx_qcreate;
1084 : : static int
1085 : 0 : sfc_efx_tx_qcreate(uint16_t port_id, uint16_t queue_id,
1086 : : const struct rte_pci_addr *pci_addr,
1087 : : int socket_id,
1088 : : const struct sfc_dp_tx_qcreate_info *info,
1089 : : struct sfc_dp_txq **dp_txqp)
1090 : : {
1091 : : struct sfc_efx_txq *txq;
1092 : : struct sfc_txq *ctrl_txq;
1093 : : int rc;
1094 : :
1095 : : rc = ENOTSUP;
1096 [ # # ]: 0 : if (info->nic_dma_info->nb_regions > 0)
1097 : 0 : goto fail_nic_dma;
1098 : :
1099 : : rc = ENOMEM;
1100 : 0 : txq = rte_zmalloc_socket("sfc-efx-txq", sizeof(*txq),
1101 : : RTE_CACHE_LINE_SIZE, socket_id);
1102 [ # # ]: 0 : if (txq == NULL)
1103 : 0 : goto fail_txq_alloc;
1104 : :
1105 : 0 : sfc_dp_queue_init(&txq->dp.dpq, port_id, queue_id, pci_addr);
1106 : :
1107 : : rc = ENOMEM;
1108 : 0 : txq->pend_desc = rte_calloc_socket("sfc-efx-txq-pend-desc",
1109 : 0 : EFX_TXQ_LIMIT(info->txq_entries),
1110 : : sizeof(*txq->pend_desc), 0,
1111 : : socket_id);
1112 [ # # ]: 0 : if (txq->pend_desc == NULL)
1113 : 0 : goto fail_pend_desc_alloc;
1114 : :
1115 : : rc = ENOMEM;
1116 : 0 : txq->sw_ring = rte_calloc_socket("sfc-efx-txq-sw_ring",
1117 : 0 : info->txq_entries,
1118 : : sizeof(*txq->sw_ring),
1119 : : RTE_CACHE_LINE_SIZE, socket_id);
1120 [ # # ]: 0 : if (txq->sw_ring == NULL)
1121 : 0 : goto fail_sw_ring_alloc;
1122 : :
1123 : 0 : ctrl_txq = sfc_txq_by_dp_txq(&txq->dp);
1124 [ # # ]: 0 : if (ctrl_txq->evq->sa->tso) {
1125 : 0 : rc = sfc_efx_tso_alloc_tsoh_objs(txq->sw_ring,
1126 : 0 : info->txq_entries, socket_id);
1127 [ # # ]: 0 : if (rc != 0)
1128 : 0 : goto fail_alloc_tsoh_objs;
1129 : : }
1130 : :
1131 : 0 : txq->evq = ctrl_txq->evq;
1132 : 0 : txq->ptr_mask = info->txq_entries - 1;
1133 : 0 : txq->max_fill_level = info->max_fill_level;
1134 : 0 : txq->free_thresh = info->free_thresh;
1135 : 0 : txq->dma_desc_size_max = info->dma_desc_size_max;
1136 : :
1137 : 0 : *dp_txqp = &txq->dp;
1138 : 0 : return 0;
1139 : :
1140 : : fail_alloc_tsoh_objs:
1141 : 0 : rte_free(txq->sw_ring);
1142 : :
1143 : 0 : fail_sw_ring_alloc:
1144 : 0 : rte_free(txq->pend_desc);
1145 : :
1146 : 0 : fail_pend_desc_alloc:
1147 : 0 : rte_free(txq);
1148 : :
1149 : : fail_txq_alloc:
1150 : : fail_nic_dma:
1151 : : return rc;
1152 : : }
1153 : :
1154 : : static sfc_dp_tx_qdestroy_t sfc_efx_tx_qdestroy;
1155 : : static void
1156 : 0 : sfc_efx_tx_qdestroy(struct sfc_dp_txq *dp_txq)
1157 : : {
1158 : : struct sfc_efx_txq *txq = sfc_efx_txq_by_dp_txq(dp_txq);
1159 : :
1160 : 0 : sfc_efx_tso_free_tsoh_objs(txq->sw_ring, txq->ptr_mask + 1);
1161 : 0 : rte_free(txq->sw_ring);
1162 : 0 : rte_free(txq->pend_desc);
1163 : 0 : rte_free(txq);
1164 : 0 : }
1165 : :
1166 : : static sfc_dp_tx_qstart_t sfc_efx_tx_qstart;
1167 : : static int
1168 : 0 : sfc_efx_tx_qstart(struct sfc_dp_txq *dp_txq,
1169 : : __rte_unused unsigned int evq_read_ptr,
1170 : : unsigned int txq_desc_index)
1171 : : {
1172 : : /* libefx-based datapath is specific to libefx-based PMD */
1173 : : struct sfc_efx_txq *txq = sfc_efx_txq_by_dp_txq(dp_txq);
1174 : 0 : struct sfc_txq *ctrl_txq = sfc_txq_by_dp_txq(dp_txq);
1175 : :
1176 : 0 : txq->common = ctrl_txq->common;
1177 : :
1178 : 0 : txq->pending = txq->completed = txq->added = txq_desc_index;
1179 : 0 : txq->hw_vlan_tci = 0;
1180 : :
1181 : 0 : txq->flags |= (SFC_EFX_TXQ_FLAG_STARTED | SFC_EFX_TXQ_FLAG_RUNNING);
1182 : :
1183 : 0 : return 0;
1184 : : }
1185 : :
1186 : : static sfc_dp_tx_qstop_t sfc_efx_tx_qstop;
1187 : : static void
1188 : 0 : sfc_efx_tx_qstop(struct sfc_dp_txq *dp_txq,
1189 : : __rte_unused unsigned int *evq_read_ptr)
1190 : : {
1191 : : struct sfc_efx_txq *txq = sfc_efx_txq_by_dp_txq(dp_txq);
1192 : :
1193 : 0 : txq->flags &= ~SFC_EFX_TXQ_FLAG_RUNNING;
1194 : 0 : }
1195 : :
1196 : : static sfc_dp_tx_qreap_t sfc_efx_tx_qreap;
1197 : : static void
1198 : 0 : sfc_efx_tx_qreap(struct sfc_dp_txq *dp_txq)
1199 : : {
1200 : : struct sfc_efx_txq *txq = sfc_efx_txq_by_dp_txq(dp_txq);
1201 : : unsigned int txds;
1202 : :
1203 : 0 : sfc_efx_tx_reap(txq);
1204 : :
1205 [ # # ]: 0 : for (txds = 0; txds <= txq->ptr_mask; txds++) {
1206 [ # # ]: 0 : if (txq->sw_ring[txds].mbuf != NULL) {
1207 : 0 : rte_pktmbuf_free(txq->sw_ring[txds].mbuf);
1208 : 0 : txq->sw_ring[txds].mbuf = NULL;
1209 : : }
1210 : : }
1211 : :
1212 : 0 : txq->flags &= ~SFC_EFX_TXQ_FLAG_STARTED;
1213 : 0 : }
1214 : :
1215 : : static sfc_dp_tx_qdesc_status_t sfc_efx_tx_qdesc_status;
1216 : : static int
1217 [ # # ]: 0 : sfc_efx_tx_qdesc_status(struct sfc_dp_txq *dp_txq, uint16_t offset)
1218 : : {
1219 : : struct sfc_efx_txq *txq = sfc_efx_txq_by_dp_txq(dp_txq);
1220 : :
1221 [ # # ]: 0 : if (unlikely(offset > txq->ptr_mask))
1222 : : return -EINVAL;
1223 : :
1224 [ # # ]: 0 : if (unlikely(offset >= txq->max_fill_level))
1225 : : return RTE_ETH_TX_DESC_UNAVAIL;
1226 : :
1227 : : /*
1228 : : * Poll EvQ to derive up-to-date 'txq->pending' figure;
1229 : : * it is required for the queue to be running, but the
1230 : : * check is omitted because API design assumes that it
1231 : : * is the duty of the caller to satisfy all conditions
1232 : : */
1233 : : SFC_ASSERT((txq->flags & SFC_EFX_TXQ_FLAG_RUNNING) ==
1234 : : SFC_EFX_TXQ_FLAG_RUNNING);
1235 : 0 : sfc_ev_qpoll(txq->evq);
1236 : :
1237 : : /*
1238 : : * Ring tail is 'txq->pending', and although descriptors
1239 : : * between 'txq->completed' and 'txq->pending' are still
1240 : : * in use by the driver, they should be reported as DONE
1241 : : */
1242 [ # # ]: 0 : if (unlikely(offset < (txq->added - txq->pending)))
1243 : 0 : return RTE_ETH_TX_DESC_FULL;
1244 : :
1245 : : /*
1246 : : * There is no separate return value for unused descriptors;
1247 : : * the latter will be reported as DONE because genuine DONE
1248 : : * descriptors will be freed anyway in SW on the next burst
1249 : : */
1250 : : return RTE_ETH_TX_DESC_DONE;
1251 : : }
1252 : :
1253 : : struct sfc_dp_tx sfc_efx_tx = {
1254 : : .dp = {
1255 : : .name = SFC_KVARG_DATAPATH_EFX,
1256 : : .type = SFC_DP_TX,
1257 : : .hw_fw_caps = SFC_DP_HW_FW_CAP_TX_EFX,
1258 : : },
1259 : : .features = 0,
1260 : : .dev_offload_capa = RTE_ETH_TX_OFFLOAD_VLAN_INSERT |
1261 : : RTE_ETH_TX_OFFLOAD_MULTI_SEGS,
1262 : : .queue_offload_capa = RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
1263 : : RTE_ETH_TX_OFFLOAD_UDP_CKSUM |
1264 : : RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
1265 : : RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM |
1266 : : RTE_ETH_TX_OFFLOAD_TCP_TSO,
1267 : : .qsize_up_rings = sfc_efx_tx_qsize_up_rings,
1268 : : .qcreate = sfc_efx_tx_qcreate,
1269 : : .qdestroy = sfc_efx_tx_qdestroy,
1270 : : .qstart = sfc_efx_tx_qstart,
1271 : : .qstop = sfc_efx_tx_qstop,
1272 : : .qreap = sfc_efx_tx_qreap,
1273 : : .qdesc_status = sfc_efx_tx_qdesc_status,
1274 : : .pkt_prepare = sfc_efx_prepare_pkts,
1275 : : .pkt_burst = sfc_efx_xmit_pkts,
1276 : : };
|