You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by "CV-Bowen (via GitHub)" <gi...@apache.org> on 2023/07/30 07:34:57 UTC

[GitHub] [nuttx] CV-Bowen commented on a diff in pull request #9297: virtio: add virtio framework in NuttX

CV-Bowen commented on code in PR #9297:
URL: https://github.com/apache/nuttx/pull/9297#discussion_r1278524394


##########
drivers/virtio/virtio-mmio.c:
##########
@@ -24,212 +24,852 @@
 
 #include <nuttx/config.h>
 
-#include <stdint.h>
-#include <stdbool.h>
 #include <debug.h>
+#include <errno.h>
+#include <stdint.h>
+#include <sys/param.h>
 
-#include <nuttx/arch.h>
-#include <nuttx/kmalloc.h>
+#include <nuttx/virtio/virtio.h>
 #include <nuttx/virtio/virtio-mmio.h>
 
-#ifdef CONFIG_DRIVERS_VIRTIO_NET
-#  include "virtio-mmio-net.h"
-#endif
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define VIRITO_PAGE_SHIFT               12
+#define VIRTIO_PAGE_SIZE                (1 << VIRITO_PAGE_SHIFT)
+#define VIRTIO_VRING_ALIGN              VIRTIO_PAGE_SIZE
+
+#define VIRTIO_MMIO_VERSION_1           1
+
+/* Control registers */
+
+/* Magic value ("virt" string) - Read Only */
+
+#define VIRTIO_MMIO_MAGIC_VALUE         0x000
+#define VIRTIO_MMIO_MAGIC_VALUE_STRING  ('v' | ('i' << 8) | ('r' << 16) | ('t' << 24))
+
+/* Virtio device version - Read Only */
+
+#define VIRTIO_MMIO_VERSION             0x004
+
+/* Virtio device ID - Read Only */
+
+#define VIRTIO_MMIO_DEVICE_ID           0x008
+
+/* Virtio vendor ID - Read Only */
+
+#define VIRTIO_MMIO_VENDOR_ID           0x00c
+
+/* Bitmask of the features supported by the device (host)
+ * (32 bits per set) - Read Only
+ */
+
+#define VIRTIO_MMIO_DEVICE_FEATURES     0x010
+
+/* Device (host) features set selector - Write Only */
+
+#define VIRTIO_MMIO_DEVICE_FEATURES_SEL 0x014
+
+/* Bitmask of features activated by the driver (guest)
+ * (32 bits per set) - Write Only
+ */
+
+#define VIRTIO_MMIO_DRIVER_FEATURES     0x020
+
+/* Activated features set selector - Write Only */
+
+#define VIRTIO_MMIO_DRIVER_FEATURES_SEL 0x024
+
+/* [VERSION 1 REGISTER] Guest page size */
+
+#define VIRTIO_MMIO_PAGE_SIZE           0X028
+
+/* Queue selector - Write Only */
+
+#define VIRTIO_MMIO_QUEUE_SEL           0x030
+
+/* Maximum size of the currently selected queue - Read Only */
+
+#define VIRTIO_MMIO_QUEUE_NUM_MAX       0x034
+
+/* Queue size for the currently selected queue - Write Only */
+
+#define VIRTIO_MMIO_QUEUE_NUM           0x038
+
+/* [VERSION 1 REGISTER] Used Ring alignment in the virtual queue */
+
+#define VIRTIO_MMIO_QUEUE_ALIGN         0x03c
+
+/* [VERSION 1 REGISTER] Guest physical page number of the virtual queue
+ * Writing to this register notifies the device about location
+ */
+
+#define VIRTIO_MMIO_QUEUE_PFN           0x040
+
+/* Ready bit for the currently selected queue - Read Write */
+
+#define VIRTIO_MMIO_QUEUE_READY         0x044
+
+/* Queue notifier - Write Only */
+
+#define VIRTIO_MMIO_QUEUE_NOTIFY        0x050
+
+/* Interrupt status - Read Only */
+
+#define VIRTIO_MMIO_INTERRUPT_STATUS    0x060
+
+/* Interrupt acknowledge - Write Only */
+
+#define VIRTIO_MMIO_INTERRUPT_ACK       0x064
+#define VIRTIO_MMIO_INTERRUPT_VRING     (1 << 0)
+#define VIRTIO_MMIO_INTERRUPT_CONFIG    (1 << 1)
+
+/* Device status register - Read Write */
+
+#define VIRTIO_MMIO_STATUS              0x070
+
+/* Selected queue's Descriptor Table address, 64 bits in two halves */
+
+#define VIRTIO_MMIO_QUEUE_DESC_LOW      0x080
+#define VIRTIO_MMIO_QUEUE_DESC_HIGH     0x084
+
+/* Selected queue's Available Ring address, 64 bits in two halves */
+
+#define VIRTIO_MMIO_QUEUE_AVAIL_LOW     0x090
+#define VIRTIO_MMIO_QUEUE_AVAIL_HIGH    0x094
+
+/* Selected queue's Used Ring address, 64 bits in two halves */
+
+#define VIRTIO_MMIO_QUEUE_USED_LOW      0x0a0
+#define VIRTIO_MMIO_QUEUE_USED_HIGH     0x0a4
+
+/* Shared memory region id */
+
+#define VIRTIO_MMIO_SHM_SEL             0x0ac
+
+/* Shared memory region length, 64 bits in two halves */
+
+#define VIRTIO_MMIO_SHM_LEN_LOW         0x0b0
+#define VIRTIO_MMIO_SHM_LEN_HIGH        0x0b4
+
+/* Shared memory region base address, 64 bits in two halves */
+
+#define VIRTIO_MMIO_SHM_BASE_LOW        0x0b8
+#define VIRTIO_MMIO_SHM_BASE_HIGH       0x0bc
 
-#ifdef CONFIG_DRIVERS_VIRTIO_BLK
-#  include "virtio-mmio-blk.h"
-#endif
+/* Configuration atomicity value */
+
+#define VIRTIO_MMIO_CONFIG_GENERATION   0x0fc
+
+/* The config space is defined by each driver as
+ * the per-driver configuration space - Read Write
+ */
+
+#define VIRTIO_MMIO_CONFIG              0x100
 
 /****************************************************************************
- * Pre-processor Definitions
+ * Private Types
  ****************************************************************************/
 
-#define ptr_to_uint64(x)  ((uint64_t)(uintptr_t)(x))
+struct virtio_mmio_device_s
+{
+  struct virtio_device   vdev;       /* Virtio deivce */
+  struct metal_io_region shm_io;     /* Share memory io region, virtqueue
+                                      * use this io.
+                                      */
+  struct metal_io_region cfg_io;     /* Config memory io region, used to
+                                      * read/write mmio register
+                                      */
+  metal_phys_addr_t      shm_phy;    /* Share memory physical address */
+  metal_phys_addr_t      cfg_phy;    /* Config memory physical address */
+  int                    irq;        /* The mmio interrupt number */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Helper functions */
+
+static uint32_t virtio_mmio_get_queue_len(FAR struct metal_io_region *io,
+                                          int idx);
+static int virtio_mmio_config_virtqueue(FAR struct metal_io_region *io,
+                                        FAR struct virtqueue *vq);
+static int virtio_mmio_init_device(FAR struct virtio_mmio_device_s *vmdev,
+                                   FAR void *regs, int irq);
+
+/* Virtio mmio dispatch functions */
+
+static int
+virtio_mmio_create_virtqueue(FAR struct virtio_mmio_device_s *vmdev,
+                             unsigned int i, FAR const char *name,
+                             vq_callback callback);
+static int virtio_mmio_create_virtqueues(FAR struct virtio_device *vdev,
+                                         unsigned int flags,
+                                         unsigned int nvqs,
+                                         FAR const char *names[],
+                                         vq_callback callbacks[]);
+static void virtio_mmio_delete_virtqueues(FAR struct virtio_device *vdev);
+static void virtio_mmio_set_status(FAR struct virtio_device *vdev,
+                                   uint8_t status);
+static uint8_t virtio_mmio_get_status(FAR struct virtio_device *vdev);
+static void virtio_mmio_write_config(FAR struct virtio_device *vdev,
+                                     uint32_t offset, void *dst,
+                                     int length);
+static void virtio_mmio_read_config(FAR struct virtio_device *vdev,
+                                    uint32_t offset, FAR void *dst,
+                                    int length);
+static uint32_t virtio_mmio_get_features(FAR struct virtio_device *vdev);
+static void virtio_mmio_set_features(FAR struct virtio_device *vdev,
+                                     uint32_t features);
+static uint32_t virtio_mmio_negotiate_features(struct virtio_device *vdev,
+                                               uint32_t features);
+static void virtio_mmio_reset_device(FAR struct virtio_device *vdev);
+static void virtio_mmio_notify(FAR struct virtqueue *vq);
+
+/* Interrupt */
+
+static int virtio_mmio_interrupt(int irq, FAR void *context, FAR void *arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct virtio_dispatch g_virtio_mmio_dispatch =
+{
+  virtio_mmio_create_virtqueues,  /* create_virtqueues */
+  virtio_mmio_delete_virtqueues,  /* delete_virtqueues */
+  virtio_mmio_get_status,         /* get_status */
+  virtio_mmio_set_status,         /* set_status */
+  virtio_mmio_get_features,       /* get_features */
+  virtio_mmio_set_features,       /* set_features */
+  virtio_mmio_negotiate_features, /* negotiate_features */
+  virtio_mmio_read_config,        /* read_config */
+  virtio_mmio_write_config,       /* write_config */
+  virtio_mmio_reset_device,       /* reset_device */
+  virtio_mmio_notify,             /* notify */
+  NULL,                           /* notify_wait */
+};
 
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
 
 /****************************************************************************
- * Name: virtq_create
+ * Name: virtio_mmio_get_queue_len
  ****************************************************************************/
 
-FAR struct virtqueue *virtq_create(uint32_t len)
+static uint32_t virtio_mmio_get_queue_len(FAR struct metal_io_region *io,
+                                          int idx)
 {
-  FAR struct virtqueue *virtq = (FAR struct virtqueue *)
-    kmm_zalloc(sizeof(struct virtqueue));
-  ASSERT(virtq);
+  uint32_t len;
+
+  /* Select the queue we're interested in */
+
+  metal_io_write32(io, VIRTIO_MMIO_QUEUE_SEL, idx);
+  len = metal_io_read32(io, VIRTIO_MMIO_QUEUE_NUM_MAX);
+
+  if (CONFIG_DRIVERS_VIRTIO_MMIO_QUEUE_LEN != 0)
+    {
+      len = MIN(len, CONFIG_DRIVERS_VIRTIO_MMIO_QUEUE_LEN);
+    }
+
+  return len;
+}
+
+/****************************************************************************
+ * Name: virtio_mmio_config_virtqueue
+ ****************************************************************************/
+
+static int virtio_mmio_config_virtqueue(FAR struct metal_io_region *io,
+                                        FAR struct virtqueue *vq)
+{
+  uint32_t version = vq->vq_dev->id.version;
+  uint64_t addr;
+
+  /* Select the queue we're interested in */
+
+  metal_io_write32(io, VIRTIO_MMIO_QUEUE_SEL, vq->vq_queue_index);
+
+  /* Queue shouldn't already be set up. */
 
-  virtq->len = len;
+  if (metal_io_read32(io, version == VIRTIO_MMIO_VERSION_1 ?
+                      VIRTIO_MMIO_QUEUE_PFN : VIRTIO_MMIO_QUEUE_READY))
+    {
+      vrterr("Virtio queue not ready\n");
+      return -ENOENT;
+    }
+
+  /* Activate the queue */
+
+  if (version == VIRTIO_MMIO_VERSION_1)
+    {
+      uint64_t pfn = (uintptr_t)vq->vq_ring.desc >> VIRITO_PAGE_SHIFT;
 
-  /* See: 2.6 Split Virtqueues */
+      vrtinfo("Legacy, desc=%p, pfn=0x%" PRIx64 ", align=%d\n",
+              vq->vq_ring.desc, pfn, VIRTIO_PAGE_SIZE);
 
-  virtq->desc  = (FAR struct virtqueue_desc *)
-    kmm_memalign(16, 16 * len);
-  ASSERT(virtq->desc);
+      /* virtio-mmio v1 uses a 32bit QUEUE PFN. If we have something
+       * that doesn't fit in 32bit, fail the setup rather than
+       * pretending to be successful.
+       */
 
-  virtq->avail = (FAR struct virtqueue_avail *)
-    kmm_memalign(2, 6 + 2 * len);
-  ASSERT(virtq->avail);
+      if (pfn >> 32)
+        {
+          vrterr("Legacy virtio-mmio used RAM shoud not above 0x%llxGB\n",
+                 0x1ull << (2 + VIRITO_PAGE_SHIFT));
+        }
 
-  virtq->used  = (FAR struct virtqueue_used *)
-    kmm_memalign(4, 6 + 8 * len);
-  ASSERT(virtq->used);
+      metal_io_write32(io, VIRTIO_MMIO_QUEUE_NUM, vq->vq_nentries);
+      metal_io_write32(io, VIRTIO_MMIO_QUEUE_ALIGN, VIRTIO_PAGE_SIZE);
+      metal_io_write32(io, VIRTIO_MMIO_QUEUE_PFN, pfn);
+    }
+  else
+    {
+      metal_io_write32(io, VIRTIO_MMIO_QUEUE_NUM, vq->vq_nentries);
 
-  virtq->desc_virt = (FAR void **)
-    kmm_memalign(16, sizeof(FAR void *) * len);
-  ASSERT(virtq->desc_virt);
+      addr = (uint64_t)(uintptr_t)vq->vq_ring.desc;
+      metal_io_write32(io, VIRTIO_MMIO_QUEUE_DESC_LOW, addr);
+      metal_io_write32(io, VIRTIO_MMIO_QUEUE_DESC_HIGH, addr >> 32);
 
-  vrtinfo("virtq=%p (len=%" PRId32 ")\n", virtq, len);
-  vrtinfo("virtq->desc=%p \n", virtq->desc);
-  vrtinfo("virtq->avail=%p \n", virtq->avail);
-  vrtinfo("virtq->used=%p \n", virtq->used);
+      addr = (uint64_t)(uintptr_t)vq->vq_ring.avail;
+      metal_io_write32(io, VIRTIO_MMIO_QUEUE_AVAIL_LOW, addr);
+      metal_io_write32(io, VIRTIO_MMIO_QUEUE_AVAIL_HIGH, addr >> 32);
 
-  virtq->avail->idx = 0;
-  virtq->used->idx = 0;
-  virtq->last_used_idx = 0;
+      addr = (uint64_t)(uintptr_t)vq->vq_ring.used;
+      metal_io_write32(io, VIRTIO_MMIO_QUEUE_USED_LOW, addr);
+      metal_io_write32(io, VIRTIO_MMIO_QUEUE_USED_HIGH, addr >> 32);
 
-  return virtq;
+      metal_io_write32(io, VIRTIO_MMIO_QUEUE_READY, 1);
+    }
+
+  return OK;
 }
 
 /****************************************************************************
- * Name: virtq_dev_init
+ * Name: virtio_mmio_create_virtqueue
  ****************************************************************************/
 
-static int virtio_dev_init(uintptr_t virt, uint32_t irq)
+static int
+virtio_mmio_create_virtqueue(FAR struct virtio_mmio_device_s *vmdev,
+                             unsigned int i, FAR const char *name,
+                             vq_callback callback)
 {
-  FAR struct virtio_mmio_regs *regs = (FAR struct virtio_mmio_regs *)virt;
-  int ret = -ENODEV;
-  uint32_t val;
-
-  vrtinfo("examine virtio at 0x%" PRIxPTR "\n", virt);
+  FAR struct virtio_device *vdev = &vmdev->vdev;
+  FAR struct virtio_vring_info *vrinfo;
+  FAR struct vring_alloc_info *vralloc;
+  FAR struct virtqueue *vq;
+  int vringsize;
+  int ret;
+
+  /* Alloc virtqueue and init the vring info and vring alloc info */
+
+  vrinfo  = &vdev->vrings_info[i];
+  vralloc = &vrinfo->info;
+  vralloc->num_descs = virtio_mmio_get_queue_len(&vmdev->cfg_io, i);
+  vq = virtqueue_allocate(vralloc->num_descs);
+  if (vq == NULL)
+    {
+      vrterr("virtqueue_allocate failed\n");
+      return -ENOMEM;
+    }
 
-  val = virtio_getreg32(&regs->magic_value);
+  /* Init the vring info and vring alloc info */
 
-  if (VIRTIO_MAGIC != val)
+  vrinfo->vq       = vq;
+  vrinfo->io       = &vmdev->shm_io;
+  vrinfo->notifyid = i;
+  vralloc->align   = VIRTIO_VRING_ALIGN;
+  vringsize        = vring_size(vralloc->num_descs, VIRTIO_VRING_ALIGN);
+  vralloc->vaddr   = virtio_zalloc_buf(vdev, vringsize, VIRTIO_VRING_ALIGN);
+  if (vralloc->vaddr == NULL)
     {
-      vrterr("error: virtio at 0x%" PRIxPTR
-             " had wrong magic value 0x%" PRIx32 "\n", virt, val);
-      return ret;
+      vrterr("vring alloc failed\n");
+      return -ENOMEM;
     }
 
-  val = virtio_getreg32(&regs->version);
+  /* Initialize the virtio queue */
 
-  if (VIRTIO_VERSION != val)
+  ret = virtqueue_create(vdev, i, name, vralloc, callback,
+                         vdev->func->notify, vq);
+  if (ret < 0)
     {
-      vrterr("error: virtio at 0x%" PRIxPTR
-             " had wrong version 0x%" PRIx32 "\n", virt, val);
+      vrterr("virtqueue create error, ret=%d\n", ret);
       return ret;
     }
 
-  /* Reset */
+  virtqueue_set_shmem_io(vq, &vmdev->shm_io);
 
-  virtio_putreg32(0, &regs->status);
-  virtio_mb();
+  /* Set the mmio virtqueue register */
 
-  /* Set ack */
+  ret = virtio_mmio_config_virtqueue(&vmdev->cfg_io, vq);
+  if (ret < 0)
+    {
+      vrterr("virtio_mmio_config_virtqueue failed, ret=%d\n", ret);
+    }
 
-  val = virtio_getreg32(&regs->status) | VIRTIO_STATUS_ACKNOWLEDGE;
-  virtio_putreg32(val, &regs->status);
-  virtio_mb();
+  return ret;
+}
 
-  /* Set driver */
+/****************************************************************************
+ * Name: virtio_mmio_create_virtqueues
+ ****************************************************************************/
 
-  val = virtio_getreg32(&regs->status) | VIRTIO_STATUS_DRIVER;
-  virtio_putreg32(val, &regs->status);
-  virtio_mb();
+static int virtio_mmio_create_virtqueues(FAR struct virtio_device *vdev,
+                                         unsigned int flags,
+                                         unsigned int nvqs,
+                                         FAR const char *names[],
+                                         vq_callback callbacks[])
+{
+  FAR struct virtio_mmio_device_s *vmdev =
+    (FAR struct virtio_mmio_device_s *)vdev;
+  unsigned int i;
+  int ret = OK;
+
+  /* Alloc vring info */
 
-  /* Check the device_id */
+  vdev->vrings_num = nvqs;
+  vdev->vrings_info = kmm_zalloc(sizeof(struct virtio_vring_info) * nvqs);
+  if (vdev->vrings_info == NULL)
+    {
+      vrterr("alloc vrings info failed\n");
+      return -ENOMEM;
+    }
 
-  val = virtio_getreg32(&regs->device_id);
+  /* Alloc and init the virtqueue */
 
-  switch (val)
+  for (i = 0; i < nvqs; i++)
     {
-#ifdef CONFIG_DRIVERS_VIRTIO_NET
-    case VIRTIO_DEV_NET:
-      ret = virtio_mmio_net_init(regs, irq);
-      break;
-#endif
-#ifdef CONFIG_DRIVERS_VIRTIO_BLK
-    case VIRTIO_DEV_BLK:
-      ret = virtio_mmio_blk_init(regs, irq);
-      break;
-#endif
-    default:
-      vrtwarn("unsupported device_id 0x%" PRIx32 "\n", val);
+      ret = virtio_mmio_create_virtqueue(vmdev, i, names[i], callbacks[i]);
+      if (ret < 0)
+        {
+          goto err;
+        }
     }
 
+  /* Finally, enable the interrupt */
+
+  up_enable_irq(vmdev->irq);
+  return ret;
+
+err:
+  virtio_mmio_delete_virtqueues(vdev);
   return ret;
 }
 
 /****************************************************************************
- * Public Functions
+ * Name: virtio_mmio_delete_virtqueues
  ****************************************************************************/
 
+static void virtio_mmio_delete_virtqueues(FAR struct virtio_device *vdev)
+{
+  FAR struct virtio_mmio_device_s *vmdev =
+    (FAR struct virtio_mmio_device_s *)vdev;
+  FAR struct virtio_vring_info *vrinfo;
+  unsigned int i;
+
+  /* Disable interrupt first */
+
+  up_disable_irq(vmdev->irq);
+
+  /* Free the memory */
+
+  if (vdev->vrings_info != NULL)
+    {
+      for (i = 0; i < vdev->vrings_num; i++)
+        {
+          metal_io_write32(&vmdev->cfg_io, VIRTIO_MMIO_QUEUE_SEL, i);
+          if (vdev->id.version == VIRTIO_MMIO_VERSION_1)
+            {
+              metal_io_write32(&vmdev->cfg_io, VIRTIO_MMIO_QUEUE_PFN, 0);
+            }
+          else
+            {
+              /* Virtio 1.2: To stop using the queue the driver MUST write
+               * zero (0x0) to this QueueReady and MUST read the value back
+               * to ensure synchronization.
+               */
+
+              metal_io_write32(&vmdev->cfg_io, VIRTIO_MMIO_QUEUE_READY, 0);
+              if (metal_io_read32(&vmdev->cfg_io, VIRTIO_MMIO_QUEUE_READY))
+                {
+                  vrtwarn("queue ready set zero failed\n");
+                }
+            }
+
+          /* Free the vring buffer and virtqueue */
+
+          vrinfo = &vdev->vrings_info[i];
+          if (vrinfo->info.vaddr != NULL)
+            {
+              virtio_free_buf(vdev, vrinfo->info.vaddr);
+            }
+
+          if (vrinfo->vq != NULL)
+            {
+              virtqueue_free(vrinfo->vq);
+            }
+        }
+
+      kmm_free(vdev->vrings_info);
+    }
+}
+
 /****************************************************************************
- * Name: virtq_alloc_desc
+ * Name: virtio_mmio_set_status
  ****************************************************************************/
 
-uint32_t virtq_alloc_desc(FAR struct virtqueue *virtq,
-                          uint32_t idx, FAR void *addr)
+static void virtio_mmio_set_status(FAR struct virtio_device *vdev,
+                                   uint8_t status)
 {
-  uint32_t id = idx % virtq->len;
+  FAR struct virtio_mmio_device_s *vmdev =
+    (FAR struct virtio_mmio_device_s *)vdev;
+  metal_io_write32(&vmdev->cfg_io, VIRTIO_MMIO_STATUS, status);
+}
 
-  vrtinfo("virtq=%p, idx=%" PRId32 "\n", virtq, idx);
+/****************************************************************************
+ * Name: virtio_mmio_get_status
+ ****************************************************************************/
+
+static uint8_t virtio_mmio_get_status(FAR struct virtio_device *vdev)
+{
+  FAR struct virtio_mmio_device_s *vmdev =
+    (FAR struct virtio_mmio_device_s *)vdev;
+  return metal_io_read32(&vmdev->cfg_io, VIRTIO_MMIO_STATUS);
+}
+
+/****************************************************************************
+ * Name: virtio_mmio_write_config
+ ****************************************************************************/
+
+static void virtio_mmio_write_config(FAR struct virtio_device *vdev,
+                                     uint32_t offset, void *src, int length)
+{
+  FAR struct virtio_mmio_device_s *vmdev =
+    (FAR struct virtio_mmio_device_s *)vdev;
+  uint32_t write_offset = VIRTIO_MMIO_CONFIG + offset;
+  uint32_t u32data;
+  uint16_t u16data;
+  uint8_t u8data;
+
+  if (vdev->id.version == VIRTIO_MMIO_VERSION_1)
+    {
+      FAR char *s = src;
+      int i;
+      for (i = 0; i < length; i++)
+        {
+          metal_io_write8(&vmdev->cfg_io, write_offset + i, s[i]);
+        }
+
+      return;
+    }
+
+  switch (length)
+    {
+      case 1:
+        memcpy(&u8data, src, sizeof(u8data));
+        metal_io_write8(&vmdev->cfg_io, write_offset, u8data);
+        break;
+      case 2:
+        memcpy(&u16data, src, sizeof(u16data));
+        metal_io_write16(&vmdev->cfg_io, write_offset, u16data);
+        break;
+      case 4:
+        memcpy(&u32data, src, sizeof(u32data));
+        metal_io_write32(&vmdev->cfg_io, write_offset, u32data);
+        break;
+      case 8:
+        memcpy(&u32data, src, sizeof(u32data));
+        metal_io_write32(&vmdev->cfg_io, write_offset, u32data);
+        memcpy(&u32data, src + sizeof(u32data), sizeof(u32data));
+        metal_io_write32(&vmdev->cfg_io, write_offset + sizeof(u32data),
+                         u32data);
+        break;
+      default:
+        DEBUGASSERT(0);
+    }
+}
+
+/****************************************************************************
+ * Name: virtio_mmio_read_config
+ ****************************************************************************/
+
+static void virtio_mmio_read_config(FAR struct virtio_device *vdev,
+                                    uint32_t offset, FAR void *dst,
+                                    int length)
+{
+  FAR struct virtio_mmio_device_s *vmdev =
+    (FAR struct virtio_mmio_device_s *)vdev;
+  uint32_t read_offset = VIRTIO_MMIO_CONFIG + offset;
+  uint32_t u32data;
+  uint16_t u16data;
+  uint8_t u8data;
+
+  if (vdev->id.version == VIRTIO_MMIO_VERSION_1)

Review Comment:
   Because it could work for version 1.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org