Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(C) 2022 Intel Corporation
3 : : */
4 : :
5 : : #include "gve_ethdev.h"
6 : : #include "base/gve_adminq.h"
7 : :
8 : : static inline void
9 : 0 : gve_free_bulk_mbuf(struct rte_mbuf **txep, int num)
10 : : {
11 : : struct rte_mbuf *m, *free[GVE_TX_MAX_FREE_SZ];
12 : : int nb_free = 0;
13 : : int i, s;
14 : :
15 [ # # ]: 0 : if (unlikely(num == 0))
16 : 0 : return;
17 : :
18 : : /* Find the 1st mbuf which needs to be free */
19 [ # # ]: 0 : for (s = 0; s < num; s++) {
20 [ # # ]: 0 : if (txep[s] != NULL) {
21 : : m = rte_pktmbuf_prefree_seg(txep[s]);
22 : : if (m != NULL)
23 : : break;
24 : : }
25 : : }
26 : :
27 [ # # ]: 0 : if (s == num)
28 : : return;
29 : :
30 : 0 : free[0] = m;
31 : : nb_free = 1;
32 [ # # ]: 0 : for (i = s + 1; i < num; i++) {
33 [ # # ]: 0 : if (likely(txep[i] != NULL)) {
34 : : m = rte_pktmbuf_prefree_seg(txep[i]);
35 [ # # ]: 0 : if (likely(m != NULL)) {
36 [ # # ]: 0 : if (likely(m->pool == free[0]->pool)) {
37 : 0 : free[nb_free++] = m;
38 : : } else {
39 [ # # ]: 0 : rte_mempool_put_bulk(free[0]->pool, (void *)free, nb_free);
40 : 0 : free[0] = m;
41 : : nb_free = 1;
42 : : }
43 : : }
44 : 0 : txep[i] = NULL;
45 : : }
46 : : }
47 [ # # ]: 0 : rte_mempool_put_bulk(free[0]->pool, (void **)free, nb_free);
48 : : }
49 : :
50 : : static inline void
51 : 0 : gve_tx_clean(struct gve_tx_queue *txq)
52 : : {
53 : 0 : uint16_t mask = txq->nb_tx_desc - 1;
54 : 0 : uint32_t start = txq->next_to_clean & mask;
55 : : uint32_t ntc, nb_clean, i;
56 : : struct gve_tx_iovec *iov;
57 : :
58 : 0 : ntc = rte_be_to_cpu_32(rte_read32(txq->qtx_head));
59 : 0 : ntc = ntc & mask;
60 : :
61 [ # # ]: 0 : if (ntc == start)
62 : : return;
63 : :
64 : : /* if wrap around, free twice. */
65 [ # # ]: 0 : if (ntc < start) {
66 : 0 : nb_clean = txq->nb_tx_desc - start;
67 : : if (nb_clean > GVE_TX_MAX_FREE_SZ)
68 : : nb_clean = GVE_TX_MAX_FREE_SZ;
69 [ # # ]: 0 : if (txq->is_gqi_qpl) {
70 [ # # ]: 0 : for (i = start; i < start + nb_clean; i++) {
71 : 0 : iov = &txq->iov_ring[i];
72 : 0 : txq->fifo_avail += iov->iov_len;
73 : 0 : iov->iov_base = 0;
74 : 0 : iov->iov_len = 0;
75 : : }
76 : : } else {
77 : 0 : gve_free_bulk_mbuf(&txq->sw_ring[start], nb_clean);
78 : : }
79 : 0 : txq->nb_free += nb_clean;
80 : 0 : start += nb_clean;
81 [ # # ]: 0 : if (start == txq->nb_tx_desc)
82 : : start = 0;
83 : 0 : txq->next_to_clean += nb_clean;
84 : : }
85 : :
86 [ # # ]: 0 : if (ntc > start) {
87 : 0 : nb_clean = ntc - start;
88 : : if (nb_clean > GVE_TX_MAX_FREE_SZ)
89 : : nb_clean = GVE_TX_MAX_FREE_SZ;
90 [ # # ]: 0 : if (txq->is_gqi_qpl) {
91 [ # # ]: 0 : for (i = start; i < start + nb_clean; i++) {
92 : 0 : iov = &txq->iov_ring[i];
93 : 0 : txq->fifo_avail += iov->iov_len;
94 : 0 : iov->iov_base = 0;
95 : 0 : iov->iov_len = 0;
96 : : }
97 : : } else {
98 : 0 : gve_free_bulk_mbuf(&txq->sw_ring[start], nb_clean);
99 : : }
100 : 0 : txq->nb_free += nb_clean;
101 : 0 : txq->next_to_clean += nb_clean;
102 : : }
103 : : }
104 : :
105 : : static inline void
106 : 0 : gve_tx_clean_swr_qpl(struct gve_tx_queue *txq)
107 : : {
108 : 0 : uint32_t start = txq->sw_ntc;
109 : : uint32_t ntc, nb_clean;
110 : :
111 : 0 : ntc = txq->sw_tail;
112 : :
113 [ # # ]: 0 : if (ntc == start)
114 : : return;
115 : :
116 : : /* if wrap around, free twice. */
117 [ # # ]: 0 : if (ntc < start) {
118 : 0 : nb_clean = txq->nb_tx_desc - start;
119 : : if (nb_clean > GVE_TX_MAX_FREE_SZ)
120 : : nb_clean = GVE_TX_MAX_FREE_SZ;
121 : 0 : gve_free_bulk_mbuf(&txq->sw_ring[start], nb_clean);
122 : :
123 : 0 : txq->sw_nb_free += nb_clean;
124 : 0 : start += nb_clean;
125 [ # # ]: 0 : if (start == txq->nb_tx_desc)
126 : : start = 0;
127 : 0 : txq->sw_ntc = start;
128 : : }
129 : :
130 [ # # ]: 0 : if (ntc > start) {
131 : 0 : nb_clean = ntc - start;
132 : : if (nb_clean > GVE_TX_MAX_FREE_SZ)
133 : : nb_clean = GVE_TX_MAX_FREE_SZ;
134 : 0 : gve_free_bulk_mbuf(&txq->sw_ring[start], nb_clean);
135 : 0 : txq->sw_nb_free += nb_clean;
136 : 0 : start += nb_clean;
137 : 0 : txq->sw_ntc = start;
138 : : }
139 : : }
140 : :
141 : : static inline void
142 : 0 : gve_tx_fill_pkt_desc(volatile union gve_tx_desc *desc, struct rte_mbuf *mbuf,
143 : : uint8_t desc_cnt, uint16_t len, uint64_t addr)
144 : : {
145 : 0 : uint64_t csum_l4 = mbuf->ol_flags & RTE_MBUF_F_TX_L4_MASK;
146 : : uint8_t l4_csum_offset = 0;
147 : : uint8_t l4_hdr_offset = 0;
148 : :
149 [ # # ]: 0 : if (mbuf->ol_flags & RTE_MBUF_F_TX_TCP_SEG)
150 : 0 : csum_l4 |= RTE_MBUF_F_TX_TCP_CKSUM;
151 : :
152 [ # # # # ]: 0 : switch (csum_l4) {
153 : 0 : case RTE_MBUF_F_TX_TCP_CKSUM:
154 : : l4_csum_offset = offsetof(struct rte_tcp_hdr, cksum);
155 : 0 : l4_hdr_offset = mbuf->l2_len + mbuf->l3_len;
156 : 0 : break;
157 : 0 : case RTE_MBUF_F_TX_UDP_CKSUM:
158 : : l4_csum_offset = offsetof(struct rte_udp_hdr, dgram_cksum);
159 : 0 : l4_hdr_offset = mbuf->l2_len + mbuf->l3_len;
160 : 0 : break;
161 : 0 : case RTE_MBUF_F_TX_SCTP_CKSUM:
162 : : l4_csum_offset = offsetof(struct rte_sctp_hdr, cksum);
163 : 0 : l4_hdr_offset = mbuf->l2_len + mbuf->l3_len;
164 : 0 : break;
165 : : }
166 : :
167 [ # # ]: 0 : if (mbuf->ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
168 : 0 : desc->pkt.type_flags = GVE_TXD_TSO | GVE_TXF_L4CSUM;
169 : 0 : desc->pkt.l4_csum_offset = l4_csum_offset >> 1;
170 : 0 : desc->pkt.l4_hdr_offset = l4_hdr_offset >> 1;
171 [ # # ]: 0 : } else if (mbuf->ol_flags & RTE_MBUF_F_TX_L4_MASK) {
172 : 0 : desc->pkt.type_flags = GVE_TXD_STD | GVE_TXF_L4CSUM;
173 : 0 : desc->pkt.l4_csum_offset = l4_csum_offset >> 1;
174 : 0 : desc->pkt.l4_hdr_offset = l4_hdr_offset >> 1;
175 : : } else {
176 : 0 : desc->pkt.type_flags = GVE_TXD_STD;
177 : 0 : desc->pkt.l4_csum_offset = 0;
178 : 0 : desc->pkt.l4_hdr_offset = 0;
179 : : }
180 : 0 : desc->pkt.desc_cnt = desc_cnt;
181 [ # # ]: 0 : desc->pkt.len = rte_cpu_to_be_16(mbuf->pkt_len);
182 [ # # ]: 0 : desc->pkt.seg_len = rte_cpu_to_be_16(len);
183 [ # # ]: 0 : desc->pkt.seg_addr = rte_cpu_to_be_64(addr);
184 : 0 : }
185 : :
186 : : static inline void
187 : 0 : gve_tx_fill_seg_desc(volatile union gve_tx_desc *desc, uint64_t ol_flags,
188 : : union gve_tx_offload tx_offload,
189 : : uint16_t len, uint64_t addr)
190 : : {
191 : 0 : desc->seg.type_flags = GVE_TXD_SEG;
192 [ # # ]: 0 : if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
193 [ # # ]: 0 : if (ol_flags & RTE_MBUF_F_TX_IPV6)
194 : 0 : desc->seg.type_flags |= GVE_TXSF_IPV6;
195 : 0 : desc->seg.l3_offset = tx_offload.l2_len >> 1;
196 [ # # ]: 0 : desc->seg.mss = rte_cpu_to_be_16(tx_offload.tso_segsz);
197 : : }
198 [ # # ]: 0 : desc->seg.seg_len = rte_cpu_to_be_16(len);
199 [ # # ]: 0 : desc->seg.seg_addr = rte_cpu_to_be_64(addr);
200 : 0 : }
201 : :
202 : : static inline bool
203 : : is_fifo_avail(struct gve_tx_queue *txq, uint16_t len)
204 : : {
205 [ # # ]: 0 : if (txq->fifo_avail < len)
206 : : return false;
207 : : /* Don't split segment. */
208 [ # # # # : 0 : if (txq->fifo_head + len > txq->fifo_size &&
# # # # ]
209 [ # # # # : 0 : txq->fifo_size - txq->fifo_head + len > txq->fifo_avail)
# # # # ]
210 : : return false;
211 : : return true;
212 : : }
213 : : static inline uint64_t
214 : 0 : gve_tx_alloc_from_fifo(struct gve_tx_queue *txq, uint16_t tx_id, uint16_t len)
215 : : {
216 : 0 : uint32_t head = txq->fifo_head;
217 : 0 : uint32_t size = txq->fifo_size;
218 : : struct gve_tx_iovec *iov;
219 : : uint32_t aligned_head;
220 : : uint32_t iov_len = 0;
221 : : uint64_t fifo_addr;
222 : :
223 : 0 : iov = &txq->iov_ring[tx_id];
224 : :
225 : : /* Don't split segment */
226 [ # # ]: 0 : if (head + len > size) {
227 : 0 : iov_len += (size - head);
228 : : head = 0;
229 : : }
230 : :
231 : 0 : fifo_addr = head;
232 : 0 : iov_len += len;
233 : 0 : iov->iov_base = head;
234 : :
235 : : /* Re-align to a cacheline for next head */
236 : 0 : head += len;
237 : 0 : aligned_head = RTE_ALIGN(head, RTE_CACHE_LINE_SIZE);
238 : 0 : iov_len += (aligned_head - head);
239 : 0 : iov->iov_len = iov_len;
240 : :
241 [ # # ]: 0 : if (aligned_head == txq->fifo_size)
242 : : aligned_head = 0;
243 : 0 : txq->fifo_head = aligned_head;
244 : 0 : txq->fifo_avail -= iov_len;
245 : :
246 : 0 : return fifo_addr;
247 : : }
248 : :
249 : : static inline uint16_t
250 : 0 : gve_tx_burst_qpl(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
251 : : {
252 : 0 : union gve_tx_offload tx_offload = {0};
253 : : volatile union gve_tx_desc *txr, *txd;
254 : : struct gve_tx_queue *txq = tx_queue;
255 : 0 : struct rte_mbuf **sw_ring = txq->sw_ring;
256 : 0 : uint16_t mask = txq->nb_tx_desc - 1;
257 : 0 : uint16_t tx_id = txq->tx_tail & mask;
258 : : uint32_t tx_tail = txq->tx_tail;
259 : : struct rte_mbuf *tx_pkt, *first;
260 : 0 : uint16_t sw_id = txq->sw_tail;
261 : : uint64_t ol_flags, fifo_addr;
262 : : uint16_t nb_used, i;
263 : : uint64_t bytes = 0;
264 : : uint16_t nb_tx = 0;
265 : : uint32_t hlen;
266 : :
267 : 0 : txr = txq->tx_desc_ring;
268 : :
269 [ # # # # ]: 0 : if (txq->nb_free < txq->free_thresh || txq->fifo_avail == 0)
270 : 0 : gve_tx_clean(txq);
271 : :
272 [ # # ]: 0 : if (txq->sw_nb_free < txq->free_thresh)
273 : 0 : gve_tx_clean_swr_qpl(txq);
274 : :
275 [ # # ]: 0 : for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
276 : : const void *mbuf_header_addr;
277 : : void *qpl_write_addr;
278 : :
279 : 0 : tx_pkt = *tx_pkts++;
280 : 0 : ol_flags = tx_pkt->ol_flags;
281 : :
282 [ # # ]: 0 : if (txq->sw_nb_free < tx_pkt->nb_segs) {
283 : 0 : gve_tx_clean_swr_qpl(txq);
284 [ # # ]: 0 : if (txq->sw_nb_free < tx_pkt->nb_segs)
285 : 0 : goto end_of_tx;
286 : : }
287 : :
288 : : /* Even for multi-segs, use 1 qpl buf for data */
289 : : nb_used = 1;
290 [ # # ]: 0 : if (ol_flags & RTE_MBUF_F_TX_TCP_SEG)
291 : : nb_used++;
292 : :
293 [ # # ]: 0 : if (txq->nb_free < nb_used)
294 : 0 : goto end_of_tx;
295 : :
296 : 0 : tx_offload.l2_len = tx_pkt->l2_len;
297 : 0 : tx_offload.l3_len = tx_pkt->l3_len;
298 : 0 : tx_offload.l4_len = tx_pkt->l4_len;
299 : 0 : tx_offload.tso_segsz = tx_pkt->tso_segsz;
300 : :
301 : : first = tx_pkt;
302 : 0 : txd = &txr[tx_id];
303 : : hlen = ol_flags & RTE_MBUF_F_TX_TCP_SEG ?
304 [ # # ]: 0 : (uint32_t)(tx_offload.l2_len + tx_offload.l3_len + tx_offload.l4_len) :
305 : : tx_pkt->pkt_len;
306 : :
307 [ # # ]: 0 : if (!is_fifo_avail(txq, hlen)) {
308 : 0 : gve_tx_clean(txq);
309 : : if (!is_fifo_avail(txq, hlen))
310 : 0 : goto end_of_tx;
311 : : }
312 : 0 : fifo_addr = gve_tx_alloc_from_fifo(txq, tx_id, hlen);
313 : :
314 : : /* For TSO, check if there's enough fifo space for data first */
315 [ # # ]: 0 : if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
316 [ # # ]: 0 : if (!is_fifo_avail(txq, tx_pkt->pkt_len - hlen)) {
317 : 0 : gve_tx_clean(txq);
318 [ # # ]: 0 : if (!is_fifo_avail(txq, tx_pkt->pkt_len - hlen))
319 : 0 : goto end_of_tx;
320 : : }
321 : : }
322 : :
323 [ # # ]: 0 : qpl_write_addr = (void *)(size_t)(fifo_addr + txq->fifo_base);
324 : : mbuf_header_addr = rte_pktmbuf_read(tx_pkt, 0, hlen, qpl_write_addr);
325 : :
326 : : /* Header data is linear in the mbuf head. Copy directly. */
327 [ # # ]: 0 : if (mbuf_header_addr != qpl_write_addr)
328 : : rte_memcpy(qpl_write_addr, mbuf_header_addr, hlen);
329 : :
330 : 0 : gve_tx_fill_pkt_desc(txd, tx_pkt, nb_used, hlen, fifo_addr);
331 : :
332 [ # # ]: 0 : if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
333 : : const void *mbuf_payload_addr;
334 : :
335 : 0 : tx_id = (tx_id + 1) & mask;
336 : 0 : txd = &txr[tx_id];
337 : 0 : fifo_addr = gve_tx_alloc_from_fifo(txq, tx_id, tx_pkt->pkt_len - hlen);
338 : 0 : qpl_write_addr = (void *)(size_t)(txq->fifo_base + fifo_addr);
339 [ # # ]: 0 : mbuf_payload_addr = rte_pktmbuf_read(tx_pkt, hlen, tx_pkt->pkt_len - hlen,
340 : : qpl_write_addr);
341 : :
342 : : /* Payload data is contiguous. Take the offset from the
343 : : * read request and copy from there.
344 : : */
345 [ # # ]: 0 : if (mbuf_payload_addr != qpl_write_addr)
346 : 0 : rte_memcpy(qpl_write_addr, mbuf_payload_addr,
347 [ # # ]: 0 : tx_pkt->pkt_len - hlen);
348 : :
349 : 0 : gve_tx_fill_seg_desc(txd, ol_flags, tx_offload,
350 : 0 : tx_pkt->pkt_len - hlen, fifo_addr);
351 : : }
352 : :
353 : : /* record mbuf in sw_ring for free */
354 [ # # ]: 0 : for (i = 0; i < first->nb_segs; i++) {
355 [ # # ]: 0 : if (!tx_pkt)
356 : : break;
357 : 0 : sw_ring[sw_id] = tx_pkt;
358 : 0 : sw_id = (sw_id + 1) & mask;
359 : 0 : tx_pkt = tx_pkt->next;
360 : : }
361 : :
362 : 0 : tx_id = (tx_id + 1) & mask;
363 : :
364 : 0 : txq->nb_free -= nb_used;
365 : 0 : txq->sw_nb_free -= first->nb_segs;
366 : 0 : tx_tail += nb_used;
367 : :
368 : 0 : bytes += first->pkt_len;
369 : : }
370 : :
371 : 0 : end_of_tx:
372 [ # # ]: 0 : if (nb_tx) {
373 [ # # ]: 0 : rte_write32(rte_cpu_to_be_32(tx_tail), txq->qtx_tail);
374 : 0 : txq->tx_tail = tx_tail;
375 : 0 : txq->sw_tail = sw_id;
376 : :
377 : 0 : txq->stats.packets += nb_tx;
378 : 0 : txq->stats.bytes += bytes;
379 : 0 : txq->stats.errors += nb_pkts - nb_tx;
380 : : }
381 : :
382 : 0 : return nb_tx;
383 : : }
384 : :
385 : : static inline uint16_t
386 : 0 : gve_tx_burst_ra(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
387 : : {
388 : 0 : union gve_tx_offload tx_offload = {0};
389 : : volatile union gve_tx_desc *txr, *txd;
390 : : struct gve_tx_queue *txq = tx_queue;
391 : 0 : struct rte_mbuf **sw_ring = txq->sw_ring;
392 : 0 : uint16_t mask = txq->nb_tx_desc - 1;
393 : 0 : uint16_t tx_id = txq->tx_tail & mask;
394 : : uint32_t tx_tail = txq->tx_tail;
395 : : struct rte_mbuf *tx_pkt, *first;
396 : : uint16_t nb_used, hlen, i;
397 : : uint64_t ol_flags, addr;
398 : : uint64_t bytes = 0;
399 : : uint16_t nb_tx = 0;
400 : :
401 : 0 : txr = txq->tx_desc_ring;
402 : :
403 [ # # ]: 0 : if (txq->nb_free < txq->free_thresh)
404 : 0 : gve_tx_clean(txq);
405 : :
406 [ # # ]: 0 : for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
407 : 0 : tx_pkt = *tx_pkts++;
408 : 0 : ol_flags = tx_pkt->ol_flags;
409 : :
410 : 0 : nb_used = tx_pkt->nb_segs;
411 [ # # ]: 0 : if (ol_flags & RTE_MBUF_F_TX_TCP_SEG)
412 : 0 : nb_used++;
413 : :
414 [ # # ]: 0 : if (txq->nb_free < nb_used)
415 : 0 : goto end_of_tx;
416 : :
417 : 0 : tx_offload.l2_len = tx_pkt->l2_len;
418 : 0 : tx_offload.l3_len = tx_pkt->l3_len;
419 : 0 : tx_offload.l4_len = tx_pkt->l4_len;
420 : 0 : tx_offload.tso_segsz = tx_pkt->tso_segsz;
421 : :
422 : : first = tx_pkt;
423 : 0 : txd = &txr[tx_id];
424 : :
425 [ # # ]: 0 : hlen = ol_flags & RTE_MBUF_F_TX_TCP_SEG ?
426 : 0 : (uint32_t)(tx_offload.l2_len + tx_offload.l3_len + tx_offload.l4_len) :
427 : 0 : tx_pkt->pkt_len;
428 : : /*
429 : : * if tso, the driver needs to fill 2 descs for 1 mbuf
430 : : * so only put this mbuf into the 1st tx entry in sw ring
431 : : */
432 : 0 : sw_ring[tx_id] = tx_pkt;
433 : : addr = rte_mbuf_data_iova(tx_pkt);
434 : 0 : gve_tx_fill_pkt_desc(txd, tx_pkt, nb_used, hlen, addr);
435 : :
436 [ # # ]: 0 : if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
437 : 0 : tx_id = (tx_id + 1) & mask;
438 : 0 : txd = &txr[tx_id];
439 : 0 : addr = rte_mbuf_data_iova(tx_pkt) + hlen;
440 : 0 : gve_tx_fill_seg_desc(txd, ol_flags, tx_offload,
441 : 0 : tx_pkt->data_len - hlen, addr);
442 : : }
443 : :
444 [ # # ]: 0 : for (i = 1; i < first->nb_segs; i++) {
445 : 0 : tx_id = (tx_id + 1) & mask;
446 : 0 : txd = &txr[tx_id];
447 : 0 : tx_pkt = tx_pkt->next;
448 : 0 : sw_ring[tx_id] = tx_pkt;
449 : : addr = rte_mbuf_data_iova(tx_pkt);
450 : 0 : gve_tx_fill_seg_desc(txd, ol_flags, tx_offload,
451 : 0 : tx_pkt->data_len, addr);
452 : : }
453 : 0 : tx_id = (tx_id + 1) & mask;
454 : :
455 : 0 : txq->nb_free -= nb_used;
456 : 0 : tx_tail += nb_used;
457 : :
458 : 0 : bytes += first->pkt_len;
459 : : }
460 : :
461 : 0 : end_of_tx:
462 [ # # ]: 0 : if (nb_tx) {
463 [ # # ]: 0 : rte_write32(rte_cpu_to_be_32(tx_tail), txq->qtx_tail);
464 : 0 : txq->tx_tail = tx_tail;
465 : :
466 : 0 : txq->stats.packets += nb_tx;
467 : 0 : txq->stats.bytes += bytes;
468 : 0 : txq->stats.errors += nb_pkts - nb_tx;
469 : : }
470 : :
471 : 0 : return nb_tx;
472 : : }
473 : :
474 : : uint16_t
475 : 0 : gve_tx_burst(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
476 : : {
477 : : struct gve_tx_queue *txq = tx_queue;
478 : :
479 [ # # ]: 0 : if (txq->is_gqi_qpl)
480 : 0 : return gve_tx_burst_qpl(tx_queue, tx_pkts, nb_pkts);
481 : :
482 : 0 : return gve_tx_burst_ra(tx_queue, tx_pkts, nb_pkts);
483 : : }
484 : :
485 : : static inline void
486 : 0 : gve_reset_txq(struct gve_tx_queue *txq)
487 : : {
488 : : struct rte_mbuf **sw_ring;
489 : : uint32_t size, i;
490 : :
491 [ # # ]: 0 : if (txq == NULL) {
492 : 0 : PMD_DRV_LOG(ERR, "Pointer to txq is NULL");
493 : 0 : return;
494 : : }
495 : :
496 : 0 : size = txq->nb_tx_desc * sizeof(union gve_tx_desc);
497 [ # # ]: 0 : for (i = 0; i < size; i++)
498 : 0 : ((volatile char *)txq->tx_desc_ring)[i] = 0;
499 : :
500 : 0 : sw_ring = txq->sw_ring;
501 [ # # ]: 0 : for (i = 0; i < txq->nb_tx_desc; i++) {
502 : 0 : sw_ring[i] = NULL;
503 [ # # ]: 0 : if (txq->is_gqi_qpl) {
504 : 0 : txq->iov_ring[i].iov_base = 0;
505 : 0 : txq->iov_ring[i].iov_len = 0;
506 : : }
507 : : }
508 : :
509 : 0 : txq->tx_tail = 0;
510 : 0 : txq->nb_free = txq->nb_tx_desc - 1;
511 : 0 : txq->next_to_clean = 0;
512 : :
513 [ # # ]: 0 : if (txq->is_gqi_qpl) {
514 : 0 : txq->fifo_size = PAGE_SIZE * txq->hw->tx_pages_per_qpl;
515 : 0 : txq->fifo_avail = txq->fifo_size;
516 : 0 : txq->fifo_head = 0;
517 : 0 : txq->fifo_base = (uint64_t)(txq->qpl->mz->addr);
518 : :
519 : 0 : txq->sw_tail = 0;
520 : 0 : txq->sw_nb_free = txq->nb_tx_desc - 1;
521 : 0 : txq->sw_ntc = 0;
522 : : }
523 : : }
524 : :
525 : : static inline void
526 : 0 : gve_release_txq_mbufs(struct gve_tx_queue *txq)
527 : : {
528 : : uint16_t i;
529 : :
530 [ # # ]: 0 : for (i = 0; i < txq->nb_tx_desc; i++) {
531 [ # # ]: 0 : if (txq->sw_ring[i]) {
532 : : rte_pktmbuf_free_seg(txq->sw_ring[i]);
533 : 0 : txq->sw_ring[i] = NULL;
534 : : }
535 : : }
536 : 0 : }
537 : :
538 : : void
539 : 0 : gve_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
540 : : {
541 : 0 : struct gve_tx_queue *q = dev->data->tx_queues[qid];
542 : :
543 [ # # ]: 0 : if (!q)
544 : : return;
545 : :
546 [ # # ]: 0 : if (q->is_gqi_qpl) {
547 : 0 : gve_teardown_queue_page_list(q->hw, q->qpl);
548 : 0 : rte_free(q->iov_ring);
549 : 0 : q->qpl = NULL;
550 : : }
551 : :
552 : 0 : gve_release_txq_mbufs(q);
553 : 0 : rte_free(q->sw_ring);
554 : 0 : rte_memzone_free(q->mz);
555 : 0 : rte_memzone_free(q->qres_mz);
556 : 0 : q->qres = NULL;
557 : 0 : rte_free(q);
558 : :
559 : 0 : dev->data->tx_queues[qid] = NULL;
560 : : }
561 : :
562 : : int
563 : 0 : gve_tx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_id, uint16_t nb_desc,
564 : : unsigned int socket_id, const struct rte_eth_txconf *conf)
565 : : {
566 : 0 : struct gve_priv *hw = dev->data->dev_private;
567 : : const struct rte_memzone *mz;
568 : : struct gve_tx_queue *txq;
569 : : uint16_t free_thresh;
570 : : int err = 0;
571 : :
572 : : /* Ring size is required to be a power of two. */
573 [ # # ]: 0 : if (!rte_is_power_of_2(nb_desc)) {
574 : 0 : PMD_DRV_LOG(ERR, "Invalid ring size %u. GVE ring size must be a power of 2.",
575 : : nb_desc);
576 : 0 : return -EINVAL;
577 : : }
578 : :
579 : : /* Free memory if needed. */
580 [ # # ]: 0 : if (dev->data->tx_queues[queue_id]) {
581 : 0 : gve_tx_queue_release(dev, queue_id);
582 : 0 : dev->data->tx_queues[queue_id] = NULL;
583 : : }
584 : :
585 : : /* Allocate the TX queue data structure. */
586 : 0 : txq = rte_zmalloc_socket("gve txq", sizeof(struct gve_tx_queue),
587 : : RTE_CACHE_LINE_SIZE, socket_id);
588 [ # # ]: 0 : if (!txq) {
589 : 0 : PMD_DRV_LOG(ERR, "Failed to allocate memory for tx queue structure");
590 : : err = -ENOMEM;
591 : 0 : goto err_txq;
592 : : }
593 : :
594 [ # # ]: 0 : free_thresh = conf->tx_free_thresh ? conf->tx_free_thresh : GVE_DEFAULT_TX_FREE_THRESH;
595 [ # # ]: 0 : if (free_thresh >= nb_desc - 3) {
596 : 0 : PMD_DRV_LOG(ERR, "tx_free_thresh (%u) must be less than nb_desc (%u) minus 3.",
597 : : free_thresh, txq->nb_tx_desc);
598 : : err = -EINVAL;
599 : 0 : goto err_txq;
600 : : }
601 : :
602 : 0 : txq->nb_tx_desc = nb_desc;
603 : 0 : txq->free_thresh = free_thresh;
604 : 0 : txq->queue_id = queue_id;
605 : 0 : txq->port_id = dev->data->port_id;
606 : 0 : txq->ntfy_id = queue_id;
607 : 0 : txq->is_gqi_qpl = hw->queue_format == GVE_GQI_QPL_FORMAT;
608 : 0 : txq->hw = hw;
609 [ # # ]: 0 : txq->ntfy_addr = &hw->db_bar2[rte_be_to_cpu_32(hw->irq_dbs[txq->ntfy_id].id)];
610 : :
611 : : /* Allocate software ring */
612 : 0 : txq->sw_ring = rte_zmalloc_socket("gve tx sw ring",
613 : : sizeof(struct rte_mbuf *) * nb_desc,
614 : : RTE_CACHE_LINE_SIZE, socket_id);
615 [ # # ]: 0 : if (!txq->sw_ring) {
616 : 0 : PMD_DRV_LOG(ERR, "Failed to allocate memory for SW TX ring");
617 : : err = -ENOMEM;
618 : 0 : goto err_txq;
619 : : }
620 : :
621 : 0 : mz = rte_eth_dma_zone_reserve(dev, "tx_ring", queue_id,
622 : : nb_desc * sizeof(union gve_tx_desc),
623 : : PAGE_SIZE, socket_id);
624 [ # # ]: 0 : if (mz == NULL) {
625 : 0 : PMD_DRV_LOG(ERR, "Failed to reserve DMA memory for TX");
626 : : err = -ENOMEM;
627 : 0 : goto err_sw_ring;
628 : : }
629 : 0 : txq->tx_desc_ring = (union gve_tx_desc *)mz->addr;
630 : 0 : txq->tx_ring_phys_addr = mz->iova;
631 : 0 : txq->mz = mz;
632 : :
633 : : /* QPL-specific allocations. */
634 [ # # ]: 0 : if (txq->is_gqi_qpl) {
635 : 0 : txq->iov_ring = rte_zmalloc_socket("gve tx iov ring",
636 : : sizeof(struct gve_tx_iovec) * nb_desc,
637 : : RTE_CACHE_LINE_SIZE, socket_id);
638 [ # # ]: 0 : if (!txq->iov_ring) {
639 : 0 : PMD_DRV_LOG(ERR, "Failed to allocate memory for SW TX ring");
640 : : err = -ENOMEM;
641 : 0 : goto err_tx_ring;
642 : : }
643 : :
644 : 0 : txq->qpl = gve_setup_queue_page_list(hw, queue_id, false,
645 : 0 : hw->tx_pages_per_qpl);
646 [ # # ]: 0 : if (!txq->qpl) {
647 : : err = -ENOMEM;
648 : 0 : PMD_DRV_LOG(ERR, "Failed to alloc tx qpl for queue %hu.",
649 : : queue_id);
650 : 0 : goto err_iov_ring;
651 : : }
652 : : }
653 : :
654 : 0 : mz = rte_eth_dma_zone_reserve(dev, "txq_res", queue_id, sizeof(struct gve_queue_resources),
655 : : PAGE_SIZE, socket_id);
656 [ # # ]: 0 : if (mz == NULL) {
657 : 0 : PMD_DRV_LOG(ERR, "Failed to reserve DMA memory for TX resource");
658 : : err = -ENOMEM;
659 : 0 : goto err_qpl;
660 : : }
661 : 0 : txq->qres = (struct gve_queue_resources *)mz->addr;
662 : 0 : txq->qres_mz = mz;
663 : :
664 : 0 : gve_reset_txq(txq);
665 : :
666 : 0 : dev->data->tx_queues[queue_id] = txq;
667 : :
668 : 0 : return 0;
669 : : err_qpl:
670 [ # # ]: 0 : if (txq->is_gqi_qpl) {
671 : 0 : gve_teardown_queue_page_list(hw, txq->qpl);
672 : 0 : txq->qpl = NULL;
673 : : }
674 : 0 : err_iov_ring:
675 [ # # ]: 0 : if (txq->is_gqi_qpl)
676 : 0 : rte_free(txq->iov_ring);
677 : 0 : err_tx_ring:
678 : 0 : rte_memzone_free(txq->mz);
679 : 0 : err_sw_ring:
680 : 0 : rte_free(txq->sw_ring);
681 : 0 : err_txq:
682 : 0 : rte_free(txq);
683 : 0 : return err;
684 : : }
685 : :
686 : : int
687 : 0 : gve_tx_queue_start(struct rte_eth_dev *dev, uint16_t tx_queue_id)
688 : : {
689 : 0 : struct gve_priv *hw = dev->data->dev_private;
690 : : struct gve_tx_queue *txq;
691 : :
692 [ # # ]: 0 : if (tx_queue_id >= dev->data->nb_tx_queues)
693 : : return -EINVAL;
694 : :
695 : 0 : txq = dev->data->tx_queues[tx_queue_id];
696 : :
697 [ # # ]: 0 : txq->qtx_tail = &hw->db_bar2[rte_be_to_cpu_32(txq->qres->db_index)];
698 : 0 : txq->qtx_head =
699 [ # # ]: 0 : &hw->cnt_array[rte_be_to_cpu_32(txq->qres->counter_index)];
700 : :
701 : 0 : rte_write32(rte_cpu_to_be_32(GVE_IRQ_MASK), txq->ntfy_addr);
702 : :
703 : 0 : dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STARTED;
704 : :
705 : 0 : return 0;
706 : : }
707 : :
708 : : int
709 : 0 : gve_tx_queue_stop(struct rte_eth_dev *dev, uint16_t tx_queue_id)
710 : : {
711 : : struct gve_tx_queue *txq;
712 : :
713 [ # # ]: 0 : if (tx_queue_id >= dev->data->nb_tx_queues)
714 : : return -EINVAL;
715 : :
716 : 0 : txq = dev->data->tx_queues[tx_queue_id];
717 : 0 : gve_release_txq_mbufs(txq);
718 : 0 : gve_reset_txq(txq);
719 : :
720 : 0 : dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
721 : :
722 : 0 : return 0;
723 : : }
724 : :
725 : : void
726 : 0 : gve_stop_tx_queues(struct rte_eth_dev *dev)
727 : : {
728 [ # # ]: 0 : struct gve_priv *hw = dev->data->dev_private;
729 : : uint16_t i;
730 : : int err;
731 : :
732 [ # # ]: 0 : if (!gve_is_gqi(hw))
733 : 0 : return gve_stop_tx_queues_dqo(dev);
734 : :
735 : 0 : err = gve_adminq_destroy_tx_queues(hw, dev->data->nb_tx_queues);
736 [ # # ]: 0 : if (err != 0)
737 : 0 : PMD_DRV_LOG(WARNING, "failed to destroy txqs");
738 : :
739 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++)
740 [ # # ]: 0 : if (gve_tx_queue_stop(dev, i) != 0)
741 : 0 : PMD_DRV_LOG(WARNING, "Fail to stop Tx queue %d", i);
742 : : }
743 : :
744 : : void
745 : 0 : gve_set_tx_function(struct rte_eth_dev *dev)
746 : : {
747 : 0 : dev->tx_pkt_burst = gve_tx_burst;
748 : 0 : }
|