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