VirtIO: Adapted the device initialization process to make it work.
authorReto Achermann <acreto@student.ethz.ch>
Mon, 16 Jun 2014 14:26:10 +0000 (16:26 +0200)
committerStefan Kaestle <stefan.kaestle@inf.ethz.ch>
Wed, 20 Aug 2014 20:19:38 +0000 (22:19 +0200)
- Changes in the notification protocol between host and guest
- Addition of information to serve the device intitalization (host side)
- introduced a yield when waiting for the ready bit.
- device specific setup is now handled during device_open

15 files changed:
devices/virtio/virtio_mmio.dev
errors/errno.fugu
include/virtio/virtio_device.h
include/virtio/virtio_host.h
include/virtio/virtqueue.h
lib/virtio/backends/virtio_device_mmio.c
lib/virtio/backends/virtio_mmio.h
lib/virtio/device.c
lib/virtio/device.h
lib/virtio/devices/virtio_block.c
lib/virtio/host.c
lib/virtio/virtqueue.c
usr/drivers/virtio/block/device.c
usr/drivers/virtio/block/main_guest.c
usr/drivers/virtio/block/main_host.c

index 320bcfd..96641b4 100644 (file)
@@ -154,7 +154,7 @@ device virtio_mmio lsbfirst ( addr base ) "Virtio MMIO Transport Specification"
     register queue_ready addr(base, 0x044) "Virtual queue ready bit" {
         ready  1 "Queue ready bit";
         _     30 "Reserved";
-        ack    1 "the host has stored the queue data";        
+        signal 1 "signal the host that something has changed";
     };
     
     constants queue width(1) "Queue Ready Bit Values" {
@@ -265,8 +265,8 @@ device virtio_mmio lsbfirst ( addr base ) "Virtio MMIO Transport Specification"
         value 32 "Value";
     };
     
-    register config_addr addr(base, 0x100) "The Offset to the start of the device config space" {
-        offset 32 "Offset to config space";
+    constants config_offset width(8) "Reset value" {
+        config_offset = 0x100 "Offset of the configuration space";
     };
     
 };
index 775f420..f581524 100755 (executable)
@@ -1011,7 +1011,8 @@ errors virtio VIRTIO_ERR_ {
     failure NOT_VIRTIO_DEVICE    "The device is not a VirtIO device",
     failure VERSION_MISMATCH     "The VirtIO versions do mismatch",
     failure DEVICE_STATUS        "VirtIO device has the wrong status",
-    failure DEVICE_TYPE                         "The VirtIO device is not of the expected type",
+    failure DEVICE_TYPE           "The VirtIO device is not of the expected type",
+    failure DEVICE_IDLE          "The VirtIO device is idle. No new requests.",
     failure QUEUE_ACTIVE         "The selected qeueue is already activated",
     failure QUEUE_INVALID        "The selected queue does not exist",
     failure QUEUE_BUSY                  "The queue is busy.",
index 123725e..5ae159a 100644 (file)
@@ -127,19 +127,25 @@ enum virtio_device_status {
 
 typedef void (*config_intr_handler_t)(struct virtio_device *dev);
 
+typedef errval_t (*virtio_device_setup_t)(struct virtio_device *dev,
+                                         void *state);
+
 /**
  * contains necessary values for the device initialization process
  */
 struct virtio_device_setup
 {
     uint8_t type;                           ///< expected type of the device
-    void *device_type;
+    void *type_state;
     char name[VIRTIO_DEVICE_NAME_MAX];
     enum virtio_device_backend  backend;    ///< which backend to use
     void *dev_reg;
     size_t dev_reg_size;
     uint64_t driver_features;
 
+    virtio_device_setup_t setup_fn;
+    void *setup_arg;
+
     uint16_t vq_num;
     struct virtqueue_setup *vq_setup;
     config_intr_handler_t cfg_intr_handler;
@@ -198,7 +204,7 @@ errval_t virtio_device_reset(struct virtio_device *dev);
  * \returns SYS_ERR_OK on success
  */
 errval_t virtio_device_get_status(struct virtio_device *dev,
-                                  uint8_t *ret_status);
+                                  uint32_t *ret_status);
 
 /**
  * \brief
@@ -214,7 +220,8 @@ errval_t virtio_device_set_driver_features(struct virtio_device *dev,
 errval_t virtio_device_get_device_features(struct virtio_device *dev,
                                            uint64_t *ret_features);
 
-errval_t virtio_device_specific_setup(struct virtio_device *dev);
+errval_t virtio_device_specific_setup(struct virtio_device *dev,
+                                      void *arg);
 
 bool     virtio_device_has_feature(struct virtio_device *dev,
                                    uint8_t feature);
@@ -256,7 +263,7 @@ errval_t virtio_device_config_write(struct virtio_device *dev,
  *
  * \returns device specific struct pointer
  */
-void *virtio_device_get_struct(struct virtio_device *vdev);
+void *virtio_device_get_type_state(struct virtio_device *vdev);
 
 /**
  * \brief allocates the virtqueues for this device based on the setup information
@@ -282,4 +289,7 @@ errval_t virtio_device_virtqueue_alloc(struct virtio_device *vdev,
  */
 struct virtqueue *virtio_device_get_virtq(struct virtio_device *vdev,
                                           uint16_t vq_idx);
+
+errval_t virtio_device_set_virtq(struct virtio_device *dev,
+                                 struct virtqueue *vq);
 #endif // VIRTIO_VIRTIO_DEVICE_H
index c20606f..39b5190 100644 (file)
@@ -26,18 +26,61 @@ enum virtio_host_channel
 struct virtio_host_cb
 {
     errval_t (*open)(struct capref *ret_frame, void **st);
+    errval_t (*close)(void);
+    errval_t (*add)(void);
+    errval_t (*ext)(void);
+    errval_t (*req)(void);
 };
 
+#if 0
 struct virtio_host_setup
 {
-    uint8_t device_type;
+    uint8_t device_type;        ///< which device we are emulating
+    uint64_t device_features;   ///< VirtIO device features bits we support
+
+    uint16_t num_queues;        ///< number of queues we have
+    uint16_t *queue_num_max;    ///<
+
+    struct {
+        void *vbase;
+        size_t size;
+        struct capref cap;
+        uint8_t type;
+        uint64_t features;
+    } device;
+
+    struct {
+        enum virtio_host_channel type;
+        char *iface;
+        struct virtio_host_cb *callback;
+    } channel;
+
+
+
+    enum virtio_device_backend backend;
+
+
+    uint32_t flags;
+};
+#endif
+
+struct virtio_host_setup
+{
+    uint8_t device_type;        ///< which device we are emulating
+    uint64_t device_features;   ///< VirtIO device features bits we support
+
+    uint16_t num_queues;        ///< number of queues we have
+    uint16_t *queue_num_max;    ///<
+
     void *dev_reg;
     lpaddr_t dev_size;
     struct capref dev_cap;
+
     enum virtio_host_channel channel_type;
     enum virtio_device_backend backend;
     char *iface;
     struct virtio_host_cb *callback;
+    uint32_t flags;
 };
 
 
index f476a0d..b49d68f 100644 (file)
@@ -58,6 +58,7 @@ struct virtqueue_setup {
     virtq_intr_hander_t intr_handler;   ///< interrupt handler function
     void *intr_arg;                     ///< argument for the interrupt handler
     uint16_t max_indirect;              ///< maximum indirect descriptors
+    uint8_t auto_add;                   ///< adds this virtqueue to the device
 };
 
 /**
index 640ddc5..6dae4a7 100644 (file)
@@ -7,6 +7,7 @@
  * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
  */
 
+#include <string.h>
 #include <barrelfish/barrelfish.h>
 
 #include <virtio/virtio.h>
 
 #include <dev/virtio/virtio_mmio_dev.h>
 
-
 #include "device.h"
 #include "backends/virtio_mmio.h"
 #include "debug.h"
 
 #define REG_WAIT_MAX 0xFFFF
+#define REG_WAIT_USE_YIELD 1
 
+#define REGISTER_SEND_READY(_reg,_dev)      \
+    do {                                    \
+        _reg(_dev->regs, 0x1);              \
+    } while(0);
 
+#if REG_WAIT_USE_YIELD
+#define REGISTER_WAIT_READY(_reg,_dev)      \
+    do {                                    \
+        /* uint32_t wait = REG_WAIT_MAX;   */    \
+        while (!_reg(_dev->regs)) {     \
+            thread_yield();                 \
+        }    \
+    } while(0);
+#else
 #define REGISTER_WAIT_READY(_reg,_dev)      \
     do {                                    \
         uint32_t wait = REG_WAIT_MAX;       \
-        while (!_reg(_dev) && (--wait))     \
+        while (!_reg(_dev->regs) && (--wait))     \
             ;                               \
-    } while(0);                             \
+    } while(0);
+
+#endif
+/**
+ * \brief queries the current status flags of the VirtIO device
+ *
+ * \param dev        VirtIO device
+ * \param ret_status pointer to memory to store the return value
+ *
+ * \returns SYS_ERR_OK on success
+ */
+static errval_t device_get_status(struct virtio_device *dev,
+                                  uint32_t *ret_status)
+{
+    virtio_mmio_status_t status;
+
+    struct virtio_device_mmio *mmio_dev = (struct virtio_device_mmio *) dev;
+
+    status = virtio_mmio_status_rd(&mmio_dev->regs);
+
+    if (ret_status) {
+        *ret_status = status;
+    }
 
+    VIRTIO_DEBUG_DEV("getting mmio device status: %x\n", status);
+
+    return SYS_ERR_OK;
+}
 
 /**
  * \brief   updates the device status field of the VirtIO device
 static errval_t device_set_status(struct virtio_device *dev,
                                   uint8_t new_status)
 {
-    struct virtio_device_mmio *mmio_dev = (struct virtio_device_mmio *)dev;
+    VIRTIO_DEBUG_DEV("setting mmio device status: %u\n", new_status);
+
+    struct virtio_device_mmio *mmio_dev = (struct virtio_device_mmio *) dev;
 
     virtio_mmio_status_t status = virtio_mmio_status_default;
 
-    switch(new_status) {
+    switch (new_status) {
         case VIRTIO_DEVICE_STATUS_RESET:
             virtio_mmio_reset_wr(&mmio_dev->regs, virtio_mmio_device_reset);
             return SYS_ERR_OK;
@@ -58,14 +100,14 @@ static errval_t device_set_status(struct virtio_device *dev,
         case VIRTIO_DEVICE_STATUS_FAILED:
             status = virtio_mmio_status_failed_insert(status, 0x1);
             break;
-        case VIRTIO_DEVICE_STATUS_ACKNOWLEDGE :
+        case VIRTIO_DEVICE_STATUS_ACKNOWLEDGE:
             status = virtio_mmio_status_rd(&mmio_dev->regs);
             if (status != 0x0) {
                 return VIRTIO_ERR_DEVICE_STATUS;
             }
             status = virtio_mmio_status_acknowledge_insert(status, 0x1);
             break;
-        case VIRTIO_DEVICE_STATUS_DRIVER :
+        case VIRTIO_DEVICE_STATUS_DRIVER:
             status = virtio_mmio_status_rd(&mmio_dev->regs);
             if (!virtio_mmio_status_acknowledge_extract(status)) {
                 return VIRTIO_ERR_DEVICE_STATUS;
@@ -73,7 +115,7 @@ static errval_t device_set_status(struct virtio_device *dev,
             status = virtio_mmio_status_driver_insert(status, 0x1);
             break;
 
-        case VIRTIO_DEVICE_STATUS_FEATURES_OK :
+        case VIRTIO_DEVICE_STATUS_FEATURES_OK:
             status = virtio_mmio_status_rd(&mmio_dev->regs);
             if (!virtio_mmio_status_driver_extract(status)) {
                 return VIRTIO_ERR_DEVICE_STATUS;
@@ -81,7 +123,7 @@ static errval_t device_set_status(struct virtio_device *dev,
             status = virtio_mmio_status_features_ok_insert(status, 0x1);
             break;
 
-        case VIRTIO_DEVICE_STATUS_DRIVER_OK :
+        case VIRTIO_DEVICE_STATUS_DRIVER_OK:
             status = virtio_mmio_status_rd(&mmio_dev->regs);
             if (!virtio_mmio_status_features_ok_extract(status)) {
                 return VIRTIO_ERR_DEVICE_STATUS;
@@ -104,72 +146,87 @@ static errval_t device_set_status(struct virtio_device *dev,
  */
 static errval_t device_reset(struct virtio_device *dev)
 {
+    VIRTIO_DEBUG_DEV("resetting mmio device: %s\n", dev->name);
     /*
      * TODO: is there some clean up needed ?
      */
     return device_set_status(dev, VIRTIO_DEVICE_STATUS_RESET);
 }
 
-
+/**
+ *
+ */
 static errval_t device_get_device_features(struct virtio_device *dev,
                                            uint64_t *ret_features)
 {
-    struct virtio_device_mmio *mmio_dev = (struct virtio_device_mmio *)dev;
+    struct virtio_device_mmio *mmio_dev = (struct virtio_device_mmio *) dev;
 
-    uint64_t features = 0;
+    uint8_t selector = 0x0;
+    uint64_t features, tmp = 0;
 
-    virtio_mmio_dev_features_sel_wr(&mmio_dev->regs, 0x1);
-
-    uint32_t wait = REG_WAIT_MAX;
-    while (!virtio_mmio_dev_features_sel_ready_rdf(&mmio_dev->regs) && (--wait))
-        ;
+    if (virtio_mmio_dev_features_sel_selector_rdf(&mmio_dev->regs)) {
+        features = virtio_mmio_dev_features_features_rdf(&mmio_dev->regs);
+        features <<= 32;
+    } else {
+        features = virtio_mmio_dev_features_features_rdf(&mmio_dev->regs);
+        selector = 0x1;
+    }
 
-    features = virtio_mmio_dev_features_features_rdf(&mmio_dev->regs);
+    virtio_mmio_dev_features_sel_selector_wrf(&mmio_dev->regs, selector);
 
-    features <<= 32;
+    REGISTER_WAIT_READY(virtio_mmio_dev_features_sel_ready_rdf, &mmio_dev);
 
-    virtio_mmio_dev_features_sel_wr(&mmio_dev->regs, 0x0);
+    tmp = virtio_mmio_dev_features_features_rdf(&mmio_dev->regs);
+    if (selector) {
+        features |= (tmp << 32);
+    } else {
+        features |= tmp;
+    }
 
-    wait = REG_WAIT_MAX;
-    while (!virtio_mmio_dev_features_sel_ready_rdf(&mmio_dev->regs) && (--wait))
-            ;
-
-    /*
-     * TODO: when do we know when the new values in the features
-     *       are ready??
-     */
-    features |= virtio_mmio_dev_features_features_rdf(&mmio_dev->regs);
+    virtio_mmio_dev_features_sel_ready_wrf(&mmio_dev->regs, 0);
 
     return SYS_ERR_OK;
 }
 
 static errval_t device_set_driver_features(struct virtio_device *dev,
-                                          uint64_t features)
+                                           uint64_t features)
 {
-    struct virtio_device_mmio *mmio_dev = (struct virtio_device_mmio *)dev;
+    struct virtio_device_mmio *mmio_dev = (struct virtio_device_mmio *) dev;
+
+    debug_printf("device_set_driver_features\n");
+
+    uint8_t selector = 0x0;
 
-    virtio_mmio_driv_features_sel_wr(&mmio_dev->regs, 0x0);
+    uint32_t reg_val;
 
-    uint32_t wait = REG_WAIT_MAX;
-    while (!virtio_mmio_driv_features_sel_ready_rdf(&mmio_dev->regs) && (--wait))
-         ;
+    if (virtio_mmio_driv_features_sel_selector_rdf(&mmio_dev->regs)) {
+        reg_val = (uint32_t)(features>>32);
+    } else {
+        reg_val = (uint32_t)(features);
+        selector = 0x1;
+    }
 
-    virtio_mmio_driv_features_wr(&mmio_dev->regs, (uint32_t)(features));
+    virtio_mmio_driv_features_features_wrf(&mmio_dev->regs, reg_val);
 
-    wait = REG_WAIT_MAX;
-    while (!virtio_mmio_driv_features_sel_ack_rdf(&mmio_dev->regs) && (--wait))
-        ;
+    REGISTER_SEND_READY(virtio_mmio_driv_features_sel_ready_wrf, &mmio_dev);
+    REGISTER_WAIT_READY(!virtio_mmio_driv_features_sel_ready_rdf, &mmio_dev);
+
+    virtio_mmio_driv_features_sel_wr(&mmio_dev->regs, selector);
+
+    if (selector) {
+        reg_val = (uint32_t)(features>>32);
+    } else {
+        reg_val = (uint32_t)(features);
+    }
 
-    virtio_mmio_driv_features_sel_wr(&mmio_dev->regs, 0x1);
-    wait = REG_WAIT_MAX;
-    while (!virtio_mmio_driv_features_sel_ready_rdf(&mmio_dev->regs) && (--wait))
-        ;
+    virtio_mmio_driv_features_features_wrf(&mmio_dev->regs, reg_val);
 
-    virtio_mmio_driv_features_wr(&mmio_dev->regs, (uint32_t)(features >> 32));
+    REGISTER_SEND_READY(virtio_mmio_driv_features_sel_ready_wrf, &mmio_dev);
+    REGISTER_WAIT_READY(!virtio_mmio_driv_features_sel_ready_rdf, &mmio_dev);
 
-    wait = REG_WAIT_MAX;
-    while (!virtio_mmio_driv_features_sel_ack_rdf(&mmio_dev->regs) && (--wait))
-            ;
+
+    // clear the ready bit in the end
+    virtio_mmio_driv_features_sel_ready_wrf(&mmio_dev->regs, 0x0);
 
     return SYS_ERR_OK;
 }
@@ -177,20 +234,17 @@ static errval_t device_set_driver_features(struct virtio_device *dev,
 static errval_t device_set_virtq(struct virtio_device *dev,
                                  struct virtqueue *vq)
 {
-    struct virtio_device_mmio *mmio_dev = (struct virtio_device_mmio *)dev;
+    struct virtio_device_mmio *mmio_dev = (struct virtio_device_mmio *) dev;
 
     uint16_t queue_index = virtio_virtqueue_get_queue_index(vq);
 
-    /* todo: wait till the previous request has been seen... */
-    uint32_t wait = REG_WAIT_MAX;
-    while (!virtio_mmio_queue_ready_ack_rdf(&mmio_dev->regs) && (--wait))
-            ;
-
-    virtio_mmio_queue_sel_wr(&mmio_dev->regs, queue_index);
-    wait = REG_WAIT_MAX;
-    while (!virtio_mmio_queue_sel_ready_rdf(&mmio_dev->regs) && (--wait))
-        ;
+    VIRTIO_DEBUG_TL("setting virtqueue [VQ(%u) @ %s]\n", queue_index, dev->name);
 
+    /* we nee to change to the correct queue */
+    if (virtio_mmio_queue_sel_selector_rdf(&mmio_dev->regs) != queue_index) {
+        virtio_mmio_queue_sel_selector_wrf(&mmio_dev->regs, queue_index);
+        REGISTER_WAIT_READY(virtio_mmio_queue_sel_ready_rdf, &mmio_dev);
+    }
 
     /* TODO> wait till queue has been selected */
 
@@ -210,23 +264,25 @@ static errval_t device_set_virtq(struct virtio_device *dev,
     lpaddr_t paddr = virtio_virtqueue_get_vring_paddr(vq);
     lpaddr_t align = virtio_virtqueue_get_vring_align(vq);
 
-
-    virtio_mmio_queue_desc_hi_addr_wrf(&mmio_dev->regs, (uint32_t)(paddr >> 32));
-    virtio_mmio_queue_desc_lo_addr_wrf(&mmio_dev->regs, (uint32_t)(paddr));
+    virtio_mmio_queue_desc_hi_addr_wrf(&mmio_dev->regs, (uint32_t) (paddr >> 32));
+    virtio_mmio_queue_desc_lo_addr_wrf(&mmio_dev->regs, (uint32_t) (paddr));
 
     paddr += size * sizeof(struct vring_desc);
 
-    virtio_mmio_queue_used_hi_addr_wrf(&mmio_dev->regs, (uint32_t)(paddr >> 32));
-    virtio_mmio_queue_used_lo_addr_wrf(&mmio_dev->regs, (uint32_t)(paddr));
+    virtio_mmio_queue_used_hi_addr_wrf(&mmio_dev->regs, (uint32_t) (paddr >> 32));
+    virtio_mmio_queue_used_lo_addr_wrf(&mmio_dev->regs, (uint32_t) (paddr));
 
     paddr += sizeof(uint16_t) * (2 + size + 1);
     paddr = (paddr + align - 1) & ~(align - 1);
 
-    virtio_mmio_queue_avail_hi_addr_wrf(&mmio_dev->regs, (uint32_t)(paddr >> 32));
-    virtio_mmio_queue_avail_lo_addr_wrf(&mmio_dev->regs, (uint32_t)(paddr));
+    virtio_mmio_queue_avail_hi_addr_wrf(&mmio_dev->regs, (uint32_t) (paddr >> 32));
+    virtio_mmio_queue_avail_lo_addr_wrf(&mmio_dev->regs, (uint32_t) (paddr));
 
     /* signal the host that the queue is ready */
     virtio_mmio_queue_ready_ready_wrf(&mmio_dev->regs, 0x1);
+    virtio_mmio_queue_ready_signal_wrf(&mmio_dev->regs, 0x1);
+
+    REGISTER_WAIT_READY(!virtio_mmio_queue_ready_signal_rdf, &mmio_dev);
 
     return SYS_ERR_OK;
 }
@@ -235,13 +291,15 @@ static errval_t device_get_queue_num_max(struct virtio_device *dev,
                                          uint16_t queue_index,
                                          uint16_t *num_max)
 {
-    struct virtio_device_mmio *mmio_dev = (struct virtio_device_mmio *)dev;
+    struct virtio_device_mmio *mmio_dev = (struct virtio_device_mmio *) dev;
 
     virtio_mmio_queue_sel_selector_wrf(&mmio_dev->regs, queue_index);
 
     /* TODO: wait till data ready */
 
-    uint16_t qmax = (uint16_t)virtio_mmio_queue_max_size_rdf(&mmio_dev->regs);
+    REGISTER_WAIT_READY(virtio_mmio_queue_sel_ready_rdf, &mmio_dev);
+
+    uint16_t qmax = (uint16_t) virtio_mmio_queue_max_size_rdf(&mmio_dev->regs);
 
     if (num_max) {
         *num_max = qmax;
@@ -258,6 +316,8 @@ static errval_t device_negotiate_features(struct virtio_device *dev,
 
     driver_features &= device_features;
 
+    VIRTIO_DEBUG_TL("setting device features to: 0x%lx\n", driver_features);
+
     device_set_driver_features(dev, driver_features);
 
     dev->features = driver_features;
@@ -265,15 +325,73 @@ static errval_t device_negotiate_features(struct virtio_device *dev,
     return SYS_ERR_OK;
 }
 
+/**
+ * \brief reads the device configuration space and copies it into a local buffer
+ *
+ * \param vdev  virtio device
+ * \param buf   pointer to the buffer to store the data
+ * \param len   the length of the buffer
+ *
+ * \returns SYS_ERR_OK on success
+ */
+static errval_t device_config_read(struct virtio_device *vdev,
+                                   void *buf,
+                                   size_t len)
+{
+    struct virtio_device_mmio *mmio_dev = (struct virtio_device_mmio *) vdev;
+
+    if (len > (mmio_dev->device_size + virtio_mmio_config_offset)) {
+        return VIRTIO_ERR_SIZE_INVALID;
+    }
+
+    uint8_t *config_space = ((uint8_t *) mmio_dev->device_base)
+                    + virtio_mmio_config_offset;
+
+    memcpy(buf, config_space, len);
+
+    return SYS_ERR_OK;
+}
+
+/**
+ * \brief writes to the configuration space of a device
+ *
+ * \param vdev  virtio device
+ * \param buf   pointer to the buffer with data to update
+ * \param len   the length of the buffer
+ *
+ * \returns SYS_ERR_OK on success
+ */
+static errval_t device_config_write(struct virtio_device *dev,
+                                    void *config,
+                                    size_t offset,
+                                    size_t length)
+{
+    struct virtio_device_mmio *mmio_dev = (struct virtio_device_mmio *) dev;
+
+    if ((length + offset) > (mmio_dev->device_size + virtio_mmio_config_offset)) {
+        return VIRTIO_ERR_SIZE_INVALID;
+    }
+
+    size_t config_offset = virtio_mmio_config_offset + offset;
+
+    uint8_t *config_space = ((uint8_t *) mmio_dev->device_base) + config_offset;
+
+    memcpy(config_space, config, length);
+
+    return SYS_ERR_OK;
+}
+
 struct virtio_device_fn virtio_mmio_fn = {
     .reset = device_reset,
     .set_status = device_set_status,
+    .get_status = device_get_status,
     .negotiate_features = device_negotiate_features,
     .set_virtq = device_set_virtq,
-    .get_queue_num_max = device_get_queue_num_max
+    .get_queue_num_max = device_get_queue_num_max,
+    .get_config = device_config_read,
+    .set_config = device_config_write
 };
 
-
 /**
  * \brief initializes and allocates a VirtIO device structure for the MMIO backend
  */
@@ -282,13 +400,14 @@ errval_t virtio_device_mmio_init(struct virtio_device **dev,
 {
     struct virtio_device_mmio *mmio_dev;
     errval_t err;
-    mmio_dev = malloc(sizeof(*mmio_dev));
+    mmio_dev = calloc(1, sizeof(*mmio_dev));
     if (mmio_dev == NULL) {
         return LIB_ERR_MALLOC_FAIL;
     }
 
     virtio_mmio_initialize(&mmio_dev->regs, (mackerel_addr_t) (info->dev_reg));
-
+    mmio_dev->device_base = info->dev_reg;
+    mmio_dev->device_size = info->dev_reg_size;
 
     /**
      * 4.2.3.1.1 Driver Requirements: Device Initialization
@@ -326,20 +445,127 @@ errval_t virtio_device_mmio_init(struct virtio_device **dev,
         return VIRTIO_ERR_NOT_VIRTIO_DEVICE;
     }
 
+    if (devid != info->type) {
+        VIRTIO_DEBUG_DEV("VirtIO device id not as expected [%x, %x].\n",
+                         devid,
+                         info->type);
+        return VIRTIO_ERR_DEVICE_TYPE;
+    }
+
     mmio_dev->dev.devid = devid;
     mmio_dev->dev.backend = VIRTIO_DEVICE_BACKEND_MMIO;
     mmio_dev->dev.f = &virtio_mmio_fn;
     mmio_dev->dev.type = virtio_mmio_deviceid_id_rdf(&mmio_dev->regs);
 
+    *dev = &mmio_dev->dev;
+
+    return SYS_ERR_OK;
+}
+
+static errval_t handle_device_status_change(struct virtio_host_mmio *mmio_host,
+                                            uint8_t new_status)
+{
+    VIRTIO_DEBUG_TL("handle_device_status_change: [0x%x]\n", new_status);
+    mmio_host->dev_reg.status = new_status;
     return SYS_ERR_OK;
 }
 
+static errval_t handle_dev_feature_sel_change(struct virtio_host_mmio *mmio_host,
+                                              uint8_t selector)
+{
+    VIRTIO_DEBUG_TL("handle_dev_feature_sel_change: [0x%x]\n", selector);
+    mmio_host->dev_reg.dev_feature_sel = selector;
 
-static errval_t virtio_device_mmio_poll_host(struct virtio_host *host)
+
+    virtio_mmio_dev_features_sel_ready_wrf(&mmio_host->regs, 0x1);
+
+    return SYS_ERR_OK;
+}
+
+static errval_t handle_driv_feature_change(struct virtio_host_mmio *mmio_host,
+                                           uint8_t selector,
+                                           uint32_t feature)
 {
+    VIRTIO_DEBUG_TL("handle_driv_feature_change: [0x%x] [0x%08x]\n", selector, feature);
+
+    mmio_host->dev_reg.driv_feature_sel = selector;
+    mmio_host->dev_reg.driv_features[selector] = feature;
+
+    virtio_mmio_driv_features_sel_ready_wrf(&mmio_host->regs, 0x0);
+
     return SYS_ERR_OK;
 }
 
+static errval_t handle_queue_sel_change(struct virtio_host_mmio *mmio_host,
+                                        uint16_t selector)
+{
+    VIRTIO_DEBUG_TL("handle_queue_sel_change: [0x%x]\n", selector);
+
+    mmio_host->dev_reg.queue_sel = selector;
+
+    /*
+     * TODO: load the respective queue registers
+     */
+
+    virtio_mmio_queue_sel_ready_wrf(&mmio_host->regs, 0x0);
+
+    return SYS_ERR_OK;
+}
+
+static errval_t handle_queue_change(struct virtio_host_mmio *mmio_host,
+                                    uint16_t selector)
+{
+    VIRTIO_DEBUG_TL("handle_queue_change: [0x%x]\n", selector);
+
+    virtio_mmio_queue_ready_signal_wrf(&mmio_host->regs, 0x0);
+
+    return SYS_ERR_OK;
+}
+
+static errval_t virtio_device_mmio_poll_host(struct virtio_host *host)
+{
+    errval_t err = VIRTIO_ERR_DEVICE_IDLE;
+    struct virtio_host_mmio *mmio_host = ( struct virtio_host_mmio *)host;
+
+    uint32_t reg_value, selector;
+
+    reg_value = virtio_mmio_status_rd(&mmio_host->regs);
+    if (mmio_host->dev_reg.status != (uint8_t)reg_value) {
+        err = handle_device_status_change(mmio_host, (uint8_t)reg_value);
+    }
+
+    selector = virtio_mmio_dev_features_sel_selector_rdf(&mmio_host->regs);
+    if (mmio_host->dev_reg.dev_feature_sel != selector) {
+        err = handle_dev_feature_sel_change(mmio_host, selector);
+    }
+
+    reg_value = virtio_mmio_driv_features_rd(&mmio_host->regs);
+    selector = virtio_mmio_driv_features_sel_selector_rdf(&mmio_host->regs);
+    if ((selector != mmio_host->dev_reg.driv_feature_sel)
+                    || (mmio_host->dev_reg.driv_features[selector] != reg_value)){
+        if (virtio_mmio_driv_features_sel_ready_rdf(&mmio_host->regs)) {
+            err = handle_driv_feature_change(mmio_host, (uint8_t)selector, reg_value);
+        }
+    } else {
+        // we have to ack the guest
+        virtio_mmio_driv_features_sel_ready_wrf(&mmio_host->regs, 0x0);
+    }
+
+    reg_value = virtio_mmio_driv_features_rd(&mmio_host->regs);
+    selector = virtio_mmio_queue_sel_selector_rdf(&mmio_host->regs);
+    if (selector != mmio_host->dev_reg.queue_sel) {
+        err = handle_queue_sel_change(mmio_host, (uint16_t)selector);
+    }
+
+    if (virtio_mmio_queue_ready_signal_rdf(&mmio_host->regs)) {
+        err = handle_queue_change(mmio_host, selector);
+    }
+
+    /* TODO: poll the queues */
+
+    return err;
+}
+
 /**
  * \brief initializes a VirtIO device on the host side using the MMIO transpot
  *
@@ -354,25 +580,53 @@ errval_t virtio_device_mmio_init_host(struct virtio_host **host,
     struct virtio_host_mmio *mmio_host;
     errval_t err;
 
+    assert(host);
+
     mmio_host = malloc(sizeof(*mmio_host));
     if (mmio_host == NULL) {
         return LIB_ERR_MALLOC_FAIL;
     }
 
+    mmio_host->host.queues = calloc(setup->num_queues, sizeof(struct virtio_host_queue));
+    if (mmio_host->host.queues  == NULL) {
+        free(mmio_host);
+        return LIB_ERR_MALLOC_FAIL;
+    }
+
     /*
      * TODO> Check for minimum MMIO devie size
      */
 
-    if (setup->dev_reg == NULL) {
-        setup->dev_size +=VIRTIO_MMIO_DEVICE_SIZE;
+    if (capref_is_null(setup->dev_cap)) {
+        VIRTIO_DEBUG_DEV("allocating a new device frame.\n");
+        setup->dev_size += VIRTIO_MMIO_DEVICE_SIZE;
         err = frame_alloc(&mmio_host->host.dev_frame,
                           setup->dev_size,
                           &setup->dev_size);
         if (err_is_fail(err)) {
+            free(mmio_host->host.queues);
             free(mmio_host);
             return err;
         }
+    } else {
+        mmio_host->host.dev_frame = setup->dev_cap;
+    }
+
+    struct frame_identity id;
+    err = invoke_frame_identify(mmio_host->host.dev_frame, &id);
+    if (err_is_fail(err)) {
+        VIRTIO_DEBUG_DEV("ERROR: could not identify the frame.");
+        return err;
+    }
+
+    assert((1UL<<id.bits) > VIRTIO_MMIO_DEVICE_SIZE);
+
+    VIRTIO_DEBUG_DEV("Using frame [0x%016lx, 0x%lx] as device frame.\n",
+                     id.base,
+                     (1UL << id.bits));
 
+    if (setup->dev_reg == NULL) {
+        VIRTIO_DEBUG_DEV("mapping device frame.\n");
         err = vspace_map_one_frame_attr(&setup->dev_reg,
                                         setup->dev_size,
                                         mmio_host->host.dev_frame,
@@ -380,15 +634,24 @@ errval_t virtio_device_mmio_init_host(struct virtio_host **host,
                                         NULL,
                                         NULL);
         if (err_is_fail(err)) {
-            cap_destroy(mmio_host->host.dev_frame);
+            if (capref_is_null(setup->dev_cap)) {
+                cap_destroy(mmio_host->host.dev_frame);
+            }
+            free(mmio_host->host.queues);
             free(mmio_host);
             return err;
         }
     } else {
         assert(setup->dev_size > VIRTIO_MMIO_DEVICE_SIZE);
-        mmio_host->host.dev_frame = setup->dev_cap;
     }
 
+    mmio_host->host.device_features = setup->device_features;
+
+    for (uint32_t i = 0; i < setup->num_queues; ++i) {
+        mmio_host->host.queues[i].ndesc = setup->queue_num_max[i];
+    }
+
+
     mmio_host->host.device_base = setup->dev_reg;
     mmio_host->host.dev_size = setup->dev_size;
     virtio_mmio_initialize(&mmio_host->regs, (mackerel_addr_t) (setup->dev_reg));
@@ -398,11 +661,23 @@ errval_t virtio_device_mmio_init_host(struct virtio_host **host,
     virtio_mmio_deviceid_id_wrf(&mmio_host->regs, setup->device_type);
     virtio_mmio_version_version_wrf(&mmio_host->regs, virtio_mmio_version_virtio10);
 
+    virtio_mmio_dev_features_sel_wr(&mmio_host->regs, 0x0);
+    virtio_mmio_driv_features_sel_wr(&mmio_host->regs, 0x0);
+    virtio_mmio_queue_sel_wr(&mmio_host->regs, 0x0);
+
+    virtio_mmio_dev_features_wr(&mmio_host->regs, (uint32_t)setup->device_features);
+    virtio_mmio_queue_max_wr(&mmio_host->regs, setup->queue_num_max[0]);
+
+    mmio_host->dev_reg.status = 0x0;
+    mmio_host->dev_reg.driv_feature_sel = 0x0;
+    mmio_host->dev_reg.dev_feature_sel = 0x0;
+    mmio_host->dev_reg.queue_sel = 0x0;
 
     mmio_host->host.poll = virtio_device_mmio_poll_host;
 
+    *host = &mmio_host->host;
+
     return SYS_ERR_OK;
 
 }
 
-
index 167fc56..da44145 100644 (file)
@@ -20,12 +20,21 @@ struct virtio_device_mmio
 {
     struct virtio_device dev;
     virtio_mmio_t regs;
+    void *device_base;
+    size_t device_size;
 };
 
 struct virtio_host_mmio
 {
     struct virtio_host host;
     virtio_mmio_t regs;
+    struct mmio_dev_regs {
+        uint8_t status;
+        uint8_t dev_feature_sel : 4;
+        uint8_t driv_feature_sel : 4;
+        uint32_t driv_features[2];
+        uint16_t queue_sel;
+    } dev_reg;
 };
 
 
index 2562a7c..1565116 100644 (file)
@@ -7,6 +7,8 @@
  * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
  */
 
+#include <string.h>
+
 #include <barrelfish/barrelfish.h>
 
 #include <virtio/virtio.h>
@@ -31,8 +33,9 @@ errval_t virtio_device_open(struct virtio_device **dev,
 {
     errval_t err = SYS_ERR_OK;
 
-    VIRTIO_DEBUG_DEV("virtio_device_open: [%s] @ [%016lx]\n", init->name,
-                     (uintptr_t)init->dev_reg);
+    VIRTIO_DEBUG_DEV("virtio_device_open: [%s] @ [%016lx]\n",
+                     init->name,
+                     (uintptr_t )init->dev_reg);
 
     if (init->dev_reg == NULL || init->dev_reg_size == 0) {
         /*
@@ -69,7 +72,12 @@ errval_t virtio_device_open(struct virtio_device **dev,
 
     struct virtio_device *vdev = *dev;
 
+    assert(vdev);
+
     vdev->state = VIRTIO_DEVICE_S_INITIALIZING;
+    strncpy(vdev->name, init->name, sizeof(vdev->name));
+    vdev->setup = init->setup_fn;
+    vdev->type_state = init->type_state;
 
     /* 1. Reset the device. */
     err = virtio_device_reset(vdev);
@@ -105,7 +113,7 @@ errval_t virtio_device_open(struct virtio_device **dev,
 
     /* 6. Re-read device status to ensure the FEATURES_OK bit is still set: otherwise, the device does not
      support our subset of features and the device is unusable.*/
-    uint8_t status = 0;
+    uint32_t status = 0;
     err = virtio_device_get_status(vdev, &status);
     assert(err_is_ok(err));
 
@@ -115,17 +123,20 @@ errval_t virtio_device_open(struct virtio_device **dev,
 
     /* 7. Perform device-specific setup, including discovery of virtqueues for the device, optional per-bus setup,
      reading and possibly writing the device’s virtio configuration space, and population of virtqueues.*/
-    err = virtio_device_specific_setup(vdev);
+    err = virtio_device_specific_setup(vdev, init->setup_arg);
     if (err_is_fail(err)) {
         goto failed;
     }
     /* 8. Set the DRIVER_OK status bit. At this point the device is “live”. */
+    VIRTIO_DEBUG_DEV("Device [%s] is now live.\n", vdev->name);
     err = virtio_device_set_status(vdev, VIRTIO_DEVICE_STATUS_DRIVER_OK);
     assert(err_is_ok(err));
 
     return SYS_ERR_OK;
 
-    failed: virtio_device_set_status(vdev, VIRTIO_DEVICE_STATUS_FAILED);
+    failed:
+    VIRTIO_DEBUG_DEV("Device initialization for [%s] failed..\n", vdev->name);
+    virtio_device_set_status(vdev, VIRTIO_DEVICE_STATUS_FAILED);
 
     return err;
 }
@@ -187,19 +198,28 @@ errval_t virtio_device_open_with_cap(struct virtio_device **dev,
  * \returns true  if the device supports that feature
  *          false if the device does not support that feature
  */
-bool     virtio_device_has_feature(struct virtio_device *dev,
-                                   uint8_t feature)
+bool virtio_device_has_feature(struct virtio_device *dev,
+                               uint8_t feature)
 {
     /*
      * if the device is not configured yet, we don't know the features
      */
-    if(dev->status_flags & VIRTIO_DEVICE_STATUS_FEATURES_OK) {
+    if (dev->status_flags & VIRTIO_DEVICE_STATUS_FEATURES_OK) {
         return false;
     }
 
-    return (dev->features & (1UL<<feature)) != 0;
+    return (dev->features & (1UL << feature)) != 0;
 }
 
+errval_t virtio_device_specific_setup(struct virtio_device *dev,
+                                      void *arg)
+{
+    if (dev->setup) {
+        return dev->setup(dev, arg);
+    }
+
+    return SYS_ERR_OK;
+}
 
 /**
  * \brief resets the virtio device
@@ -210,8 +230,9 @@ bool     virtio_device_has_feature(struct virtio_device *dev,
  */
 errval_t virtio_device_reset(struct virtio_device *dev)
 {
-    VIRTIO_DEBUG_DEV("resetting device: %s\n", dev->name);
-    assert(!"NYI:");
+    if (dev->f->reset) {
+        return dev->f->reset(dev);
+    }
     return SYS_ERR_OK;
 }
 
@@ -224,10 +245,12 @@ errval_t virtio_device_reset(struct virtio_device *dev)
  * \returns SYS_ERR_OK on success
  */
 errval_t virtio_device_get_status(struct virtio_device *dev,
-                                  uint8_t *ret_status)
+                                  uint32_t *ret_status)
 {
-    assert(!"NYI:");
-    return SYS_ERR_OK;
+    if (dev->f->get_status) {
+        return dev->f->get_status(dev, ret_status);
+    }
+    return VIRTIO_ERR_BACKEND;
 }
 
 /**
@@ -238,8 +261,10 @@ errval_t virtio_device_get_status(struct virtio_device *dev,
 errval_t virtio_device_set_status(struct virtio_device *dev,
                                   uint8_t status)
 {
-    assert(!"NYI:");
-    return SYS_ERR_OK;
+    if (dev->f->set_status) {
+        return dev->f->set_status(dev, status);
+    }
+    return VIRTIO_ERR_BACKEND;
 }
 
 /**
@@ -249,13 +274,11 @@ errval_t virtio_device_set_status(struct virtio_device *dev,
  *
  * \returns device specific struct pointer
  */
-void *virtio_device_get_struct(struct virtio_device *vdev)
+void *virtio_device_get_type_state(struct virtio_device *vdev)
 {
-    assert(!"NYI:");
-    return NULL;
+    return vdev->type_state;
 }
 
-
 /**
  * \brief reads the device configuration space and copies it into a local buffer
  *
@@ -266,11 +289,14 @@ void *virtio_device_get_struct(struct virtio_device *vdev)
  * \returns SYS_ERR_OK on success
  */
 errval_t virtio_device_config_read(struct virtio_device *vdev,
-                                  void *buf,
-                                  size_t len)
+                                   void *buf,
+                                   size_t len)
 {
-    assert(!"NYI:");
-    return SYS_ERR_OK;
+    if (vdev->f->get_config) {
+        return vdev->f->get_config(vdev, buf, len);
+    }
+
+    return VIRTIO_ERR_BACKEND;
 }
 
 /**
@@ -287,10 +313,12 @@ errval_t virtio_device_config_write(struct virtio_device *dev,
                                     size_t offset,
                                     size_t length)
 {
-    assert(!"NYI:");
-    return SYS_ERR_OK;
-}
+    if (dev->f->set_config) {
+        return dev->f->set_config(dev, config, offset, length);
+    }
 
+    return VIRTIO_ERR_BACKEND;
+}
 
 errval_t virtio_device_set_driver_features(struct virtio_device *dev,
                                            uint64_t features)
@@ -309,8 +337,21 @@ errval_t virtio_device_get_device_features(struct virtio_device *dev,
 errval_t virtio_device_feature_negotiate(struct virtio_device *dev,
                                          uint64_t driver_features)
 {
-    assert(!"NYI:");
-    return dev->f->negotiate_features(dev, driver_features);
+    if (dev->f->negotiate_features) {
+        return dev->f->negotiate_features(dev, driver_features);
+    }
+
+    return VIRTIO_ERR_BACKEND;
+}
+
+errval_t virtio_device_set_virtq(struct virtio_device *dev,
+                                 struct virtqueue *vq)
+{
+    if (dev->f->set_virtq) {
+        return dev->f->set_virtq(dev, vq);
+    }
+
+    return VIRTIO_ERR_BACKEND;
 }
 
 /**
@@ -328,13 +369,15 @@ errval_t virtio_device_virtqueue_alloc(struct virtio_device *vdev,
 {
     errval_t err;
 
+    VIRTIO_DEBUG_VQ("Allocating %u virtqueues for [%s].\n", vq_num, vdev->name);
+
     vdev->vq = calloc(vq_num, sizeof(void *));
     if (vdev->vq == NULL) {
         return LIB_ERR_MALLOC_FAIL;
     }
 
     struct virtqueue_setup *setup;
-    for(uint16_t i = 0; i < vq_num; ++i) {
+    for (uint16_t i = 0; i < vq_num; ++i) {
         setup = &vq_setup[i];
         setup->queue_id = i;
         setup->device = vdev;
@@ -348,6 +391,20 @@ errval_t virtio_device_virtqueue_alloc(struct virtio_device *vdev,
         }
     }
 
+    for (uint16_t i = 0; i < vq_num; ++i) {
+        setup = &vq_setup[i];
+        struct virtqueue *vq = vdev->vq[i];
+        if (setup->auto_add) {
+            err = virtio_device_set_virtq(vdev, vq);
+            if (err_is_fail(err)) {
+                USER_PANIC_ERR(err, "adding the virtqueue to the deivce\n");
+            }
+            // TODO propper error handling
+        }
+    }
+
+    vdev->vq_num = vq_num;
+
     return SYS_ERR_OK;
 }
 
index ffed491..2e07c07 100644 (file)
 // forward declaration
 struct virtqueue;
 
+struct virtio_host_queue
+{
+    lpaddr_t base;
+    size_t   length;
+    uint16_t ndesc;
+};
+
 struct virtio_host
 {
     uint8_t device_type;
+
+    uint64_t device_features;
+    uint16_t num_queues;
+    struct virtio_host_queue *queues;
+
     struct capref dev_frame;
     lpaddr_t dev_size;
     void *device_base;
+
     enum virtio_device_backend backend;
     struct virtio_host_cb *callback;
     errval_t (*poll)(struct virtio_host *);
+
+
 };
 
 /**
@@ -37,7 +52,7 @@ struct virtio_device
     uint32_t devid;
 
     uint8_t type;
-    void *device_type;
+    void *type_state;
 
     uint8_t status_flags;
     enum virtio_device_status state;
@@ -46,6 +61,8 @@ struct virtio_device
     enum virtio_device_backend backend;
     struct virtio_device_fn *f;
 
+    virtio_device_setup_t setup;
+
     uint16_t vq_num;
     struct virtqueue **vq;
 };
@@ -57,10 +74,12 @@ struct virtio_device_fn
 {
     errval_t (*reset)(struct virtio_device *dev);
     errval_t (*set_status)(struct virtio_device *dev, uint8_t status);
+    errval_t (*get_status)(struct virtio_device *dev, uint32_t *status);
     errval_t (*negotiate_features)(struct virtio_device *dev, uint64_t driv_features);
-    errval_t (*setup)(struct virtio_device *dev);
     errval_t (*get_queue_num_max)(struct virtio_device *dev, uint16_t queue_index, uint16_t *num_max);
     errval_t (*set_virtq)(struct virtio_device *dev, struct virtqueue *vq);
+    errval_t (*get_config)(struct virtio_device *vdev, void *buf,size_t len);
+    errval_t (*set_config)(struct virtio_device *dev,void *config,size_t offset, size_t length);
 };
 
 
index 0415aa8..59e16f4 100644 (file)
@@ -88,6 +88,7 @@ bool virtio_block_get_geometry(struct virtio_device_blk *dev,
  */
 errval_t virtio_block_config_read(struct virtio_device_blk *dev)
 {
+    VIRTIO_DEBUG_DT("reading device configuration\n");
     if (dev->config_addr == NULL) {
         dev->config_addr = malloc(VIRTIO_BLOCK_CONFIG_SIZE);
         if (dev->config_addr == NULL) {
@@ -108,11 +109,16 @@ errval_t virtio_block_config_read(struct virtio_device_blk *dev)
  *
  * \returns SYS_ERR_OK on success
  */
-static errval_t virtio_block_init_common(struct virtio_device_blk *dev,
-                                         struct virtio_device_setup *setup)
+static errval_t virtio_block_init_common(struct virtio_device *vdev,
+                                         void *arg)
 {
     errval_t err;
 
+    VIRTIO_DEBUG_DT("Doing device specific setup: Block Device\n");
+
+    struct virtio_device_setup *setup = arg;
+    struct virtio_device_blk *dev = virtio_device_get_type_state(vdev);
+
     /* read the device configuration */
     err = virtio_block_config_read(dev);
     if (err_is_fail(err)) {
@@ -155,20 +161,17 @@ static errval_t virtio_block_init_common(struct virtio_device_blk *dev,
 errval_t virtio_block_init_device(struct virtio_device_blk *dev,
                                   struct virtio_device_setup *setup)
 {
-    errval_t err;
-
     if (setup->type != VIRTIO_DEVICE_TYPE_BLOCK) {
         VIRTIO_DEBUG_DT("ERROR: Device type was not VIRTIO_DEVICE_TYPE_BLOCK\n");
         return VIRTIO_ERR_DEVICE_TYPE;
     }
 
-    /* initialize the VirtIO device */
-    err = virtio_device_open(&dev->vdev, setup);
-    if (err_is_fail(err)) {
-        return err;
-    }
+    setup->setup_fn = virtio_block_init_common;
+    setup->setup_arg = setup;
+    setup->type_state = dev;
 
-    return virtio_block_init_common(dev, setup);
+    /* initialize the VirtIO device */
+    return virtio_device_open(&dev->vdev, setup);
 }
 
 /**
@@ -185,17 +188,13 @@ errval_t virtio_block_init_device_with_cap(struct virtio_device_blk *dev,
                                            struct virtio_device_setup *setup,
                                            struct capref dev_cap)
 {
-    errval_t err;
-
     if (setup->type != VIRTIO_DEVICE_TYPE_BLOCK) {
         return VIRTIO_ERR_DEVICE_TYPE;
     }
 
-    /* initialize the VirtIO device */
-    err = virtio_device_open_with_cap(&dev->vdev, setup, dev_cap);
-    if (err_is_fail(err)) {
-        return err;
-    }
+    setup->setup_fn = virtio_block_init_common;
+    setup->setup_arg = setup;
 
-    return virtio_block_init_common(dev, setup);
+    /* initialize the VirtIO device */
+    return virtio_device_open_with_cap(&dev->vdev, setup, dev_cap);
 }
index 25e819a..91bab69 100644 (file)
@@ -44,7 +44,7 @@ errval_t virtio_host_init(struct virtio_host **host,
         assert(!"NYI: IO backend");
         break;
     default:
-
+        err = VIRTIO_ERR_ARG_INVALID;
         break;
     }
 
@@ -52,6 +52,8 @@ errval_t virtio_host_init(struct virtio_host **host,
         return err;
     }
 
+
+
     switch (setup->channel_type) {
     case VIRTIO_HOST_CHAN_FLOUNDER:
         err = virtio_host_flounder_init(setup->iface, setup->callback);
@@ -74,7 +76,10 @@ errval_t virtio_host_init(struct virtio_host **host,
 
 errval_t virtio_host_poll_device(struct virtio_host *host)
 {
-    return SYS_ERR_OK;
+    if (host->poll) {
+        return host->poll(host);
+    }
+    return VIRTIO_ERR_BACKEND;
 }
 
 errval_t virtio_host_get_device_cap(struct virtio_host *host,
index f6ed110..ab34119 100644 (file)
@@ -203,6 +203,9 @@ errval_t virtio_virtqueue_alloc(struct virtqueue_setup *setup,
 {
     errval_t err;
 
+    VIRTIO_DEBUG_VQ("Allocating VQ(%u) of size %u\n",
+                    setup->queue_id, setup->vring_ndesc);
+
     assert(vq);
 
     if (setup->vring_ndesc == 0 || !IS_POW2(setup->vring_ndesc)) {
@@ -220,7 +223,7 @@ errval_t virtio_virtqueue_alloc(struct virtqueue_setup *setup,
         return err;
     }
 
-    VIRTIO_DEBUG_VQ("Allocated memory for vring: [%lx & %lx]",
+    VIRTIO_DEBUG_VQ("Allocated memory for vring: [0x%lx & 0x%lx]\n",
                     (uint64_t )size,
                     (uint64_t )framesize);
 
@@ -985,7 +988,7 @@ errval_t virtio_virtqueue_poll(struct virtqueue *vq,
 
     err = virtio_virtqueue_desc_dequeue(vq, ret_bl, ret_st);
 
-    while(err_no(err) == VIRTIO_ERR_NO_DESC_AVAIL) {
+    while (err_no(err) == VIRTIO_ERR_NO_DESC_AVAIL) {
         if (handle_msg) {
             err = event_dispatch_non_block(get_default_waitset());
             if (err_is_fail(err)) {
@@ -1001,14 +1004,3 @@ errval_t virtio_virtqueue_poll(struct virtqueue *vq,
 
     return err;
 }
-
-#if 0
-
-
-void *virtio_virtqueue_poll(struct virtqueue *vq)
-{
-    return NULL;
-};
-
-#endif
-
index eeae0b4..ca2305f 100644 (file)
@@ -33,7 +33,7 @@ void vblock_device_config_changed_intr(struct virtio_device *vdev)
 {
     struct virtio_device_blk *bdev;
 
-    bdev = virtio_device_get_struct(vdev);
+    bdev = virtio_device_get_type_state(vdev);
     if (bdev == NULL) {
         return;
     }
@@ -81,11 +81,12 @@ errval_t vblock_device_init(struct virtio_device_blk *blk,
 
     struct virtqueue_setup vq_setup =  {
         .name = "Request Virtqueue",
-        .vring_ndesc = 0,
-        .vring_align = 0,
+        .vring_ndesc = 16,
+        .vring_align = 4096,
         .intr_handler = 0,
         .intr_arg = 0,
-        .max_indirect =0
+        .max_indirect =0,
+        .auto_add = 1
     };
 
     struct virtio_device_setup setup = {
index c803448..2e5cd92 100644 (file)
@@ -41,12 +41,24 @@ int main(int argc, char *argv[])
     struct capref dev_frame;
     err = virtio_guest_open_device(VIRTIO_DEVICE_BACKEND_MMIO, &dev_frame);
     if (err_is_fail(err)) {
-        USER_PANIC_ERR(err, "Could not initialize the library\n");
+        USER_PANIC_ERR(err, "Could not open the device\n");
+    }
+
+    struct frame_identity id;
+    err = invoke_frame_identify(dev_frame, &id);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "identifying the frame failed\n");
     }
 
-    void *dev_regs = malloc(4096);
+    size_t dev_size = (1UL<<id.bits);
+
+    void *dev_regs;
+    err = vspace_map_one_frame_attr(&dev_regs, dev_size, dev_frame, VIRTIO_VREGION_FLAGS_DEVICE, NULL, NULL);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "failed to map the device frame");
+    }
 
-    vblock_device_init(&blk_dev, dev_regs, 4096);
+    vblock_device_init(&blk_dev, dev_regs, dev_size);
 
     debug_printf("VirtIO block device driver terminated.\n");
 }
index 09a6c96..201522d 100644 (file)
@@ -13,6 +13,7 @@
  */
 
 #include <barrelfish/barrelfish.h>
+#include <barrelfish/waitset.h>
 
 #include <virtio/virtio.h>
 #include <virtio/virtio_device.h>
@@ -28,6 +29,10 @@ struct virtio_host *host;
 
 static errval_t handle_open(struct capref *ret_frame, void **st)
 {
+    assert(host);
+
+    virtio_host_get_device_cap(host, ret_frame);
+
     return SYS_ERR_OK;
 }
 
@@ -42,10 +47,17 @@ int main(int argc, char *argv[])
 
     debug_printf("VirtIO block device host started.\n");
 
+    uint16_t queue_num_max = 32;
+
     struct virtio_host_setup setup = {
+        .device_features = 0xFFFFFFFFFFFFFFFF,
+        .num_queues = 1,
+        .queue_num_max = &queue_num_max,
         .callback = &host_cb,
         .channel_type = VIRTIO_HOST_CHAN_FLOUNDER,
-        .iface = VIRTIO_BLOCK_FLOUNDER_IFACE
+        .backend = VIRTIO_DEVICE_BACKEND_MMIO,
+        .iface = VIRTIO_BLOCK_FLOUNDER_IFACE,
+        .device_type = VIRTIO_DEVICE_TYPE_BLOCK
     };
 
     err = virtio_host_init(&host,
@@ -54,8 +66,29 @@ int main(int argc, char *argv[])
         USER_PANIC_ERR(err, "Service initialization failed.\n");
     }
 
-
-    messages_handler_loop();
+    struct waitset *ws = get_default_waitset();
+    while(1) {
+        uint8_t idle_count = 0;
+        err = virtio_host_poll_device(host);
+        if (err_is_fail(err)) {
+            if (err_no(err) == VIRTIO_ERR_DEVICE_IDLE) {
+                idle_count++;
+            } else {
+                USER_PANIC_ERR(err, "error while polling device");
+            }
+        }
+        err = event_dispatch_non_block(ws);
+        if (err_is_fail(err)) {
+            if (err_no(err) == LIB_ERR_NO_EVENT) {
+                idle_count++;
+            } else {
+                USER_PANIC_ERR(err, "error while dispatching events");
+            }
+        }
+        if (idle_count == 2) {
+            thread_yield();
+        }
+    }
 
     debug_printf("VirtIO block device host terminated.\n");
 }