net/virtio-user: fix packed vq option parsing
[dpdk.git] / drivers / net / virtio / virtqueue.h
index 9c4f96d..d8ae5cd 100644 (file)
@@ -1,34 +1,5 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2014 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-2014 Intel Corporation
  */
 
 #ifndef _VIRTQUEUE_H_
@@ -38,7 +9,6 @@
 
 #include <rte_atomic.h>
 #include <rte_memory.h>
-#include <rte_memzone.h>
 #include <rte_mempool.h>
 
 #include "virtio_pci.h"
@@ -80,7 +50,7 @@ struct rte_mbuf;
 #define VIRTIO_MBUF_ADDR(mb, vq) \
        ((uint64_t)(*(uintptr_t *)((uintptr_t)(mb) + (vq)->offset)))
 #else
-#define VIRTIO_MBUF_ADDR(mb, vq) ((mb)->buf_physaddr)
+#define VIRTIO_MBUF_ADDR(mb, vq) ((mb)->buf_iova)
 #endif
 
 /**
@@ -159,6 +129,17 @@ struct virtio_net_ctrl_mac {
 #define VIRTIO_NET_CTRL_VLAN_ADD 0
 #define VIRTIO_NET_CTRL_VLAN_DEL 1
 
+/*
+ * Control link announce acknowledgement
+ *
+ * The command VIRTIO_NET_CTRL_ANNOUNCE_ACK is used to indicate that
+ * driver has recevied the notification; device would clear the
+ * VIRTIO_NET_S_ANNOUNCE bit in the status field after it receives
+ * this command.
+ */
+#define VIRTIO_NET_CTRL_ANNOUNCE     3
+#define VIRTIO_NET_CTRL_ANNOUNCE_ACK 0
+
 struct virtio_net_ctrl_hdr {
        uint8_t class;
        uint8_t cmd;
@@ -180,11 +161,17 @@ struct virtio_pmd_ctrl {
 struct vq_desc_extra {
        void *cookie;
        uint16_t ndescs;
+       uint16_t next;
 };
 
 struct virtqueue {
        struct virtio_hw  *hw; /**< virtio_hw structure pointer. */
        struct vring vq_ring;  /**< vring keeping desc, used and avail */
+       struct vring_packed ring_packed;  /**< vring keeping descs */
+       bool avail_wrap_counter;
+       bool used_wrap_counter;
+       uint16_t event_flags_shadow;
+       uint16_t avail_used_flags;
        /**
         * Last consumed descriptor in the used table,
         * trails vq_ring.used->idx.
@@ -204,8 +191,8 @@ struct virtqueue {
                struct virtnet_ctl cq;
        };
 
-       phys_addr_t vq_ring_mem; /**< physical address of vring,
-                                 * or virtual address for virtio_user. */
+       rte_iova_t vq_ring_mem; /**< physical address of vring,
+                                * or virtual address for virtio_user. */
 
        /**
         * Head of the free chain in the descriptor table. If
@@ -227,8 +214,6 @@ struct virtqueue {
 #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN        1
 #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX        0x8000
 
-#define VIRTIO_NET_CTRL_MAC_ADDR_SET         1
-
 /**
  * This is the first element of the scatter-gather list.  If you don't
  * specify GSO or CSUM features, you can simply ignore the header.
@@ -262,13 +247,42 @@ struct virtio_net_hdr_mrg_rxbuf {
 #define VIRTIO_MAX_TX_INDIRECT 8
 struct virtio_tx_region {
        struct virtio_net_hdr_mrg_rxbuf tx_hdr;
-       struct vring_desc tx_indir[VIRTIO_MAX_TX_INDIRECT]
-                          __attribute__((__aligned__(16)));
+       union {
+               struct vring_desc tx_indir[VIRTIO_MAX_TX_INDIRECT]
+                       __attribute__((__aligned__(16)));
+               struct vring_packed_desc tx_indir_pq[VIRTIO_MAX_TX_INDIRECT]
+                       __attribute__((__aligned__(16)));
+       };
 };
 
+static inline int
+desc_is_used(struct vring_packed_desc *desc, struct virtqueue *vq)
+{
+       uint16_t used, avail, flags;
+
+       flags = desc->flags;
+       used = !!(flags & VRING_DESC_F_USED(1));
+       avail = !!(flags & VRING_DESC_F_AVAIL(1));
+
+       return avail == used && used == vq->used_wrap_counter;
+}
+
+
+static inline void
+vring_desc_init_packed(struct virtqueue *vq, int n)
+{
+       int i;
+       for (i = 0; i < n - 1; i++) {
+               vq->ring_packed.desc_packed[i].id = i;
+               vq->vq_descx[i].next = i + 1;
+       }
+       vq->ring_packed.desc_packed[i].id = i;
+       vq->vq_descx[i].next = VQ_RING_DESC_CHAIN_END;
+}
+
 /* Chain all the descriptors in the ring with an END */
 static inline void
-vring_desc_init(struct vring_desc *dp, uint16_t n)
+vring_desc_init_split(struct vring_desc *dp, uint16_t n)
 {
        uint16_t i;
 
@@ -277,13 +291,53 @@ vring_desc_init(struct vring_desc *dp, uint16_t n)
        dp[i].next = VQ_RING_DESC_CHAIN_END;
 }
 
+/**
+ * Tell the backend not to interrupt us.
+ */
+static inline void
+virtqueue_disable_intr_packed(struct virtqueue *vq)
+{
+       uint16_t *event_flags = &vq->ring_packed.driver_event->desc_event_flags;
+
+       *event_flags = RING_EVENT_FLAGS_DISABLE;
+}
+
+
 /**
  * Tell the backend not to interrupt us.
  */
 static inline void
 virtqueue_disable_intr(struct virtqueue *vq)
 {
-       vq->vq_ring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
+       if (vtpci_packed_queue(vq->hw))
+               virtqueue_disable_intr_packed(vq);
+       else
+               vq->vq_ring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
+}
+
+/**
+ * Tell the backend to interrupt. Implementation for packed virtqueues.
+ */
+static inline void
+virtqueue_enable_intr_packed(struct virtqueue *vq)
+{
+       uint16_t *event_flags = &vq->ring_packed.driver_event->desc_event_flags;
+
+
+       if (vq->event_flags_shadow == RING_EVENT_FLAGS_DISABLE) {
+               virtio_wmb();
+               vq->event_flags_shadow = RING_EVENT_FLAGS_ENABLE;
+               *event_flags = vq->event_flags_shadow;
+       }
+}
+
+/**
+ * Tell the backend to interrupt. Implementation for split virtqueues.
+ */
+static inline void
+virtqueue_enable_intr_split(struct virtqueue *vq)
+{
+       vq->vq_ring.avail->flags &= (~VRING_AVAIL_F_NO_INTERRUPT);
 }
 
 /**
@@ -292,7 +346,10 @@ virtqueue_disable_intr(struct virtqueue *vq)
 static inline void
 virtqueue_enable_intr(struct virtqueue *vq)
 {
-       vq->vq_ring.avail->flags &= (~VRING_AVAIL_F_NO_INTERRUPT);
+       if (vtpci_packed_queue(vq->hw))
+               virtqueue_enable_intr_packed(vq);
+       else
+               virtqueue_enable_intr_split(vq);
 }
 
 /**
@@ -302,7 +359,10 @@ void virtqueue_dump(struct virtqueue *vq);
 /**
  *  Get all mbufs to be freed.
  */
-struct rte_mbuf *virtqueue_detatch_unused(struct virtqueue *vq);
+struct rte_mbuf *virtqueue_detach_unused(struct virtqueue *vq);
+
+/* Flush the elements in the used ring. */
+void virtqueue_rxvq_flush(struct virtqueue *vq);
 
 static inline int
 virtqueue_full(const struct virtqueue *vq)
@@ -310,8 +370,24 @@ virtqueue_full(const struct virtqueue *vq)
        return vq->vq_free_cnt == 0;
 }
 
+static inline int
+virtio_get_queue_type(struct virtio_hw *hw, uint16_t vtpci_queue_idx)
+{
+       if (vtpci_queue_idx == hw->max_queue_pairs * 2)
+               return VTNET_CQ;
+       else if (vtpci_queue_idx % 2 == 0)
+               return VTNET_RQ;
+       else
+               return VTNET_TQ;
+}
+
 #define VIRTQUEUE_NUSED(vq) ((uint16_t)((vq)->vq_ring.used->idx - (vq)->vq_used_cons_idx))
 
+void vq_ring_free_chain(struct virtqueue *vq, uint16_t desc_idx);
+void vq_ring_free_chain_packed(struct virtqueue *vq, uint16_t used_idx);
+void vq_ring_free_inorder(struct virtqueue *vq, uint16_t desc_idx,
+                         uint16_t num);
+
 static inline void
 vq_update_avail_idx(struct virtqueue *vq)
 {
@@ -342,6 +418,17 @@ virtqueue_kick_prepare(struct virtqueue *vq)
        return !(vq->vq_ring.used->flags & VRING_USED_F_NO_NOTIFY);
 }
 
+static inline int
+virtqueue_kick_prepare_packed(struct virtqueue *vq)
+{
+       uint16_t flags;
+
+       virtio_mb();
+       flags = vq->ring_packed.device_event->desc_event_flags;
+
+       return flags != RING_EVENT_FLAGS_DISABLE;
+}
+
 static inline void
 virtqueue_notify(struct virtqueue *vq)
 {
@@ -358,6 +445,15 @@ virtqueue_notify(struct virtqueue *vq)
        uint16_t used_idx, nused; \
        used_idx = (vq)->vq_ring.used->idx; \
        nused = (uint16_t)(used_idx - (vq)->vq_used_cons_idx); \
+       if (vtpci_packed_queue((vq)->hw)) { \
+               PMD_INIT_LOG(DEBUG, \
+               "VQ: - size=%d; free=%d; used_cons_idx=%d; avail_idx=%d;" \
+               "VQ: - avail_wrap_counter=%d; used_wrap_counter=%d", \
+               (vq)->vq_nentries, (vq)->vq_free_cnt, (vq)->vq_used_cons_idx, \
+               (vq)->vq_avail_idx, (vq)->avail_wrap_counter, \
+               (vq)->used_wrap_counter); \
+               break; \
+       } \
        PMD_INIT_LOG(DEBUG, \
          "VQ: - size=%d; free=%d; used=%d; desc_head_idx=%d;" \
          " avail.idx=%d; used_cons_idx=%d; used.idx=%d;" \