Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
3 : : */
4 : :
5 : : #include <rte_common.h>
6 : : #include <rte_net.h>
7 : : #include <rte_vect.h>
8 : : #include <rte_malloc.h>
9 : : #include <rte_memzone.h>
10 : : #include <ethdev_driver.h>
11 : : #include "sxe2_tx.h"
12 : : #include "sxe2_ethdev.h"
13 : : #include "sxe2_common_log.h"
14 : : #include "sxe2_cmd_chnl.h"
15 : :
16 : 0 : static void *sxe2_tx_doorbell_addr_get(struct sxe2_adapter *adapter, uint16_t queue_id)
17 : : {
18 : 0 : return sxe2_pci_map_addr_get(adapter, SXE2_PCI_MAP_RES_DOORBELL_TX,
19 : : queue_id);
20 : : }
21 : :
22 : 0 : static void sxe2_tx_queue_desc_ring_reset(struct sxe2_tx_queue *txq)
23 : : {
24 : 0 : uint16_t i;
25 : 0 : static const union sxe2_tx_data_desc zeroed_desc = {{0}};
26 : :
27 [ # # # # ]: 0 : for (i = 0; i < txq->ring_depth; i++) {
28 : 0 : txq->desc_ring[i] = zeroed_desc;
29 : 0 : txq->desc_ring[i].wb.dd = rte_cpu_to_le_64(SXE2_TX_DESC_DTYPE_DESC_DONE);
30 : : }
31 : : }
32 : :
33 : 0 : static void sxe2_tx_tail_init(struct sxe2_adapter *adapter, struct sxe2_tx_queue *txq)
34 : : {
35 : 0 : txq->tdt_reg_addr = sxe2_tx_doorbell_addr_get(adapter, txq->queue_id);
36 : 0 : SXE2_PCI_REG_WRITE_WC(txq->tdt_reg_addr, 0);
37 : 0 : }
38 : :
39 : 0 : void __rte_cold sxe2_tx_queue_reset(struct sxe2_tx_queue *txq)
40 : : {
41 : 0 : uint16_t prev, i;
42 : 0 : struct sxe2_tx_buffer *tx_buffer = txq->buffer_ring;
43 : :
44 : 0 : sxe2_tx_queue_desc_ring_reset(txq);
45 : :
46 : 0 : prev = txq->ring_depth - 1;
47 [ # # ]: 0 : for (i = 0; i < txq->ring_depth; i++) {
48 : 0 : tx_buffer[i].mbuf = NULL;
49 : 0 : tx_buffer[i].last_id = i;
50 : 0 : tx_buffer[prev].next_id = i;
51 : 0 : prev = i;
52 : : }
53 : :
54 : 0 : txq->desc_used_num = 0;
55 : 0 : txq->desc_free_num = txq->ring_depth - 1;
56 : 0 : txq->next_use = 0;
57 : 0 : txq->next_clean = txq->ring_depth - 1;
58 : 0 : txq->next_dd = txq->rs_thresh - 1;
59 : 0 : txq->next_rs = txq->rs_thresh - 1;
60 : 0 : }
61 : :
62 : 0 : void __rte_cold sxe2_tx_queue_reset_vec(struct sxe2_tx_queue *txq)
63 : : {
64 : 0 : sxe2_tx_queue_desc_ring_reset(txq);
65 : :
66 : 0 : memset(txq->buffer_ring, 0,
67 : 0 : sizeof(struct sxe2_tx_buffer) * txq->ring_depth);
68 : :
69 : 0 : txq->desc_used_num = 0;
70 : 0 : txq->desc_free_num = txq->ring_depth - 1;
71 : 0 : txq->next_use = 0;
72 : 0 : txq->next_clean = txq->ring_depth - 1;
73 : 0 : txq->next_dd = txq->rs_thresh - 1;
74 : 0 : txq->next_rs = txq->rs_thresh - 1;
75 : 0 : }
76 : :
77 : 0 : void __rte_cold sxe2_tx_queue_mbufs_release(struct sxe2_tx_queue *txq)
78 : : {
79 : 0 : uint32_t i;
80 : :
81 [ # # # # ]: 0 : if (txq != NULL && txq->buffer_ring != NULL) {
82 [ # # ]: 0 : for (i = 0; i < txq->ring_depth; i++) {
83 [ # # ]: 0 : if (txq->buffer_ring[i].mbuf != NULL) {
84 : 0 : rte_pktmbuf_free_seg(txq->buffer_ring[i].mbuf);
85 : 0 : txq->buffer_ring[i].mbuf = NULL;
86 : : }
87 : : }
88 : : }
89 : 0 : }
90 : :
91 : 0 : void __rte_cold sxe2_tx_buffer_ring_free(struct sxe2_tx_queue *txq)
92 : : {
93 [ # # # # ]: 0 : if (txq != NULL && txq->buffer_ring != NULL) {
94 : 0 : rte_free(txq->buffer_ring);
95 : 0 : txq->buffer_ring = NULL;
96 : : }
97 : 0 : }
98 : :
99 : : const struct sxe2_txq_ops sxe2_default_txq_ops = {
100 : : .queue_reset = sxe2_tx_queue_reset,
101 : : .mbufs_release = sxe2_tx_queue_mbufs_release,
102 : : .buffer_ring_free = sxe2_tx_buffer_ring_free,
103 : : };
104 : :
105 : 0 : static struct sxe2_txq_ops sxe2_tx_default_ops_get(void)
106 : : {
107 : 0 : return sxe2_default_txq_ops;
108 : : }
109 : :
110 : 0 : static int32_t sxe2_txq_arg_validate(struct rte_eth_dev *dev, uint16_t ring_depth,
111 : : uint16_t *rs_thresh, uint16_t *free_thresh, const struct rte_eth_txconf *tx_conf)
112 : : {
113 : 0 : int32_t ret = 0;
114 : :
115 [ # # ]: 0 : if ((ring_depth % SXE2_TX_DESC_RING_ALIGN) != 0 ||
116 [ # # ]: 0 : ring_depth > SXE2_MAX_RING_DESC ||
117 : : ring_depth < SXE2_MIN_RING_DESC) {
118 : 0 : PMD_LOG_ERR(TX, "number:%u of receive descriptors is invalid", ring_depth);
119 : 0 : ret = -EINVAL;
120 : 0 : goto l_end;
121 : : }
122 : :
123 [ # # ]: 0 : *free_thresh = (uint16_t)((tx_conf->tx_free_thresh) ?
124 : : tx_conf->tx_free_thresh : DEFAULT_TX_FREE_THRESH);
125 [ # # ]: 0 : *rs_thresh = (uint16_t)((tx_conf->tx_rs_thresh) ?
126 : : tx_conf->tx_rs_thresh : DEFAULT_TX_RS_THRESH);
127 : :
128 [ # # ]: 0 : if (*rs_thresh >= (ring_depth - 2)) {
129 : 0 : PMD_LOG_ERR(TX, "tx_rs_thresh must be less than the number "
130 : : "of tx descriptors minus 2. (tx_rs_thresh:%u port:%u)",
131 : : *rs_thresh, dev->data->port_id);
132 : 0 : ret = -EINVAL;
133 : 0 : goto l_end;
134 : : }
135 : :
136 [ # # ]: 0 : if (*free_thresh >= (ring_depth - 3)) {
137 : 0 : PMD_LOG_ERR(TX, "tx_free_thresh must be less than the number "
138 : : "of tx descriptors minus 3. (tx_free_thresh:%u port:%u)",
139 : : *free_thresh, dev->data->port_id);
140 : 0 : ret = -EINVAL;
141 : 0 : goto l_end;
142 : : }
143 : :
144 [ # # ]: 0 : if (*rs_thresh > *free_thresh) {
145 : 0 : PMD_LOG_ERR(TX, "tx_rs_thresh must be less than or equal to "
146 : : "tx_free_thresh. (tx_free_thresh:%u tx_rs_thresh:%u port:%u)",
147 : : *free_thresh, *rs_thresh, dev->data->port_id);
148 : 0 : ret = -EINVAL;
149 : 0 : goto l_end;
150 : : }
151 : :
152 [ # # ]: 0 : if ((ring_depth % *rs_thresh) != 0) {
153 : 0 : PMD_LOG_ERR(TX, "tx_rs_thresh must be a divisor of the "
154 : : "number of tx descriptors. (tx_rs_thresh:%u port:%d ring_depth:%u)",
155 : : *rs_thresh, dev->data->port_id, ring_depth);
156 : 0 : ret = -EINVAL;
157 : 0 : goto l_end;
158 : : }
159 : :
160 : : ret = 0;
161 : :
162 : 0 : l_end:
163 : 0 : return ret;
164 : : }
165 : :
166 : 0 : void __rte_cold sxe2_tx_queue_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
167 : : struct rte_eth_txq_info *qinfo)
168 : : {
169 : 0 : struct sxe2_tx_queue *txq = NULL;
170 : :
171 : 0 : txq = dev->data->tx_queues[queue_id];
172 [ # # ]: 0 : if (txq == NULL) {
173 : 0 : PMD_LOG_WARN(TX, "tx queue:%u is NULL", queue_id);
174 : 0 : goto end;
175 : : }
176 : :
177 : 0 : qinfo->nb_desc = txq->ring_depth;
178 : :
179 : 0 : qinfo->conf.tx_thresh.pthresh = txq->pthresh;
180 : 0 : qinfo->conf.tx_thresh.hthresh = txq->hthresh;
181 : 0 : qinfo->conf.tx_thresh.wthresh = txq->wthresh;
182 : 0 : qinfo->conf.tx_free_thresh = txq->free_thresh;
183 : 0 : qinfo->conf.tx_rs_thresh = txq->rs_thresh;
184 : 0 : qinfo->conf.offloads = txq->offloads;
185 : 0 : qinfo->conf.tx_deferred_start = txq->tx_deferred_start;
186 : :
187 : 0 : end:
188 : 0 : return;
189 : : }
190 : :
191 : 0 : int32_t __rte_cold sxe2_tx_queue_stop(struct rte_eth_dev *dev, uint16_t queue_id)
192 : : {
193 : 0 : struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
194 : 0 : struct sxe2_tx_queue *txq;
195 : 0 : int32_t ret;
196 : 0 : PMD_INIT_FUNC_TRACE();
197 : :
198 [ # # ]: 0 : if (dev->data->tx_queue_state[queue_id] ==
199 : : RTE_ETH_QUEUE_STATE_STOPPED) {
200 : 0 : ret = 0;
201 : 0 : goto l_end;
202 : : }
203 : :
204 : 0 : txq = dev->data->tx_queues[queue_id];
205 [ # # ]: 0 : if (txq == NULL) {
206 : 0 : ret = 0;
207 : 0 : goto l_end;
208 : : }
209 : :
210 : 0 : ret = sxe2_drv_txq_switch(adapter, txq, false);
211 [ # # ]: 0 : if (ret) {
212 : 0 : PMD_LOG_ERR(TX, "Failed to switch tx queue %u off",
213 : : queue_id);
214 : 0 : goto l_end;
215 : : }
216 : :
217 : 0 : txq->ops.mbufs_release(txq);
218 : 0 : txq->ops.queue_reset(txq);
219 : 0 : dev->data->tx_queue_state[queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
220 : 0 : ret = 0;
221 : :
222 : 0 : l_end:
223 : 0 : return ret;
224 : : }
225 : :
226 : 0 : static void __rte_cold sxe2_tx_queue_free(struct sxe2_tx_queue *txq)
227 : : {
228 [ # # ]: 0 : if (txq != NULL) {
229 : 0 : txq->ops.mbufs_release(txq);
230 : 0 : txq->ops.buffer_ring_free(txq);
231 : :
232 : 0 : rte_memzone_free(txq->mz);
233 : 0 : rte_free(txq);
234 : : }
235 : 0 : }
236 : :
237 : 0 : void __rte_cold sxe2_tx_queue_release(struct rte_eth_dev *dev, uint16_t queue_idx)
238 : : {
239 : 0 : (void)sxe2_tx_queue_stop(dev, queue_idx);
240 : 0 : sxe2_tx_queue_free(dev->data->tx_queues[queue_idx]);
241 : 0 : dev->data->tx_queues[queue_idx] = NULL;
242 : 0 : }
243 : :
244 : 0 : void __rte_cold sxe2_all_txqs_release(struct rte_eth_dev *dev)
245 : : {
246 : 0 : struct rte_eth_dev_data *data = dev->data;
247 : 0 : uint16_t nb_txq;
248 : :
249 [ # # ]: 0 : for (nb_txq = 0; nb_txq < data->nb_tx_queues; nb_txq++) {
250 [ # # ]: 0 : if (data->tx_queues[nb_txq] == NULL)
251 : 0 : continue;
252 : :
253 : 0 : sxe2_tx_queue_release(dev, nb_txq);
254 : 0 : data->tx_queues[nb_txq] = NULL;
255 : : }
256 : 0 : data->nb_tx_queues = 0;
257 : 0 : }
258 : :
259 : : static struct sxe2_tx_queue
260 : 0 : *sxe2_tx_queue_alloc(struct rte_eth_dev *dev, uint16_t queue_idx,
261 : : uint16_t ring_depth, uint32_t socket_id)
262 : : {
263 : 0 : struct sxe2_tx_queue *txq;
264 : 0 : const struct rte_memzone *tz;
265 : :
266 [ # # ]: 0 : if (dev->data->tx_queues[queue_idx]) {
267 : 0 : sxe2_tx_queue_release(dev, queue_idx);
268 : 0 : dev->data->tx_queues[queue_idx] = NULL;
269 : : }
270 : :
271 : 0 : txq = rte_zmalloc_socket("tx_queue", sizeof(struct sxe2_tx_queue),
272 : : RTE_CACHE_LINE_SIZE, socket_id);
273 [ # # ]: 0 : if (txq == NULL) {
274 : 0 : PMD_LOG_ERR(TX, "tx queue:%d alloc failed", queue_idx);
275 : 0 : goto l_end;
276 : : }
277 : :
278 : 0 : tz = rte_eth_dma_zone_reserve(dev, "tx_dma", queue_idx,
279 : : sizeof(union sxe2_tx_data_desc) * SXE2_MAX_RING_DESC,
280 : : SXE2_DESC_ADDR_ALIGN, socket_id);
281 [ # # ]: 0 : if (tz == NULL) {
282 : 0 : PMD_LOG_ERR(TX, "tx desc ring alloc failed, queue_id:%d", queue_idx);
283 : 0 : rte_free(txq);
284 : 0 : txq = NULL;
285 : 0 : goto l_end;
286 : : }
287 : :
288 : 0 : txq->buffer_ring = rte_zmalloc_socket("tx_buffer_ring",
289 : : sizeof(struct sxe2_tx_buffer) * ring_depth,
290 : : RTE_CACHE_LINE_SIZE, socket_id);
291 [ # # ]: 0 : if (txq->buffer_ring == NULL) {
292 : 0 : PMD_LOG_ERR(TX, "tx buffer alloc failed, queue_id:%d", queue_idx);
293 : 0 : rte_memzone_free(tz);
294 : 0 : rte_free(txq);
295 : 0 : txq = NULL;
296 : 0 : goto l_end;
297 : : }
298 : :
299 : 0 : txq->mz = tz;
300 : 0 : txq->base_addr = tz->iova;
301 : 0 : txq->desc_ring = (volatile union sxe2_tx_data_desc *)tz->addr;
302 : :
303 : 0 : l_end:
304 : 0 : return txq;
305 : : }
306 : :
307 : 0 : int32_t __rte_cold sxe2_tx_queue_setup(struct rte_eth_dev *dev,
308 : : uint16_t queue_idx, uint16_t nb_desc, uint32_t socket_id,
309 : : const struct rte_eth_txconf *tx_conf)
310 : : {
311 : 0 : int32_t ret = 0;
312 : 0 : uint16_t tx_rs_thresh;
313 : 0 : uint16_t tx_free_thresh;
314 : 0 : struct sxe2_tx_queue *txq;
315 : 0 : struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
316 : 0 : struct sxe2_vsi *vsi = adapter->vsi_ctxt.main_vsi;
317 : 0 : uint64_t offloads;
318 : 0 : PMD_INIT_FUNC_TRACE();
319 : :
320 : 0 : ret = sxe2_txq_arg_validate(dev, nb_desc, &tx_rs_thresh, &tx_free_thresh, tx_conf);
321 [ # # ]: 0 : if (ret) {
322 : 0 : PMD_LOG_ERR(TX, "tx queue:%u arg validate failed", queue_idx);
323 : 0 : goto end;
324 : : }
325 : :
326 : 0 : offloads = tx_conf->offloads | dev->data->dev_conf.txmode.offloads;
327 [ # # ]: 0 : if (!sxe2_ipsec_valid_tx_offloads(offloads)) {
328 : 0 : ret = -EINVAL;
329 : 0 : goto end;
330 : : }
331 : :
332 : 0 : txq = sxe2_tx_queue_alloc(dev, queue_idx, nb_desc, socket_id);
333 [ # # ]: 0 : if (txq == NULL) {
334 : 0 : PMD_LOG_ERR(TX, "failed to alloc sxe2vf tx queue:%u resource", queue_idx);
335 : 0 : ret = -ENOMEM;
336 : 0 : goto end;
337 : : }
338 : :
339 : 0 : txq->vlan_flag = SXE2_TX_FLAGS_VLAN_TAG_LOC_L2TAG1;
340 : 0 : txq->ring_depth = nb_desc;
341 : 0 : txq->rs_thresh = tx_rs_thresh;
342 : 0 : txq->free_thresh = tx_free_thresh;
343 : 0 : txq->pthresh = tx_conf->tx_thresh.pthresh;
344 : 0 : txq->hthresh = tx_conf->tx_thresh.hthresh;
345 : 0 : txq->wthresh = tx_conf->tx_thresh.wthresh;
346 : 0 : txq->queue_id = queue_idx;
347 : 0 : txq->idx_in_func = vsi->txqs.base_idx_in_func + queue_idx;
348 : 0 : txq->port_id = dev->data->port_id;
349 : 0 : txq->offloads = offloads;
350 : 0 : txq->tx_deferred_start = tx_conf->tx_deferred_start;
351 : 0 : txq->vsi = vsi;
352 : 0 : txq->ops = sxe2_tx_default_ops_get();
353 : 0 : txq->ops.queue_reset(txq);
354 : :
355 [ # # # # ]: 0 : if (sxe2_ipsec_supported(adapter) && txq->offloads & RTE_ETH_TX_OFFLOAD_SECURITY)
356 : 0 : txq->ipsec_pkt_md_offset = sxe2_ipsec_pkt_md_offset_get(adapter);
357 : :
358 : 0 : dev->data->tx_queues[queue_idx] = txq;
359 : 0 : ret = 0;
360 : :
361 : 0 : end:
362 : 0 : return ret;
363 : : }
364 : :
365 : 0 : int32_t __rte_cold sxe2_tx_queue_start(struct rte_eth_dev *dev, uint16_t queue_id)
366 : : {
367 : 0 : int32_t ret = 0;
368 : 0 : struct sxe2_tx_queue *txq;
369 : 0 : struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
370 : 0 : PMD_INIT_FUNC_TRACE();
371 : :
372 [ # # ]: 0 : if (dev->data->tx_queue_state[queue_id] == RTE_ETH_QUEUE_STATE_STARTED) {
373 : 0 : ret = 0;
374 : 0 : goto l_end;
375 : : }
376 : :
377 : 0 : txq = dev->data->tx_queues[queue_id];
378 [ # # ]: 0 : if (txq == NULL) {
379 : 0 : PMD_LOG_ERR(TX, "tx queue:%u is not available or setup", queue_id);
380 : 0 : ret = -EINVAL;
381 : 0 : goto l_end;
382 : : }
383 : :
384 : 0 : ret = sxe2_drv_txq_ctxt_cfg(adapter, txq, 1);
385 [ # # ]: 0 : if (ret) {
386 : 0 : PMD_LOG_ERR(TX, "tx queue:%u config ctxt fail", queue_id);
387 : :
388 : 0 : (void)sxe2_drv_txq_switch(adapter, txq, false);
389 : 0 : txq->ops.mbufs_release(txq);
390 : 0 : txq->ops.queue_reset(txq);
391 : 0 : goto l_end;
392 : : }
393 : :
394 : 0 : sxe2_tx_tail_init(adapter, txq);
395 : :
396 : 0 : dev->data->tx_queue_state[queue_id] = RTE_ETH_QUEUE_STATE_STARTED;
397 : 0 : ret = 0;
398 : :
399 : 0 : l_end:
400 : 0 : return ret;
401 : : }
402 : :
403 : 0 : int32_t __rte_cold sxe2_txqs_all_start(struct rte_eth_dev *dev)
404 : : {
405 : 0 : struct rte_eth_dev_data *data = dev->data;
406 : 0 : struct sxe2_tx_queue *txq;
407 : 0 : uint16_t nb_txq;
408 : 0 : uint16_t nb_started_txq;
409 : 0 : int32_t ret;
410 : 0 : PMD_INIT_FUNC_TRACE();
411 : :
412 [ # # ]: 0 : for (nb_txq = 0; nb_txq < data->nb_tx_queues; nb_txq++) {
413 : 0 : txq = dev->data->tx_queues[nb_txq];
414 [ # # # # ]: 0 : if (!txq || txq->tx_deferred_start)
415 : 0 : continue;
416 : :
417 : 0 : ret = sxe2_tx_queue_start(dev, nb_txq);
418 [ # # ]: 0 : if (ret) {
419 : 0 : PMD_LOG_ERR(TX, "Fail to start tx queue %u", nb_txq);
420 : 0 : goto l_free_started_queue;
421 : : }
422 : : }
423 : 0 : ret = 0;
424 : 0 : goto l_end;
425 : :
426 : 0 : l_free_started_queue:
427 [ # # ]: 0 : for (nb_started_txq = 0; nb_started_txq <= nb_txq; nb_started_txq++)
428 : 0 : (void)sxe2_tx_queue_stop(dev, nb_started_txq);
429 : :
430 : 0 : l_end:
431 : 0 : return ret;
432 : : }
433 : :
434 : 0 : void __rte_cold sxe2_txqs_all_stop(struct rte_eth_dev *dev)
435 : : {
436 : 0 : struct rte_eth_dev_data *data = dev->data;
437 : 0 : uint16_t nb_txq;
438 : 0 : int32_t ret;
439 : :
440 [ # # ]: 0 : for (nb_txq = 0; nb_txq < data->nb_tx_queues; nb_txq++) {
441 : 0 : ret = sxe2_tx_queue_stop(dev, nb_txq);
442 [ # # ]: 0 : if (ret) {
443 : 0 : PMD_LOG_WARN(TX, "Fail to stop tx queue %u", nb_txq);
444 : 0 : continue;
445 : : }
446 : : }
447 : 0 : }
|