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 : :
9 : : static inline void
10 : 0 : gve_tx_clean_dqo(struct gve_tx_queue *txq)
11 : : {
12 : : struct gve_tx_compl_desc *compl_ring;
13 : : struct gve_tx_compl_desc *compl_desc;
14 : : struct gve_tx_queue *aim_txq;
15 : : uint16_t nb_desc_clean;
16 : : struct rte_mbuf *txe, *txe_next;
17 : : uint16_t compl_tag;
18 : : uint16_t next;
19 : :
20 : 0 : next = txq->complq_tail;
21 : 0 : compl_ring = txq->compl_ring;
22 : 0 : compl_desc = &compl_ring[next];
23 : :
24 [ # # ]: 0 : if (compl_desc->generation != txq->cur_gen_bit)
25 : : return;
26 : :
27 : 0 : rte_io_rmb();
28 : :
29 : 0 : compl_tag = rte_le_to_cpu_16(compl_desc->completion_tag);
30 : :
31 : 0 : aim_txq = txq->txqs[compl_desc->id];
32 : :
33 [ # # # # : 0 : switch (compl_desc->type) {
# ]
34 : 0 : case GVE_COMPL_TYPE_DQO_DESC:
35 : : /* need to clean Descs from last_cleaned to compl_tag */
36 [ # # ]: 0 : if (aim_txq->last_desc_cleaned > compl_tag)
37 : 0 : nb_desc_clean = aim_txq->nb_tx_desc - aim_txq->last_desc_cleaned +
38 : : compl_tag;
39 : : else
40 : 0 : nb_desc_clean = compl_tag - aim_txq->last_desc_cleaned;
41 : 0 : aim_txq->nb_free += nb_desc_clean;
42 : 0 : aim_txq->last_desc_cleaned = compl_tag;
43 : 0 : break;
44 : 0 : case GVE_COMPL_TYPE_DQO_REINJECTION:
45 : 0 : PMD_DRV_LOG(DEBUG, "GVE_COMPL_TYPE_DQO_REINJECTION !!!");
46 : : /* FALLTHROUGH */
47 : 0 : case GVE_COMPL_TYPE_DQO_PKT:
48 : : /* free all segments. */
49 : 0 : txe = aim_txq->sw_ring[compl_tag];
50 [ # # ]: 0 : while (txe != NULL) {
51 : 0 : txe_next = txe->next;
52 : : rte_pktmbuf_free_seg(txe);
53 [ # # ]: 0 : if (aim_txq->sw_ring[compl_tag] == txe)
54 : 0 : aim_txq->sw_ring[compl_tag] = NULL;
55 : : txe = txe_next;
56 : 0 : compl_tag = (compl_tag + 1) & (aim_txq->sw_size - 1);
57 : : }
58 : : break;
59 : 0 : case GVE_COMPL_TYPE_DQO_MISS:
60 : 0 : rte_delay_us_sleep(1);
61 : 0 : PMD_DRV_LOG(DEBUG, "GVE_COMPL_TYPE_DQO_MISS ignored !!!");
62 : 0 : break;
63 : 0 : default:
64 : 0 : PMD_DRV_LOG(ERR, "unknown completion type.");
65 : 0 : return;
66 : : }
67 : :
68 : 0 : next++;
69 [ # # ]: 0 : if (next == txq->nb_tx_desc * DQO_TX_MULTIPLIER) {
70 : : next = 0;
71 : 0 : txq->cur_gen_bit ^= 1;
72 : : }
73 : :
74 : 0 : txq->complq_tail = next;
75 : : }
76 : :
77 : : static inline void
78 : : gve_tx_fill_seg_desc_dqo(volatile union gve_tx_desc_dqo *desc, struct rte_mbuf *tx_pkt)
79 : : {
80 : 0 : uint32_t hlen = tx_pkt->l2_len + tx_pkt->l3_len + tx_pkt->l4_len;
81 : 0 : desc->tso_ctx.cmd_dtype.dtype = GVE_TX_TSO_CTX_DESC_DTYPE_DQO;
82 : 0 : desc->tso_ctx.cmd_dtype.tso = 1;
83 : 0 : desc->tso_ctx.mss = (uint16_t)tx_pkt->tso_segsz;
84 : 0 : desc->tso_ctx.tso_total_len = tx_pkt->pkt_len - hlen;
85 : 0 : desc->tso_ctx.header_len = (uint8_t)hlen;
86 : : }
87 : :
88 : : uint16_t
89 : 0 : gve_tx_burst_dqo(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
90 : : {
91 : : struct gve_tx_queue *txq = tx_queue;
92 : : volatile union gve_tx_desc_dqo *txr;
93 : : volatile union gve_tx_desc_dqo *txd;
94 : : struct rte_mbuf **sw_ring;
95 : : struct rte_mbuf *tx_pkt;
96 : : uint16_t mask, sw_mask;
97 : : uint16_t nb_to_clean;
98 : : uint16_t nb_tx = 0;
99 : : uint64_t ol_flags;
100 : : uint16_t nb_used;
101 : : uint16_t tx_id;
102 : : uint16_t sw_id;
103 : : uint64_t bytes;
104 : : uint16_t first_sw_id;
105 : : uint8_t tso;
106 : : uint8_t csum;
107 : :
108 : 0 : sw_ring = txq->sw_ring;
109 : 0 : txr = txq->tx_ring;
110 : :
111 : : bytes = 0;
112 : 0 : mask = txq->nb_tx_desc - 1;
113 : 0 : sw_mask = txq->sw_size - 1;
114 : 0 : tx_id = txq->tx_tail;
115 : 0 : sw_id = txq->sw_tail;
116 : :
117 [ # # ]: 0 : for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
118 : 0 : tx_pkt = tx_pkts[nb_tx];
119 : :
120 [ # # ]: 0 : if (txq->nb_free <= txq->free_thresh) {
121 : 0 : nb_to_clean = DQO_TX_MULTIPLIER * txq->rs_thresh;
122 [ # # ]: 0 : while (nb_to_clean--)
123 : 0 : gve_tx_clean_dqo(txq);
124 : : }
125 : :
126 : 0 : ol_flags = tx_pkt->ol_flags;
127 : 0 : nb_used = tx_pkt->nb_segs;
128 : : first_sw_id = sw_id;
129 : :
130 : 0 : tso = !!(ol_flags & RTE_MBUF_F_TX_TCP_SEG);
131 : 0 : csum = !!(ol_flags & GVE_TX_CKSUM_OFFLOAD_MASK_DQO);
132 : :
133 : 0 : nb_used += tso;
134 [ # # ]: 0 : if (txq->nb_free < nb_used)
135 : : break;
136 : :
137 [ # # ]: 0 : if (tso) {
138 : 0 : txd = &txr[tx_id];
139 : : gve_tx_fill_seg_desc_dqo(txd, tx_pkt);
140 : 0 : tx_id = (tx_id + 1) & mask;
141 : : }
142 : :
143 : : do {
144 [ # # ]: 0 : if (sw_ring[sw_id] != NULL)
145 : 0 : PMD_DRV_LOG(DEBUG, "Overwriting an entry in sw_ring");
146 : :
147 : 0 : txd = &txr[tx_id];
148 [ # # ]: 0 : sw_ring[sw_id] = tx_pkt;
149 : :
150 : : /* fill Tx descriptor */
151 : 0 : txd->pkt.buf_addr = rte_cpu_to_le_64(rte_mbuf_data_iova(tx_pkt));
152 : 0 : txd->pkt.dtype = GVE_TX_PKT_DESC_DTYPE_DQO;
153 : 0 : txd->pkt.compl_tag = rte_cpu_to_le_16(first_sw_id);
154 : 0 : txd->pkt.buf_size = RTE_MIN(tx_pkt->data_len, GVE_TX_MAX_BUF_SIZE_DQO);
155 : 0 : txd->pkt.end_of_packet = 0;
156 : 0 : txd->pkt.checksum_offload_enable = csum;
157 : :
158 : : /* size of desc_ring and sw_ring could be different */
159 : 0 : tx_id = (tx_id + 1) & mask;
160 : 0 : sw_id = (sw_id + 1) & sw_mask;
161 : :
162 : 0 : bytes += tx_pkt->data_len;
163 : 0 : tx_pkt = tx_pkt->next;
164 [ # # ]: 0 : } while (tx_pkt);
165 : :
166 : : /* fill the last descriptor with End of Packet (EOP) bit */
167 : 0 : txd->pkt.end_of_packet = 1;
168 : :
169 : 0 : txq->nb_free -= nb_used;
170 : 0 : txq->nb_used += nb_used;
171 : : }
172 : :
173 : : /* update the tail pointer if any packets were processed */
174 [ # # ]: 0 : if (nb_tx > 0) {
175 : : /* Request a descriptor completion on the last descriptor */
176 : 0 : txq->re_cnt += nb_tx;
177 [ # # ]: 0 : if (txq->re_cnt >= GVE_TX_MIN_RE_INTERVAL) {
178 : 0 : txd = &txr[(tx_id - 1) & mask];
179 : 0 : txd->pkt.report_event = true;
180 : 0 : txq->re_cnt = 0;
181 : : }
182 : :
183 : 0 : rte_write32(tx_id, txq->qtx_tail);
184 : 0 : txq->tx_tail = tx_id;
185 : 0 : txq->sw_tail = sw_id;
186 : :
187 : 0 : txq->stats.packets += nb_tx;
188 : 0 : txq->stats.bytes += bytes;
189 : 0 : txq->stats.errors += nb_pkts - nb_tx;
190 : : }
191 : :
192 : 0 : return nb_tx;
193 : : }
194 : :
195 : : static inline void
196 : 0 : gve_release_txq_mbufs_dqo(struct gve_tx_queue *txq)
197 : : {
198 : : uint16_t i;
199 : :
200 [ # # ]: 0 : for (i = 0; i < txq->sw_size; i++) {
201 [ # # ]: 0 : if (txq->sw_ring[i]) {
202 : : rte_pktmbuf_free_seg(txq->sw_ring[i]);
203 : 0 : txq->sw_ring[i] = NULL;
204 : : }
205 : : }
206 : 0 : }
207 : :
208 : : void
209 : 0 : gve_tx_queue_release_dqo(struct rte_eth_dev *dev, uint16_t qid)
210 : : {
211 : 0 : struct gve_tx_queue *q = dev->data->tx_queues[qid];
212 : :
213 [ # # ]: 0 : if (q == NULL)
214 : : return;
215 : :
216 : 0 : gve_release_txq_mbufs_dqo(q);
217 : 0 : rte_free(q->sw_ring);
218 : 0 : rte_memzone_free(q->mz);
219 : 0 : rte_memzone_free(q->compl_ring_mz);
220 : 0 : rte_memzone_free(q->qres_mz);
221 : 0 : q->qres = NULL;
222 : 0 : rte_free(q);
223 : : }
224 : :
225 : : static int
226 : 0 : check_tx_thresh_dqo(uint16_t nb_desc, uint16_t tx_rs_thresh,
227 : : uint16_t tx_free_thresh)
228 : : {
229 [ # # ]: 0 : if (tx_rs_thresh >= (nb_desc - 2)) {
230 : 0 : PMD_DRV_LOG(ERR, "tx_rs_thresh (%u) must be less than the "
231 : : "number of TX descriptors (%u) minus 2",
232 : : tx_rs_thresh, nb_desc);
233 : 0 : return -EINVAL;
234 : : }
235 [ # # ]: 0 : if (tx_free_thresh >= (nb_desc - 3)) {
236 : 0 : PMD_DRV_LOG(ERR, "tx_free_thresh (%u) must be less than the "
237 : : "number of TX descriptors (%u) minus 3.",
238 : : tx_free_thresh, nb_desc);
239 : 0 : return -EINVAL;
240 : : }
241 [ # # ]: 0 : if (tx_rs_thresh > tx_free_thresh) {
242 : 0 : PMD_DRV_LOG(ERR, "tx_rs_thresh (%u) must be less than or "
243 : : "equal to tx_free_thresh (%u).",
244 : : tx_rs_thresh, tx_free_thresh);
245 : 0 : return -EINVAL;
246 : : }
247 [ # # ]: 0 : if ((nb_desc % tx_rs_thresh) != 0) {
248 : 0 : PMD_DRV_LOG(ERR, "tx_rs_thresh (%u) must be a divisor of the "
249 : : "number of TX descriptors (%u).",
250 : : tx_rs_thresh, nb_desc);
251 : 0 : return -EINVAL;
252 : : }
253 : :
254 : : return 0;
255 : : }
256 : :
257 : : static void
258 : 0 : gve_reset_txq_dqo(struct gve_tx_queue *txq)
259 : : {
260 : : struct rte_mbuf **sw_ring;
261 : : uint32_t size, i;
262 : :
263 [ # # ]: 0 : if (txq == NULL) {
264 : 0 : PMD_DRV_LOG(DEBUG, "Pointer to txq is NULL");
265 : 0 : return;
266 : : }
267 : :
268 : 0 : size = txq->nb_tx_desc * sizeof(union gve_tx_desc_dqo);
269 [ # # ]: 0 : for (i = 0; i < size; i++)
270 : 0 : ((volatile char *)txq->tx_ring)[i] = 0;
271 : :
272 : 0 : size = txq->sw_size * sizeof(struct gve_tx_compl_desc);
273 [ # # ]: 0 : for (i = 0; i < size; i++)
274 : 0 : ((volatile char *)txq->compl_ring)[i] = 0;
275 : :
276 : 0 : sw_ring = txq->sw_ring;
277 [ # # ]: 0 : for (i = 0; i < txq->sw_size; i++)
278 : 0 : sw_ring[i] = NULL;
279 : :
280 : 0 : txq->tx_tail = 0;
281 : 0 : txq->nb_used = 0;
282 : :
283 : 0 : txq->last_desc_cleaned = 0;
284 : 0 : txq->sw_tail = 0;
285 : 0 : txq->nb_free = txq->nb_tx_desc - 1;
286 : :
287 : 0 : txq->complq_tail = 0;
288 : 0 : txq->cur_gen_bit = 1;
289 : : }
290 : :
291 : : int
292 : 0 : gve_tx_queue_setup_dqo(struct rte_eth_dev *dev, uint16_t queue_id,
293 : : uint16_t nb_desc, unsigned int socket_id,
294 : : const struct rte_eth_txconf *conf)
295 : : {
296 : 0 : struct gve_priv *hw = dev->data->dev_private;
297 : : const struct rte_memzone *mz;
298 : : struct gve_tx_queue *txq;
299 : : uint16_t free_thresh;
300 : : uint16_t rs_thresh;
301 : : uint16_t sw_size;
302 : : int err = 0;
303 : :
304 : : /* Free memory if needed. */
305 [ # # ]: 0 : if (dev->data->tx_queues[queue_id]) {
306 : 0 : gve_tx_queue_release_dqo(dev, queue_id);
307 : 0 : dev->data->tx_queues[queue_id] = NULL;
308 : : }
309 : :
310 : : /* Allocate the TX queue data structure. */
311 : 0 : txq = rte_zmalloc_socket("gve txq",
312 : : sizeof(struct gve_tx_queue),
313 : : RTE_CACHE_LINE_SIZE, socket_id);
314 [ # # ]: 0 : if (txq == NULL) {
315 : 0 : PMD_DRV_LOG(ERR, "Failed to allocate memory for tx queue structure");
316 : 0 : return -ENOMEM;
317 : : }
318 : :
319 : : /* need to check free_thresh here */
320 [ # # ]: 0 : free_thresh = conf->tx_free_thresh ?
321 : : conf->tx_free_thresh : GVE_DEFAULT_TX_FREE_THRESH;
322 [ # # ]: 0 : rs_thresh = conf->tx_rs_thresh ?
323 : : conf->tx_rs_thresh : GVE_DEFAULT_TX_RS_THRESH;
324 [ # # ]: 0 : if (check_tx_thresh_dqo(nb_desc, rs_thresh, free_thresh))
325 : : return -EINVAL;
326 : :
327 : 0 : txq->nb_tx_desc = nb_desc;
328 : 0 : txq->free_thresh = free_thresh;
329 : 0 : txq->rs_thresh = rs_thresh;
330 : 0 : txq->queue_id = queue_id;
331 : 0 : txq->port_id = dev->data->port_id;
332 : 0 : txq->ntfy_id = queue_id;
333 : 0 : txq->hw = hw;
334 [ # # ]: 0 : txq->ntfy_addr = &hw->db_bar2[rte_be_to_cpu_32(hw->irq_dbs[txq->ntfy_id].id)];
335 : :
336 : : /* Allocate software ring */
337 : 0 : sw_size = nb_desc * DQO_TX_MULTIPLIER;
338 : 0 : txq->sw_ring = rte_zmalloc_socket("gve tx sw ring",
339 : : sw_size * sizeof(struct rte_mbuf *),
340 : : RTE_CACHE_LINE_SIZE, socket_id);
341 [ # # ]: 0 : if (txq->sw_ring == NULL) {
342 : 0 : PMD_DRV_LOG(ERR, "Failed to allocate memory for SW TX ring");
343 : : err = -ENOMEM;
344 : 0 : goto free_txq;
345 : : }
346 : 0 : txq->sw_size = sw_size;
347 : :
348 : : /* Allocate TX hardware ring descriptors. */
349 : 0 : mz = rte_eth_dma_zone_reserve(dev, "tx_ring", queue_id,
350 : : nb_desc * sizeof(union gve_tx_desc_dqo),
351 : : PAGE_SIZE, socket_id);
352 [ # # ]: 0 : if (mz == NULL) {
353 : 0 : PMD_DRV_LOG(ERR, "Failed to reserve DMA memory for TX");
354 : : err = -ENOMEM;
355 : 0 : goto free_txq_sw_ring;
356 : : }
357 : 0 : txq->tx_ring = (union gve_tx_desc_dqo *)mz->addr;
358 : 0 : txq->tx_ring_phys_addr = mz->iova;
359 : 0 : txq->mz = mz;
360 : :
361 : : /* Allocate TX completion ring descriptors. */
362 : 0 : mz = rte_eth_dma_zone_reserve(dev, "tx_compl_ring", queue_id,
363 : : sw_size * sizeof(struct gve_tx_compl_desc),
364 : : PAGE_SIZE, socket_id);
365 [ # # ]: 0 : if (mz == NULL) {
366 : 0 : PMD_DRV_LOG(ERR, "Failed to reserve DMA memory for TX completion queue");
367 : : err = -ENOMEM;
368 : 0 : goto free_txq_mz;
369 : : }
370 : 0 : txq->compl_ring = (struct gve_tx_compl_desc *)mz->addr;
371 : 0 : txq->compl_ring_phys_addr = mz->iova;
372 : 0 : txq->compl_ring_mz = mz;
373 : 0 : txq->txqs = dev->data->tx_queues;
374 : :
375 : 0 : mz = rte_eth_dma_zone_reserve(dev, "txq_res", queue_id,
376 : : sizeof(struct gve_queue_resources),
377 : : PAGE_SIZE, socket_id);
378 [ # # ]: 0 : if (mz == NULL) {
379 : 0 : PMD_DRV_LOG(ERR, "Failed to reserve DMA memory for TX resource");
380 : : err = -ENOMEM;
381 : 0 : goto free_txq_cq_mz;
382 : : }
383 : 0 : txq->qres = (struct gve_queue_resources *)mz->addr;
384 : 0 : txq->qres_mz = mz;
385 : :
386 : 0 : gve_reset_txq_dqo(txq);
387 : :
388 : 0 : dev->data->tx_queues[queue_id] = txq;
389 : :
390 : 0 : return 0;
391 : :
392 : : free_txq_cq_mz:
393 : 0 : rte_memzone_free(txq->compl_ring_mz);
394 : 0 : free_txq_mz:
395 : 0 : rte_memzone_free(txq->mz);
396 : 0 : free_txq_sw_ring:
397 : 0 : rte_free(txq->sw_ring);
398 : 0 : free_txq:
399 : 0 : rte_free(txq);
400 : 0 : return err;
401 : : }
402 : :
403 : : int
404 : 0 : gve_tx_queue_start_dqo(struct rte_eth_dev *dev, uint16_t tx_queue_id)
405 : : {
406 : 0 : struct gve_priv *hw = dev->data->dev_private;
407 : : struct gve_tx_queue *txq;
408 : :
409 [ # # ]: 0 : if (tx_queue_id >= dev->data->nb_tx_queues)
410 : : return -EINVAL;
411 : :
412 : 0 : txq = dev->data->tx_queues[tx_queue_id];
413 : :
414 [ # # ]: 0 : txq->qtx_tail = &hw->db_bar2[rte_be_to_cpu_32(txq->qres->db_index)];
415 : 0 : txq->qtx_head =
416 [ # # ]: 0 : &hw->cnt_array[rte_be_to_cpu_32(txq->qres->counter_index)];
417 : :
418 : 0 : rte_write32(rte_cpu_to_be_32(GVE_IRQ_MASK), txq->ntfy_addr);
419 : :
420 : 0 : dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STARTED;
421 : :
422 : 0 : return 0;
423 : : }
424 : :
425 : : int
426 : 0 : gve_tx_queue_stop_dqo(struct rte_eth_dev *dev, uint16_t tx_queue_id)
427 : : {
428 : : struct gve_tx_queue *txq;
429 : :
430 [ # # ]: 0 : if (tx_queue_id >= dev->data->nb_tx_queues)
431 : : return -EINVAL;
432 : :
433 : 0 : txq = dev->data->tx_queues[tx_queue_id];
434 : 0 : gve_release_txq_mbufs_dqo(txq);
435 : 0 : gve_reset_txq_dqo(txq);
436 : :
437 : 0 : dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
438 : :
439 : 0 : return 0;
440 : : }
441 : :
442 : : void
443 : 0 : gve_stop_tx_queues_dqo(struct rte_eth_dev *dev)
444 : : {
445 : 0 : struct gve_priv *hw = dev->data->dev_private;
446 : : uint16_t i;
447 : : int err;
448 : :
449 : 0 : err = gve_adminq_destroy_tx_queues(hw, dev->data->nb_tx_queues);
450 [ # # ]: 0 : if (err != 0)
451 : 0 : PMD_DRV_LOG(WARNING, "failed to destroy txqs");
452 : :
453 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++)
454 [ # # ]: 0 : if (gve_tx_queue_stop_dqo(dev, i) != 0)
455 : 0 : PMD_DRV_LOG(WARNING, "Fail to stop Tx queue %d", i);
456 : 0 : }
457 : :
458 : : void
459 : 0 : gve_set_tx_function_dqo(struct rte_eth_dev *dev)
460 : : {
461 : 0 : dev->tx_pkt_burst = gve_tx_burst_dqo;
462 : 0 : }
|