New upstream version 18.02.1
[deb_dpdk.git] / examples / vhost / virtio_net.c
index 1ab57f5..5a965a3 100644 (file)
@@ -1,34 +1,5 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2017 Intel Corporation. All rights reserved.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2017 Intel Corporation
  */
 
 #include <stdint.h>
@@ -85,16 +56,20 @@ enqueue_pkt(struct vhost_dev *dev, struct rte_vhost_vring *vr,
            struct rte_mbuf *m, uint16_t desc_idx)
 {
        uint32_t desc_avail, desc_offset;
+       uint64_t desc_chunck_len;
        uint32_t mbuf_avail, mbuf_offset;
        uint32_t cpy_len;
        struct vring_desc *desc;
-       uint64_t desc_addr;
+       uint64_t desc_addr, desc_gaddr;
        struct virtio_net_hdr virtio_hdr = {0, 0, 0, 0, 0, 0};
        /* A counter to avoid desc dead loop chain */
        uint16_t nr_desc = 1;
 
        desc = &vr->desc[desc_idx];
-       desc_addr = rte_vhost_gpa_to_vva(dev->mem, desc->addr);
+       desc_chunck_len = desc->len;
+       desc_gaddr = desc->addr;
+       desc_addr = rte_vhost_va_from_guest_pa(
+                       dev->mem, desc_gaddr, &desc_chunck_len);
        /*
         * Checking of 'desc_addr' placed outside of 'unlikely' macro to avoid
         * performance issue with some versions of gcc (4.8.4 and 5.3.0) which
@@ -106,9 +81,42 @@ enqueue_pkt(struct vhost_dev *dev, struct rte_vhost_vring *vr,
        rte_prefetch0((void *)(uintptr_t)desc_addr);
 
        /* write virtio-net header */
-       *(struct virtio_net_hdr *)(uintptr_t)desc_addr = virtio_hdr;
+       if (likely(desc_chunck_len >= dev->hdr_len)) {
+               *(struct virtio_net_hdr *)(uintptr_t)desc_addr = virtio_hdr;
+               desc_offset = dev->hdr_len;
+       } else {
+               uint64_t len;
+               uint64_t remain = dev->hdr_len;
+               uint64_t src = (uint64_t)(uintptr_t)&virtio_hdr, dst;
+               uint64_t guest_addr = desc_gaddr;
+
+               while (remain) {
+                       len = remain;
+                       dst = rte_vhost_va_from_guest_pa(dev->mem,
+                                       guest_addr, &len);
+                       if (unlikely(!dst || !len))
+                               return -1;
+
+                       rte_memcpy((void *)(uintptr_t)dst,
+                                       (void *)(uintptr_t)src,
+                                       len);
+
+                       remain -= len;
+                       guest_addr += len;
+                       dst += len;
+               }
+
+               desc_chunck_len = desc->len - dev->hdr_len;
+               desc_gaddr += dev->hdr_len;
+               desc_addr = rte_vhost_va_from_guest_pa(
+                               dev->mem, desc_gaddr,
+                               &desc_chunck_len);
+               if (unlikely(!desc_addr))
+                       return -1;
+
+               desc_offset = 0;
+       }
 
-       desc_offset = dev->hdr_len;
        desc_avail  = desc->len - dev->hdr_len;
 
        mbuf_avail  = rte_pktmbuf_data_len(m);
@@ -133,15 +141,28 @@ enqueue_pkt(struct vhost_dev *dev, struct rte_vhost_vring *vr,
                                return -1;
 
                        desc = &vr->desc[desc->next];
-                       desc_addr = rte_vhost_gpa_to_vva(dev->mem, desc->addr);
+                       desc_chunck_len = desc->len;
+                       desc_gaddr = desc->addr;
+                       desc_addr = rte_vhost_va_from_guest_pa(
+                                       dev->mem, desc_gaddr, &desc_chunck_len);
                        if (unlikely(!desc_addr))
                                return -1;
 
                        desc_offset = 0;
                        desc_avail  = desc->len;
+               } else if (unlikely(desc_chunck_len == 0)) {
+                       desc_chunck_len = desc_avail;
+                       desc_gaddr += desc_offset;
+                       desc_addr = rte_vhost_va_from_guest_pa(dev->mem,
+                                       desc_gaddr,
+                                       &desc_chunck_len);
+                       if (unlikely(!desc_addr))
+                               return -1;
+
+                       desc_offset = 0;
                }
 
-               cpy_len = RTE_MIN(desc_avail, mbuf_avail);
+               cpy_len = RTE_MIN(desc_chunck_len, mbuf_avail);
                rte_memcpy((void *)((uintptr_t)(desc_addr + desc_offset)),
                        rte_pktmbuf_mtod_offset(m, void *, mbuf_offset),
                        cpy_len);
@@ -150,6 +171,7 @@ enqueue_pkt(struct vhost_dev *dev, struct rte_vhost_vring *vr,
                mbuf_offset += cpy_len;
                desc_avail  -= cpy_len;
                desc_offset += cpy_len;
+               desc_chunck_len -= cpy_len;
        }
 
        return 0;
@@ -207,13 +229,8 @@ vs_enqueue_pkts(struct vhost_dev *dev, uint16_t queue_id,
        *(volatile uint16_t *)&vr->used->idx += count;
        queue->last_used_idx += count;
 
-       /* flush used->idx update before we read avail->flags. */
-       rte_mb();
+       rte_vhost_vring_call(dev->vid, queue_id);
 
-       /* Kick the guest if necessary. */
-       if (!(vr->avail->flags & VRING_AVAIL_F_NO_INTERRUPT)
-                       && (vr->callfd >= 0))
-               eventfd_write(vr->callfd, (eventfd_t)1);
        return count;
 }
 
@@ -223,8 +240,9 @@ dequeue_pkt(struct vhost_dev *dev, struct rte_vhost_vring *vr,
            struct rte_mempool *mbuf_pool)
 {
        struct vring_desc *desc;
-       uint64_t desc_addr;
+       uint64_t desc_addr, desc_gaddr;
        uint32_t desc_avail, desc_offset;
+       uint64_t desc_chunck_len;
        uint32_t mbuf_avail, mbuf_offset;
        uint32_t cpy_len;
        struct rte_mbuf *cur = m, *prev = m;
@@ -236,7 +254,10 @@ dequeue_pkt(struct vhost_dev *dev, struct rte_vhost_vring *vr,
                        (desc->flags & VRING_DESC_F_INDIRECT))
                return -1;
 
-       desc_addr = rte_vhost_gpa_to_vva(dev->mem, desc->addr);
+       desc_chunck_len = desc->len;
+       desc_gaddr = desc->addr;
+       desc_addr = rte_vhost_va_from_guest_pa(
+                       dev->mem, desc_gaddr, &desc_chunck_len);
        if (unlikely(!desc_addr))
                return -1;
 
@@ -250,7 +271,10 @@ dequeue_pkt(struct vhost_dev *dev, struct rte_vhost_vring *vr,
         * header.
         */
        desc = &vr->desc[desc->next];
-       desc_addr = rte_vhost_gpa_to_vva(dev->mem, desc->addr);
+       desc_chunck_len = desc->len;
+       desc_gaddr = desc->addr;
+       desc_addr = rte_vhost_va_from_guest_pa(
+                       dev->mem, desc_gaddr, &desc_chunck_len);
        if (unlikely(!desc_addr))
                return -1;
        rte_prefetch0((void *)(uintptr_t)desc_addr);
@@ -262,7 +286,7 @@ dequeue_pkt(struct vhost_dev *dev, struct rte_vhost_vring *vr,
        mbuf_offset = 0;
        mbuf_avail  = m->buf_len - RTE_PKTMBUF_HEADROOM;
        while (1) {
-               cpy_len = RTE_MIN(desc_avail, mbuf_avail);
+               cpy_len = RTE_MIN(desc_chunck_len, mbuf_avail);
                rte_memcpy(rte_pktmbuf_mtod_offset(cur, void *,
                                                   mbuf_offset),
                        (void *)((uintptr_t)(desc_addr + desc_offset)),
@@ -272,6 +296,7 @@ dequeue_pkt(struct vhost_dev *dev, struct rte_vhost_vring *vr,
                mbuf_offset += cpy_len;
                desc_avail  -= cpy_len;
                desc_offset += cpy_len;
+               desc_chunck_len -= cpy_len;
 
                /* This desc reaches to its end, get the next one */
                if (desc_avail == 0) {
@@ -283,13 +308,26 @@ dequeue_pkt(struct vhost_dev *dev, struct rte_vhost_vring *vr,
                                return -1;
                        desc = &vr->desc[desc->next];
 
-                       desc_addr = rte_vhost_gpa_to_vva(dev->mem, desc->addr);
+                       desc_chunck_len = desc->len;
+                       desc_gaddr = desc->addr;
+                       desc_addr = rte_vhost_va_from_guest_pa(
+                                       dev->mem, desc_gaddr, &desc_chunck_len);
                        if (unlikely(!desc_addr))
                                return -1;
                        rte_prefetch0((void *)(uintptr_t)desc_addr);
 
                        desc_offset = 0;
                        desc_avail  = desc->len;
+               } else if (unlikely(desc_chunck_len == 0)) {
+                       desc_chunck_len = desc_avail;
+                       desc_gaddr += desc_offset;
+                       desc_addr = rte_vhost_va_from_guest_pa(dev->mem,
+                                       desc_gaddr,
+                                       &desc_chunck_len);
+                       if (unlikely(!desc_addr))
+                               return -1;
+
+                       desc_offset = 0;
                }
 
                /*
@@ -396,9 +434,7 @@ vs_dequeue_pkts(struct vhost_dev *dev, uint16_t queue_id,
 
        vr->used->idx += i;
 
-       if (!(vr->avail->flags & VRING_AVAIL_F_NO_INTERRUPT)
-                       && (vr->callfd >= 0))
-               eventfd_write(vr->callfd, (eventfd_t)1);
+       rte_vhost_vring_call(dev->vid, queue_id);
 
        return i;
 }