Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (c) 2022-2023 Google LLC
3 : : * Copyright (c) 2022-2023 Intel Corporation
4 : : */
5 : :
6 : : #include "gve_ethdev.h"
7 : : #include "base/gve_adminq.h"
8 : : #include "rte_malloc.h"
9 : :
10 : : static inline void
11 : : gve_free_compl_tags_init(struct gve_tx_queue *txq)
12 : : {
13 : 0 : uint16_t sw_mask = txq->sw_size - 1;
14 : : int i;
15 : :
16 [ # # ]: 0 : for (i = 0; i < sw_mask; i++)
17 : 0 : txq->pkt_ring_dqo[i].next_avail_pkt = (i + 1) & sw_mask;
18 : :
19 : 0 : txq->pkt_ring_dqo[sw_mask].next_avail_pkt = -1;
20 : 0 : txq->free_compl_tags_head = 0;
21 : 0 : txq->num_free_compl_tags = txq->sw_size;
22 : : }
23 : :
24 : : /* Removes first item from the buffer free list, and return its array index. */
25 : : static inline bool
26 : 0 : gve_free_compl_tags_pop(struct gve_tx_queue *txq, uint16_t *compl_tag)
27 : : {
28 : 0 : int16_t head = txq->free_compl_tags_head;
29 [ # # ]: 0 : if (likely(head != -1)) {
30 : 0 : struct gve_tx_pkt *head_pkt = &txq->pkt_ring_dqo[head];
31 : :
32 : 0 : txq->free_compl_tags_head = head_pkt->next_avail_pkt;
33 : 0 : txq->num_free_compl_tags--;
34 : 0 : *compl_tag = head;
35 : 0 : return true;
36 : : }
37 : :
38 : 0 : PMD_DRV_DP_LOG(ERR, "Completion tags list is empty!");
39 : 0 : return false;
40 : : }
41 : :
42 : : /* Adds gve_tx_pkt in pkt_ring to free list. Assumes that
43 : : * buf_id < txq->sw_size.
44 : : */
45 : : static inline void
46 : : gve_free_compl_tags_push(struct gve_tx_queue *txq, uint16_t compl_tag)
47 : : {
48 : 0 : txq->pkt_ring_dqo[compl_tag].next_avail_pkt = txq->free_compl_tags_head;
49 : 0 : txq->free_compl_tags_head = compl_tag;
50 : 0 : txq->num_free_compl_tags++;
51 : 0 : }
52 : :
53 : : static inline void
54 : 0 : gve_tx_clean_dqo(struct gve_tx_queue *txq)
55 : : {
56 : : struct gve_tx_compl_desc *compl_ring;
57 : : struct gve_tx_compl_desc *compl_desc;
58 : : struct gve_tx_queue *aim_txq;
59 : : struct gve_tx_pkt *pkt;
60 : : uint16_t new_tx_head;
61 : : uint16_t compl_tag;
62 : : uint16_t next;
63 : :
64 : 0 : next = txq->complq_tail;
65 : 0 : compl_ring = txq->compl_ring;
66 : 0 : compl_desc = &compl_ring[next];
67 : :
68 [ # # ]: 0 : if (compl_desc->generation != txq->cur_gen_bit)
69 : : return;
70 : :
71 : 0 : rte_io_rmb();
72 : :
73 : 0 : aim_txq = txq->txqs[compl_desc->id];
74 : :
75 [ # # # # ]: 0 : switch (compl_desc->type) {
76 : 0 : case GVE_COMPL_TYPE_DQO_DESC:
77 : 0 : new_tx_head = rte_le_to_cpu_16(compl_desc->tx_head);
78 : 0 : aim_txq->nb_free +=
79 : 0 : (new_tx_head - aim_txq->last_desc_cleaned)
80 : 0 : & (aim_txq->nb_tx_desc - 1);
81 : 0 : aim_txq->last_desc_cleaned = new_tx_head;
82 : 0 : break;
83 : 0 : case GVE_COMPL_TYPE_DQO_REINJECTION:
84 : : PMD_DRV_DP_LOG(DEBUG, "GVE_COMPL_TYPE_DQO_REINJECTION !!!");
85 : : /* FALLTHROUGH */
86 : : case GVE_COMPL_TYPE_DQO_PKT:
87 : : /* The first segment has buf_id == completion_tag. */
88 : 0 : compl_tag = rte_le_to_cpu_16(compl_desc->completion_tag);
89 [ # # ]: 0 : if (unlikely(compl_tag >= txq->sw_size)) {
90 : 0 : PMD_DRV_DP_LOG(ERR, "Invalid completion tag %d",
91 : : compl_tag);
92 : 0 : break;
93 : : }
94 : :
95 : : /* Free packet.*/
96 : 0 : pkt = &aim_txq->pkt_ring_dqo[compl_tag];
97 [ # # ]: 0 : if (unlikely(!pkt->mbuf)) {
98 : 0 : PMD_DRV_DP_LOG(ERR, "No outstanding packet for completion tag %d",
99 : : compl_tag);
100 : 0 : break;
101 : : }
102 : 0 : rte_pktmbuf_free(pkt->mbuf);
103 : 0 : pkt->mbuf = NULL;
104 : : gve_free_compl_tags_push(txq, compl_tag);
105 : : break;
106 : 0 : case GVE_COMPL_TYPE_DQO_MISS:
107 : 0 : rte_delay_us_sleep(1);
108 : : PMD_DRV_DP_LOG(DEBUG, "GVE_COMPL_TYPE_DQO_MISS ignored !!!");
109 : 0 : break;
110 : 0 : default:
111 : 0 : PMD_DRV_DP_LOG(ERR, "unknown completion type.");
112 : 0 : return;
113 : : }
114 : :
115 : 0 : next++;
116 [ # # ]: 0 : if (next == txq->nb_complq_desc) {
117 : : next = 0;
118 : 0 : txq->cur_gen_bit ^= 1;
119 : : }
120 : 0 : txq->complq_tail = next;
121 : : }
122 : :
123 : : static inline void
124 : : gve_tx_clean_descs_dqo(struct gve_tx_queue *txq, uint16_t nb_descs) {
125 [ # # # # ]: 0 : while (--nb_descs)
126 : 0 : gve_tx_clean_dqo(txq);
127 : : }
128 : :
129 : : /* GVE expects at most 10 data descriptors per mtu-sized segment. Beyond this,
130 : : * the hardware will assume the driver is malicious and stop transmitting
131 : : * packets altogether. Validate that a packet can be sent to avoid sending
132 : : * posting descriptors for an invalid packet.
133 : : */
134 : : static inline bool
135 : 0 : gve_tx_validate_descs(struct rte_mbuf *tx_pkt, uint16_t nb_descs, bool is_tso)
136 : : {
137 [ # # ]: 0 : if (!is_tso)
138 : 0 : return nb_descs <= GVE_TX_MAX_DATA_DESCS;
139 : :
140 : 0 : int tso_segsz = tx_pkt->tso_segsz;
141 : : int num_descs, seg_offset, mbuf_len;
142 : 0 : int headlen = tx_pkt->l2_len + tx_pkt->l3_len + tx_pkt->l4_len;
143 : :
144 : : /* Headers will be split into their own buffer. */
145 : : num_descs = 1;
146 : : seg_offset = 0;
147 : 0 : mbuf_len = tx_pkt->data_len - headlen;
148 : :
149 [ # # ]: 0 : while (tx_pkt) {
150 [ # # ]: 0 : if (!mbuf_len)
151 : 0 : goto next_mbuf;
152 : :
153 : 0 : int seg_remain = tso_segsz - seg_offset;
154 [ # # ]: 0 : if (num_descs == GVE_TX_MAX_DATA_DESCS && seg_remain)
155 : : return false;
156 : :
157 [ # # ]: 0 : if (seg_remain < mbuf_len) {
158 : 0 : seg_offset = mbuf_len % tso_segsz;
159 : : /* The MSS is bound from above by 9728B, so a
160 : : * single TSO segment in the middle of an mbuf
161 : : * will be part of at most two descriptors, and
162 : : * is not at risk of defying this limitation.
163 : : * Thus, such segments are ignored.
164 : : */
165 : 0 : int mbuf_remain = tx_pkt->data_len % GVE_TX_MAX_BUF_SIZE_DQO;
166 : :
167 : : /* For each TSO segment, HW will prepend
168 : : * headers. The remaining bytes of this mbuf
169 : : * will be the start of the payload of the next
170 : : * TSO segment. In addition, if the final
171 : : * segment in this mbuf is divided between two
172 : : * descriptors, both must be counted.
173 : : */
174 [ # # ]: 0 : num_descs = 1 + !!(seg_offset) +
175 : 0 : (mbuf_remain < seg_offset && mbuf_remain);
176 : : } else {
177 : 0 : seg_offset += mbuf_len;
178 : 0 : num_descs++;
179 : : }
180 : :
181 : 0 : next_mbuf:
182 : 0 : tx_pkt = tx_pkt->next;
183 [ # # ]: 0 : if (tx_pkt)
184 : 0 : mbuf_len = tx_pkt->data_len;
185 : : }
186 : :
187 : :
188 : : return true;
189 : : }
190 : :
191 : : static uint16_t
192 : : gve_tx_pkt_nb_data_descs(struct rte_mbuf *tx_pkt)
193 : : {
194 : : int nb_descs = 0;
195 : :
196 [ # # ]: 0 : while (tx_pkt) {
197 : 0 : nb_descs += (GVE_TX_MAX_BUF_SIZE_DQO - 1 + tx_pkt->data_len) /
198 : : GVE_TX_MAX_BUF_SIZE_DQO;
199 : 0 : tx_pkt = tx_pkt->next;
200 : : }
201 : 0 : return nb_descs;
202 : : }
203 : :
204 : : static inline bool
205 : : gve_can_tx(struct gve_tx_queue *txq, uint16_t nb_desc, uint16_t nb_pkts)
206 : : {
207 [ # # # # : 0 : return txq->nb_free >= nb_desc && txq->num_free_compl_tags >= nb_pkts;
# # # # ]
208 : : }
209 : :
210 : : static inline void
211 : : gve_tx_fill_seg_desc_dqo(volatile union gve_tx_desc_dqo *desc, struct rte_mbuf *tx_pkt)
212 : : {
213 : 0 : uint32_t hlen = tx_pkt->l2_len + tx_pkt->l3_len + tx_pkt->l4_len;
214 : :
215 : 0 : desc->tso_ctx = (struct gve_tx_tso_context_desc_dqo) {};
216 : 0 : desc->tso_ctx.cmd_dtype.dtype = GVE_TX_TSO_CTX_DESC_DTYPE_DQO;
217 : 0 : desc->tso_ctx.cmd_dtype.tso = 1;
218 : 0 : desc->tso_ctx.mss = (uint16_t)tx_pkt->tso_segsz;
219 : 0 : desc->tso_ctx.tso_total_len = tx_pkt->pkt_len - hlen;
220 : 0 : desc->tso_ctx.header_len = (uint8_t)hlen;
221 : : }
222 : :
223 : : static void
224 : 0 : gve_fill_tx_pkt_desc(struct gve_tx_queue *txq, uint16_t *tx_id,
225 : : struct rte_mbuf *tx_pkt, uint16_t compl_tag,
226 : : bool checksum_offload_enable)
227 : : {
228 : : volatile union gve_tx_desc_dqo *desc;
229 : 0 : uint16_t mask = txq->nb_tx_desc - 1;
230 : : int mbuf_offset = 0;
231 : :
232 [ # # ]: 0 : while (mbuf_offset < tx_pkt->data_len) {
233 : 0 : uint64_t buf_addr = rte_mbuf_data_iova(tx_pkt) + mbuf_offset;
234 : :
235 : 0 : desc = &txq->tx_ring[*tx_id];
236 : 0 : desc->pkt = (struct gve_tx_pkt_desc_dqo) {};
237 : 0 : desc->pkt.buf_addr = rte_cpu_to_le_64(buf_addr);
238 : 0 : desc->pkt.compl_tag = rte_cpu_to_le_16(compl_tag);
239 : 0 : desc->pkt.dtype = GVE_TX_PKT_DESC_DTYPE_DQO;
240 : 0 : desc->pkt.buf_size = RTE_MIN(tx_pkt->data_len - mbuf_offset,
241 : : GVE_TX_MAX_BUF_SIZE_DQO);
242 : 0 : desc->pkt.end_of_packet = 0;
243 : 0 : desc->pkt.checksum_offload_enable = checksum_offload_enable;
244 : :
245 : 0 : mbuf_offset += desc->pkt.buf_size;
246 : 0 : *tx_id = (*tx_id + 1) & mask;
247 : : }
248 : 0 : }
249 : :
250 : : uint16_t
251 : 0 : gve_tx_burst_dqo(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
252 : : {
253 : : struct gve_tx_queue *txq = tx_queue;
254 : : volatile union gve_tx_desc_dqo *txr;
255 : : volatile union gve_tx_desc_dqo *txd;
256 : 0 : uint16_t mask = txq->nb_tx_desc - 1;
257 : : struct gve_tx_pkt *pkts;
258 : : struct rte_mbuf *tx_pkt;
259 : : uint16_t compl_tag;
260 : : const char *reason;
261 : : uint16_t nb_tx = 0;
262 : : uint64_t bytes = 0;
263 : : uint64_t ol_flags;
264 : : uint16_t nb_descs;
265 : : bool csum, tso;
266 : : uint16_t tx_id;
267 : :
268 : 0 : pkts = txq->pkt_ring_dqo;
269 : 0 : txr = txq->tx_ring;
270 : :
271 : 0 : tx_id = txq->tx_tail;
272 : :
273 [ # # ]: 0 : for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
274 : 0 : tx_pkt = tx_pkts[nb_tx];
275 : :
276 [ # # # # ]: 0 : if (!gve_can_tx(txq, txq->free_thresh, nb_pkts - nb_tx))
277 : 0 : gve_tx_clean_descs_dqo(txq, DQO_TX_MULTIPLIER *
278 : 0 : txq->rs_thresh);
279 : :
280 : :
281 [ # # ]: 0 : if (rte_mbuf_check(tx_pkt, true, &reason)) {
282 : : PMD_DRV_DP_LOG(DEBUG, "Invalid mbuf: %s", reason);
283 : : break;
284 : : }
285 : :
286 : 0 : ol_flags = tx_pkt->ol_flags;
287 : 0 : tso = !!(ol_flags & RTE_MBUF_F_TX_TCP_SEG);
288 : 0 : csum = !!(ol_flags & GVE_TX_CKSUM_OFFLOAD_MASK_DQO);
289 : :
290 : : nb_descs = gve_tx_pkt_nb_data_descs(tx_pkt);
291 : 0 : nb_descs += tso;
292 : :
293 : : /* Clean if there aren't enough descriptors to send the packet. */
294 [ # # # # ]: 0 : if (unlikely(!gve_can_tx(txq, nb_descs, 1))) {
295 : 0 : int nb_to_clean = RTE_MAX(DQO_TX_MULTIPLIER * txq->rs_thresh,
296 : : nb_descs);
297 : :
298 : 0 : gve_tx_clean_descs_dqo(txq, nb_to_clean);
299 [ # # ]: 0 : if (!gve_can_tx(txq, nb_descs, 1))
300 : : break;
301 : : }
302 : :
303 : : /* Drop packet if it doesn't adhere to hardware limits. */
304 [ # # ]: 0 : if (!gve_tx_validate_descs(tx_pkt, nb_descs, tso)) {
305 : 0 : txq->stats.too_many_descs++;
306 : 0 : break;
307 : : }
308 : :
309 [ # # ]: 0 : if (tso) {
310 : 0 : txd = &txr[tx_id];
311 : : gve_tx_fill_seg_desc_dqo(txd, tx_pkt);
312 : 0 : tx_id = (tx_id + 1) & mask;
313 : : }
314 : :
315 [ # # ]: 0 : if (!gve_free_compl_tags_pop(txq, &compl_tag))
316 : : break;
317 : :
318 : 0 : pkts[compl_tag].mbuf = tx_pkt;
319 [ # # ]: 0 : while (tx_pkt) {
320 : : /* Skip writing descriptors if mbuf has no data. */
321 [ # # ]: 0 : if (!tx_pkt->data_len) {
322 : 0 : tx_pkt = tx_pkt->next;
323 : 0 : continue;
324 : : }
325 : 0 : gve_fill_tx_pkt_desc(txq, &tx_id, tx_pkt, compl_tag,
326 : : csum);
327 : 0 : bytes += tx_pkt->data_len;
328 : 0 : tx_pkt = tx_pkt->next;
329 : : }
330 : : /* fill the last written descriptor with End of Packet (EOP) bit */
331 : 0 : txd = &txr[(tx_id - 1) & mask];
332 : 0 : txd->pkt.end_of_packet = 1;
333 : :
334 : 0 : txq->nb_free -= nb_descs;
335 : 0 : txq->nb_used += nb_descs;
336 : : }
337 : :
338 : : /* update the tail pointer if any packets were processed */
339 [ # # ]: 0 : if (nb_tx > 0) {
340 : : /* Request a descriptor completion on the last descriptor */
341 : 0 : txq->re_cnt += nb_tx;
342 [ # # ]: 0 : if (txq->re_cnt >= GVE_TX_MIN_RE_INTERVAL) {
343 : 0 : txd = &txr[(tx_id - 1) & mask];
344 : 0 : txd->pkt.report_event = true;
345 : 0 : txq->re_cnt = 0;
346 : : }
347 : :
348 : 0 : rte_write32(tx_id, txq->qtx_tail);
349 : 0 : txq->tx_tail = tx_id;
350 : :
351 : 0 : txq->stats.packets += nb_tx;
352 : 0 : txq->stats.bytes += bytes;
353 : 0 : txq->stats.errors += nb_pkts - nb_tx;
354 : : }
355 : :
356 : 0 : return nb_tx;
357 : : }
358 : :
359 : : static inline void
360 : : gve_release_txq_mbufs_dqo(struct gve_tx_queue *txq)
361 : : {
362 : : uint16_t i;
363 : :
364 [ # # # # ]: 0 : for (i = 0; i < txq->sw_size; i++)
365 : 0 : rte_pktmbuf_free(txq->pkt_ring_dqo[i].mbuf);
366 : : }
367 : :
368 : : void
369 : 0 : gve_tx_queue_release_dqo(struct rte_eth_dev *dev, uint16_t qid)
370 : : {
371 : 0 : struct gve_tx_queue *q = dev->data->tx_queues[qid];
372 : :
373 [ # # ]: 0 : if (q == NULL)
374 : : return;
375 : :
376 : : gve_release_txq_mbufs_dqo(q);
377 : 0 : rte_free(q->pkt_ring_dqo);
378 : 0 : rte_memzone_free(q->mz);
379 : 0 : rte_memzone_free(q->compl_ring_mz);
380 : 0 : rte_memzone_free(q->qres_mz);
381 : 0 : q->qres = NULL;
382 : 0 : rte_free(q);
383 : :
384 : 0 : dev->data->tx_queues[qid] = NULL;
385 : : }
386 : :
387 : : static int
388 : 0 : check_tx_thresh_dqo(uint16_t nb_desc, uint16_t tx_rs_thresh,
389 : : uint16_t tx_free_thresh)
390 : : {
391 [ # # ]: 0 : if (tx_rs_thresh >= (nb_desc - 2)) {
392 : 0 : PMD_DRV_LOG(ERR, "tx_rs_thresh (%u) must be less than the "
393 : : "number of TX descriptors (%u) minus 2",
394 : : tx_rs_thresh, nb_desc);
395 : 0 : return -EINVAL;
396 : : }
397 [ # # ]: 0 : if (tx_free_thresh >= (nb_desc - 3)) {
398 : 0 : PMD_DRV_LOG(ERR, "tx_free_thresh (%u) must be less than the "
399 : : "number of TX descriptors (%u) minus 3.",
400 : : tx_free_thresh, nb_desc);
401 : 0 : return -EINVAL;
402 : : }
403 [ # # ]: 0 : if (tx_rs_thresh > tx_free_thresh) {
404 : 0 : PMD_DRV_LOG(ERR, "tx_rs_thresh (%u) must be less than or "
405 : : "equal to tx_free_thresh (%u).",
406 : : tx_rs_thresh, tx_free_thresh);
407 : 0 : return -EINVAL;
408 : : }
409 [ # # ]: 0 : if ((nb_desc % tx_rs_thresh) != 0) {
410 : 0 : PMD_DRV_LOG(ERR, "tx_rs_thresh (%u) must be a divisor of the "
411 : : "number of TX descriptors (%u).",
412 : : tx_rs_thresh, nb_desc);
413 : 0 : return -EINVAL;
414 : : }
415 : :
416 : : return 0;
417 : : }
418 : :
419 : : static void
420 : 0 : gve_reset_tx_ring_state_dqo(struct gve_tx_queue *txq)
421 : : {
422 : : struct gve_tx_pkt *pkt_ring_dqo;
423 : : uint32_t size, i;
424 : :
425 [ # # ]: 0 : if (txq == NULL) {
426 : 0 : PMD_DRV_LOG(ERR, "Pointer to txq is NULL");
427 : 0 : return;
428 : : }
429 : :
430 : 0 : size = txq->nb_tx_desc * sizeof(union gve_tx_desc_dqo);
431 [ # # ]: 0 : for (i = 0; i < size; i++)
432 : 0 : ((volatile char *)txq->tx_ring)[i] = 0;
433 : :
434 : 0 : size = txq->nb_complq_desc * sizeof(struct gve_tx_compl_desc);
435 [ # # ]: 0 : for (i = 0; i < size; i++)
436 : 0 : ((volatile char *)txq->compl_ring)[i] = 0;
437 : :
438 : 0 : pkt_ring_dqo = txq->pkt_ring_dqo;
439 [ # # ]: 0 : for (i = 0; i < txq->sw_size; i++)
440 : 0 : pkt_ring_dqo[i].mbuf = NULL;
441 : :
442 : : gve_free_compl_tags_init(txq);
443 : :
444 : 0 : txq->tx_tail = 0;
445 : 0 : txq->nb_used = 0;
446 : :
447 : 0 : txq->last_desc_cleaned = 0;
448 : 0 : txq->nb_free = txq->nb_tx_desc - 1;
449 : :
450 : 0 : txq->complq_tail = 0;
451 : 0 : txq->cur_gen_bit = 1;
452 : : }
453 : :
454 : : int
455 : 0 : gve_tx_queue_setup_dqo(struct rte_eth_dev *dev, uint16_t queue_id,
456 : : uint16_t nb_desc, unsigned int socket_id,
457 : : const struct rte_eth_txconf *conf)
458 : : {
459 : 0 : struct gve_priv *hw = dev->data->dev_private;
460 : : const struct rte_memzone *mz;
461 : : struct gve_tx_queue *txq;
462 : : uint16_t free_thresh;
463 : : uint16_t rs_thresh;
464 : : uint16_t sw_size;
465 : : int err = 0;
466 : :
467 : : /* Free memory if needed. */
468 [ # # ]: 0 : if (dev->data->tx_queues[queue_id]) {
469 : 0 : gve_tx_queue_release_dqo(dev, queue_id);
470 : 0 : dev->data->tx_queues[queue_id] = NULL;
471 : : }
472 : :
473 : : /* Allocate the TX queue data structure. */
474 : 0 : txq = rte_zmalloc_socket("gve txq",
475 : : sizeof(struct gve_tx_queue),
476 : : RTE_CACHE_LINE_SIZE, socket_id);
477 [ # # ]: 0 : if (txq == NULL) {
478 : 0 : PMD_DRV_LOG(ERR, "Failed to allocate memory for tx queue structure");
479 : 0 : return -ENOMEM;
480 : : }
481 : :
482 : : /* need to check free_thresh here */
483 [ # # ]: 0 : free_thresh = conf->tx_free_thresh ?
484 : : conf->tx_free_thresh : GVE_DEFAULT_TX_FREE_THRESH;
485 [ # # ]: 0 : rs_thresh = conf->tx_rs_thresh ?
486 : : conf->tx_rs_thresh : GVE_DEFAULT_TX_RS_THRESH;
487 [ # # ]: 0 : if (check_tx_thresh_dqo(nb_desc, rs_thresh, free_thresh))
488 : : return -EINVAL;
489 : :
490 : 0 : txq->nb_tx_desc = nb_desc;
491 : 0 : txq->nb_complq_desc = nb_desc * DQO_TX_MULTIPLIER;
492 : 0 : txq->free_thresh = free_thresh;
493 : 0 : txq->rs_thresh = rs_thresh;
494 : 0 : txq->queue_id = queue_id;
495 : 0 : txq->port_id = dev->data->port_id;
496 : 0 : txq->ntfy_id = queue_id;
497 : 0 : txq->hw = hw;
498 [ # # ]: 0 : txq->ntfy_addr = &hw->db_bar2[rte_be_to_cpu_32(hw->irq_dbs[txq->ntfy_id].id)];
499 : :
500 : : /* Allocate software ring */
501 : : sw_size = nb_desc;
502 : 0 : txq->pkt_ring_dqo = rte_zmalloc_socket("gve tx sw ring",
503 : : sw_size * sizeof(struct gve_tx_pkt),
504 : : RTE_CACHE_LINE_SIZE, socket_id);
505 [ # # ]: 0 : if (txq->pkt_ring_dqo == NULL) {
506 : 0 : PMD_DRV_LOG(ERR, "Failed to allocate memory for SW TX ring");
507 : : err = -ENOMEM;
508 : 0 : goto free_txq;
509 : : }
510 : 0 : txq->sw_size = sw_size;
511 : :
512 : : /* Allocate TX hardware ring descriptors. */
513 : 0 : mz = rte_eth_dma_zone_reserve(dev, "tx_ring", queue_id,
514 : : nb_desc * sizeof(union gve_tx_desc_dqo),
515 : : PAGE_SIZE, socket_id);
516 [ # # ]: 0 : if (mz == NULL) {
517 : 0 : PMD_DRV_LOG(ERR, "Failed to reserve DMA memory for TX");
518 : : err = -ENOMEM;
519 : 0 : goto free_txq_pkt_ring;
520 : : }
521 : 0 : txq->tx_ring = (union gve_tx_desc_dqo *)mz->addr;
522 : 0 : txq->tx_ring_phys_addr = mz->iova;
523 : 0 : txq->mz = mz;
524 : :
525 : : /* Allocate TX completion ring descriptors. */
526 : 0 : mz = rte_eth_dma_zone_reserve(dev, "tx_compl_ring", queue_id,
527 : 0 : txq->nb_complq_desc * sizeof(struct gve_tx_compl_desc),
528 : : PAGE_SIZE, socket_id);
529 [ # # ]: 0 : if (mz == NULL) {
530 : 0 : PMD_DRV_LOG(ERR, "Failed to reserve DMA memory for TX completion queue");
531 : : err = -ENOMEM;
532 : 0 : goto free_txq_mz;
533 : : }
534 : 0 : txq->compl_ring = (struct gve_tx_compl_desc *)mz->addr;
535 : 0 : txq->compl_ring_phys_addr = mz->iova;
536 : 0 : txq->compl_ring_mz = mz;
537 : 0 : txq->txqs = dev->data->tx_queues;
538 : :
539 : 0 : mz = rte_eth_dma_zone_reserve(dev, "txq_res", queue_id,
540 : : sizeof(struct gve_queue_resources),
541 : : PAGE_SIZE, socket_id);
542 [ # # ]: 0 : if (mz == NULL) {
543 : 0 : PMD_DRV_LOG(ERR, "Failed to reserve DMA memory for TX resource");
544 : : err = -ENOMEM;
545 : 0 : goto free_txq_cq_mz;
546 : : }
547 : 0 : txq->qres = (struct gve_queue_resources *)mz->addr;
548 : 0 : txq->qres_mz = mz;
549 : :
550 : 0 : gve_reset_tx_ring_state_dqo(txq);
551 : :
552 : 0 : dev->data->tx_queues[queue_id] = txq;
553 : :
554 : 0 : return 0;
555 : :
556 : : free_txq_cq_mz:
557 : 0 : rte_memzone_free(txq->compl_ring_mz);
558 : 0 : free_txq_mz:
559 : 0 : rte_memzone_free(txq->mz);
560 : 0 : free_txq_pkt_ring:
561 : 0 : rte_free(txq->pkt_ring_dqo);
562 : 0 : free_txq:
563 : 0 : rte_free(txq);
564 : 0 : return err;
565 : : }
566 : :
567 : : int
568 : 0 : gve_tx_queue_start_dqo(struct rte_eth_dev *dev, uint16_t tx_queue_id)
569 : : {
570 : 0 : struct gve_priv *hw = dev->data->dev_private;
571 : : struct gve_tx_queue *txq;
572 : :
573 [ # # ]: 0 : if (tx_queue_id >= dev->data->nb_tx_queues)
574 : : return -EINVAL;
575 : :
576 : 0 : txq = dev->data->tx_queues[tx_queue_id];
577 : :
578 [ # # ]: 0 : txq->qtx_tail = &hw->db_bar2[rte_be_to_cpu_32(txq->qres->db_index)];
579 : 0 : txq->qtx_head =
580 [ # # ]: 0 : &hw->cnt_array[rte_be_to_cpu_32(txq->qres->counter_index)];
581 : :
582 : : rte_write32(rte_cpu_to_le_32(GVE_NO_INT_MODE_DQO |
583 : : GVE_ITR_NO_UPDATE_DQO),
584 : 0 : txq->ntfy_addr);
585 : :
586 : 0 : dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STARTED;
587 : :
588 : 0 : return 0;
589 : : }
590 : :
591 : : int
592 : 0 : gve_tx_queue_stop_dqo(struct rte_eth_dev *dev, uint16_t tx_queue_id)
593 : : {
594 : : struct gve_tx_queue *txq;
595 : :
596 [ # # ]: 0 : if (tx_queue_id >= dev->data->nb_tx_queues)
597 : : return -EINVAL;
598 : :
599 : 0 : txq = dev->data->tx_queues[tx_queue_id];
600 : : gve_release_txq_mbufs_dqo(txq);
601 : 0 : gve_reset_tx_ring_state_dqo(txq);
602 : :
603 : 0 : dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
604 : :
605 : 0 : return 0;
606 : : }
607 : :
608 : : void
609 : 0 : gve_stop_tx_queues_dqo(struct rte_eth_dev *dev)
610 : : {
611 : 0 : struct gve_priv *hw = dev->data->dev_private;
612 : : uint16_t i;
613 : : int err;
614 : :
615 : 0 : err = gve_adminq_destroy_tx_queues(hw, dev->data->nb_tx_queues);
616 [ # # ]: 0 : if (err != 0)
617 : 0 : PMD_DRV_LOG(WARNING, "failed to destroy txqs");
618 : :
619 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++)
620 [ # # ]: 0 : if (gve_tx_queue_stop_dqo(dev, i) != 0)
621 : 0 : PMD_DRV_LOG(WARNING, "Fail to stop Tx queue %d", i);
622 : 0 : }
623 : :
624 : : void
625 : 0 : gve_set_tx_function_dqo(struct rte_eth_dev *dev)
626 : : {
627 : 0 : dev->tx_pkt_burst = gve_tx_burst_dqo;
628 : 0 : }
|