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