13998e2a0SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 23998e2a0SBruce Richardson * Copyright(c) 2010-2017 Intel Corporation 3ca059fa5SYuanhan Liu */ 4ca059fa5SYuanhan Liu 5ca059fa5SYuanhan Liu #include <stdint.h> 6ca059fa5SYuanhan Liu #include <stdbool.h> 7ca059fa5SYuanhan Liu #include <linux/virtio_net.h> 8ca059fa5SYuanhan Liu 9ca059fa5SYuanhan Liu #include <rte_mbuf.h> 10ca059fa5SYuanhan Liu #include <rte_memcpy.h> 11ca059fa5SYuanhan Liu #include <rte_vhost.h> 12ca059fa5SYuanhan Liu 13ca059fa5SYuanhan Liu #include "main.h" 14ca059fa5SYuanhan Liu 15ca059fa5SYuanhan Liu /* 16ca059fa5SYuanhan Liu * A very simple vhost-user net driver implementation, without 17ca059fa5SYuanhan Liu * any extra features being enabled, such as TSO and mrg-Rx. 18ca059fa5SYuanhan Liu */ 19ca059fa5SYuanhan Liu 20ca059fa5SYuanhan Liu void 21ca059fa5SYuanhan Liu vs_vhost_net_setup(struct vhost_dev *dev) 22ca059fa5SYuanhan Liu { 23ca059fa5SYuanhan Liu uint16_t i; 24ca059fa5SYuanhan Liu int vid = dev->vid; 25ca059fa5SYuanhan Liu struct vhost_queue *queue; 26ca059fa5SYuanhan Liu 27ca059fa5SYuanhan Liu RTE_LOG(INFO, VHOST_CONFIG, 28ca059fa5SYuanhan Liu "setting builtin vhost-user net driver\n"); 29ca059fa5SYuanhan Liu 30ca059fa5SYuanhan Liu rte_vhost_get_negotiated_features(vid, &dev->features); 31ca059fa5SYuanhan Liu if (dev->features & (1 << VIRTIO_NET_F_MRG_RXBUF)) 32ca059fa5SYuanhan Liu dev->hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf); 33ca059fa5SYuanhan Liu else 34ca059fa5SYuanhan Liu dev->hdr_len = sizeof(struct virtio_net_hdr); 35ca059fa5SYuanhan Liu 36ca059fa5SYuanhan Liu rte_vhost_get_mem_table(vid, &dev->mem); 37ca059fa5SYuanhan Liu 38ca059fa5SYuanhan Liu dev->nr_vrings = rte_vhost_get_vring_num(vid); 39ca059fa5SYuanhan Liu for (i = 0; i < dev->nr_vrings; i++) { 40ca059fa5SYuanhan Liu queue = &dev->queues[i]; 41ca059fa5SYuanhan Liu 42ca059fa5SYuanhan Liu queue->last_used_idx = 0; 43ca059fa5SYuanhan Liu queue->last_avail_idx = 0; 44ca059fa5SYuanhan Liu rte_vhost_get_vhost_vring(vid, i, &queue->vr); 45ca059fa5SYuanhan Liu } 46ca059fa5SYuanhan Liu } 47ca059fa5SYuanhan Liu 48ca059fa5SYuanhan Liu void 49ca059fa5SYuanhan Liu vs_vhost_net_remove(struct vhost_dev *dev) 50ca059fa5SYuanhan Liu { 51ca059fa5SYuanhan Liu free(dev->mem); 52ca059fa5SYuanhan Liu } 53ca059fa5SYuanhan Liu 54c0583d98SJerin Jacob static __rte_always_inline int 55ca059fa5SYuanhan Liu enqueue_pkt(struct vhost_dev *dev, struct rte_vhost_vring *vr, 56ca059fa5SYuanhan Liu struct rte_mbuf *m, uint16_t desc_idx) 57ca059fa5SYuanhan Liu { 58ca059fa5SYuanhan Liu uint32_t desc_avail, desc_offset; 59ca059fa5SYuanhan Liu uint32_t mbuf_avail, mbuf_offset; 60ca059fa5SYuanhan Liu uint32_t cpy_len; 61ca059fa5SYuanhan Liu struct vring_desc *desc; 62ca059fa5SYuanhan Liu uint64_t desc_addr; 63ca059fa5SYuanhan Liu struct virtio_net_hdr virtio_hdr = {0, 0, 0, 0, 0, 0}; 64ca059fa5SYuanhan Liu /* A counter to avoid desc dead loop chain */ 65ca059fa5SYuanhan Liu uint16_t nr_desc = 1; 66ca059fa5SYuanhan Liu 67ca059fa5SYuanhan Liu desc = &vr->desc[desc_idx]; 68ca059fa5SYuanhan Liu desc_addr = rte_vhost_gpa_to_vva(dev->mem, desc->addr); 69ca059fa5SYuanhan Liu /* 70ca059fa5SYuanhan Liu * Checking of 'desc_addr' placed outside of 'unlikely' macro to avoid 71ca059fa5SYuanhan Liu * performance issue with some versions of gcc (4.8.4 and 5.3.0) which 72ca059fa5SYuanhan Liu * otherwise stores offset on the stack instead of in a register. 73ca059fa5SYuanhan Liu */ 74ca059fa5SYuanhan Liu if (unlikely(desc->len < dev->hdr_len) || !desc_addr) 75ca059fa5SYuanhan Liu return -1; 76ca059fa5SYuanhan Liu 77ca059fa5SYuanhan Liu rte_prefetch0((void *)(uintptr_t)desc_addr); 78ca059fa5SYuanhan Liu 79ca059fa5SYuanhan Liu /* write virtio-net header */ 80ca059fa5SYuanhan Liu *(struct virtio_net_hdr *)(uintptr_t)desc_addr = virtio_hdr; 81ca059fa5SYuanhan Liu 82ca059fa5SYuanhan Liu desc_offset = dev->hdr_len; 83ca059fa5SYuanhan Liu desc_avail = desc->len - dev->hdr_len; 84ca059fa5SYuanhan Liu 85ca059fa5SYuanhan Liu mbuf_avail = rte_pktmbuf_data_len(m); 86ca059fa5SYuanhan Liu mbuf_offset = 0; 87ca059fa5SYuanhan Liu while (mbuf_avail != 0 || m->next != NULL) { 88ca059fa5SYuanhan Liu /* done with current mbuf, fetch next */ 89ca059fa5SYuanhan Liu if (mbuf_avail == 0) { 90ca059fa5SYuanhan Liu m = m->next; 91ca059fa5SYuanhan Liu 92ca059fa5SYuanhan Liu mbuf_offset = 0; 93ca059fa5SYuanhan Liu mbuf_avail = rte_pktmbuf_data_len(m); 94ca059fa5SYuanhan Liu } 95ca059fa5SYuanhan Liu 96ca059fa5SYuanhan Liu /* done with current desc buf, fetch next */ 97ca059fa5SYuanhan Liu if (desc_avail == 0) { 98ca059fa5SYuanhan Liu if ((desc->flags & VRING_DESC_F_NEXT) == 0) { 99ca059fa5SYuanhan Liu /* Room in vring buffer is not enough */ 100ca059fa5SYuanhan Liu return -1; 101ca059fa5SYuanhan Liu } 102ca059fa5SYuanhan Liu if (unlikely(desc->next >= vr->size || 103ca059fa5SYuanhan Liu ++nr_desc > vr->size)) 104ca059fa5SYuanhan Liu return -1; 105ca059fa5SYuanhan Liu 106ca059fa5SYuanhan Liu desc = &vr->desc[desc->next]; 107ca059fa5SYuanhan Liu desc_addr = rte_vhost_gpa_to_vva(dev->mem, desc->addr); 108ca059fa5SYuanhan Liu if (unlikely(!desc_addr)) 109ca059fa5SYuanhan Liu return -1; 110ca059fa5SYuanhan Liu 111ca059fa5SYuanhan Liu desc_offset = 0; 112ca059fa5SYuanhan Liu desc_avail = desc->len; 113ca059fa5SYuanhan Liu } 114ca059fa5SYuanhan Liu 115ca059fa5SYuanhan Liu cpy_len = RTE_MIN(desc_avail, mbuf_avail); 116ca059fa5SYuanhan Liu rte_memcpy((void *)((uintptr_t)(desc_addr + desc_offset)), 117ca059fa5SYuanhan Liu rte_pktmbuf_mtod_offset(m, void *, mbuf_offset), 118ca059fa5SYuanhan Liu cpy_len); 119ca059fa5SYuanhan Liu 120ca059fa5SYuanhan Liu mbuf_avail -= cpy_len; 121ca059fa5SYuanhan Liu mbuf_offset += cpy_len; 122ca059fa5SYuanhan Liu desc_avail -= cpy_len; 123ca059fa5SYuanhan Liu desc_offset += cpy_len; 124ca059fa5SYuanhan Liu } 125ca059fa5SYuanhan Liu 126ca059fa5SYuanhan Liu return 0; 127ca059fa5SYuanhan Liu } 128ca059fa5SYuanhan Liu 129ca059fa5SYuanhan Liu uint16_t 130ca059fa5SYuanhan Liu vs_enqueue_pkts(struct vhost_dev *dev, uint16_t queue_id, 131ca059fa5SYuanhan Liu struct rte_mbuf **pkts, uint32_t count) 132ca059fa5SYuanhan Liu { 133ca059fa5SYuanhan Liu struct vhost_queue *queue; 134ca059fa5SYuanhan Liu struct rte_vhost_vring *vr; 135ca059fa5SYuanhan Liu uint16_t avail_idx, free_entries, start_idx; 136ca059fa5SYuanhan Liu uint16_t desc_indexes[MAX_PKT_BURST]; 137ca059fa5SYuanhan Liu uint16_t used_idx; 138ca059fa5SYuanhan Liu uint32_t i; 139ca059fa5SYuanhan Liu 140ca059fa5SYuanhan Liu queue = &dev->queues[queue_id]; 141ca059fa5SYuanhan Liu vr = &queue->vr; 142ca059fa5SYuanhan Liu 143ca059fa5SYuanhan Liu avail_idx = *((volatile uint16_t *)&vr->avail->idx); 144ca059fa5SYuanhan Liu start_idx = queue->last_used_idx; 145ca059fa5SYuanhan Liu free_entries = avail_idx - start_idx; 146ca059fa5SYuanhan Liu count = RTE_MIN(count, free_entries); 147ca059fa5SYuanhan Liu count = RTE_MIN(count, (uint32_t)MAX_PKT_BURST); 148ca059fa5SYuanhan Liu if (count == 0) 149ca059fa5SYuanhan Liu return 0; 150ca059fa5SYuanhan Liu 151ca059fa5SYuanhan Liu /* Retrieve all of the desc indexes first to avoid caching issues. */ 152ca059fa5SYuanhan Liu rte_prefetch0(&vr->avail->ring[start_idx & (vr->size - 1)]); 153ca059fa5SYuanhan Liu for (i = 0; i < count; i++) { 154ca059fa5SYuanhan Liu used_idx = (start_idx + i) & (vr->size - 1); 155ca059fa5SYuanhan Liu desc_indexes[i] = vr->avail->ring[used_idx]; 156ca059fa5SYuanhan Liu vr->used->ring[used_idx].id = desc_indexes[i]; 157ca059fa5SYuanhan Liu vr->used->ring[used_idx].len = pkts[i]->pkt_len + 158ca059fa5SYuanhan Liu dev->hdr_len; 159ca059fa5SYuanhan Liu } 160ca059fa5SYuanhan Liu 161ca059fa5SYuanhan Liu rte_prefetch0(&vr->desc[desc_indexes[0]]); 162ca059fa5SYuanhan Liu for (i = 0; i < count; i++) { 163ca059fa5SYuanhan Liu uint16_t desc_idx = desc_indexes[i]; 164ca059fa5SYuanhan Liu int err; 165ca059fa5SYuanhan Liu 166ca059fa5SYuanhan Liu err = enqueue_pkt(dev, vr, pkts[i], desc_idx); 167ca059fa5SYuanhan Liu if (unlikely(err)) { 168ca059fa5SYuanhan Liu used_idx = (start_idx + i) & (vr->size - 1); 169ca059fa5SYuanhan Liu vr->used->ring[used_idx].len = dev->hdr_len; 170ca059fa5SYuanhan Liu } 171ca059fa5SYuanhan Liu 172ca059fa5SYuanhan Liu if (i + 1 < count) 173ca059fa5SYuanhan Liu rte_prefetch0(&vr->desc[desc_indexes[i+1]]); 174ca059fa5SYuanhan Liu } 175ca059fa5SYuanhan Liu 176ca059fa5SYuanhan Liu rte_smp_wmb(); 177ca059fa5SYuanhan Liu 178ca059fa5SYuanhan Liu *(volatile uint16_t *)&vr->used->idx += count; 179ca059fa5SYuanhan Liu queue->last_used_idx += count; 180ca059fa5SYuanhan Liu 181*6c299bb7SStefan Hajnoczi rte_vhost_vring_call(dev->vid, queue_id); 182ca059fa5SYuanhan Liu 183ca059fa5SYuanhan Liu return count; 184ca059fa5SYuanhan Liu } 185ca059fa5SYuanhan Liu 186c0583d98SJerin Jacob static __rte_always_inline int 187ca059fa5SYuanhan Liu dequeue_pkt(struct vhost_dev *dev, struct rte_vhost_vring *vr, 188ca059fa5SYuanhan Liu struct rte_mbuf *m, uint16_t desc_idx, 189ca059fa5SYuanhan Liu struct rte_mempool *mbuf_pool) 190ca059fa5SYuanhan Liu { 191ca059fa5SYuanhan Liu struct vring_desc *desc; 192ca059fa5SYuanhan Liu uint64_t desc_addr; 193ca059fa5SYuanhan Liu uint32_t desc_avail, desc_offset; 194ca059fa5SYuanhan Liu uint32_t mbuf_avail, mbuf_offset; 195ca059fa5SYuanhan Liu uint32_t cpy_len; 196ca059fa5SYuanhan Liu struct rte_mbuf *cur = m, *prev = m; 197ca059fa5SYuanhan Liu /* A counter to avoid desc dead loop chain */ 198ca059fa5SYuanhan Liu uint32_t nr_desc = 1; 199ca059fa5SYuanhan Liu 200ca059fa5SYuanhan Liu desc = &vr->desc[desc_idx]; 201ca059fa5SYuanhan Liu if (unlikely((desc->len < dev->hdr_len)) || 202ca059fa5SYuanhan Liu (desc->flags & VRING_DESC_F_INDIRECT)) 203ca059fa5SYuanhan Liu return -1; 204ca059fa5SYuanhan Liu 205ca059fa5SYuanhan Liu desc_addr = rte_vhost_gpa_to_vva(dev->mem, desc->addr); 206ca059fa5SYuanhan Liu if (unlikely(!desc_addr)) 207ca059fa5SYuanhan Liu return -1; 208ca059fa5SYuanhan Liu 209ca059fa5SYuanhan Liu /* 210ca059fa5SYuanhan Liu * We don't support ANY_LAYOUT, neither VERSION_1, meaning 211ca059fa5SYuanhan Liu * a Tx packet from guest must have 2 desc buffers at least: 212ca059fa5SYuanhan Liu * the first for storing the header and the others for 213ca059fa5SYuanhan Liu * storing the data. 214ca059fa5SYuanhan Liu * 215ca059fa5SYuanhan Liu * And since we don't support TSO, we could simply skip the 216ca059fa5SYuanhan Liu * header. 217ca059fa5SYuanhan Liu */ 218ca059fa5SYuanhan Liu desc = &vr->desc[desc->next]; 219ca059fa5SYuanhan Liu desc_addr = rte_vhost_gpa_to_vva(dev->mem, desc->addr); 220ca059fa5SYuanhan Liu if (unlikely(!desc_addr)) 221ca059fa5SYuanhan Liu return -1; 222ca059fa5SYuanhan Liu rte_prefetch0((void *)(uintptr_t)desc_addr); 223ca059fa5SYuanhan Liu 224ca059fa5SYuanhan Liu desc_offset = 0; 225ca059fa5SYuanhan Liu desc_avail = desc->len; 226ca059fa5SYuanhan Liu nr_desc += 1; 227ca059fa5SYuanhan Liu 228ca059fa5SYuanhan Liu mbuf_offset = 0; 229ca059fa5SYuanhan Liu mbuf_avail = m->buf_len - RTE_PKTMBUF_HEADROOM; 230ca059fa5SYuanhan Liu while (1) { 231ca059fa5SYuanhan Liu cpy_len = RTE_MIN(desc_avail, mbuf_avail); 232ca059fa5SYuanhan Liu rte_memcpy(rte_pktmbuf_mtod_offset(cur, void *, 233ca059fa5SYuanhan Liu mbuf_offset), 234ca059fa5SYuanhan Liu (void *)((uintptr_t)(desc_addr + desc_offset)), 235ca059fa5SYuanhan Liu cpy_len); 236ca059fa5SYuanhan Liu 237ca059fa5SYuanhan Liu mbuf_avail -= cpy_len; 238ca059fa5SYuanhan Liu mbuf_offset += cpy_len; 239ca059fa5SYuanhan Liu desc_avail -= cpy_len; 240ca059fa5SYuanhan Liu desc_offset += cpy_len; 241ca059fa5SYuanhan Liu 242ca059fa5SYuanhan Liu /* This desc reaches to its end, get the next one */ 243ca059fa5SYuanhan Liu if (desc_avail == 0) { 244ca059fa5SYuanhan Liu if ((desc->flags & VRING_DESC_F_NEXT) == 0) 245ca059fa5SYuanhan Liu break; 246ca059fa5SYuanhan Liu 247ca059fa5SYuanhan Liu if (unlikely(desc->next >= vr->size || 248ca059fa5SYuanhan Liu ++nr_desc > vr->size)) 249ca059fa5SYuanhan Liu return -1; 250ca059fa5SYuanhan Liu desc = &vr->desc[desc->next]; 251ca059fa5SYuanhan Liu 252ca059fa5SYuanhan Liu desc_addr = rte_vhost_gpa_to_vva(dev->mem, desc->addr); 253ca059fa5SYuanhan Liu if (unlikely(!desc_addr)) 254ca059fa5SYuanhan Liu return -1; 255ca059fa5SYuanhan Liu rte_prefetch0((void *)(uintptr_t)desc_addr); 256ca059fa5SYuanhan Liu 257ca059fa5SYuanhan Liu desc_offset = 0; 258ca059fa5SYuanhan Liu desc_avail = desc->len; 259ca059fa5SYuanhan Liu } 260ca059fa5SYuanhan Liu 261ca059fa5SYuanhan Liu /* 262ca059fa5SYuanhan Liu * This mbuf reaches to its end, get a new one 263ca059fa5SYuanhan Liu * to hold more data. 264ca059fa5SYuanhan Liu */ 265ca059fa5SYuanhan Liu if (mbuf_avail == 0) { 266ca059fa5SYuanhan Liu cur = rte_pktmbuf_alloc(mbuf_pool); 267ca059fa5SYuanhan Liu if (unlikely(cur == NULL)) { 268ca059fa5SYuanhan Liu RTE_LOG(ERR, VHOST_DATA, "Failed to " 269ca059fa5SYuanhan Liu "allocate memory for mbuf.\n"); 270ca059fa5SYuanhan Liu return -1; 271ca059fa5SYuanhan Liu } 272ca059fa5SYuanhan Liu 273ca059fa5SYuanhan Liu prev->next = cur; 274ca059fa5SYuanhan Liu prev->data_len = mbuf_offset; 275ca059fa5SYuanhan Liu m->nb_segs += 1; 276ca059fa5SYuanhan Liu m->pkt_len += mbuf_offset; 277ca059fa5SYuanhan Liu prev = cur; 278ca059fa5SYuanhan Liu 279ca059fa5SYuanhan Liu mbuf_offset = 0; 280ca059fa5SYuanhan Liu mbuf_avail = cur->buf_len - RTE_PKTMBUF_HEADROOM; 281ca059fa5SYuanhan Liu } 282ca059fa5SYuanhan Liu } 283ca059fa5SYuanhan Liu 284ca059fa5SYuanhan Liu prev->data_len = mbuf_offset; 285ca059fa5SYuanhan Liu m->pkt_len += mbuf_offset; 286ca059fa5SYuanhan Liu 287ca059fa5SYuanhan Liu return 0; 288ca059fa5SYuanhan Liu } 289ca059fa5SYuanhan Liu 290ca059fa5SYuanhan Liu uint16_t 291ca059fa5SYuanhan Liu vs_dequeue_pkts(struct vhost_dev *dev, uint16_t queue_id, 292ca059fa5SYuanhan Liu struct rte_mempool *mbuf_pool, struct rte_mbuf **pkts, uint16_t count) 293ca059fa5SYuanhan Liu { 294ca059fa5SYuanhan Liu struct vhost_queue *queue; 295ca059fa5SYuanhan Liu struct rte_vhost_vring *vr; 296ca059fa5SYuanhan Liu uint32_t desc_indexes[MAX_PKT_BURST]; 297ca059fa5SYuanhan Liu uint32_t used_idx; 298ca059fa5SYuanhan Liu uint32_t i = 0; 299ca059fa5SYuanhan Liu uint16_t free_entries; 300ca059fa5SYuanhan Liu uint16_t avail_idx; 301ca059fa5SYuanhan Liu 302ca059fa5SYuanhan Liu queue = &dev->queues[queue_id]; 303ca059fa5SYuanhan Liu vr = &queue->vr; 304ca059fa5SYuanhan Liu 305ca059fa5SYuanhan Liu free_entries = *((volatile uint16_t *)&vr->avail->idx) - 306ca059fa5SYuanhan Liu queue->last_avail_idx; 307ca059fa5SYuanhan Liu if (free_entries == 0) 308ca059fa5SYuanhan Liu return 0; 309ca059fa5SYuanhan Liu 310ca059fa5SYuanhan Liu /* Prefetch available and used ring */ 311ca059fa5SYuanhan Liu avail_idx = queue->last_avail_idx & (vr->size - 1); 312ca059fa5SYuanhan Liu used_idx = queue->last_used_idx & (vr->size - 1); 313ca059fa5SYuanhan Liu rte_prefetch0(&vr->avail->ring[avail_idx]); 314ca059fa5SYuanhan Liu rte_prefetch0(&vr->used->ring[used_idx]); 315ca059fa5SYuanhan Liu 316ca059fa5SYuanhan Liu count = RTE_MIN(count, MAX_PKT_BURST); 317ca059fa5SYuanhan Liu count = RTE_MIN(count, free_entries); 318ca059fa5SYuanhan Liu 31962a0e941SJerin Jacob if (unlikely(count == 0)) 32062a0e941SJerin Jacob return 0; 32162a0e941SJerin Jacob 322ca059fa5SYuanhan Liu /* 323ca059fa5SYuanhan Liu * Retrieve all of the head indexes first and pre-update used entries 324ca059fa5SYuanhan Liu * to avoid caching issues. 325ca059fa5SYuanhan Liu */ 326ca059fa5SYuanhan Liu for (i = 0; i < count; i++) { 327ca059fa5SYuanhan Liu avail_idx = (queue->last_avail_idx + i) & (vr->size - 1); 328ca059fa5SYuanhan Liu used_idx = (queue->last_used_idx + i) & (vr->size - 1); 329ca059fa5SYuanhan Liu desc_indexes[i] = vr->avail->ring[avail_idx]; 330ca059fa5SYuanhan Liu 331ca059fa5SYuanhan Liu vr->used->ring[used_idx].id = desc_indexes[i]; 332ca059fa5SYuanhan Liu vr->used->ring[used_idx].len = 0; 333ca059fa5SYuanhan Liu } 334ca059fa5SYuanhan Liu 335ca059fa5SYuanhan Liu /* Prefetch descriptor index. */ 336ca059fa5SYuanhan Liu rte_prefetch0(&vr->desc[desc_indexes[0]]); 337ca059fa5SYuanhan Liu for (i = 0; i < count; i++) { 338ca059fa5SYuanhan Liu int err; 339ca059fa5SYuanhan Liu 340ca059fa5SYuanhan Liu if (likely(i + 1 < count)) 341ca059fa5SYuanhan Liu rte_prefetch0(&vr->desc[desc_indexes[i + 1]]); 342ca059fa5SYuanhan Liu 343ca059fa5SYuanhan Liu pkts[i] = rte_pktmbuf_alloc(mbuf_pool); 344ca059fa5SYuanhan Liu if (unlikely(pkts[i] == NULL)) { 345ca059fa5SYuanhan Liu RTE_LOG(ERR, VHOST_DATA, 346ca059fa5SYuanhan Liu "Failed to allocate memory for mbuf.\n"); 347ca059fa5SYuanhan Liu break; 348ca059fa5SYuanhan Liu } 349ca059fa5SYuanhan Liu 350ca059fa5SYuanhan Liu err = dequeue_pkt(dev, vr, pkts[i], desc_indexes[i], mbuf_pool); 351ca059fa5SYuanhan Liu if (unlikely(err)) { 352ca059fa5SYuanhan Liu rte_pktmbuf_free(pkts[i]); 353ca059fa5SYuanhan Liu break; 354ca059fa5SYuanhan Liu } 355ca059fa5SYuanhan Liu 356ca059fa5SYuanhan Liu } 357ca059fa5SYuanhan Liu 358ca059fa5SYuanhan Liu queue->last_avail_idx += i; 359ca059fa5SYuanhan Liu queue->last_used_idx += i; 360ca059fa5SYuanhan Liu rte_smp_wmb(); 361ca059fa5SYuanhan Liu rte_smp_rmb(); 362ca059fa5SYuanhan Liu 363ca059fa5SYuanhan Liu vr->used->idx += i; 364ca059fa5SYuanhan Liu 365*6c299bb7SStefan Hajnoczi rte_vhost_vring_call(dev->vid, queue_id); 366ca059fa5SYuanhan Liu 367ca059fa5SYuanhan Liu return i; 368ca059fa5SYuanhan Liu } 369