From: Bin Meng Date: Mon, 15 Oct 2018 09:21:25 +0000 (-0700) Subject: virtio: Add a Sandbox transport driver X-Git-Url: http://git.dujemihanovic.xyz/html/index.html?a=commitdiff_plain;h=640aae0fb1f8b5741e62782cf06fc0f1beb0f612;p=u-boot.git virtio: Add a Sandbox transport driver 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 Reviewed-by: Simon Glass --- diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index 753912f0f9..a9d5fd07b7 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -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 diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile index 072fb563b3..4579044ae3 100644 --- a/drivers/virtio/Makefile +++ b/drivers/virtio/Makefile @@ -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 index 0000000000..2addb1ebc5 --- /dev/null +++ b/drivers/virtio/virtio_sandbox.c @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018, Bin Meng + * + * VirtIO Sandbox transport driver, for testing purpose only + */ + +#include +#include +#include +#include +#include +#include +#include + +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), +};