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