xref: /dpdk/drivers/net/virtio/virtqueue.c (revision 4710e16a4a7b53c9f2cf38e6f6af945e9af59c26)
15566a3e3SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
25566a3e3SBruce Richardson  * Copyright(c) 2010-2015 Intel Corporation
36c3169a3SBruce Richardson  */
46c3169a3SBruce Richardson #include <stdint.h>
56c3169a3SBruce Richardson 
66c3169a3SBruce Richardson #include <rte_mbuf.h>
76c3169a3SBruce Richardson 
86c3169a3SBruce Richardson #include "virtqueue.h"
96c3169a3SBruce Richardson #include "virtio_logs.h"
106c3169a3SBruce Richardson #include "virtio_pci.h"
11bcf55c93STiwei Bie #include "virtio_rxtx_simple.h"
126c3169a3SBruce Richardson 
136c3169a3SBruce Richardson /*
146c3169a3SBruce Richardson  * Two types of mbuf to be cleaned:
156c3169a3SBruce Richardson  * 1) mbuf that has been consumed by backend but not used by virtio.
166c3169a3SBruce Richardson  * 2) mbuf that hasn't been consued by backend.
176c3169a3SBruce Richardson  */
186c3169a3SBruce Richardson struct rte_mbuf *
19727411f5SOlivier Matz virtqueue_detach_unused(struct virtqueue *vq)
206c3169a3SBruce Richardson {
216c3169a3SBruce Richardson 	struct rte_mbuf *cookie;
22e67ae1e2SOlivier Matz 	struct virtio_hw *hw;
23e67ae1e2SOlivier Matz 	uint16_t start, end;
24e67ae1e2SOlivier Matz 	int type, idx;
256c3169a3SBruce Richardson 
26e67ae1e2SOlivier Matz 	if (vq == NULL)
27e67ae1e2SOlivier Matz 		return NULL;
28e67ae1e2SOlivier Matz 
29e67ae1e2SOlivier Matz 	hw = vq->hw;
30e67ae1e2SOlivier Matz 	type = virtio_get_queue_type(hw, vq->vq_queue_index);
31e67ae1e2SOlivier Matz 	start = vq->vq_avail_idx & (vq->vq_nentries - 1);
32e67ae1e2SOlivier Matz 	end = (vq->vq_avail_idx + vq->vq_free_cnt) & (vq->vq_nentries - 1);
33e67ae1e2SOlivier Matz 
346c3169a3SBruce Richardson 	for (idx = 0; idx < vq->vq_nentries; idx++) {
35*4710e16aSMarvin Liu 		if (hw->use_vec_rx && !vtpci_packed_queue(hw) &&
36*4710e16aSMarvin Liu 		    type == VTNET_RQ) {
37e67ae1e2SOlivier Matz 			if (start <= end && idx >= start && idx < end)
38e67ae1e2SOlivier Matz 				continue;
39e67ae1e2SOlivier Matz 			if (start > end && (idx >= start || idx < end))
40e67ae1e2SOlivier Matz 				continue;
41e67ae1e2SOlivier Matz 			cookie = vq->sw_ring[idx];
42e67ae1e2SOlivier Matz 			if (cookie != NULL) {
43e67ae1e2SOlivier Matz 				vq->sw_ring[idx] = NULL;
44e67ae1e2SOlivier Matz 				return cookie;
45e67ae1e2SOlivier Matz 			}
46e67ae1e2SOlivier Matz 		} else {
472f7fdb9dSBernard Iremonger 			cookie = vq->vq_descx[idx].cookie;
482f7fdb9dSBernard Iremonger 			if (cookie != NULL) {
496c3169a3SBruce Richardson 				vq->vq_descx[idx].cookie = NULL;
506c3169a3SBruce Richardson 				return cookie;
516c3169a3SBruce Richardson 			}
526c3169a3SBruce Richardson 		}
53e67ae1e2SOlivier Matz 	}
54e67ae1e2SOlivier Matz 
556c3169a3SBruce Richardson 	return NULL;
566c3169a3SBruce Richardson }
57d8227497STiwei Bie 
58a76290c8SJens Freimann /* Flush used descs */
59a76290c8SJens Freimann static void
60a76290c8SJens Freimann virtqueue_rxvq_flush_packed(struct virtqueue *vq)
61a76290c8SJens Freimann {
62a76290c8SJens Freimann 	struct vq_desc_extra *dxp;
63a76290c8SJens Freimann 	uint16_t i;
64a76290c8SJens Freimann 
654cdc4d98STiwei Bie 	struct vring_packed_desc *descs = vq->vq_packed.ring.desc;
66a76290c8SJens Freimann 	int cnt = 0;
67a76290c8SJens Freimann 
68a76290c8SJens Freimann 	i = vq->vq_used_cons_idx;
69a76290c8SJens Freimann 	while (desc_is_used(&descs[i], vq) && cnt++ < vq->vq_nentries) {
70a76290c8SJens Freimann 		dxp = &vq->vq_descx[descs[i].id];
71a76290c8SJens Freimann 		if (dxp->cookie != NULL) {
72a76290c8SJens Freimann 			rte_pktmbuf_free(dxp->cookie);
73a76290c8SJens Freimann 			dxp->cookie = NULL;
74a76290c8SJens Freimann 		}
75a76290c8SJens Freimann 		vq->vq_free_cnt++;
76a76290c8SJens Freimann 		vq->vq_used_cons_idx++;
77a76290c8SJens Freimann 		if (vq->vq_used_cons_idx >= vq->vq_nentries) {
78a76290c8SJens Freimann 			vq->vq_used_cons_idx -= vq->vq_nentries;
79dfd33aa4STiwei Bie 			vq->vq_packed.used_wrap_counter ^= 1;
80a76290c8SJens Freimann 		}
81a76290c8SJens Freimann 		i = vq->vq_used_cons_idx;
82a76290c8SJens Freimann 	}
83a76290c8SJens Freimann }
84a76290c8SJens Freimann 
85d8227497STiwei Bie /* Flush the elements in the used ring. */
86a76290c8SJens Freimann static void
87a76290c8SJens Freimann virtqueue_rxvq_flush_split(struct virtqueue *vq)
88d8227497STiwei Bie {
89bcf55c93STiwei Bie 	struct virtnet_rx *rxq = &vq->rxq;
90bcf55c93STiwei Bie 	struct virtio_hw *hw = vq->hw;
91d8227497STiwei Bie 	struct vring_used_elem *uep;
92d8227497STiwei Bie 	struct vq_desc_extra *dxp;
93d8227497STiwei Bie 	uint16_t used_idx, desc_idx;
94d8227497STiwei Bie 	uint16_t nb_used, i;
95d8227497STiwei Bie 
96d8227497STiwei Bie 	nb_used = VIRTQUEUE_NUSED(vq);
97d8227497STiwei Bie 
98d8227497STiwei Bie 	for (i = 0; i < nb_used; i++) {
99d8227497STiwei Bie 		used_idx = vq->vq_used_cons_idx & (vq->vq_nentries - 1);
100dfd33aa4STiwei Bie 		uep = &vq->vq_split.ring.used->ring[used_idx];
101*4710e16aSMarvin Liu 		if (hw->use_vec_rx) {
102bcf55c93STiwei Bie 			desc_idx = used_idx;
103bcf55c93STiwei Bie 			rte_pktmbuf_free(vq->sw_ring[desc_idx]);
104bcf55c93STiwei Bie 			vq->vq_free_cnt++;
1057097ca1bSMarvin Liu 		} else if (hw->use_inorder_rx) {
1067097ca1bSMarvin Liu 			desc_idx = (uint16_t)uep->id;
1077097ca1bSMarvin Liu 			dxp = &vq->vq_descx[desc_idx];
1087097ca1bSMarvin Liu 			if (dxp->cookie != NULL) {
1097097ca1bSMarvin Liu 				rte_pktmbuf_free(dxp->cookie);
1107097ca1bSMarvin Liu 				dxp->cookie = NULL;
1117097ca1bSMarvin Liu 			}
1127097ca1bSMarvin Liu 			vq_ring_free_inorder(vq, desc_idx, 1);
113bcf55c93STiwei Bie 		} else {
114d8227497STiwei Bie 			desc_idx = (uint16_t)uep->id;
115d8227497STiwei Bie 			dxp = &vq->vq_descx[desc_idx];
116d8227497STiwei Bie 			if (dxp->cookie != NULL) {
117d8227497STiwei Bie 				rte_pktmbuf_free(dxp->cookie);
118d8227497STiwei Bie 				dxp->cookie = NULL;
119d8227497STiwei Bie 			}
120d8227497STiwei Bie 			vq_ring_free_chain(vq, desc_idx);
121d8227497STiwei Bie 		}
122bcf55c93STiwei Bie 		vq->vq_used_cons_idx++;
123bcf55c93STiwei Bie 	}
124bcf55c93STiwei Bie 
125*4710e16aSMarvin Liu 	if (hw->use_vec_rx) {
126bcf55c93STiwei Bie 		while (vq->vq_free_cnt >= RTE_VIRTIO_VPMD_RX_REARM_THRESH) {
127bcf55c93STiwei Bie 			virtio_rxq_rearm_vec(rxq);
128bcf55c93STiwei Bie 			if (virtqueue_kick_prepare(vq))
129bcf55c93STiwei Bie 				virtqueue_notify(vq);
130bcf55c93STiwei Bie 		}
131bcf55c93STiwei Bie 	}
132d8227497STiwei Bie }
133a76290c8SJens Freimann 
134a76290c8SJens Freimann /* Flush the elements in the used ring. */
135a76290c8SJens Freimann void
136a76290c8SJens Freimann virtqueue_rxvq_flush(struct virtqueue *vq)
137a76290c8SJens Freimann {
138a76290c8SJens Freimann 	struct virtio_hw *hw = vq->hw;
139a76290c8SJens Freimann 
140a76290c8SJens Freimann 	if (vtpci_packed_queue(hw))
141a76290c8SJens Freimann 		virtqueue_rxvq_flush_packed(vq);
142a76290c8SJens Freimann 	else
143a76290c8SJens Freimann 		virtqueue_rxvq_flush_split(vq);
144a76290c8SJens Freimann }
1456ebbf410SXuan Ding 
1466ebbf410SXuan Ding int
1476ebbf410SXuan Ding virtqueue_rxvq_reset_packed(struct virtqueue *vq)
1486ebbf410SXuan Ding {
1496ebbf410SXuan Ding 	int size = vq->vq_nentries;
1506ebbf410SXuan Ding 	struct vq_desc_extra *dxp;
1516ebbf410SXuan Ding 	struct virtnet_rx *rxvq;
1526ebbf410SXuan Ding 	uint16_t desc_idx;
1536ebbf410SXuan Ding 
1546ebbf410SXuan Ding 	vq->vq_used_cons_idx = 0;
1556ebbf410SXuan Ding 	vq->vq_desc_head_idx = 0;
1566ebbf410SXuan Ding 	vq->vq_avail_idx = 0;
1576ebbf410SXuan Ding 	vq->vq_desc_tail_idx = (uint16_t)(vq->vq_nentries - 1);
1586ebbf410SXuan Ding 	vq->vq_free_cnt = vq->vq_nentries;
1596ebbf410SXuan Ding 
1606ebbf410SXuan Ding 	vq->vq_packed.used_wrap_counter = 1;
1616ebbf410SXuan Ding 	vq->vq_packed.cached_flags = VRING_PACKED_DESC_F_AVAIL;
1626ebbf410SXuan Ding 	vq->vq_packed.event_flags_shadow = 0;
1636ebbf410SXuan Ding 	vq->vq_packed.cached_flags |= VRING_DESC_F_WRITE;
1646ebbf410SXuan Ding 
1656ebbf410SXuan Ding 	rxvq = &vq->rxq;
1666ebbf410SXuan Ding 	memset(rxvq->mz->addr, 0, rxvq->mz->len);
1676ebbf410SXuan Ding 
1686ebbf410SXuan Ding 	for (desc_idx = 0; desc_idx < vq->vq_nentries; desc_idx++) {
1696ebbf410SXuan Ding 		dxp = &vq->vq_descx[desc_idx];
1706ebbf410SXuan Ding 		if (dxp->cookie != NULL) {
1716ebbf410SXuan Ding 			rte_pktmbuf_free(dxp->cookie);
1726ebbf410SXuan Ding 			dxp->cookie = NULL;
1736ebbf410SXuan Ding 		}
1746ebbf410SXuan Ding 	}
1756ebbf410SXuan Ding 
1766ebbf410SXuan Ding 	vring_desc_init_packed(vq, size);
1776ebbf410SXuan Ding 
1786ebbf410SXuan Ding 	return 0;
1796ebbf410SXuan Ding }
1806ebbf410SXuan Ding 
1816ebbf410SXuan Ding int
1826ebbf410SXuan Ding virtqueue_txvq_reset_packed(struct virtqueue *vq)
1836ebbf410SXuan Ding {
1846ebbf410SXuan Ding 	int size = vq->vq_nentries;
1856ebbf410SXuan Ding 	struct vq_desc_extra *dxp;
1866ebbf410SXuan Ding 	struct virtnet_tx *txvq;
1876ebbf410SXuan Ding 	uint16_t desc_idx;
1886ebbf410SXuan Ding 
1896ebbf410SXuan Ding 	vq->vq_used_cons_idx = 0;
1906ebbf410SXuan Ding 	vq->vq_desc_head_idx = 0;
1916ebbf410SXuan Ding 	vq->vq_avail_idx = 0;
1926ebbf410SXuan Ding 	vq->vq_desc_tail_idx = (uint16_t)(vq->vq_nentries - 1);
1936ebbf410SXuan Ding 	vq->vq_free_cnt = vq->vq_nentries;
1946ebbf410SXuan Ding 
1956ebbf410SXuan Ding 	vq->vq_packed.used_wrap_counter = 1;
1966ebbf410SXuan Ding 	vq->vq_packed.cached_flags = VRING_PACKED_DESC_F_AVAIL;
1976ebbf410SXuan Ding 	vq->vq_packed.event_flags_shadow = 0;
1986ebbf410SXuan Ding 
1996ebbf410SXuan Ding 	txvq = &vq->txq;
2006ebbf410SXuan Ding 	memset(txvq->mz->addr, 0, txvq->mz->len);
2016ebbf410SXuan Ding 	memset(txvq->virtio_net_hdr_mz->addr, 0,
2026ebbf410SXuan Ding 		txvq->virtio_net_hdr_mz->len);
2036ebbf410SXuan Ding 
2046ebbf410SXuan Ding 	for (desc_idx = 0; desc_idx < vq->vq_nentries; desc_idx++) {
2056ebbf410SXuan Ding 		dxp = &vq->vq_descx[desc_idx];
2066ebbf410SXuan Ding 		if (dxp->cookie != NULL) {
2076ebbf410SXuan Ding 			rte_pktmbuf_free(dxp->cookie);
2086ebbf410SXuan Ding 			dxp->cookie = NULL;
2096ebbf410SXuan Ding 		}
2106ebbf410SXuan Ding 	}
2116ebbf410SXuan Ding 
2126ebbf410SXuan Ding 	vring_desc_init_packed(vq, size);
2136ebbf410SXuan Ding 
2146ebbf410SXuan Ding 	return 0;
2156ebbf410SXuan Ding }
216