xref: /dpdk/drivers/net/virtio/virtqueue.c (revision 4cdc4d98313e717df7d1dba769d71e7e4050da54)
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++) {
35e67ae1e2SOlivier Matz 		if (hw->use_simple_rx && type == VTNET_RQ) {
36e67ae1e2SOlivier Matz 			if (start <= end && idx >= start && idx < end)
37e67ae1e2SOlivier Matz 				continue;
38e67ae1e2SOlivier Matz 			if (start > end && (idx >= start || idx < end))
39e67ae1e2SOlivier Matz 				continue;
40e67ae1e2SOlivier Matz 			cookie = vq->sw_ring[idx];
41e67ae1e2SOlivier Matz 			if (cookie != NULL) {
42e67ae1e2SOlivier Matz 				vq->sw_ring[idx] = NULL;
43e67ae1e2SOlivier Matz 				return cookie;
44e67ae1e2SOlivier Matz 			}
45e67ae1e2SOlivier Matz 		} else {
462f7fdb9dSBernard Iremonger 			cookie = vq->vq_descx[idx].cookie;
472f7fdb9dSBernard Iremonger 			if (cookie != NULL) {
486c3169a3SBruce Richardson 				vq->vq_descx[idx].cookie = NULL;
496c3169a3SBruce Richardson 				return cookie;
506c3169a3SBruce Richardson 			}
516c3169a3SBruce Richardson 		}
52e67ae1e2SOlivier Matz 	}
53e67ae1e2SOlivier Matz 
546c3169a3SBruce Richardson 	return NULL;
556c3169a3SBruce Richardson }
56d8227497STiwei Bie 
57a76290c8SJens Freimann /* Flush used descs */
58a76290c8SJens Freimann static void
59a76290c8SJens Freimann virtqueue_rxvq_flush_packed(struct virtqueue *vq)
60a76290c8SJens Freimann {
61a76290c8SJens Freimann 	struct vq_desc_extra *dxp;
62a76290c8SJens Freimann 	uint16_t i;
63a76290c8SJens Freimann 
64*4cdc4d98STiwei Bie 	struct vring_packed_desc *descs = vq->vq_packed.ring.desc;
65a76290c8SJens Freimann 	int cnt = 0;
66a76290c8SJens Freimann 
67a76290c8SJens Freimann 	i = vq->vq_used_cons_idx;
68a76290c8SJens Freimann 	while (desc_is_used(&descs[i], vq) && cnt++ < vq->vq_nentries) {
69a76290c8SJens Freimann 		dxp = &vq->vq_descx[descs[i].id];
70a76290c8SJens Freimann 		if (dxp->cookie != NULL) {
71a76290c8SJens Freimann 			rte_pktmbuf_free(dxp->cookie);
72a76290c8SJens Freimann 			dxp->cookie = NULL;
73a76290c8SJens Freimann 		}
74a76290c8SJens Freimann 		vq->vq_free_cnt++;
75a76290c8SJens Freimann 		vq->vq_used_cons_idx++;
76a76290c8SJens Freimann 		if (vq->vq_used_cons_idx >= vq->vq_nentries) {
77a76290c8SJens Freimann 			vq->vq_used_cons_idx -= vq->vq_nentries;
78dfd33aa4STiwei Bie 			vq->vq_packed.used_wrap_counter ^= 1;
79a76290c8SJens Freimann 		}
80a76290c8SJens Freimann 		i = vq->vq_used_cons_idx;
81a76290c8SJens Freimann 	}
82a76290c8SJens Freimann }
83a76290c8SJens Freimann 
84d8227497STiwei Bie /* Flush the elements in the used ring. */
85a76290c8SJens Freimann static void
86a76290c8SJens Freimann virtqueue_rxvq_flush_split(struct virtqueue *vq)
87d8227497STiwei Bie {
88bcf55c93STiwei Bie 	struct virtnet_rx *rxq = &vq->rxq;
89bcf55c93STiwei Bie 	struct virtio_hw *hw = vq->hw;
90d8227497STiwei Bie 	struct vring_used_elem *uep;
91d8227497STiwei Bie 	struct vq_desc_extra *dxp;
92d8227497STiwei Bie 	uint16_t used_idx, desc_idx;
93d8227497STiwei Bie 	uint16_t nb_used, i;
94d8227497STiwei Bie 
95d8227497STiwei Bie 	nb_used = VIRTQUEUE_NUSED(vq);
96d8227497STiwei Bie 
97d8227497STiwei Bie 	for (i = 0; i < nb_used; i++) {
98d8227497STiwei Bie 		used_idx = vq->vq_used_cons_idx & (vq->vq_nentries - 1);
99dfd33aa4STiwei Bie 		uep = &vq->vq_split.ring.used->ring[used_idx];
100bcf55c93STiwei Bie 		if (hw->use_simple_rx) {
101bcf55c93STiwei Bie 			desc_idx = used_idx;
102bcf55c93STiwei Bie 			rte_pktmbuf_free(vq->sw_ring[desc_idx]);
103bcf55c93STiwei Bie 			vq->vq_free_cnt++;
1047097ca1bSMarvin Liu 		} else if (hw->use_inorder_rx) {
1057097ca1bSMarvin Liu 			desc_idx = (uint16_t)uep->id;
1067097ca1bSMarvin Liu 			dxp = &vq->vq_descx[desc_idx];
1077097ca1bSMarvin Liu 			if (dxp->cookie != NULL) {
1087097ca1bSMarvin Liu 				rte_pktmbuf_free(dxp->cookie);
1097097ca1bSMarvin Liu 				dxp->cookie = NULL;
1107097ca1bSMarvin Liu 			}
1117097ca1bSMarvin Liu 			vq_ring_free_inorder(vq, desc_idx, 1);
112bcf55c93STiwei Bie 		} else {
113d8227497STiwei Bie 			desc_idx = (uint16_t)uep->id;
114d8227497STiwei Bie 			dxp = &vq->vq_descx[desc_idx];
115d8227497STiwei Bie 			if (dxp->cookie != NULL) {
116d8227497STiwei Bie 				rte_pktmbuf_free(dxp->cookie);
117d8227497STiwei Bie 				dxp->cookie = NULL;
118d8227497STiwei Bie 			}
119d8227497STiwei Bie 			vq_ring_free_chain(vq, desc_idx);
120d8227497STiwei Bie 		}
121bcf55c93STiwei Bie 		vq->vq_used_cons_idx++;
122bcf55c93STiwei Bie 	}
123bcf55c93STiwei Bie 
124bcf55c93STiwei Bie 	if (hw->use_simple_rx) {
125bcf55c93STiwei Bie 		while (vq->vq_free_cnt >= RTE_VIRTIO_VPMD_RX_REARM_THRESH) {
126bcf55c93STiwei Bie 			virtio_rxq_rearm_vec(rxq);
127bcf55c93STiwei Bie 			if (virtqueue_kick_prepare(vq))
128bcf55c93STiwei Bie 				virtqueue_notify(vq);
129bcf55c93STiwei Bie 		}
130bcf55c93STiwei Bie 	}
131d8227497STiwei Bie }
132a76290c8SJens Freimann 
133a76290c8SJens Freimann /* Flush the elements in the used ring. */
134a76290c8SJens Freimann void
135a76290c8SJens Freimann virtqueue_rxvq_flush(struct virtqueue *vq)
136a76290c8SJens Freimann {
137a76290c8SJens Freimann 	struct virtio_hw *hw = vq->hw;
138a76290c8SJens Freimann 
139a76290c8SJens Freimann 	if (vtpci_packed_queue(hw))
140a76290c8SJens Freimann 		virtqueue_rxvq_flush_packed(vq);
141a76290c8SJens Freimann 	else
142a76290c8SJens Freimann 		virtqueue_rxvq_flush_split(vq);
143a76290c8SJens Freimann }
144