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