[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Minios-devel] [UNIKRAFT PATCH 5/7] plat/drivers: Reintroduce the virtio ring



Hey Sharan,

it seems that you are correcting lots of white spacing, format strings, comments, etc. of your previous commits. Did you by mistake fixup commits in you history wrongly? ;-)

Cheers,

Simon

On 19.10.18 15:06, Sharan Santhanam wrote:
This patch introduces the API to create destroy the virtio ring. The
configuration API for find the number of queues and setting up
individual queues for a device.

Signed-off-by: Sharan Santhanam <sharan.santhanam@xxxxxxxxx>
---
  plat/drivers/include/virtio/virtio.h    | 138 +++++++++++++++++++---
  plat/drivers/include/virtio/virtqueue.h | 145 +++++++++++++++++++++++
  plat/drivers/virtio/virtio_bus.c        |   6 +-
  plat/drivers/virtio/virtio_pci.c        | 147 ++++++++++++++++++------
  plat/drivers/virtio/virtio_ring.c       | 196 ++++++++++++++++++++++++++++++++
  plat/kvm/Config.uk                      |   1 +
  plat/kvm/Makefile.uk                    |   2 +
  7 files changed, 579 insertions(+), 56 deletions(-)
  create mode 100644 plat/drivers/include/virtio/virtqueue.h
  create mode 100644 plat/drivers/virtio/virtio_ring.c

diff --git a/plat/drivers/include/virtio/virtio.h 
b/plat/drivers/include/virtio/virtio.h
index b01faf6..1dfa495 100644
--- a/plat/drivers/include/virtio/virtio.h
+++ b/plat/drivers/include/virtio/virtio.h
@@ -42,6 +42,7 @@
  #include <uk/arch/lcpu.h>
  #include <uk/alloc.h>
  #include <virtio/virtio_config.h>
+#include <virtio/virtqueue.h>
#ifdef __cplusplus
  extern "C" {
@@ -80,20 +81,27 @@ struct virtio_dev_id {
   */
  struct virtio_config_ops {
        /** Resetting the device */
-       void (*reset_device)(struct virtio_dev *vdev);
+       void (*device_reset)(struct virtio_dev *vdev);
        /** Set configuration option */
-       int (*set_config)(struct virtio_dev *vdev, __u16 offset,
-                       const void *buf, __u32 len);
+       int (*config_set)(struct virtio_dev *vdev, __u16 offset,
+                         const void *buf, __u32 len);
        /** Get configuration option */
-       int (*get_config)(struct virtio_dev *vdev, __u16 offset, void *buf,
-                       __u32 len, __u8 type_len);
+       int (*config_get)(struct virtio_dev *vdev, __u16 offset, void *buf,
+                         __u32 len, __u8 type_len);
        /** Get the feature */
-       __u64 (*get_features)(struct virtio_dev *vdev);
+       __u64 (*features_get)(struct virtio_dev *vdev);
        /** Set the feature */
-       void (*set_features)(struct virtio_dev *vdev, __u64 features);
+       void (*features_set)(struct virtio_dev *vdev, __u64 features);
        /** Get and Set Status */
-       __u8 (*get_status)(struct virtio_dev *vdev);
-       void (*set_status)(struct virtio_dev *vdev, __u8 status);
+       __u8 (*status_get)(struct virtio_dev *vdev);
+       void (*status_set)(struct virtio_dev *vdev, __u8 status);
+       /** Find the virtqueue */
+       int (*vqs_find)(struct virtio_dev *vdev, __u16 num_vq, __u16 *vq_size);
+       /** Setup the virtqueue */
+       struct virtqueue *(*vq_setup)(struct virtio_dev *vdev, __u16 num_desc,
+                                     __u16 queue_id,
+                                     virtqueue_callback_t callback,
+                                     struct uk_alloc *a);
  };
/**
@@ -116,6 +124,8 @@ struct virtio_driver {
  struct virtio_dev {
        /* Feature bit describing the virtio device */
        __u64 features;
+       /* List of the virtqueue for the device */
+       UK_TAILQ_HEAD(virtqueue_head, struct virtqueue) vqs;
        /* Private data of the driver */
        void *priv;
        /* Virtio device identifier */
@@ -142,6 +152,7 @@ void _virtio_register_driver(struct virtio_driver *vdrv);
   *      The status to update.
   * @return
   *      0 on successful updating the status.
+ *      -ENOTSUP, if the operation is not supported on the virtio device.
   */
  static inline int virtio_dev_status_update(struct virtio_dev *vdev, __u8 
status)
  {
@@ -149,32 +160,63 @@ static inline int virtio_dev_status_update(struct 
virtio_dev *vdev, __u8 status)
UK_ASSERT(vdev); - if (likely(vdev->cops->set_status)) {
-               vdev->cops->set_status(vdev, status);
+       if (likely(vdev->cops->status_set)) {
+               vdev->cops->status_set(vdev, status);
                rc = 0;
        }
        return rc;
  }
+/**
+ * The function to get the feature supported by the device.
+ * @param vdev
+ *     Reference to the virtio device.
+ *
+ * @return __u64
+ *     A bit map of the feature supported by the device.
+ */
  static inline __u64 virtio_feature_get(struct virtio_dev *vdev)
  {
        __u64 features = 0;
UK_ASSERT(vdev); - if (likely(vdev->cops->get_features))
-               features = vdev->cops->get_features(vdev);
+       if (likely(vdev->cops->features_get))
+               features = vdev->cops->features_get(vdev);
        return features;
  }
+/**
+ * The function to set the negotiated features.
+ * @param vdev
+ *     Reference to the virtio device.
+ * @param feature
+ *     A bit map of the feature negotiated.
+ */
  static inline void virtio_feature_set(struct virtio_dev *vdev, __u32 feature)
  {
        UK_ASSERT(vdev);
- if (likely(vdev->cops->set_features))
-               vdev->cops->set_features(vdev, feature);
+       if (likely(vdev->cops->features_set))
+               vdev->cops->features_set(vdev, feature);
  }
+/**
+ * Get the configuration information from the virtio device.
+ * @param vdev
+ *     Reference to the virtio device.
+ * @param offset
+ *     Offset into the virtio device configuration space.
+ * @param buf
+ *     A buffer to store the configuration information.
+ * @param len
+ *     The length of the buffer.
+ * @param type_len
+ *     The data type of the configuration data.
+ * @return int
+ *     0, on successful reading the configuration space.
+ *     < 0, on error.
+ */
  static inline int virtio_config_get(struct virtio_dev *vdev, __u16 offset,
                                    void *buf, __u32 len, __u8 type_len)
  {
@@ -182,12 +224,74 @@ static inline int virtio_config_get(struct virtio_dev 
*vdev, __u16 offset,
UK_ASSERT(vdev); - if (likely(vdev->cops->get_config))
-               rc = vdev->cops->get_config(vdev, offset, buf, len, type_len);
+       if (likely(vdev->cops->config_get))
+               rc = vdev->cops->config_get(vdev, offset, buf, len, type_len);
+
+       return rc;
+}
+
+/**
+ * The helper function to find the number of the vqs supported on the device.
+ * @param vdev
+ *     A reference to the virtio device.
+ * @param total_vqs
+ *     The total number of virtqueues requested.
+ * @param vq_size
+ *     An array of max descriptors on each virtqueue found on the
+ *     virtio device
+ * @return int
+ *     On success, the function return the number of available virtqueues
+ *     On error,
+ *             -ENOTSUP if the function is not supported.
+ */
+static inline int virtio_find_vqs(struct virtio_dev *vdev, __u16 total_vqs,
+                                 __u16 *vq_size)
+{
+       int rc = -ENOTSUP;
+
+       UK_ASSERT(vdev);
+
+       if (likely(vdev->cops->vqs_find))
+               rc = vdev->cops->vqs_find(vdev, total_vqs, vq_size);
return rc;
  }
+/**
+ * A helper function to setup an individual virtqueue.
+ * @param vdev
+ *     Reference to the virtio device.
+ * @param vq_id
+ *     The virtqueue queue id.
+ * @param nr_desc
+ *     The count of the descriptor to be configured.
+ * @param callback
+ *     A reference to callback function to invoked by the virtio device on an
+ *     interrupt from the virtqueue.
+ * @param a
+ *     A reference to the allocator.
+ *
+ * @return struct virtqueue *
+ *     On success, a reference to the virtqueue.
+ *     On error,
+ *             -ENOTSUP operation not supported on the device.
+ *             -ENOMEM  Failed allocating the virtqueue.
+ */
+static inline struct virtqueue *virtio_vqueue_setup(struct virtio_dev *vdev,
+                                           __u16 vq_id, __u16 nr_desc,
+                                           virtqueue_callback_t  callback,
+                                           struct uk_alloc *a)
+{
+       struct virtqueue *vq = ERR2PTR(-ENOTSUP);
+
+       UK_ASSERT(vdev && a);
+
+       if (likely(vdev->cops->vq_setup))
+               vq = vdev->cops->vq_setup(vdev, vq_id, nr_desc, callback, a);
+
+       return vq;
+}
+
  static inline int virtio_has_features(__u64 features, __u8 bpos)
  {
        __u64 tmp_feature = 0;
diff --git a/plat/drivers/include/virtio/virtqueue.h 
b/plat/drivers/include/virtio/virtqueue.h
new file mode 100644
index 0000000..a8a4bc0
--- /dev/null
+++ b/plat/drivers/include/virtio/virtqueue.h
@@ -0,0 +1,145 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Sharan Santhanam <sharan.santhanam@xxxxxxxxx>
+ *
+ * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the copyright holder 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 HOLDER 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.
+ *
+ * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
+ */
+
+#ifndef __PLAT_DRV_VIRTQUEUE_H__
+#define __PLAT_DRV_VIRTQUEUE_H__
+
+#include <uk/config.h>
+#include <uk/list.h>
+#include <uk/sglist.h>
+#include <uk/arch/types.h>
+#include <virtio/virtio_ring.h>
+#include <virtio/virtio_config.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * Type declarations
+ */
+struct virtqueue;
+struct virtio_dev;
+typedef int (*virtqueue_callback_t)(struct virtqueue *, void *priv);
+typedef int (*virtqueue_notify_host_t)(struct virtio_dev *, __u16 queue_nr);
+
+/**
+ * Structure to describe the virtqueue.
+ */
+struct virtqueue {
+       /* Reference the virtio_dev it belong to */
+       struct virtio_dev *vdev;
+       /* Virtqueue identifier */
+       __u16 queue_id;
+       /* Notify to the host */
+       virtqueue_notify_host_t vq_notify_host;
+       /* Callback from the virtqueue */
+       virtqueue_callback_t vq_callback;
+       /* Next entry of the queue */
+       UK_TAILQ_ENTRY(struct virtqueue) next;
+       /* Private data structure used by the driver of the queue */
+       void *priv;
+};
+
+/**
+ * Fetch the physical address of the descriptor ring.
+ * @param vq
+ *     Reference to the virtqueue.
+ *
+ * @return
+ *     Return the guest physical address of the vring.
+ */
+__phys_addr virtqueue_physaddr(struct virtqueue *vq);
+
+/**
+ * Negotiate with the virtqueue features.
+ * @param feature_set
+ *     The feature set the device request.
+ *
+ * @return __u64
+ *     The negotiated feature set.
+ */
+__u64 virtqueue_feature_negotiate(__u64 feature_set);
+
+/**
+ * Allocate a virtqueue.
+ * @param queue_id
+ *     The virtqueue hw id.
+ * @param nr_descs
+ *     The number of descriptor for the queue.
+ * @param align
+ *     The memory alignment for the ring memory.
+ * @param callback
+ *     A reference to callback to the virtio-dev.
+ * @param notify
+ *     A reference to notification function to the host.
+ * @param vdev:
+ *     A reference to the virtio device.
+ * @param  a:
+ *     A reference to the allocator.
+ *
+ * @return struct virtqueue *
+ *     On success, return a reference to the virtqueue.
+ *     On failure,
+ *                -ENOMEM: Failed to allocate the queue.
+ */
+struct virtqueue *virtqueue_create(__u16 queue_id, __u16 nr_descs, __u16 align,
+                                  virtqueue_callback_t callback,
+                                  virtqueue_notify_host_t notify,
+                                  struct virtio_dev *vdev, struct uk_alloc *a);
+
+/**
+ * Check the virtqueue if full.
+ * @param vq
+ *     A reference to the virtqueue.
+ * @return int
+ *     1 on full,
+ *     0 otherwise
+ */
+int virtqueue_is_full(struct virtqueue *vq);
+
+/*
+ * Destroy a virtual queue
+ * @param vq
+ *     A reference to the virtual queue
+ * @param a
+ *     Reference to the memory allocator
+ */
+void virtqueue_destroy(struct virtqueue *vq, struct uk_alloc *a);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __PLAT_DRV_VIRTQUEUE_H__ */
diff --git a/plat/drivers/virtio/virtio_bus.c b/plat/drivers/virtio/virtio_bus.c
index ef66ae8..b0ab9c8 100644
--- a/plat/drivers/virtio/virtio_bus.c
+++ b/plat/drivers/virtio/virtio_bus.c
@@ -92,8 +92,8 @@ static int virtio_device_reinit(struct virtio_dev *vdev)
         * This may not be necessary while initializing the device for the first
         * time.
         */
-       if (vdev->cops->reset_device) {
-               vdev->cops->reset_device(vdev);
+       if (vdev->cops->device_reset) {
+               vdev->cops->device_reset(vdev);
                /* Set the device status */
                vdev->status = VIRTIO_DEV_RESET;
        }
@@ -140,6 +140,8 @@ int virtio_register_device(struct virtio_dev *vdev)
                return rc;
        }
+ /* Initialize the virtqueue list */
+       UK_TAILQ_INIT(&vdev->vqs);
/* Calling the driver add device */
        rc = drv->add_dev(vdev);
diff --git a/plat/drivers/virtio/virtio_pci.c b/plat/drivers/virtio/virtio_pci.c
index ab2f2c8..d07b011 100644
--- a/plat/drivers/virtio/virtio_pci.c
+++ b/plat/drivers/virtio/virtio_pci.c
@@ -35,16 +35,13 @@
  #include <uk/config.h>
  #include <uk/arch/types.h>
  #include <errno.h>
-#ifdef CONFIG_LIBUKALLOC
  #include <uk/alloc.h>
-#else
-#error "Virtio PCI device requires UKALLOC"
-#endif /* CONFIG_LIBUKALLOC */
  #include <uk/print.h>
  #include <uk/plat/lcpu.h>
  #include <uk/plat/irq.h>
  #include <pci/pci_bus.h>
  #include <virtio/virtio_config.h>
+#include <virtio/virtqueue.h>
  #include <virtio/virtio.h>
  #include <virtio/virtio_pci.h>
@@ -69,44 +66,118 @@ struct virtio_pci_dev {
  };
/**
- * Fetch the virtio pci information from the virtiodev.
+ * Fetch the virtio pci information from the virtio device.
+ * @param vdev
+ *     Reference to the virtio device.
   */
  #define to_virtiopcidev(vdev) \
                __containerof(vdev, struct virtio_pci_dev, vdev)
-
  /**
   * Static function declaration.
   */
  static void vpci_legacy_pci_dev_reset(struct virtio_dev *vdev);
  static int vpci_legacy_pci_config_set(struct virtio_dev *vdev, __u16 offset,
-                               const void *buf, __u32 len);
+                                     const void *buf, __u32 len);
  static int vpci_legacy_pci_config_get(struct virtio_dev *vdev, __u16 offset,
-                                       void *buf, __u32 len,
-                                       __u8 type_len __maybe_unused);
+                                     void *buf, __u32 len,
+                                     __u8 type_len __maybe_unused);
  static __u64 vpci_legacy_pci_features_get(struct virtio_dev *vdev);
  static void vpci_legacy_pci_features_set(struct virtio_dev *vdev,
-                                               __u64 features);
+                                        __u64 features);
+static int vpci_legacy_pci_vq_find(struct virtio_dev *vdev, __u16 num_vq,
+                                  __u16 *qdesc_size);
  static void vpci_legacy_pci_status_set(struct virtio_dev *vdev, __u8 status);
  static __u8 vpci_legacy_pci_status_get(struct virtio_dev *vdev);
+static struct virtqueue *vpci_legacy_vq_setup(struct virtio_dev *vdev,
+                                             __u16 queue_id,
+                                             __u16 num_desc,
+                                             virtqueue_callback_t callback,
+                                             struct uk_alloc *a);
  static inline void virtio_device_id_add(struct virtio_dev *vdev,
-                               __u16 pci_dev_id, __u16 vpci_dev_id_start);
+                                       __u16 pci_dev_id,
+                                       __u16 vpci_dev_id_start);
  static int virtio_pci_legacy_add_dev(struct pci_device *pci_dev,
-               struct virtio_pci_dev *vpci_dev);
+                                    struct virtio_pci_dev *vpci_dev);
/**
   * Configuration operations legacy PCI device.
   */
  static struct virtio_config_ops vpci_legacy_ops = {
-       .reset_device = vpci_legacy_pci_dev_reset,
-       .set_config   = vpci_legacy_pci_config_set,
-       .get_config   = vpci_legacy_pci_config_get,
-       .get_features = vpci_legacy_pci_features_get,
-       .set_features = vpci_legacy_pci_features_set,
-       .get_status   = vpci_legacy_pci_status_get,
-       .set_status   = vpci_legacy_pci_status_set,
+       .device_reset = vpci_legacy_pci_dev_reset,
+       .config_get   = vpci_legacy_pci_config_get,
+       .config_set   = vpci_legacy_pci_config_set,
+       .features_get = vpci_legacy_pci_features_get,
+       .features_set = vpci_legacy_pci_features_set,
+       .status_get   = vpci_legacy_pci_status_get,
+       .status_set   = vpci_legacy_pci_status_set,
+       .vqs_find     = vpci_legacy_pci_vq_find,
+       .vq_setup     = vpci_legacy_vq_setup,
  };
+static struct virtqueue *vpci_legacy_vq_setup(struct virtio_dev *vdev,
+                                             __u16 queue_id,
+                                             __u16 num_desc,
+                                             virtqueue_callback_t callback,
+                                             struct uk_alloc *a)
+{
+       struct virtio_pci_dev *vpdev = NULL;
+       struct virtqueue *vq;
+       __phys_addr addr;
+       long flags;
+
+       UK_ASSERT(vdev != NULL);
+
+       vpdev = to_virtiopcidev(vdev);
+       vq = virtqueue_create(queue_id, num_desc, VIRTIO_PCI_VRING_ALIGN,
+                             callback, NULL, vdev, a);
+       if (PTRISERR(vq)) {
+               uk_pr_err("Failed to create the virtqueue: %d\n",
+                               PTR2ERR(vq));
+               goto err_exit;
+       }
+
+       /* Physical address of the queue */
+       addr = virtqueue_physaddr(vq);
+       /* Select the queue of interest */
+       virtio_cwrite16((void *)(unsigned long)vpdev->pci_base_addr,
+                       VIRTIO_PCI_QUEUE_SEL, queue_id);
+       virtio_cwrite32((void *)(unsigned long)vpdev->pci_base_addr,
+                       VIRTIO_PCI_QUEUE_PFN,
+                       addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
+
+       flags = ukplat_lcpu_save_irqf();
+       UK_TAILQ_INSERT_TAIL(&vpdev->vdev.vqs, vq, next);
+       ukplat_lcpu_restore_irqf(flags);
+
+err_exit:
+       return vq;
+}
+
+static int vpci_legacy_pci_vq_find(struct virtio_dev *vdev, __u16 num_vqs,
+                                  __u16 *qdesc_size)
+{
+       struct virtio_pci_dev *vpdev = NULL;
+       int vq_cnt = 0, i = 0;
+
+       UK_ASSERT(vdev);
+       vpdev = to_virtiopcidev(vdev);
+
+       for (i = 0; i < num_vqs; i++) {
+               virtio_cwrite16((void *) (unsigned long)vpdev->pci_base_addr,
+                               VIRTIO_PCI_QUEUE_SEL, i);
+               qdesc_size[i] = virtio_cread16(
+                               (void *) (unsigned long)vpdev->pci_base_addr,
+                               VIRTIO_PCI_QUEUE_SIZE);
+               if (unlikely(!qdesc_size[i])) {
+                       uk_pr_err("Virtqueue %d not available\n", i);
+                       continue;
+               }
+               vq_cnt++;
+       }
+       return vq_cnt;
+}
+
  static int vpci_legacy_pci_config_set(struct virtio_dev *vdev, __u16 offset,
                                const void *buf, __u32 len)
  {
@@ -116,14 +187,14 @@ static int vpci_legacy_pci_config_set(struct virtio_dev 
*vdev, __u16 offset,
        vpdev = to_virtiopcidev(vdev);
_virtio_cwrite_bytes((void *)(unsigned long)vpdev->pci_base_addr,
-                       VIRTIO_PCI_CONFIG_OFF + offset, buf, len, 1);
+                            VIRTIO_PCI_CONFIG_OFF + offset, buf, len, 1);
return 0;
  }
static int vpci_legacy_pci_config_get(struct virtio_dev *vdev, __u16 offset,
-                                       void *buf, __u32 len,
-                                       __u8 type_len __maybe_unused)
+                                     void *buf, __u32 len,
+                                     __u8 type_len __maybe_unused)
  {
        struct virtio_pci_dev *vpdev = NULL;
        int rc = 0;
@@ -152,7 +223,7 @@ static __u8 vpci_legacy_pci_status_get(struct virtio_dev 
*vdev)
        UK_ASSERT(vdev);
        vpdev = to_virtiopcidev(vdev);
        return virtio_cread8((void *) (unsigned long) vpdev->pci_base_addr,
-                       VIRTIO_PCI_STATUS);
+                            VIRTIO_PCI_STATUS);
  }
static void vpci_legacy_pci_status_set(struct virtio_dev *vdev, __u8 status)
@@ -167,7 +238,7 @@ static void vpci_legacy_pci_status_set(struct virtio_dev 
*vdev, __u8 status)
        curr_status = vpci_legacy_pci_status_get(vdev);
        status |= curr_status;
        virtio_cwrite8((void *)(unsigned long) vpdev->pci_base_addr,
-                        VIRTIO_PCI_STATUS, status);
+                      VIRTIO_PCI_STATUS, status);
  }
static void vpci_legacy_pci_dev_reset(struct virtio_dev *vdev)
@@ -182,7 +253,7 @@ static void vpci_legacy_pci_dev_reset(struct virtio_dev 
*vdev)
         * Resetting the device.
         */
        virtio_cwrite8((void *) (unsigned long)vpdev->pci_base_addr,
-                       VIRTIO_PCI_STATUS, VIRTIO_CONFIG_STATUS_RESET);
+                      VIRTIO_PCI_STATUS, VIRTIO_CONFIG_STATUS_RESET);
        /**
         * Waiting for the resetting the device. Find a better way
         * of doing this instead of repeating register read.
@@ -206,19 +277,21 @@ static __u64 vpci_legacy_pci_features_get(struct 
virtio_dev *vdev)
vpdev = to_virtiopcidev(vdev);
        features = virtio_cread32((void *) (unsigned long)vpdev->pci_base_addr,
-                               VIRTIO_PCI_HOST_FEATURES);
+                                 VIRTIO_PCI_HOST_FEATURES);
        return features;
  }
static void vpci_legacy_pci_features_set(struct virtio_dev *vdev,
-                                               __u64 features)
+                                        __u64 features)
  {
        struct virtio_pci_dev *vpdev = NULL;
UK_ASSERT(vdev);
        vpdev = to_virtiopcidev(vdev);
+       /* Mask out features not supported by the virtqueue driver */
+       features = virtqueue_feature_negotiate(features);
        virtio_cwrite32((void *) (unsigned long)vpdev->pci_base_addr,
-                VIRTIO_PCI_GUEST_FEATURES, (__u32)features);
+                       VIRTIO_PCI_GUEST_FEATURES, (__u32)features);
  }
static inline void virtio_device_id_add(struct virtio_dev *vdev,
@@ -232,8 +305,8 @@ static int virtio_pci_legacy_add_dev(struct pci_device 
*pci_dev,
  {
        /* Check the valid range of the virtio legacy device */
        if (pci_dev->id.device_id < 0x1000 || pci_dev->id.device_id > 0x103f) {
-               uk_pr_err("Error: Invalid Virtio Devices %d\n",
-                               pci_dev->id.device_id);
+               uk_pr_err("Invalid Virtio Devices %04x\n",
+                         pci_dev->id.device_id);
                return -EINVAL;
        }
@@ -242,12 +315,12 @@ static int virtio_pci_legacy_add_dev(struct pci_device *pci_dev,
        /* Setting the configuration operation */
        vpci_dev->vdev.cops = &vpci_legacy_ops;
- uk_pr_info("Added a virtio-pci device(%02x)\n",
-                       (int) pci_dev->id.device_id);
+       uk_pr_info("Added virtio-pci device %04x\n",
+                  pci_dev->id.device_id);
/* Mapping the virtio device identifier */
        virtio_device_id_add(&vpci_dev->vdev, pci_dev->id.device_id,
-                       VIRTIO_PCI_LEGACY_DEVICEID_START);
+                            VIRTIO_PCI_LEGACY_DEVICEID_START);
        return 0;
  }
@@ -261,7 +334,7 @@ static int virtio_pci_add_dev(struct pci_device *pci_dev) vpci_dev = uk_malloc(a, sizeof(*vpci_dev));
        if (!vpci_dev) {
-               uk_pr_err("Error in memory allocation of pci_device\n");
+               uk_pr_err("Failed to allocate virtio-pci device\n");
                return -ENOMEM;
        }
@@ -276,19 +349,19 @@ static int virtio_pci_add_dev(struct pci_device *pci_dev)
         */
        rc = virtio_pci_legacy_add_dev(pci_dev, vpci_dev);
        if (rc != 0) {
-               uk_pr_err("Failed(%d) to probe the legacy device\n",
-                               rc);
+               uk_pr_err("Failed to probe (legacy) pci device: %d\n", rc);
                goto free_pci_dev;
        }
rc = virtio_register_device(&vpci_dev->vdev);
        if (rc != 0) {
-               uk_pr_err("Failed(%d) to register the virtio device\n", rc);
+               uk_pr_err("Failed to register the virtio device: %d\n", rc);
                goto free_pci_dev;
        }
exit:
        return rc;
+
  free_pci_dev:
        uk_free(a, vpci_dev);
        goto exit;
diff --git a/plat/drivers/virtio/virtio_ring.c 
b/plat/drivers/virtio/virtio_ring.c
new file mode 100644
index 0000000..ba91594
--- /dev/null
+++ b/plat/drivers/virtio/virtio_ring.c
@@ -0,0 +1,196 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Sharan Santhanam <sharan.santhanam@xxxxxxxxx>
+ *
+ * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the copyright holder 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 HOLDER 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.
+ *
+ * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
+ */
+/**
+ * Inspired from the FreeBSD.
+ * Commit-id: a89e7a10d501
+ */
+#include <uk/config.h>
+#include <string.h>
+#include <uk/print.h>
+#include <uk/errptr.h>
+#include <cpu.h>
+#include <uk/sglist.h>
+#include <uk/arch/atomic.h>
+#include <uk/plat/io.h>
+#include <virtio/virtio_ring.h>
+#include <virtio/virtqueue.h>
+
+#define VIRTQUEUE_MAX_SIZE  32768
+#define to_virtqueue_vring(vq)                 \
+       __containerof(vq, struct virtqueue_vring, vq)
+
+struct virtqueue_desc_info {
+       void *cookie;
+       __u16 desc_count;
+};
+
+struct virtqueue_vring {
+       struct virtqueue vq;
+       /* Descriptor Ring */
+       struct vring vring;
+       /* Reference to the vring */
+       void   *vring_mem;
+       /* Keep track of available descriptors */
+       __u16 desc_avail;
+       /* Index of the next available slot */
+       __u16 head_free_desc;
+       /* Index of the last used descriptor by the host */
+       __u16 last_used_desc_idx;
+       /* Cookie to identify driver buffer */
+       struct virtqueue_desc_info vq_info[];
+};
+
+/**
+ * Static function Declaration(s).
+ */
+static void virtqueue_vring_init(struct virtqueue_vring *vrq, __u16 nr_desc,
+                                __u16 align);
+
+/**
+ * Driver implementation
+ */
+__u64 virtqueue_feature_negotiate(__u64 feature_set)
+{
+       __u64 feature = (1ULL << VIRTIO_TRANSPORT_F_START) - 1;
+
+       /**
+        * Currently out vring driver does not support any ring feature. We will
+        * add support to transport feature in the future.
+        */
+       feature &= feature_set;
+       return feature;
+}
+
+__phys_addr virtqueue_physaddr(struct virtqueue *vq)
+{
+       struct virtqueue_vring *vrq = NULL;
+
+       UK_ASSERT(vq);
+
+       vrq = to_virtqueue_vring(vq);
+       return ukplat_virt_to_phys(vrq->vring_mem);
+}
+
+static void virtqueue_vring_init(struct virtqueue_vring *vrq, __u16 nr_desc,
+                                __u16 align)
+{
+       int i = 0;
+
+       vring_init(&vrq->vring, nr_desc, vrq->vring_mem, align);
+
+       vrq->desc_avail = vrq->vring.num;
+       vrq->head_free_desc = 0;
+       vrq->last_used_desc_idx = 0;
+       for (i = 0; i < nr_desc - 1; i++)
+               vrq->vring.desc[i].next = i + 1;
+       /**
+        * When we reach this descriptor we have completely used all the
+        * descriptor in the vring.
+        */
+       vrq->vring.desc[nr_desc - 1].next = VIRTQUEUE_MAX_SIZE;
+}
+
+struct virtqueue *virtqueue_create(__u16 queue_id, __u16 nr_descs, __u16 align,
+                                  virtqueue_callback_t callback,
+                                  virtqueue_notify_host_t notify,
+                                  struct virtio_dev *vdev, struct uk_alloc *a)
+{
+       struct virtqueue_vring *vrq;
+       struct virtqueue *vq;
+       int rc;
+       size_t ring_size = 0;
+
+       UK_ASSERT(a);
+
+       vrq = uk_malloc(a, sizeof(struct virtqueue) +
+                       nr_descs * sizeof(struct virtqueue_desc_info));
+       if (!vrq) {
+               uk_pr_err("Allocation of virtqueue failed\n");
+               rc = -ENOMEM;
+               goto err_exit;
+       }
+       /**
+        * Initialize the value before referencing it in
+        * uk_posix_memalign as we don't set NULL on all failures in the
+        * allocation.
+        */
+       vrq->vring_mem = NULL;
+
+       ring_size = vring_size(nr_descs, align);
+       uk_posix_memalign(a, (void **)&vrq->vring_mem, __PAGE_SIZE, ring_size);
+       if (!vrq->vring_mem) {
+               uk_pr_err("Allocation of vring failed\n");
+               rc = -ENOMEM;
+               goto err_freevq;
+       }
+       memset(vrq->vring_mem, 0, ring_size);
+       virtqueue_vring_init(vrq, nr_descs, align);
+
+       vq = &vrq->vq;
+       vq->queue_id = queue_id;
+       vq->vdev = vdev;
+       vq->vq_callback = callback;
+       vq->vq_notify_host = notify;
+       return vq;
+
+err_freevq:
+       uk_free(a, vrq);
+err_exit:
+       return ERR2PTR(rc);
+}
+
+void virtqueue_destroy(struct virtqueue *vq, struct uk_alloc *a)
+{
+       struct virtqueue_vring *vrq;
+
+       UK_ASSERT(vq);
+
+       vrq = to_virtqueue_vring(vq);
+
+       /* Free the ring */
+       uk_free(a, vrq->vring_mem);
+
+       /* Free the virtqueue metadata */
+       uk_free(a, vrq);
+}
+
+int virtqueue_is_full(struct virtqueue *vq)
+{
+       struct virtqueue_vring *vrq;
+
+       UK_ASSERT(vq);
+
+       vrq = to_virtqueue_vring(vq);
+       return (vrq->desc_avail == 0);
+}
diff --git a/plat/kvm/Config.uk b/plat/kvm/Config.uk
index afcedc0..13e5575 100644
--- a/plat/kvm/Config.uk
+++ b/plat/kvm/Config.uk
@@ -57,6 +57,7 @@ config VIRTIO_BUS
        depends on (ARCH_X86_64)
        depends on LIBUKBUS
        select LIBUKALLOC
+      select LIBUKSGLIST
        help
                 Virtio bus driver for probing and operating virtio device and
                 transport layer.
diff --git a/plat/kvm/Makefile.uk b/plat/kvm/Makefile.uk
index 986bf4a..ccc8319 100644
--- a/plat/kvm/Makefile.uk
+++ b/plat/kvm/Makefile.uk
@@ -92,5 +92,7 @@ LIBKVMVIRTIO_ASINCLUDES-y   += 
-I$(UK_PLAT_DRIVERS_BASE)/include
  LIBKVMVIRTIO_CINCLUDES-y    += -I$(UK_PLAT_DRIVERS_BASE)/include
  LIBKVMVIRTIO_SRCS-$(CONFIG_VIRTIO_BUS) +=\
                                                        
$(UK_PLAT_DRIVERS_BASE)/virtio/virtio_bus.c
+LIBKVMVIRTIO_SRCS-$(CONFIG_VIRTIO_BUS) +=\
+                                                       
$(UK_PLAT_DRIVERS_BASE)/virtio/virtio_ring.c
  LIBKVMVIRTIO_SRCS-$(CONFIG_VIRTIO_PCI) +=\
                                                        
$(UK_PLAT_DRIVERS_BASE)/virtio/virtio_pci.c


_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.