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 : :
385 : : static int
386 : 0 : check_tx_thresh_dqo(uint16_t nb_desc, uint16_t tx_rs_thresh,
387 : : uint16_t tx_free_thresh)
388 : : {
389 [ # # ]: 0 : if (tx_rs_thresh >= (nb_desc - 2)) {
390 : 0 : PMD_DRV_LOG(ERR, "tx_rs_thresh (%u) must be less than the "
391 : : "number of TX descriptors (%u) minus 2",
392 : : tx_rs_thresh, nb_desc);
393 : 0 : return -EINVAL;
394 : : }
395 [ # # ]: 0 : if (tx_free_thresh >= (nb_desc - 3)) {
396 : 0 : PMD_DRV_LOG(ERR, "tx_free_thresh (%u) must be less than the "
397 : : "number of TX descriptors (%u) minus 3.",
398 : : tx_free_thresh, nb_desc);
399 : 0 : return -EINVAL;
400 : : }
401 [ # # ]: 0 : if (tx_rs_thresh > tx_free_thresh) {
402 : 0 : PMD_DRV_LOG(ERR, "tx_rs_thresh (%u) must be less than or "
403 : : "equal to tx_free_thresh (%u).",
404 : : tx_rs_thresh, tx_free_thresh);
405 : 0 : return -EINVAL;
406 : : }
407 [ # # ]: 0 : if ((nb_desc % tx_rs_thresh) != 0) {
408 : 0 : PMD_DRV_LOG(ERR, "tx_rs_thresh (%u) must be a divisor of the "
409 : : "number of TX descriptors (%u).",
410 : : tx_rs_thresh, nb_desc);
411 : 0 : return -EINVAL;
412 : : }
413 : :
414 : : return 0;
415 : : }
416 : :
417 : : static void
418 : 0 : gve_reset_tx_ring_state_dqo(struct gve_tx_queue *txq)
419 : : {
420 : : struct gve_tx_pkt *pkt_ring_dqo;
421 : : uint32_t size, i;
422 : :
423 [ # # ]: 0 : if (txq == NULL) {
424 : 0 : PMD_DRV_LOG(ERR, "Pointer to txq is NULL");
425 : 0 : return;
426 : : }
427 : :
428 : 0 : size = txq->nb_tx_desc * sizeof(union gve_tx_desc_dqo);
429 [ # # ]: 0 : for (i = 0; i < size; i++)
430 : 0 : ((volatile char *)txq->tx_ring)[i] = 0;
431 : :
432 : 0 : size = txq->nb_complq_desc * sizeof(struct gve_tx_compl_desc);
433 [ # # ]: 0 : for (i = 0; i < size; i++)
434 : 0 : ((volatile char *)txq->compl_ring)[i] = 0;
435 : :
436 : 0 : pkt_ring_dqo = txq->pkt_ring_dqo;
437 [ # # ]: 0 : for (i = 0; i < txq->sw_size; i++)
438 : 0 : pkt_ring_dqo[i].mbuf = NULL;
439 : :
440 : : gve_free_compl_tags_init(txq);
441 : :
442 : 0 : txq->tx_tail = 0;
443 : 0 : txq->nb_used = 0;
444 : :
445 : 0 : txq->last_desc_cleaned = 0;
446 : 0 : txq->nb_free = txq->nb_tx_desc - 1;
447 : :
448 : 0 : txq->complq_tail = 0;
449 : 0 : txq->cur_gen_bit = 1;
450 : : }
451 : :
452 : : int
453 : 0 : gve_tx_queue_setup_dqo(struct rte_eth_dev *dev, uint16_t queue_id,
454 : : uint16_t nb_desc, unsigned int socket_id,
455 : : const struct rte_eth_txconf *conf)
456 : : {
457 : 0 : struct gve_priv *hw = dev->data->dev_private;
458 : : const struct rte_memzone *mz;
459 : : struct gve_tx_queue *txq;
460 : : uint16_t free_thresh;
461 : : uint16_t rs_thresh;
462 : : uint16_t sw_size;
463 : : int err = 0;
464 : :
465 : : /* Free memory if needed. */
466 [ # # ]: 0 : if (dev->data->tx_queues[queue_id]) {
467 : 0 : gve_tx_queue_release_dqo(dev, queue_id);
468 : 0 : dev->data->tx_queues[queue_id] = NULL;
469 : : }
470 : :
471 : : /* Allocate the TX queue data structure. */
472 : 0 : txq = rte_zmalloc_socket("gve txq",
473 : : sizeof(struct gve_tx_queue),
474 : : RTE_CACHE_LINE_SIZE, socket_id);
475 [ # # ]: 0 : if (txq == NULL) {
476 : 0 : PMD_DRV_LOG(ERR, "Failed to allocate memory for tx queue structure");
477 : 0 : return -ENOMEM;
478 : : }
479 : :
480 : : /* need to check free_thresh here */
481 [ # # ]: 0 : free_thresh = conf->tx_free_thresh ?
482 : : conf->tx_free_thresh : GVE_DEFAULT_TX_FREE_THRESH;
483 [ # # ]: 0 : rs_thresh = conf->tx_rs_thresh ?
484 : : conf->tx_rs_thresh : GVE_DEFAULT_TX_RS_THRESH;
485 [ # # ]: 0 : if (check_tx_thresh_dqo(nb_desc, rs_thresh, free_thresh))
486 : : return -EINVAL;
487 : :
488 : 0 : txq->nb_tx_desc = nb_desc;
489 : 0 : txq->nb_complq_desc = nb_desc * DQO_TX_MULTIPLIER;
490 : 0 : txq->free_thresh = free_thresh;
491 : 0 : txq->rs_thresh = rs_thresh;
492 : 0 : txq->queue_id = queue_id;
493 : 0 : txq->port_id = dev->data->port_id;
494 : 0 : txq->ntfy_id = queue_id;
495 : 0 : txq->hw = hw;
496 [ # # ]: 0 : txq->ntfy_addr = &hw->db_bar2[rte_be_to_cpu_32(hw->irq_dbs[txq->ntfy_id].id)];
497 : :
498 : : /* Allocate software ring */
499 : : sw_size = nb_desc;
500 : 0 : txq->pkt_ring_dqo = rte_zmalloc_socket("gve tx sw ring",
501 : : sw_size * sizeof(struct gve_tx_pkt),
502 : : RTE_CACHE_LINE_SIZE, socket_id);
503 [ # # ]: 0 : if (txq->pkt_ring_dqo == NULL) {
504 : 0 : PMD_DRV_LOG(ERR, "Failed to allocate memory for SW TX ring");
505 : : err = -ENOMEM;
506 : 0 : goto free_txq;
507 : : }
508 : 0 : txq->sw_size = sw_size;
509 : :
510 : : /* Allocate TX hardware ring descriptors. */
511 : 0 : mz = rte_eth_dma_zone_reserve(dev, "tx_ring", queue_id,
512 : : nb_desc * sizeof(union gve_tx_desc_dqo),
513 : : PAGE_SIZE, socket_id);
514 [ # # ]: 0 : if (mz == NULL) {
515 : 0 : PMD_DRV_LOG(ERR, "Failed to reserve DMA memory for TX");
516 : : err = -ENOMEM;
517 : 0 : goto free_txq_pkt_ring;
518 : : }
519 : 0 : txq->tx_ring = (union gve_tx_desc_dqo *)mz->addr;
520 : 0 : txq->tx_ring_phys_addr = mz->iova;
521 : 0 : txq->mz = mz;
522 : :
523 : : /* Allocate TX completion ring descriptors. */
524 : 0 : mz = rte_eth_dma_zone_reserve(dev, "tx_compl_ring", queue_id,
525 : 0 : txq->nb_complq_desc * sizeof(struct gve_tx_compl_desc),
526 : : PAGE_SIZE, socket_id);
527 [ # # ]: 0 : if (mz == NULL) {
528 : 0 : PMD_DRV_LOG(ERR, "Failed to reserve DMA memory for TX completion queue");
529 : : err = -ENOMEM;
530 : 0 : goto free_txq_mz;
531 : : }
532 : 0 : txq->compl_ring = (struct gve_tx_compl_desc *)mz->addr;
533 : 0 : txq->compl_ring_phys_addr = mz->iova;
534 : 0 : txq->compl_ring_mz = mz;
535 : 0 : txq->txqs = dev->data->tx_queues;
536 : :
537 : 0 : mz = rte_eth_dma_zone_reserve(dev, "txq_res", queue_id,
538 : : sizeof(struct gve_queue_resources),
539 : : PAGE_SIZE, socket_id);
540 [ # # ]: 0 : if (mz == NULL) {
541 : 0 : PMD_DRV_LOG(ERR, "Failed to reserve DMA memory for TX resource");
542 : : err = -ENOMEM;
543 : 0 : goto free_txq_cq_mz;
544 : : }
545 : 0 : txq->qres = (struct gve_queue_resources *)mz->addr;
546 : 0 : txq->qres_mz = mz;
547 : :
548 : 0 : gve_reset_tx_ring_state_dqo(txq);
549 : :
550 : 0 : dev->data->tx_queues[queue_id] = txq;
551 : :
552 : 0 : return 0;
553 : :
554 : : free_txq_cq_mz:
555 : 0 : rte_memzone_free(txq->compl_ring_mz);
556 : 0 : free_txq_mz:
557 : 0 : rte_memzone_free(txq->mz);
558 : 0 : free_txq_pkt_ring:
559 : 0 : rte_free(txq->pkt_ring_dqo);
560 : 0 : free_txq:
561 : 0 : rte_free(txq);
562 : 0 : return err;
563 : : }
564 : :
565 : : int
566 : 0 : gve_tx_queue_start_dqo(struct rte_eth_dev *dev, uint16_t tx_queue_id)
567 : : {
568 : 0 : struct gve_priv *hw = dev->data->dev_private;
569 : : struct gve_tx_queue *txq;
570 : :
571 [ # # ]: 0 : if (tx_queue_id >= dev->data->nb_tx_queues)
572 : : return -EINVAL;
573 : :
574 : 0 : txq = dev->data->tx_queues[tx_queue_id];
575 : :
576 [ # # ]: 0 : txq->qtx_tail = &hw->db_bar2[rte_be_to_cpu_32(txq->qres->db_index)];
577 : 0 : txq->qtx_head =
578 [ # # ]: 0 : &hw->cnt_array[rte_be_to_cpu_32(txq->qres->counter_index)];
579 : :
580 : : rte_write32(rte_cpu_to_le_32(GVE_NO_INT_MODE_DQO |
581 : : GVE_ITR_NO_UPDATE_DQO),
582 : 0 : txq->ntfy_addr);
583 : :
584 : 0 : dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STARTED;
585 : :
586 : 0 : return 0;
587 : : }
588 : :
589 : : int
590 : 0 : gve_tx_queue_stop_dqo(struct rte_eth_dev *dev, uint16_t tx_queue_id)
591 : : {
592 : : struct gve_tx_queue *txq;
593 : :
594 [ # # ]: 0 : if (tx_queue_id >= dev->data->nb_tx_queues)
595 : : return -EINVAL;
596 : :
597 : 0 : txq = dev->data->tx_queues[tx_queue_id];
598 : : gve_release_txq_mbufs_dqo(txq);
599 : 0 : gve_reset_tx_ring_state_dqo(txq);
600 : :
601 : 0 : dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
602 : :
603 : 0 : return 0;
604 : : }
605 : :
606 : : void
607 : 0 : gve_stop_tx_queues_dqo(struct rte_eth_dev *dev)
608 : : {
609 : 0 : struct gve_priv *hw = dev->data->dev_private;
610 : : uint16_t i;
611 : : int err;
612 : :
613 : 0 : err = gve_adminq_destroy_tx_queues(hw, dev->data->nb_tx_queues);
614 [ # # ]: 0 : if (err != 0)
615 : 0 : PMD_DRV_LOG(WARNING, "failed to destroy txqs");
616 : :
617 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++)
618 [ # # ]: 0 : if (gve_tx_queue_stop_dqo(dev, i) != 0)
619 : 0 : PMD_DRV_LOG(WARNING, "Fail to stop Tx queue %d", i);
620 : 0 : }
621 : :
622 : : void
623 : 0 : gve_set_tx_function_dqo(struct rte_eth_dev *dev)
624 : : {
625 : 0 : dev->tx_pkt_burst = gve_tx_burst_dqo;
626 : 0 : }
|