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