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