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