1*ca059fa5SYuanhan Liu /*- 2*ca059fa5SYuanhan Liu * BSD LICENSE 3*ca059fa5SYuanhan Liu * 4*ca059fa5SYuanhan Liu * Copyright(c) 2010-2017 Intel Corporation. All rights reserved. 5*ca059fa5SYuanhan Liu * All rights reserved. 6*ca059fa5SYuanhan Liu * 7*ca059fa5SYuanhan Liu * Redistribution and use in source and binary forms, with or without 8*ca059fa5SYuanhan Liu * modification, are permitted provided that the following conditions 9*ca059fa5SYuanhan Liu * are met: 10*ca059fa5SYuanhan Liu * 11*ca059fa5SYuanhan Liu * * Redistributions of source code must retain the above copyright 12*ca059fa5SYuanhan Liu * notice, this list of conditions and the following disclaimer. 13*ca059fa5SYuanhan Liu * * Redistributions in binary form must reproduce the above copyright 14*ca059fa5SYuanhan Liu * notice, this list of conditions and the following disclaimer in 15*ca059fa5SYuanhan Liu * the documentation and/or other materials provided with the 16*ca059fa5SYuanhan Liu * distribution. 17*ca059fa5SYuanhan Liu * * Neither the name of Intel Corporation nor the names of its 18*ca059fa5SYuanhan Liu * contributors may be used to endorse or promote products derived 19*ca059fa5SYuanhan Liu * from this software without specific prior written permission. 20*ca059fa5SYuanhan Liu * 21*ca059fa5SYuanhan Liu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22*ca059fa5SYuanhan Liu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23*ca059fa5SYuanhan Liu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24*ca059fa5SYuanhan Liu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25*ca059fa5SYuanhan Liu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26*ca059fa5SYuanhan Liu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27*ca059fa5SYuanhan Liu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28*ca059fa5SYuanhan Liu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29*ca059fa5SYuanhan Liu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30*ca059fa5SYuanhan Liu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31*ca059fa5SYuanhan Liu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32*ca059fa5SYuanhan Liu */ 33*ca059fa5SYuanhan Liu 34*ca059fa5SYuanhan Liu #include <stdint.h> 35*ca059fa5SYuanhan Liu #include <stdbool.h> 36*ca059fa5SYuanhan Liu #include <linux/virtio_net.h> 37*ca059fa5SYuanhan Liu 38*ca059fa5SYuanhan Liu #include <rte_mbuf.h> 39*ca059fa5SYuanhan Liu #include <rte_memcpy.h> 40*ca059fa5SYuanhan Liu #include <rte_vhost.h> 41*ca059fa5SYuanhan Liu 42*ca059fa5SYuanhan Liu #include "main.h" 43*ca059fa5SYuanhan Liu 44*ca059fa5SYuanhan Liu /* 45*ca059fa5SYuanhan Liu * A very simple vhost-user net driver implementation, without 46*ca059fa5SYuanhan Liu * any extra features being enabled, such as TSO and mrg-Rx. 47*ca059fa5SYuanhan Liu */ 48*ca059fa5SYuanhan Liu 49*ca059fa5SYuanhan Liu void 50*ca059fa5SYuanhan Liu vs_vhost_net_setup(struct vhost_dev *dev) 51*ca059fa5SYuanhan Liu { 52*ca059fa5SYuanhan Liu uint16_t i; 53*ca059fa5SYuanhan Liu int vid = dev->vid; 54*ca059fa5SYuanhan Liu struct vhost_queue *queue; 55*ca059fa5SYuanhan Liu 56*ca059fa5SYuanhan Liu RTE_LOG(INFO, VHOST_CONFIG, 57*ca059fa5SYuanhan Liu "setting builtin vhost-user net driver\n"); 58*ca059fa5SYuanhan Liu 59*ca059fa5SYuanhan Liu rte_vhost_get_negotiated_features(vid, &dev->features); 60*ca059fa5SYuanhan Liu if (dev->features & (1 << VIRTIO_NET_F_MRG_RXBUF)) 61*ca059fa5SYuanhan Liu dev->hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf); 62*ca059fa5SYuanhan Liu else 63*ca059fa5SYuanhan Liu dev->hdr_len = sizeof(struct virtio_net_hdr); 64*ca059fa5SYuanhan Liu 65*ca059fa5SYuanhan Liu rte_vhost_get_mem_table(vid, &dev->mem); 66*ca059fa5SYuanhan Liu 67*ca059fa5SYuanhan Liu dev->nr_vrings = rte_vhost_get_vring_num(vid); 68*ca059fa5SYuanhan Liu for (i = 0; i < dev->nr_vrings; i++) { 69*ca059fa5SYuanhan Liu queue = &dev->queues[i]; 70*ca059fa5SYuanhan Liu 71*ca059fa5SYuanhan Liu queue->last_used_idx = 0; 72*ca059fa5SYuanhan Liu queue->last_avail_idx = 0; 73*ca059fa5SYuanhan Liu rte_vhost_get_vhost_vring(vid, i, &queue->vr); 74*ca059fa5SYuanhan Liu } 75*ca059fa5SYuanhan Liu } 76*ca059fa5SYuanhan Liu 77*ca059fa5SYuanhan Liu void 78*ca059fa5SYuanhan Liu vs_vhost_net_remove(struct vhost_dev *dev) 79*ca059fa5SYuanhan Liu { 80*ca059fa5SYuanhan Liu free(dev->mem); 81*ca059fa5SYuanhan Liu } 82*ca059fa5SYuanhan Liu 83*ca059fa5SYuanhan Liu static inline int __attribute__((always_inline)) 84*ca059fa5SYuanhan Liu enqueue_pkt(struct vhost_dev *dev, struct rte_vhost_vring *vr, 85*ca059fa5SYuanhan Liu struct rte_mbuf *m, uint16_t desc_idx) 86*ca059fa5SYuanhan Liu { 87*ca059fa5SYuanhan Liu uint32_t desc_avail, desc_offset; 88*ca059fa5SYuanhan Liu uint32_t mbuf_avail, mbuf_offset; 89*ca059fa5SYuanhan Liu uint32_t cpy_len; 90*ca059fa5SYuanhan Liu struct vring_desc *desc; 91*ca059fa5SYuanhan Liu uint64_t desc_addr; 92*ca059fa5SYuanhan Liu struct virtio_net_hdr virtio_hdr = {0, 0, 0, 0, 0, 0}; 93*ca059fa5SYuanhan Liu /* A counter to avoid desc dead loop chain */ 94*ca059fa5SYuanhan Liu uint16_t nr_desc = 1; 95*ca059fa5SYuanhan Liu 96*ca059fa5SYuanhan Liu desc = &vr->desc[desc_idx]; 97*ca059fa5SYuanhan Liu desc_addr = rte_vhost_gpa_to_vva(dev->mem, desc->addr); 98*ca059fa5SYuanhan Liu /* 99*ca059fa5SYuanhan Liu * Checking of 'desc_addr' placed outside of 'unlikely' macro to avoid 100*ca059fa5SYuanhan Liu * performance issue with some versions of gcc (4.8.4 and 5.3.0) which 101*ca059fa5SYuanhan Liu * otherwise stores offset on the stack instead of in a register. 102*ca059fa5SYuanhan Liu */ 103*ca059fa5SYuanhan Liu if (unlikely(desc->len < dev->hdr_len) || !desc_addr) 104*ca059fa5SYuanhan Liu return -1; 105*ca059fa5SYuanhan Liu 106*ca059fa5SYuanhan Liu rte_prefetch0((void *)(uintptr_t)desc_addr); 107*ca059fa5SYuanhan Liu 108*ca059fa5SYuanhan Liu /* write virtio-net header */ 109*ca059fa5SYuanhan Liu *(struct virtio_net_hdr *)(uintptr_t)desc_addr = virtio_hdr; 110*ca059fa5SYuanhan Liu 111*ca059fa5SYuanhan Liu desc_offset = dev->hdr_len; 112*ca059fa5SYuanhan Liu desc_avail = desc->len - dev->hdr_len; 113*ca059fa5SYuanhan Liu 114*ca059fa5SYuanhan Liu mbuf_avail = rte_pktmbuf_data_len(m); 115*ca059fa5SYuanhan Liu mbuf_offset = 0; 116*ca059fa5SYuanhan Liu while (mbuf_avail != 0 || m->next != NULL) { 117*ca059fa5SYuanhan Liu /* done with current mbuf, fetch next */ 118*ca059fa5SYuanhan Liu if (mbuf_avail == 0) { 119*ca059fa5SYuanhan Liu m = m->next; 120*ca059fa5SYuanhan Liu 121*ca059fa5SYuanhan Liu mbuf_offset = 0; 122*ca059fa5SYuanhan Liu mbuf_avail = rte_pktmbuf_data_len(m); 123*ca059fa5SYuanhan Liu } 124*ca059fa5SYuanhan Liu 125*ca059fa5SYuanhan Liu /* done with current desc buf, fetch next */ 126*ca059fa5SYuanhan Liu if (desc_avail == 0) { 127*ca059fa5SYuanhan Liu if ((desc->flags & VRING_DESC_F_NEXT) == 0) { 128*ca059fa5SYuanhan Liu /* Room in vring buffer is not enough */ 129*ca059fa5SYuanhan Liu return -1; 130*ca059fa5SYuanhan Liu } 131*ca059fa5SYuanhan Liu if (unlikely(desc->next >= vr->size || 132*ca059fa5SYuanhan Liu ++nr_desc > vr->size)) 133*ca059fa5SYuanhan Liu return -1; 134*ca059fa5SYuanhan Liu 135*ca059fa5SYuanhan Liu desc = &vr->desc[desc->next]; 136*ca059fa5SYuanhan Liu desc_addr = rte_vhost_gpa_to_vva(dev->mem, desc->addr); 137*ca059fa5SYuanhan Liu if (unlikely(!desc_addr)) 138*ca059fa5SYuanhan Liu return -1; 139*ca059fa5SYuanhan Liu 140*ca059fa5SYuanhan Liu desc_offset = 0; 141*ca059fa5SYuanhan Liu desc_avail = desc->len; 142*ca059fa5SYuanhan Liu } 143*ca059fa5SYuanhan Liu 144*ca059fa5SYuanhan Liu cpy_len = RTE_MIN(desc_avail, mbuf_avail); 145*ca059fa5SYuanhan Liu rte_memcpy((void *)((uintptr_t)(desc_addr + desc_offset)), 146*ca059fa5SYuanhan Liu rte_pktmbuf_mtod_offset(m, void *, mbuf_offset), 147*ca059fa5SYuanhan Liu cpy_len); 148*ca059fa5SYuanhan Liu 149*ca059fa5SYuanhan Liu mbuf_avail -= cpy_len; 150*ca059fa5SYuanhan Liu mbuf_offset += cpy_len; 151*ca059fa5SYuanhan Liu desc_avail -= cpy_len; 152*ca059fa5SYuanhan Liu desc_offset += cpy_len; 153*ca059fa5SYuanhan Liu } 154*ca059fa5SYuanhan Liu 155*ca059fa5SYuanhan Liu return 0; 156*ca059fa5SYuanhan Liu } 157*ca059fa5SYuanhan Liu 158*ca059fa5SYuanhan Liu uint16_t 159*ca059fa5SYuanhan Liu vs_enqueue_pkts(struct vhost_dev *dev, uint16_t queue_id, 160*ca059fa5SYuanhan Liu struct rte_mbuf **pkts, uint32_t count) 161*ca059fa5SYuanhan Liu { 162*ca059fa5SYuanhan Liu struct vhost_queue *queue; 163*ca059fa5SYuanhan Liu struct rte_vhost_vring *vr; 164*ca059fa5SYuanhan Liu uint16_t avail_idx, free_entries, start_idx; 165*ca059fa5SYuanhan Liu uint16_t desc_indexes[MAX_PKT_BURST]; 166*ca059fa5SYuanhan Liu uint16_t used_idx; 167*ca059fa5SYuanhan Liu uint32_t i; 168*ca059fa5SYuanhan Liu 169*ca059fa5SYuanhan Liu queue = &dev->queues[queue_id]; 170*ca059fa5SYuanhan Liu vr = &queue->vr; 171*ca059fa5SYuanhan Liu 172*ca059fa5SYuanhan Liu avail_idx = *((volatile uint16_t *)&vr->avail->idx); 173*ca059fa5SYuanhan Liu start_idx = queue->last_used_idx; 174*ca059fa5SYuanhan Liu free_entries = avail_idx - start_idx; 175*ca059fa5SYuanhan Liu count = RTE_MIN(count, free_entries); 176*ca059fa5SYuanhan Liu count = RTE_MIN(count, (uint32_t)MAX_PKT_BURST); 177*ca059fa5SYuanhan Liu if (count == 0) 178*ca059fa5SYuanhan Liu return 0; 179*ca059fa5SYuanhan Liu 180*ca059fa5SYuanhan Liu /* Retrieve all of the desc indexes first to avoid caching issues. */ 181*ca059fa5SYuanhan Liu rte_prefetch0(&vr->avail->ring[start_idx & (vr->size - 1)]); 182*ca059fa5SYuanhan Liu for (i = 0; i < count; i++) { 183*ca059fa5SYuanhan Liu used_idx = (start_idx + i) & (vr->size - 1); 184*ca059fa5SYuanhan Liu desc_indexes[i] = vr->avail->ring[used_idx]; 185*ca059fa5SYuanhan Liu vr->used->ring[used_idx].id = desc_indexes[i]; 186*ca059fa5SYuanhan Liu vr->used->ring[used_idx].len = pkts[i]->pkt_len + 187*ca059fa5SYuanhan Liu dev->hdr_len; 188*ca059fa5SYuanhan Liu } 189*ca059fa5SYuanhan Liu 190*ca059fa5SYuanhan Liu rte_prefetch0(&vr->desc[desc_indexes[0]]); 191*ca059fa5SYuanhan Liu for (i = 0; i < count; i++) { 192*ca059fa5SYuanhan Liu uint16_t desc_idx = desc_indexes[i]; 193*ca059fa5SYuanhan Liu int err; 194*ca059fa5SYuanhan Liu 195*ca059fa5SYuanhan Liu err = enqueue_pkt(dev, vr, pkts[i], desc_idx); 196*ca059fa5SYuanhan Liu if (unlikely(err)) { 197*ca059fa5SYuanhan Liu used_idx = (start_idx + i) & (vr->size - 1); 198*ca059fa5SYuanhan Liu vr->used->ring[used_idx].len = dev->hdr_len; 199*ca059fa5SYuanhan Liu } 200*ca059fa5SYuanhan Liu 201*ca059fa5SYuanhan Liu if (i + 1 < count) 202*ca059fa5SYuanhan Liu rte_prefetch0(&vr->desc[desc_indexes[i+1]]); 203*ca059fa5SYuanhan Liu } 204*ca059fa5SYuanhan Liu 205*ca059fa5SYuanhan Liu rte_smp_wmb(); 206*ca059fa5SYuanhan Liu 207*ca059fa5SYuanhan Liu *(volatile uint16_t *)&vr->used->idx += count; 208*ca059fa5SYuanhan Liu queue->last_used_idx += count; 209*ca059fa5SYuanhan Liu 210*ca059fa5SYuanhan Liu /* flush used->idx update before we read avail->flags. */ 211*ca059fa5SYuanhan Liu rte_mb(); 212*ca059fa5SYuanhan Liu 213*ca059fa5SYuanhan Liu /* Kick the guest if necessary. */ 214*ca059fa5SYuanhan Liu if (!(vr->avail->flags & VRING_AVAIL_F_NO_INTERRUPT) 215*ca059fa5SYuanhan Liu && (vr->callfd >= 0)) 216*ca059fa5SYuanhan Liu eventfd_write(vr->callfd, (eventfd_t)1); 217*ca059fa5SYuanhan Liu return count; 218*ca059fa5SYuanhan Liu } 219*ca059fa5SYuanhan Liu 220*ca059fa5SYuanhan Liu static inline int __attribute__((always_inline)) 221*ca059fa5SYuanhan Liu dequeue_pkt(struct vhost_dev *dev, struct rte_vhost_vring *vr, 222*ca059fa5SYuanhan Liu struct rte_mbuf *m, uint16_t desc_idx, 223*ca059fa5SYuanhan Liu struct rte_mempool *mbuf_pool) 224*ca059fa5SYuanhan Liu { 225*ca059fa5SYuanhan Liu struct vring_desc *desc; 226*ca059fa5SYuanhan Liu uint64_t desc_addr; 227*ca059fa5SYuanhan Liu uint32_t desc_avail, desc_offset; 228*ca059fa5SYuanhan Liu uint32_t mbuf_avail, mbuf_offset; 229*ca059fa5SYuanhan Liu uint32_t cpy_len; 230*ca059fa5SYuanhan Liu struct rte_mbuf *cur = m, *prev = m; 231*ca059fa5SYuanhan Liu /* A counter to avoid desc dead loop chain */ 232*ca059fa5SYuanhan Liu uint32_t nr_desc = 1; 233*ca059fa5SYuanhan Liu 234*ca059fa5SYuanhan Liu desc = &vr->desc[desc_idx]; 235*ca059fa5SYuanhan Liu if (unlikely((desc->len < dev->hdr_len)) || 236*ca059fa5SYuanhan Liu (desc->flags & VRING_DESC_F_INDIRECT)) 237*ca059fa5SYuanhan Liu return -1; 238*ca059fa5SYuanhan Liu 239*ca059fa5SYuanhan Liu desc_addr = rte_vhost_gpa_to_vva(dev->mem, desc->addr); 240*ca059fa5SYuanhan Liu if (unlikely(!desc_addr)) 241*ca059fa5SYuanhan Liu return -1; 242*ca059fa5SYuanhan Liu 243*ca059fa5SYuanhan Liu /* 244*ca059fa5SYuanhan Liu * We don't support ANY_LAYOUT, neither VERSION_1, meaning 245*ca059fa5SYuanhan Liu * a Tx packet from guest must have 2 desc buffers at least: 246*ca059fa5SYuanhan Liu * the first for storing the header and the others for 247*ca059fa5SYuanhan Liu * storing the data. 248*ca059fa5SYuanhan Liu * 249*ca059fa5SYuanhan Liu * And since we don't support TSO, we could simply skip the 250*ca059fa5SYuanhan Liu * header. 251*ca059fa5SYuanhan Liu */ 252*ca059fa5SYuanhan Liu desc = &vr->desc[desc->next]; 253*ca059fa5SYuanhan Liu desc_addr = rte_vhost_gpa_to_vva(dev->mem, desc->addr); 254*ca059fa5SYuanhan Liu if (unlikely(!desc_addr)) 255*ca059fa5SYuanhan Liu return -1; 256*ca059fa5SYuanhan Liu rte_prefetch0((void *)(uintptr_t)desc_addr); 257*ca059fa5SYuanhan Liu 258*ca059fa5SYuanhan Liu desc_offset = 0; 259*ca059fa5SYuanhan Liu desc_avail = desc->len; 260*ca059fa5SYuanhan Liu nr_desc += 1; 261*ca059fa5SYuanhan Liu 262*ca059fa5SYuanhan Liu mbuf_offset = 0; 263*ca059fa5SYuanhan Liu mbuf_avail = m->buf_len - RTE_PKTMBUF_HEADROOM; 264*ca059fa5SYuanhan Liu while (1) { 265*ca059fa5SYuanhan Liu cpy_len = RTE_MIN(desc_avail, mbuf_avail); 266*ca059fa5SYuanhan Liu rte_memcpy(rte_pktmbuf_mtod_offset(cur, void *, 267*ca059fa5SYuanhan Liu mbuf_offset), 268*ca059fa5SYuanhan Liu (void *)((uintptr_t)(desc_addr + desc_offset)), 269*ca059fa5SYuanhan Liu cpy_len); 270*ca059fa5SYuanhan Liu 271*ca059fa5SYuanhan Liu mbuf_avail -= cpy_len; 272*ca059fa5SYuanhan Liu mbuf_offset += cpy_len; 273*ca059fa5SYuanhan Liu desc_avail -= cpy_len; 274*ca059fa5SYuanhan Liu desc_offset += cpy_len; 275*ca059fa5SYuanhan Liu 276*ca059fa5SYuanhan Liu /* This desc reaches to its end, get the next one */ 277*ca059fa5SYuanhan Liu if (desc_avail == 0) { 278*ca059fa5SYuanhan Liu if ((desc->flags & VRING_DESC_F_NEXT) == 0) 279*ca059fa5SYuanhan Liu break; 280*ca059fa5SYuanhan Liu 281*ca059fa5SYuanhan Liu if (unlikely(desc->next >= vr->size || 282*ca059fa5SYuanhan Liu ++nr_desc > vr->size)) 283*ca059fa5SYuanhan Liu return -1; 284*ca059fa5SYuanhan Liu desc = &vr->desc[desc->next]; 285*ca059fa5SYuanhan Liu 286*ca059fa5SYuanhan Liu desc_addr = rte_vhost_gpa_to_vva(dev->mem, desc->addr); 287*ca059fa5SYuanhan Liu if (unlikely(!desc_addr)) 288*ca059fa5SYuanhan Liu return -1; 289*ca059fa5SYuanhan Liu rte_prefetch0((void *)(uintptr_t)desc_addr); 290*ca059fa5SYuanhan Liu 291*ca059fa5SYuanhan Liu desc_offset = 0; 292*ca059fa5SYuanhan Liu desc_avail = desc->len; 293*ca059fa5SYuanhan Liu } 294*ca059fa5SYuanhan Liu 295*ca059fa5SYuanhan Liu /* 296*ca059fa5SYuanhan Liu * This mbuf reaches to its end, get a new one 297*ca059fa5SYuanhan Liu * to hold more data. 298*ca059fa5SYuanhan Liu */ 299*ca059fa5SYuanhan Liu if (mbuf_avail == 0) { 300*ca059fa5SYuanhan Liu cur = rte_pktmbuf_alloc(mbuf_pool); 301*ca059fa5SYuanhan Liu if (unlikely(cur == NULL)) { 302*ca059fa5SYuanhan Liu RTE_LOG(ERR, VHOST_DATA, "Failed to " 303*ca059fa5SYuanhan Liu "allocate memory for mbuf.\n"); 304*ca059fa5SYuanhan Liu return -1; 305*ca059fa5SYuanhan Liu } 306*ca059fa5SYuanhan Liu 307*ca059fa5SYuanhan Liu prev->next = cur; 308*ca059fa5SYuanhan Liu prev->data_len = mbuf_offset; 309*ca059fa5SYuanhan Liu m->nb_segs += 1; 310*ca059fa5SYuanhan Liu m->pkt_len += mbuf_offset; 311*ca059fa5SYuanhan Liu prev = cur; 312*ca059fa5SYuanhan Liu 313*ca059fa5SYuanhan Liu mbuf_offset = 0; 314*ca059fa5SYuanhan Liu mbuf_avail = cur->buf_len - RTE_PKTMBUF_HEADROOM; 315*ca059fa5SYuanhan Liu } 316*ca059fa5SYuanhan Liu } 317*ca059fa5SYuanhan Liu 318*ca059fa5SYuanhan Liu prev->data_len = mbuf_offset; 319*ca059fa5SYuanhan Liu m->pkt_len += mbuf_offset; 320*ca059fa5SYuanhan Liu 321*ca059fa5SYuanhan Liu return 0; 322*ca059fa5SYuanhan Liu } 323*ca059fa5SYuanhan Liu 324*ca059fa5SYuanhan Liu uint16_t 325*ca059fa5SYuanhan Liu vs_dequeue_pkts(struct vhost_dev *dev, uint16_t queue_id, 326*ca059fa5SYuanhan Liu struct rte_mempool *mbuf_pool, struct rte_mbuf **pkts, uint16_t count) 327*ca059fa5SYuanhan Liu { 328*ca059fa5SYuanhan Liu struct vhost_queue *queue; 329*ca059fa5SYuanhan Liu struct rte_vhost_vring *vr; 330*ca059fa5SYuanhan Liu uint32_t desc_indexes[MAX_PKT_BURST]; 331*ca059fa5SYuanhan Liu uint32_t used_idx; 332*ca059fa5SYuanhan Liu uint32_t i = 0; 333*ca059fa5SYuanhan Liu uint16_t free_entries; 334*ca059fa5SYuanhan Liu uint16_t avail_idx; 335*ca059fa5SYuanhan Liu 336*ca059fa5SYuanhan Liu queue = &dev->queues[queue_id]; 337*ca059fa5SYuanhan Liu vr = &queue->vr; 338*ca059fa5SYuanhan Liu 339*ca059fa5SYuanhan Liu free_entries = *((volatile uint16_t *)&vr->avail->idx) - 340*ca059fa5SYuanhan Liu queue->last_avail_idx; 341*ca059fa5SYuanhan Liu if (free_entries == 0) 342*ca059fa5SYuanhan Liu return 0; 343*ca059fa5SYuanhan Liu 344*ca059fa5SYuanhan Liu /* Prefetch available and used ring */ 345*ca059fa5SYuanhan Liu avail_idx = queue->last_avail_idx & (vr->size - 1); 346*ca059fa5SYuanhan Liu used_idx = queue->last_used_idx & (vr->size - 1); 347*ca059fa5SYuanhan Liu rte_prefetch0(&vr->avail->ring[avail_idx]); 348*ca059fa5SYuanhan Liu rte_prefetch0(&vr->used->ring[used_idx]); 349*ca059fa5SYuanhan Liu 350*ca059fa5SYuanhan Liu count = RTE_MIN(count, MAX_PKT_BURST); 351*ca059fa5SYuanhan Liu count = RTE_MIN(count, free_entries); 352*ca059fa5SYuanhan Liu 353*ca059fa5SYuanhan Liu /* 354*ca059fa5SYuanhan Liu * Retrieve all of the head indexes first and pre-update used entries 355*ca059fa5SYuanhan Liu * to avoid caching issues. 356*ca059fa5SYuanhan Liu */ 357*ca059fa5SYuanhan Liu for (i = 0; i < count; i++) { 358*ca059fa5SYuanhan Liu avail_idx = (queue->last_avail_idx + i) & (vr->size - 1); 359*ca059fa5SYuanhan Liu used_idx = (queue->last_used_idx + i) & (vr->size - 1); 360*ca059fa5SYuanhan Liu desc_indexes[i] = vr->avail->ring[avail_idx]; 361*ca059fa5SYuanhan Liu 362*ca059fa5SYuanhan Liu vr->used->ring[used_idx].id = desc_indexes[i]; 363*ca059fa5SYuanhan Liu vr->used->ring[used_idx].len = 0; 364*ca059fa5SYuanhan Liu } 365*ca059fa5SYuanhan Liu 366*ca059fa5SYuanhan Liu /* Prefetch descriptor index. */ 367*ca059fa5SYuanhan Liu rte_prefetch0(&vr->desc[desc_indexes[0]]); 368*ca059fa5SYuanhan Liu for (i = 0; i < count; i++) { 369*ca059fa5SYuanhan Liu int err; 370*ca059fa5SYuanhan Liu 371*ca059fa5SYuanhan Liu if (likely(i + 1 < count)) 372*ca059fa5SYuanhan Liu rte_prefetch0(&vr->desc[desc_indexes[i + 1]]); 373*ca059fa5SYuanhan Liu 374*ca059fa5SYuanhan Liu pkts[i] = rte_pktmbuf_alloc(mbuf_pool); 375*ca059fa5SYuanhan Liu if (unlikely(pkts[i] == NULL)) { 376*ca059fa5SYuanhan Liu RTE_LOG(ERR, VHOST_DATA, 377*ca059fa5SYuanhan Liu "Failed to allocate memory for mbuf.\n"); 378*ca059fa5SYuanhan Liu break; 379*ca059fa5SYuanhan Liu } 380*ca059fa5SYuanhan Liu 381*ca059fa5SYuanhan Liu err = dequeue_pkt(dev, vr, pkts[i], desc_indexes[i], mbuf_pool); 382*ca059fa5SYuanhan Liu if (unlikely(err)) { 383*ca059fa5SYuanhan Liu rte_pktmbuf_free(pkts[i]); 384*ca059fa5SYuanhan Liu break; 385*ca059fa5SYuanhan Liu } 386*ca059fa5SYuanhan Liu 387*ca059fa5SYuanhan Liu } 388*ca059fa5SYuanhan Liu if (!i) 389*ca059fa5SYuanhan Liu return 0; 390*ca059fa5SYuanhan Liu 391*ca059fa5SYuanhan Liu queue->last_avail_idx += i; 392*ca059fa5SYuanhan Liu queue->last_used_idx += i; 393*ca059fa5SYuanhan Liu rte_smp_wmb(); 394*ca059fa5SYuanhan Liu rte_smp_rmb(); 395*ca059fa5SYuanhan Liu 396*ca059fa5SYuanhan Liu vr->used->idx += i; 397*ca059fa5SYuanhan Liu 398*ca059fa5SYuanhan Liu if (!(vr->avail->flags & VRING_AVAIL_F_NO_INTERRUPT) 399*ca059fa5SYuanhan Liu && (vr->callfd >= 0)) 400*ca059fa5SYuanhan Liu eventfd_write(vr->callfd, (eventfd_t)1); 401*ca059fa5SYuanhan Liu 402*ca059fa5SYuanhan Liu return i; 403*ca059fa5SYuanhan Liu } 404