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

[Minios-devel] [UNIKRAFT PATCH v3 08/14] plat/drivers: Configure virtio block queue



This patch introduces the initialization of the virtqueue used for
communication to Backend.

Signed-off-by: Roxana Nicolescu <nicolescu.roxana1996@xxxxxxxxx>
---
 plat/drivers/include/virtio/virtio_blk.h |   6 +
 plat/drivers/virtio/virtio_blk.c         | 205 ++++++++++++++++++++++-
 2 files changed, 210 insertions(+), 1 deletion(-)

diff --git a/plat/drivers/include/virtio/virtio_blk.h 
b/plat/drivers/include/virtio/virtio_blk.h
index 0efb5ba9..4877e404 100644
--- a/plat/drivers/include/virtio/virtio_blk.h
+++ b/plat/drivers/include/virtio/virtio_blk.h
@@ -39,6 +39,8 @@
 #include <virtio/virtio_types.h>
 
 /* Feature bits */
+#define VIRTIO_BLK_F_SIZE_MAX  1       /* Indicates maximum segment size */
+#define VIRTIO_BLK_F_SEG_MAX   2       /* Indicates maximum # of segments */
 #define VIRTIO_BLK_F_RO                5       /* Disk is read-only */
 #define VIRTIO_BLK_F_BLK_SIZE  6       /* Block size of disk is available*/
 #define VIRTIO_BLK_F_MQ                12      /* support more than one vq */
@@ -46,6 +48,10 @@
 struct virtio_blk_config {
        /* The capacity (in 512-byte sectors). */
        __u64 capacity;
+       /* The maximum segment size (if VIRTIO_BLK_F_SIZE_MAX) */
+       __u32 size_max;
+       /* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */
+       __u32 seg_max;
 
        /* block size of device (if VIRTIO_BLK_F_BLK_SIZE) */
        __u32 blk_size;
diff --git a/plat/drivers/virtio/virtio_blk.c b/plat/drivers/virtio/virtio_blk.c
index 077daf35..46d3236f 100644
--- a/plat/drivers/virtio/virtio_blk.c
+++ b/plat/drivers/virtio/virtio_blk.c
@@ -29,6 +29,7 @@
 #include <virtio/virtio_ids.h>
 #include <uk/blkdev.h>
 #include <virtio/virtio_blk.h>
+#include <uk/sglist.h>
 #include <uk/blkdev_driver.h>
 
 #define DRIVER_NAME            "virtio-blk"
@@ -41,10 +42,13 @@
  *     Access Mode
  *     Sector_size;
  *     Multi-queue,
+ *     Maximum size of a segment for requests,
+ *     Maximum number of segments per request,
  **/
 #define VIRTIO_BLK_DRV_FEATURES(features) \
        (VIRTIO_FEATURES_UPDATE(features, VIRTIO_BLK_F_RO | \
-       VIRTIO_BLK_F_BLK_SIZE | VIRTIO_BLK_F_MQ))
+       VIRTIO_BLK_F_BLK_SIZE | VIRTIO_BLK_F_MQ | \
+       VIRTIO_BLK_F_SEG_MAX | VIRTIO_BLK_F_SIZE_MAX))
 
 static struct uk_alloc *a;
 static const char *drv_name = DRIVER_NAME;
@@ -64,6 +68,10 @@ struct virtio_blk_device {
        __u16    nb_queues;
        /* List of queues */
        struct   uk_blkdev_queue *qs;
+       /* Maximum number of segments for a request */
+       __u32 max_segments;
+       /* Maximum size of a segment */
+       __u32 max_size_segment;
 };
 
 struct uk_blkdev_queue {
@@ -76,11 +84,164 @@ struct uk_blkdev_queue {
        struct uk_alloc *a;
        /* The nr. of descriptor limit */
        uint16_t max_nb_desc;
+       /* The nr. of descriptor user configured */
+       uint16_t nb_desc;
        /* Reference to virtio_blk_device  */
        struct virtio_blk_device *vbd;
+       /* The scatter list and its associated fragments */
+       struct uk_sglist sg;
+       struct uk_sglist_seg *sgsegs;
 };
 
 
+static int virtio_blkdev_recv_done(struct virtqueue *vq, void *priv)
+{
+       struct uk_blkdev_queue *queue = NULL;
+
+       UK_ASSERT(vq && priv);
+
+       queue = (struct uk_blkdev_queue *) priv;
+
+       uk_blkdev_drv_queue_event(&queue->vbd->blkdev, queue->lqueue_id);
+
+       return 1;
+}
+
+/**
+ * This function setup the vring infrastructure.
+ */
+static int virtio_blkdev_vqueue_setup(struct uk_blkdev_queue *queue,
+               uint16_t nr_desc)
+{
+       uint16_t max_desc;
+       struct virtqueue *vq;
+
+       UK_ASSERT(queue);
+       max_desc = queue->max_nb_desc;
+       if (unlikely(max_desc < nr_desc)) {
+               uk_pr_err("Max desc: %"__PRIu16" Requested desc:%"__PRIu16"\n",
+                         max_desc, nr_desc);
+               return -ENOBUFS;
+       }
+
+       nr_desc = (nr_desc) ? nr_desc : max_desc;
+       uk_pr_debug("Configuring the %d descriptors\n", nr_desc);
+
+       /* Check if the descriptor is a power of 2 */
+       if (unlikely(nr_desc & (nr_desc - 1))) {
+               uk_pr_err("Expected descriptor count as a power 2\n");
+               return -EINVAL;
+       }
+
+       vq = virtio_vqueue_setup(queue->vbd->vdev, queue->lqueue_id, nr_desc,
+                       virtio_blkdev_recv_done, a);
+       if (unlikely(PTRISERR(vq))) {
+               uk_pr_err("Failed to set up virtqueue %"__PRIu16"\n",
+                         queue->lqueue_id);
+               return PTR2ERR(vq);
+       }
+
+       queue->vq = vq;
+       vq->priv = queue;
+
+       return 0;
+}
+
+static struct uk_blkdev_queue *virtio_blkdev_queue_setup(struct uk_blkdev *dev,
+               uint16_t queue_id,
+               uint16_t nb_desc,
+               const struct uk_blkdev_queue_conf *queue_conf)
+{
+       struct virtio_blk_device *vbdev;
+       int rc = 0;
+       struct uk_blkdev_queue *queue;
+
+       UK_ASSERT(dev != NULL);
+       UK_ASSERT(queue_conf != NULL);
+
+       vbdev = to_virtioblkdev(dev);
+       if (unlikely(queue_id >= vbdev->nb_queues)) {
+               uk_pr_err("Invalid queue_id %"__PRIu16"\n", queue_id);
+               rc = -EINVAL;
+               goto err_exit;
+       }
+
+       queue = &vbdev->qs[queue_id];
+       queue->a = queue_conf->a;
+
+       /* Init sglist */
+       queue->sgsegs = uk_malloc(queue->a,
+                       vbdev->max_segments * sizeof(*queue->sgsegs));
+       if (unlikely(!queue->sgsegs)) {
+               rc = -ENOMEM;
+               goto err_exit;
+       }
+
+       uk_sglist_init(&queue->sg, vbdev->max_segments,
+                       queue->sgsegs);
+       queue->vbd = vbdev;
+       queue->nb_desc = nb_desc;
+       queue->lqueue_id = queue_id;
+
+       /* Setup the virtqueue with the descriptor */
+       rc = virtio_blkdev_vqueue_setup(queue, nb_desc);
+       if (rc < 0) {
+               uk_pr_err("Failed to set up virtqueue %"__PRIu16": %d\n",
+                         queue_id, rc);
+               goto setup_err;
+       }
+
+exit:
+       return queue;
+setup_err:
+       uk_free(queue->a, queue->sgsegs);
+err_exit:
+       queue = ERR2PTR(rc);
+       goto exit;
+}
+
+static int virtio_blkdev_queue_release(struct uk_blkdev *dev,
+               struct uk_blkdev_queue *queue)
+{
+       struct virtio_blk_device *vbdev;
+       int rc = 0;
+
+       UK_ASSERT(dev != NULL);
+       vbdev = to_virtioblkdev(dev);
+
+       uk_free(queue->a, queue->sgsegs);
+       virtio_vqueue_release(vbdev->vdev, queue->vq, queue->a);
+
+       return rc;
+}
+
+static int virtio_blkdev_queue_info_get(struct uk_blkdev *dev,
+               uint16_t queue_id,
+               struct uk_blkdev_queue_info *qinfo)
+{
+       struct virtio_blk_device *vbdev = NULL;
+       struct uk_blkdev_queue *queue = NULL;
+       int rc = 0;
+
+       UK_ASSERT(dev);
+       UK_ASSERT(qinfo);
+
+       vbdev = to_virtioblkdev(dev);
+       if (unlikely(queue_id >= vbdev->nb_queues)) {
+               uk_pr_err("Invalid queue_id %"__PRIu16"\n", queue_id);
+               rc = -EINVAL;
+               goto exit;
+       }
+
+       queue = &vbdev->qs[queue_id];
+       qinfo->nb_min = queue->max_nb_desc;
+       qinfo->nb_max = queue->max_nb_desc;
+       qinfo->nb_is_power_of_two = 1;
+
+exit:
+       return rc;
+}
+
 static int virtio_blkdev_queues_alloc(struct virtio_blk_device *vbdev,
                                    const struct uk_blkdev_conf *conf)
 {
@@ -177,6 +338,8 @@ static int virtio_blkdev_feature_negotiate(struct 
virtio_blk_device *vbdev)
        __sector sectors;
        __sector ssize;
        __u16 num_queues;
+       __u32 max_segments;
+       __u32 max_size_segment;
        int rc = 0;
 
        UK_ASSERT(vbdev);
@@ -228,13 +391,50 @@ static int virtio_blkdev_feature_negotiate(struct 
virtio_blk_device *vbdev)
                }
        } else
                num_queues = 1;
+
+       if (virtio_has_features(host_features, VIRTIO_BLK_F_SEG_MAX)) {
+               bytes_to_read = virtio_config_get(vbdev->vdev,
+                       __offsetof(struct virtio_blk_config, seg_max),
+                       &max_segments,
+                       sizeof(max_segments),
+                       1);
+               if (bytes_to_read != sizeof(max_segments))  {
+                       uk_pr_err("Failed to get maximum nb of segments\n");
+                       rc = -EAGAIN;
+                       goto exit;
+               }
+       } else
+               max_segments = 1;
+
+       /* We need extra sg elements for head (header) and tail (status). */
+       max_segments += 2;
+
+       if (virtio_has_features(host_features, VIRTIO_BLK_F_SIZE_MAX)) {
+               bytes_to_read = virtio_config_get(vbdev->vdev,
+                       __offsetof(struct virtio_blk_config, size_max),
+                       &max_size_segment,
+                       sizeof(max_size_segment),
+                       1);
+               if (bytes_to_read != sizeof(max_size_segment))  {
+                       uk_pr_err("Failed to get size max from device %d\n",
+                                       rc);
+                       rc = -EAGAIN;
+                       goto exit;
+               }
+       } else
+               max_size_segment = __PAGE_SIZE;
+
        cap->ssize = ssize;
        cap->sectors = sectors;
        cap->ioalign = sizeof(void *);
        cap->mode = (virtio_has_features(
                        host_features, VIRTIO_BLK_F_RO)) ? O_RDONLY : O_RDWR;
+       cap->max_sectors_per_req =
+                       max_size_segment / ssize * (max_segments - 2);
 
        vbdev->max_vqueue_pairs = num_queues;
+       vbdev->max_segments = max_segments;
+       vbdev->max_size_segment = max_size_segment;
 
        /**
         * Mask out features supported by both driver and device.
@@ -257,6 +457,9 @@ static inline void virtio_blkdev_feature_set(struct 
virtio_blk_device *vbdev)
 static const struct uk_blkdev_ops virtio_blkdev_ops = {
                .get_info = virtio_blkdev_get_info,
                .dev_configure = virtio_blkdev_configure,
+               .queue_get_info = virtio_blkdev_queue_info_get,
+               .queue_setup = virtio_blkdev_queue_setup,
+               .queue_release = virtio_blkdev_queue_release,
                .dev_unconfigure = virtio_blkdev_unconfigure,
 };
 
-- 
2.17.1


_______________________________________________
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®.