virtio: Add a Sandbox transport driver
authorBin Meng <bmeng.cn@gmail.com>
Mon, 15 Oct 2018 09:21:25 +0000 (02:21 -0700)
committerSimon Glass <sjg@chromium.org>
Wed, 14 Nov 2018 17:16:28 +0000 (09:16 -0800)
This driver provides support for Sandbox implementation of virtio
transport driver which is used for testing purpose only.

Two drivers are provided. The 2nd one is a driver that lacks the
'notify' op.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
drivers/virtio/Kconfig
drivers/virtio/Makefile
drivers/virtio/virtio_sandbox.c [new file with mode: 0644]

index 753912f0f952cdb9aad2d0745560e9e203d5c902..a9d5fd07b775db571cb2586267182054642d671c 100644 (file)
@@ -37,6 +37,14 @@ config VIRTIO_PCI
          This driver provides support for virtio based paravirtual device
          drivers over PCI.
 
+config VIRTIO_SANDBOX
+       bool "Sandbox driver for virtio devices"
+       depends on SANDBOX
+       select VIRTIO
+       help
+         This driver provides support for Sandbox implementation of virtio
+         transport driver which is used for testing purpose only.
+
 config VIRTIO_NET
        bool "virtio net driver"
        depends on VIRTIO
index 072fb563b3a1e5caba1c14a2f330782bda6d96d9..4579044ae39fd1133a53a9c3b515ef1d976af5a2 100644 (file)
@@ -6,5 +6,6 @@
 obj-y += virtio-uclass.o virtio_ring.o
 obj-$(CONFIG_VIRTIO_MMIO) += virtio_mmio.o
 obj-$(CONFIG_VIRTIO_PCI) += virtio_pci_legacy.o virtio_pci_modern.o
+obj-$(CONFIG_VIRTIO_SANDBOX) += virtio_sandbox.o
 obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
 obj-$(CONFIG_VIRTIO_BLK) += virtio_blk.o
diff --git a/drivers/virtio/virtio_sandbox.c b/drivers/virtio/virtio_sandbox.c
new file mode 100644 (file)
index 0000000..2addb1e
--- /dev/null
@@ -0,0 +1,233 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * VirtIO Sandbox transport driver, for testing purpose only
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <virtio_types.h>
+#include <virtio.h>
+#include <virtio_ring.h>
+#include <linux/compat.h>
+#include <linux/io.h>
+
+struct virtio_sandbox_priv {
+       u8 id;
+       u8 status;
+       u64 device_features;
+       u64 driver_features;
+       ulong queue_desc;
+       ulong queue_available;
+       ulong queue_used;
+};
+
+static int virtio_sandbox_get_config(struct udevice *udev, unsigned int offset,
+                                    void *buf, unsigned int len)
+{
+       return 0;
+}
+
+static int virtio_sandbox_set_config(struct udevice *udev, unsigned int offset,
+                                    const void *buf, unsigned int len)
+{
+       return 0;
+}
+
+static int virtio_sandbox_get_status(struct udevice *udev, u8 *status)
+{
+       struct virtio_sandbox_priv *priv = dev_get_priv(udev);
+
+       *status = priv->status;
+
+       return 0;
+}
+
+static int virtio_sandbox_set_status(struct udevice *udev, u8 status)
+{
+       struct virtio_sandbox_priv *priv = dev_get_priv(udev);
+
+       /* We should never be setting status to 0 */
+       WARN_ON(status == 0);
+
+       priv->status = status;
+
+       return 0;
+}
+
+static int virtio_sandbox_reset(struct udevice *udev)
+{
+       struct virtio_sandbox_priv *priv = dev_get_priv(udev);
+
+       /* 0 status means a reset */
+       priv->status = 0;
+
+       return 0;
+}
+
+static int virtio_sandbox_get_features(struct udevice *udev, u64 *features)
+{
+       struct virtio_sandbox_priv *priv = dev_get_priv(udev);
+
+       *features = priv->device_features;
+
+       return 0;
+}
+
+static int virtio_sandbox_set_features(struct udevice *udev)
+{
+       struct virtio_sandbox_priv *priv = dev_get_priv(udev);
+       struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
+
+       priv->driver_features = uc_priv->features;
+
+       return 0;
+}
+
+static struct virtqueue *virtio_sandbox_setup_vq(struct udevice *udev,
+                                                unsigned int index)
+{
+       struct virtio_sandbox_priv *priv = dev_get_priv(udev);
+       struct virtqueue *vq;
+       ulong addr;
+       int err;
+
+       /* Create the vring */
+       vq = vring_create_virtqueue(index, 4, 4096, udev);
+       if (!vq) {
+               err = -ENOMEM;
+               goto error_new_virtqueue;
+       }
+
+       addr = virtqueue_get_desc_addr(vq);
+       priv->queue_desc = addr;
+
+       addr = virtqueue_get_avail_addr(vq);
+       priv->queue_available = addr;
+
+       addr = virtqueue_get_used_addr(vq);
+       priv->queue_used = addr;
+
+       return vq;
+
+error_new_virtqueue:
+       return ERR_PTR(err);
+}
+
+static void virtio_sandbox_del_vq(struct virtqueue *vq)
+{
+       vring_del_virtqueue(vq);
+}
+
+static int virtio_sandbox_del_vqs(struct udevice *udev)
+{
+       struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
+       struct virtqueue *vq, *n;
+
+       list_for_each_entry_safe(vq, n, &uc_priv->vqs, list)
+               virtio_sandbox_del_vq(vq);
+
+       return 0;
+}
+
+static int virtio_sandbox_find_vqs(struct udevice *udev, unsigned int nvqs,
+                                  struct virtqueue *vqs[])
+{
+       int i;
+
+       for (i = 0; i < nvqs; ++i) {
+               vqs[i] = virtio_sandbox_setup_vq(udev, i);
+               if (IS_ERR(vqs[i])) {
+                       virtio_sandbox_del_vqs(udev);
+                       return PTR_ERR(vqs[i]);
+               }
+       }
+
+       return 0;
+}
+
+static int virtio_sandbox_notify(struct udevice *udev, struct virtqueue *vq)
+{
+       return 0;
+}
+
+static int virtio_sandbox_probe(struct udevice *udev)
+{
+       struct virtio_sandbox_priv *priv = dev_get_priv(udev);
+       struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
+
+       /* fake some information for testing */
+       priv->device_features = VIRTIO_F_VERSION_1;
+       uc_priv->device = VIRTIO_ID_BLOCK;
+       uc_priv->vendor = ('u' << 24) | ('b' << 16) | ('o' << 8) | 't';
+
+       return 0;
+}
+
+/* check virtio device driver's remove routine was called to reset the device */
+static int virtio_sandbox_child_post_remove(struct udevice *vdev)
+{
+       u8 status;
+
+       virtio_get_status(vdev, &status);
+       if (status)
+               panic("virtio device was not reset\n");
+
+       return 0;
+}
+
+static const struct dm_virtio_ops virtio_sandbox1_ops = {
+       .get_config     = virtio_sandbox_get_config,
+       .set_config     = virtio_sandbox_set_config,
+       .get_status     = virtio_sandbox_get_status,
+       .set_status     = virtio_sandbox_set_status,
+       .reset          = virtio_sandbox_reset,
+       .get_features   = virtio_sandbox_get_features,
+       .set_features   = virtio_sandbox_set_features,
+       .find_vqs       = virtio_sandbox_find_vqs,
+       .del_vqs        = virtio_sandbox_del_vqs,
+       .notify         = virtio_sandbox_notify,
+};
+
+static const struct udevice_id virtio_sandbox1_ids[] = {
+       { .compatible = "sandbox,virtio1" },
+       { }
+};
+
+U_BOOT_DRIVER(virtio_sandbox1) = {
+       .name   = "virtio-sandbox1",
+       .id     = UCLASS_VIRTIO,
+       .of_match = virtio_sandbox1_ids,
+       .ops    = &virtio_sandbox1_ops,
+       .probe  = virtio_sandbox_probe,
+       .child_post_remove = virtio_sandbox_child_post_remove,
+       .priv_auto_alloc_size = sizeof(struct virtio_sandbox_priv),
+};
+
+/* this one without notify op */
+static const struct dm_virtio_ops virtio_sandbox2_ops = {
+       .get_config     = virtio_sandbox_get_config,
+       .set_config     = virtio_sandbox_set_config,
+       .get_status     = virtio_sandbox_get_status,
+       .set_status     = virtio_sandbox_set_status,
+       .reset          = virtio_sandbox_reset,
+       .get_features   = virtio_sandbox_get_features,
+       .set_features   = virtio_sandbox_set_features,
+       .find_vqs       = virtio_sandbox_find_vqs,
+       .del_vqs        = virtio_sandbox_del_vqs,
+};
+
+static const struct udevice_id virtio_sandbox2_ids[] = {
+       { .compatible = "sandbox,virtio2" },
+       { }
+};
+
+U_BOOT_DRIVER(virtio_sandbox2) = {
+       .name   = "virtio-sandbox2",
+       .id     = UCLASS_VIRTIO,
+       .of_match = virtio_sandbox2_ids,
+       .ops    = &virtio_sandbox2_ops,
+       .probe  = virtio_sandbox_probe,
+       .priv_auto_alloc_size = sizeof(struct virtio_sandbox_priv),
+};