xref: /dpdk/drivers/net/virtio/virtqueue.c (revision 7be78d02)
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"
10b5ba7ee4SMaxime Coquelin #include "virtio.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.
16*7be78d02SJosh Soref  * 2) mbuf that hasn't been consumed by backend.
176c3169a3SBruce Richardson  */
186c3169a3SBruce Richardson struct rte_mbuf *
virtqueue_detach_unused(struct virtqueue * vq)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++) {
35b4f9a45aSMaxime Coquelin 		if (hw->use_vec_rx && !virtio_with_packed_queue(hw) &&
364710e16aSMarvin 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
virtqueue_rxvq_flush_packed(struct virtqueue * vq)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
virtqueue_rxvq_flush_split(struct virtqueue * vq)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 
96ea5207c1SJoyce Kong 	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];
1014710e16aSMarvin 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 
1254710e16aSMarvin 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
virtqueue_rxvq_flush(struct virtqueue * vq)136a76290c8SJens Freimann virtqueue_rxvq_flush(struct virtqueue *vq)
137a76290c8SJens Freimann {
138a76290c8SJens Freimann 	struct virtio_hw *hw = vq->hw;
139a76290c8SJens Freimann 
140b4f9a45aSMaxime Coquelin 	if (virtio_with_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
virtqueue_rxvq_reset_packed(struct virtqueue * vq)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 
178f50560a5SMarvin Liu 	virtqueue_disable_intr(vq);
1796ebbf410SXuan Ding 	return 0;
1806ebbf410SXuan Ding }
1816ebbf410SXuan Ding 
1826ebbf410SXuan Ding int
virtqueue_txvq_reset_packed(struct virtqueue * vq)1836ebbf410SXuan Ding virtqueue_txvq_reset_packed(struct virtqueue *vq)
1846ebbf410SXuan Ding {
1856ebbf410SXuan Ding 	int size = vq->vq_nentries;
1866ebbf410SXuan Ding 	struct vq_desc_extra *dxp;
1876ebbf410SXuan Ding 	struct virtnet_tx *txvq;
1886ebbf410SXuan Ding 	uint16_t desc_idx;
18904bcc802SXuan Ding 	struct virtio_tx_region *txr;
19004bcc802SXuan Ding 	struct vring_packed_desc *start_dp;
1916ebbf410SXuan Ding 
1926ebbf410SXuan Ding 	vq->vq_used_cons_idx = 0;
1936ebbf410SXuan Ding 	vq->vq_desc_head_idx = 0;
1946ebbf410SXuan Ding 	vq->vq_avail_idx = 0;
1956ebbf410SXuan Ding 	vq->vq_desc_tail_idx = (uint16_t)(vq->vq_nentries - 1);
1966ebbf410SXuan Ding 	vq->vq_free_cnt = vq->vq_nentries;
1976ebbf410SXuan Ding 
1986ebbf410SXuan Ding 	vq->vq_packed.used_wrap_counter = 1;
1996ebbf410SXuan Ding 	vq->vq_packed.cached_flags = VRING_PACKED_DESC_F_AVAIL;
2006ebbf410SXuan Ding 	vq->vq_packed.event_flags_shadow = 0;
2016ebbf410SXuan Ding 
2026ebbf410SXuan Ding 	txvq = &vq->txq;
20304bcc802SXuan Ding 	txr = txvq->virtio_net_hdr_mz->addr;
2046ebbf410SXuan Ding 	memset(txvq->mz->addr, 0, txvq->mz->len);
2056ebbf410SXuan Ding 	memset(txvq->virtio_net_hdr_mz->addr, 0,
2066ebbf410SXuan Ding 		txvq->virtio_net_hdr_mz->len);
2076ebbf410SXuan Ding 
2086ebbf410SXuan Ding 	for (desc_idx = 0; desc_idx < vq->vq_nentries; desc_idx++) {
2096ebbf410SXuan Ding 		dxp = &vq->vq_descx[desc_idx];
2106ebbf410SXuan Ding 		if (dxp->cookie != NULL) {
2116ebbf410SXuan Ding 			rte_pktmbuf_free(dxp->cookie);
2126ebbf410SXuan Ding 			dxp->cookie = NULL;
2136ebbf410SXuan Ding 		}
21404bcc802SXuan Ding 
21504bcc802SXuan Ding 		if (virtio_with_feature(vq->hw, VIRTIO_RING_F_INDIRECT_DESC)) {
21604bcc802SXuan Ding 			/* first indirect descriptor is always the tx header */
21704bcc802SXuan Ding 			start_dp = txr[desc_idx].tx_packed_indir;
21804bcc802SXuan Ding 			vring_desc_init_indirect_packed(start_dp,
21904bcc802SXuan Ding 							RTE_DIM(txr[desc_idx].tx_packed_indir));
22004bcc802SXuan Ding 			start_dp->addr = txvq->virtio_net_hdr_mem
22104bcc802SXuan Ding 					 + desc_idx * sizeof(*txr)
22204bcc802SXuan Ding 					 + offsetof(struct virtio_tx_region, tx_hdr);
22304bcc802SXuan Ding 			start_dp->len = vq->hw->vtnet_hdr_size;
22404bcc802SXuan Ding 		}
2256ebbf410SXuan Ding 	}
2266ebbf410SXuan Ding 
2276ebbf410SXuan Ding 	vring_desc_init_packed(vq, size);
2286ebbf410SXuan Ding 
229f50560a5SMarvin Liu 	virtqueue_disable_intr(vq);
2306ebbf410SXuan Ding 	return 0;
2316ebbf410SXuan Ding }
232