Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2025 Yunsilicon Technology Co., Ltd.
3 : : */
4 : :
5 : : #include <rte_io.h>
6 : :
7 : : #include "xsc_log.h"
8 : : #include "xsc_defs.h"
9 : : #include "xsc_dev.h"
10 : : #include "xsc_ethdev.h"
11 : : #include "xsc_cmd.h"
12 : : #include "xsc_tx.h"
13 : : #include "xsc_np.h"
14 : :
15 : : void
16 : 0 : xsc_txq_elts_alloc(struct xsc_txq_data *txq_data)
17 : : {
18 : 0 : const uint32_t elts_s = 1 << txq_data->elts_n;
19 : : uint32_t i;
20 : :
21 [ # # ]: 0 : for (i = 0; i < elts_s; ++i)
22 : 0 : txq_data->elts[i] = NULL;
23 : 0 : txq_data->elts_head = 0;
24 : 0 : txq_data->elts_tail = 0;
25 : 0 : txq_data->elts_comp = 0;
26 : 0 : }
27 : :
28 : : int
29 : 0 : xsc_txq_obj_new(struct xsc_dev *xdev, struct xsc_txq_data *txq_data, uint16_t idx)
30 : : {
31 : : int ret = 0;
32 : 0 : struct xsc_tx_cq_params cq_params = {0};
33 : 0 : struct xsc_tx_cq_info cq_info = {0};
34 : 0 : struct xsc_tx_qp_params qp_params = {0};
35 : 0 : struct xsc_tx_qp_info qp_info = {0};
36 : :
37 : 0 : cq_params.port_id = txq_data->port_id;
38 : 0 : cq_params.qp_id = txq_data->idx;
39 : 0 : cq_params.elts_n = txq_data->elts_n;
40 : 0 : cq_params.socket_id = txq_data->socket;
41 : 0 : ret = xsc_dev_tx_cq_create(xdev, &cq_params, &cq_info);
42 [ # # ]: 0 : if (ret) {
43 : 0 : rte_errno = errno;
44 : 0 : goto error;
45 : : }
46 : :
47 : 0 : txq_data->cq = cq_info.cq;
48 : 0 : txq_data->cqe_n = cq_info.cqe_n;
49 : 0 : txq_data->cqe_s = cq_info.cqe_s;
50 : 0 : txq_data->cq_db = cq_info.cq_db;
51 : 0 : txq_data->cqn = cq_info.cqn;
52 : 0 : txq_data->cqes = cq_info.cqes;
53 : 0 : txq_data->cqe_m = (uint16_t)(1 << cq_info.cqe_n) - 1;
54 : :
55 : 0 : PMD_DRV_LOG(INFO, "Create tx cq, cqe_s:%d, cqe_n:%d, cq_db=%p, cqn:%u",
56 : : txq_data->cqe_s, txq_data->cqe_n,
57 : : txq_data->cq_db, txq_data->cqn);
58 : :
59 : 0 : qp_params.cq = txq_data->cq;
60 : 0 : qp_params.tx_offloads = txq_data->offloads;
61 : 0 : qp_params.port_id = txq_data->port_id;
62 : 0 : qp_params.qp_id = idx;
63 : 0 : qp_params.elts_n = txq_data->elts_n;
64 : 0 : qp_params.socket_id = txq_data->socket;
65 : 0 : ret = xsc_dev_tx_qp_create(xdev, &qp_params, &qp_info);
66 : :
67 [ # # ]: 0 : if (ret != 0) {
68 : 0 : rte_errno = errno;
69 : 0 : goto error;
70 : : }
71 : :
72 : 0 : txq_data->qp = qp_info.qp;
73 : 0 : txq_data->qpn = qp_info.qpn;
74 : 0 : txq_data->wqes = qp_info.wqes;
75 : 0 : txq_data->wqe_n = qp_info.wqe_n;
76 : 0 : txq_data->wqe_s = 1 << txq_data->wqe_n;
77 : 0 : txq_data->wqe_m = txq_data->wqe_s - 1;
78 [ # # ]: 0 : txq_data->wqe_ds_n = rte_log2_u32(xdev->hwinfo.send_seg_num);
79 : 0 : txq_data->qp_db = qp_info.qp_db;
80 : 0 : txq_data->tso_en = qp_info.tso_en ? 1 : 0;
81 : :
82 : 0 : txq_data->cq_ci = 0;
83 : 0 : txq_data->cq_pi = 0;
84 : 0 : txq_data->wqe_ci = 0;
85 : 0 : txq_data->wqe_pi = 0;
86 : 0 : txq_data->wqe_comp = 0;
87 : :
88 [ # # ]: 0 : PMD_DRV_LOG(INFO, "Create tx qp, wqe_s:%d, wqe_n:%d, qp_db=%p, qpn:%u, %s",
89 : : txq_data->wqe_s, txq_data->wqe_n,
90 : : txq_data->qp_db, txq_data->qpn,
91 : : txq_data->tso_en ? "tso" : "non-tso");
92 : :
93 : 0 : return 0;
94 : :
95 : 0 : error:
96 : 0 : return -rte_errno;
97 : : }
98 : :
99 : : void
100 : 0 : xsc_txq_obj_release(struct xsc_dev *xdev, struct xsc_txq_data *txq_data)
101 : : {
102 : 0 : PMD_DRV_LOG(DEBUG, "Destroy tx queue %u, portid %u",
103 : : txq_data->idx, txq_data->port_id);
104 [ # # ]: 0 : if (txq_data->qp != NULL)
105 : 0 : xsc_dev_destroy_qp(xdev, txq_data->qp);
106 [ # # ]: 0 : if (txq_data->cq != NULL)
107 : 0 : xsc_dev_destroy_cq(xdev, txq_data->cq);
108 : 0 : }
109 : :
110 : : void
111 : 0 : xsc_txq_elts_free(struct xsc_txq_data *txq_data)
112 : : {
113 : 0 : const uint16_t elts_n = 1 << txq_data->elts_n;
114 : 0 : const uint16_t elts_m = elts_n - 1;
115 : 0 : uint16_t elts_head = txq_data->elts_head;
116 : 0 : uint16_t elts_tail = txq_data->elts_tail;
117 : : struct rte_mbuf *(*elts)[elts_n] = &txq_data->elts;
118 : :
119 : 0 : txq_data->elts_head = 0;
120 : 0 : txq_data->elts_tail = 0;
121 : 0 : txq_data->elts_comp = 0;
122 : :
123 [ # # ]: 0 : while (elts_tail != elts_head) {
124 [ # # ]: 0 : struct rte_mbuf *elt = (*elts)[elts_tail & elts_m];
125 : :
126 : : rte_pktmbuf_free_seg(elt);
127 : 0 : ++elts_tail;
128 : : }
129 : 0 : PMD_DRV_LOG(DEBUG, "Port %u txq %u free elts", txq_data->port_id, txq_data->idx);
130 : 0 : }
131 : :
132 : : static __rte_always_inline void
133 : : xsc_tx_elts_flush(struct xsc_txq_data *__rte_restrict txq, uint16_t tail)
134 : : {
135 : 0 : uint16_t elts_n = tail - txq->elts_tail;
136 : : uint32_t free_n;
137 : :
138 : : do {
139 : 0 : free_n = txq->elts_s - (txq->elts_tail & txq->elts_m);
140 : 0 : free_n = RTE_MIN(free_n, elts_n);
141 : 0 : rte_pktmbuf_free_bulk(&txq->elts[txq->elts_tail & txq->elts_m], free_n);
142 : 0 : txq->elts_tail += free_n;
143 : 0 : elts_n -= free_n;
144 [ # # ]: 0 : } while (elts_n > 0);
145 : : }
146 : :
147 : : static void
148 : 0 : xsc_tx_cqes_handle(struct xsc_txq_data *__rte_restrict txq)
149 : : {
150 : : uint32_t count = XSC_TX_COMP_CQE_HANDLE_MAX;
151 : : volatile struct xsc_cqe *last_cqe = NULL;
152 : : volatile struct xsc_cqe *cqe;
153 : : bool doorbell = false;
154 : : int ret;
155 : : uint16_t tail;
156 : :
157 : : do {
158 : 0 : cqe = &txq->cqes[txq->cq_ci & txq->cqe_m];
159 [ # # ]: 0 : ret = xsc_check_cqe_own(cqe, txq->cqe_n, txq->cq_ci);
160 [ # # ]: 0 : if (unlikely(ret != XSC_CQE_OWNER_SW)) {
161 [ # # ]: 0 : if (likely(ret != XSC_CQE_OWNER_ERR))
162 : : /* No new CQEs in completion queue. */
163 : : break;
164 : : doorbell = true;
165 : 0 : ++txq->cq_ci;
166 : 0 : txq->cq_pi = txq->cq_ci;
167 : : last_cqe = NULL;
168 : 0 : ++txq->stats.tx_errors;
169 : 0 : continue;
170 : : }
171 : :
172 : : doorbell = true;
173 : 0 : ++txq->cq_ci;
174 : : last_cqe = cqe;
175 [ # # ]: 0 : } while (--count > 0);
176 : :
177 [ # # ]: 0 : if (likely(doorbell)) {
178 : 0 : union xsc_cq_doorbell cq_db = {
179 : : .cq_data = 0
180 : : };
181 : 0 : cq_db.next_cid = txq->cq_ci;
182 : 0 : cq_db.cq_num = txq->cqn;
183 : :
184 : : /* Ring doorbell */
185 : 0 : rte_write32(rte_cpu_to_le_32(cq_db.cq_data), txq->cq_db);
186 : :
187 : : /* Release completed elts */
188 [ # # ]: 0 : if (likely(last_cqe != NULL)) {
189 : 0 : txq->wqe_pi = rte_le_to_cpu_16(last_cqe->wqe_id) >> txq->wqe_ds_n;
190 : 0 : tail = txq->fcqs[(txq->cq_ci - 1) & txq->cqe_m];
191 [ # # ]: 0 : if (likely(tail != txq->elts_tail))
192 : : xsc_tx_elts_flush(txq, tail);
193 : : }
194 : : }
195 : 0 : }
196 : :
197 : : static __rte_always_inline void
198 : : xsc_tx_wqe_ctrl_seg_init(struct xsc_txq_data *__rte_restrict txq,
199 : : struct rte_mbuf *__rte_restrict mbuf,
200 : : struct xsc_wqe *__rte_restrict wqe)
201 : : {
202 : : struct xsc_send_wqe_ctrl_seg *cs = &wqe->cseg;
203 : : int i = 0;
204 : 0 : int ds_max = (1 << txq->wqe_ds_n) - 1;
205 : :
206 : 0 : cs->msg_opcode = XSC_OPCODE_RAW;
207 : 0 : cs->wqe_id = rte_cpu_to_le_16(txq->wqe_ci << txq->wqe_ds_n);
208 : 0 : cs->has_pph = 0;
209 : : /* Clear dseg's seg len */
210 [ # # ]: 0 : if (cs->ds_data_num > 1 && cs->ds_data_num <= ds_max) {
211 [ # # ]: 0 : for (i = 1; i < cs->ds_data_num; i++)
212 : 0 : wqe->dseg[i].seg_len = 0;
213 : : }
214 : :
215 : 0 : cs->ds_data_num = mbuf->nb_segs;
216 [ # # ]: 0 : if (mbuf->ol_flags & RTE_MBUF_F_TX_IP_CKSUM)
217 : 0 : cs->csum_en = 0x2;
218 : : else
219 : 0 : cs->csum_en = 0;
220 : :
221 [ # # # # ]: 0 : if (txq->tso_en == 1 && (mbuf->ol_flags & RTE_MBUF_F_TX_TCP_SEG)) {
222 : 0 : cs->so_type = 1;
223 : 0 : cs->so_hdr_len = mbuf->l2_len + mbuf->l3_len + mbuf->l4_len;
224 : 0 : cs->so_data_size = rte_cpu_to_le_16(mbuf->tso_segsz);
225 : : }
226 : :
227 : 0 : cs->msg_len = rte_cpu_to_le_32(rte_pktmbuf_pkt_len(mbuf));
228 [ # # ]: 0 : if (unlikely(cs->msg_len == 0))
229 : 0 : cs->msg_len = rte_cpu_to_le_32(rte_pktmbuf_data_len(mbuf));
230 : :
231 : : /* Do not generate cqe for every pkts */
232 : 0 : cs->ce = 0;
233 : : }
234 : :
235 : : static __rte_always_inline void
236 : : xsc_tx_wqe_data_seg_init(struct rte_mbuf *mbuf, struct xsc_wqe *wqe)
237 : : {
238 : : uint16_t i, nb_segs = mbuf->nb_segs;
239 : : uint32_t data_len;
240 : : rte_iova_t iova;
241 : : struct xsc_wqe_data_seg *dseg;
242 : :
243 [ # # ]: 0 : for (i = 0; i < nb_segs; ++i) {
244 : 0 : dseg = &wqe->dseg[i];
245 : 0 : iova = rte_pktmbuf_iova(mbuf);
246 : 0 : data_len = rte_pktmbuf_data_len(mbuf);
247 : :
248 : 0 : dseg->in_line = 0;
249 : 0 : dseg->seg_len = rte_cpu_to_le_32(data_len);
250 : 0 : dseg->lkey = 0;
251 : 0 : dseg->va = rte_cpu_to_le_64(iova);
252 : 0 : mbuf = mbuf->next;
253 : : }
254 : : }
255 : :
256 : : static __rte_always_inline struct xsc_wqe *
257 : : xsc_tx_wqes_fill(struct xsc_txq_data *__rte_restrict txq,
258 : : struct rte_mbuf **__rte_restrict pkts,
259 : : uint32_t pkts_n)
260 : : {
261 : : uint32_t i;
262 : : struct xsc_wqe *wqe = NULL;
263 : : struct rte_mbuf *mbuf;
264 : :
265 [ # # ]: 0 : for (i = 0; i < pkts_n; i++) {
266 : 0 : rte_prefetch0(pkts[i]);
267 : : mbuf = pkts[i];
268 : 0 : wqe = (struct xsc_wqe *)((struct xsc_send_wqe_ctrl_seg *)txq->wqes +
269 [ # # ]: 0 : (txq->wqe_ci & txq->wqe_m) * (1 << txq->wqe_ds_n));
270 : :
271 : : /* Init wqe ctrl seg */
272 : : xsc_tx_wqe_ctrl_seg_init(txq, mbuf, wqe);
273 : : /* Init wqe data segs */
274 : : xsc_tx_wqe_data_seg_init(mbuf, wqe);
275 : 0 : ++txq->wqe_ci;
276 : 0 : txq->stats.tx_bytes += rte_pktmbuf_pkt_len(mbuf);
277 : : }
278 : :
279 : : return wqe;
280 : : }
281 : :
282 : : static __rte_always_inline void
283 : : xsc_tx_doorbell_ring(volatile uint32_t *db, uint32_t index,
284 : : uint32_t qpn, uint16_t ds_n)
285 : : {
286 : : union xsc_send_doorbell tx_db;
287 : :
288 : 0 : tx_db.next_pid = index << ds_n;
289 : 0 : tx_db.qp_num = qpn;
290 : :
291 : 0 : rte_write32(rte_cpu_to_le_32(tx_db.send_data), db);
292 : : }
293 : :
294 : : static __rte_always_inline void
295 : : xsc_tx_elts_store(struct xsc_txq_data *__rte_restrict txq,
296 : : struct rte_mbuf **__rte_restrict pkts,
297 : : uint32_t pkts_n)
298 : : {
299 : : uint32_t part;
300 : 0 : struct rte_mbuf **elts = (struct rte_mbuf **)txq->elts;
301 : :
302 : 0 : part = txq->elts_s - (txq->elts_head & txq->elts_m);
303 : 0 : rte_memcpy((void *)(elts + (txq->elts_head & txq->elts_m)),
304 : : (void *)pkts,
305 [ # # ]: 0 : RTE_MIN(part, pkts_n) * sizeof(struct rte_mbuf *));
306 : :
307 [ # # ]: 0 : if (unlikely(part < pkts_n))
308 : 0 : rte_memcpy((void *)elts, (void *)(pkts + part),
309 [ # # ]: 0 : (pkts_n - part) * sizeof(struct rte_mbuf *));
310 : : }
311 : :
312 : : uint16_t
313 : 0 : xsc_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
314 : : {
315 : : struct xsc_txq_data *txq = dpdk_txq;
316 : 0 : uint32_t tx_n, remain_n = pkts_n;
317 : : uint16_t idx, elts_free, wqe_free;
318 : : uint16_t elts_head;
319 : : struct xsc_wqe *last_wqe;
320 : :
321 [ # # ]: 0 : if (unlikely(!pkts_n))
322 : : return 0;
323 : :
324 : : do {
325 : 0 : xsc_tx_cqes_handle(txq);
326 : :
327 : 0 : elts_free = txq->elts_s - (uint16_t)(txq->elts_head - txq->elts_tail);
328 : 0 : wqe_free = txq->wqe_s - ((uint16_t)((txq->wqe_ci << txq->wqe_ds_n) -
329 : 0 : (txq->wqe_pi << txq->wqe_ds_n)) >> txq->wqe_ds_n);
330 [ # # ]: 0 : if (unlikely(elts_free == 0 || wqe_free == 0))
331 : : break;
332 : :
333 : : /* Fill in WQEs */
334 : 0 : tx_n = RTE_MIN(remain_n, wqe_free);
335 : 0 : idx = pkts_n - remain_n;
336 : 0 : last_wqe = xsc_tx_wqes_fill(txq, &pkts[idx], tx_n);
337 : 0 : remain_n -= tx_n;
338 : 0 : last_wqe->cseg.ce = 1;
339 : :
340 : : /* Update free-cqs, elts_comp */
341 : : elts_head = txq->elts_head;
342 : 0 : elts_head += tx_n;
343 [ # # ]: 0 : if ((uint16_t)(elts_head - txq->elts_comp) > 0) {
344 : 0 : txq->elts_comp = elts_head;
345 : 0 : txq->fcqs[txq->cq_pi++ & txq->cqe_m] = elts_head;
346 : : }
347 : :
348 : : /* Ring tx doorbell */
349 : 0 : xsc_tx_doorbell_ring(txq->qp_db, txq->wqe_ci, txq->qpn, txq->wqe_ds_n);
350 : :
351 : : xsc_tx_elts_store(txq, &pkts[idx], tx_n);
352 : 0 : txq->elts_head += tx_n;
353 [ # # ]: 0 : } while (remain_n > 0);
354 : :
355 : 0 : txq->stats.tx_pkts += (pkts_n - remain_n);
356 : 0 : return pkts_n - remain_n;
357 : : }
|