uboot/drivers/virtio/virtio_sandbox.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
   4 *
   5 * VirtIO Sandbox transport driver, for testing purpose only
   6 */
   7
   8#include <common.h>
   9#include <dm.h>
  10#include <virtio_types.h>
  11#include <virtio.h>
  12#include <virtio_ring.h>
  13#include <linux/compat.h>
  14#include <linux/io.h>
  15
  16struct virtio_sandbox_priv {
  17        u8 id;
  18        u8 status;
  19        u64 device_features;
  20        u64 driver_features;
  21        ulong queue_desc;
  22        ulong queue_available;
  23        ulong queue_used;
  24};
  25
  26static int virtio_sandbox_get_config(struct udevice *udev, unsigned int offset,
  27                                     void *buf, unsigned int len)
  28{
  29        return 0;
  30}
  31
  32static int virtio_sandbox_set_config(struct udevice *udev, unsigned int offset,
  33                                     const void *buf, unsigned int len)
  34{
  35        return 0;
  36}
  37
  38static int virtio_sandbox_get_status(struct udevice *udev, u8 *status)
  39{
  40        struct virtio_sandbox_priv *priv = dev_get_priv(udev);
  41
  42        *status = priv->status;
  43
  44        return 0;
  45}
  46
  47static int virtio_sandbox_set_status(struct udevice *udev, u8 status)
  48{
  49        struct virtio_sandbox_priv *priv = dev_get_priv(udev);
  50
  51        /* We should never be setting status to 0 */
  52        WARN_ON(status == 0);
  53
  54        priv->status = status;
  55
  56        return 0;
  57}
  58
  59static int virtio_sandbox_reset(struct udevice *udev)
  60{
  61        struct virtio_sandbox_priv *priv = dev_get_priv(udev);
  62
  63        /* 0 status means a reset */
  64        priv->status = 0;
  65
  66        return 0;
  67}
  68
  69static int virtio_sandbox_get_features(struct udevice *udev, u64 *features)
  70{
  71        struct virtio_sandbox_priv *priv = dev_get_priv(udev);
  72
  73        *features = priv->device_features;
  74
  75        return 0;
  76}
  77
  78static int virtio_sandbox_set_features(struct udevice *udev)
  79{
  80        struct virtio_sandbox_priv *priv = dev_get_priv(udev);
  81        struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
  82
  83        priv->driver_features = uc_priv->features;
  84
  85        return 0;
  86}
  87
  88static struct virtqueue *virtio_sandbox_setup_vq(struct udevice *udev,
  89                                                 unsigned int index)
  90{
  91        struct virtio_sandbox_priv *priv = dev_get_priv(udev);
  92        struct virtqueue *vq;
  93        ulong addr;
  94        int err;
  95
  96        /* Create the vring */
  97        vq = vring_create_virtqueue(index, 4, 4096, udev);
  98        if (!vq) {
  99                err = -ENOMEM;
 100                goto error_new_virtqueue;
 101        }
 102
 103        addr = virtqueue_get_desc_addr(vq);
 104        priv->queue_desc = addr;
 105
 106        addr = virtqueue_get_avail_addr(vq);
 107        priv->queue_available = addr;
 108
 109        addr = virtqueue_get_used_addr(vq);
 110        priv->queue_used = addr;
 111
 112        return vq;
 113
 114error_new_virtqueue:
 115        return ERR_PTR(err);
 116}
 117
 118static void virtio_sandbox_del_vq(struct virtqueue *vq)
 119{
 120        vring_del_virtqueue(vq);
 121}
 122
 123static int virtio_sandbox_del_vqs(struct udevice *udev)
 124{
 125        struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
 126        struct virtqueue *vq, *n;
 127
 128        list_for_each_entry_safe(vq, n, &uc_priv->vqs, list)
 129                virtio_sandbox_del_vq(vq);
 130
 131        return 0;
 132}
 133
 134static int virtio_sandbox_find_vqs(struct udevice *udev, unsigned int nvqs,
 135                                   struct virtqueue *vqs[])
 136{
 137        int i;
 138
 139        for (i = 0; i < nvqs; ++i) {
 140                vqs[i] = virtio_sandbox_setup_vq(udev, i);
 141                if (IS_ERR(vqs[i])) {
 142                        virtio_sandbox_del_vqs(udev);
 143                        return PTR_ERR(vqs[i]);
 144                }
 145        }
 146
 147        return 0;
 148}
 149
 150static int virtio_sandbox_notify(struct udevice *udev, struct virtqueue *vq)
 151{
 152        return 0;
 153}
 154
 155static int virtio_sandbox_probe(struct udevice *udev)
 156{
 157        struct virtio_sandbox_priv *priv = dev_get_priv(udev);
 158        struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
 159
 160        /* fake some information for testing */
 161        priv->device_features = VIRTIO_F_VERSION_1;
 162        uc_priv->device = VIRTIO_ID_BLOCK;
 163        uc_priv->vendor = ('u' << 24) | ('b' << 16) | ('o' << 8) | 't';
 164
 165        return 0;
 166}
 167
 168/* check virtio device driver's remove routine was called to reset the device */
 169static int virtio_sandbox_child_post_remove(struct udevice *vdev)
 170{
 171        u8 status;
 172
 173        virtio_get_status(vdev, &status);
 174        if (status)
 175                panic("virtio device was not reset\n");
 176
 177        return 0;
 178}
 179
 180static const struct dm_virtio_ops virtio_sandbox1_ops = {
 181        .get_config     = virtio_sandbox_get_config,
 182        .set_config     = virtio_sandbox_set_config,
 183        .get_status     = virtio_sandbox_get_status,
 184        .set_status     = virtio_sandbox_set_status,
 185        .reset          = virtio_sandbox_reset,
 186        .get_features   = virtio_sandbox_get_features,
 187        .set_features   = virtio_sandbox_set_features,
 188        .find_vqs       = virtio_sandbox_find_vqs,
 189        .del_vqs        = virtio_sandbox_del_vqs,
 190        .notify         = virtio_sandbox_notify,
 191};
 192
 193static const struct udevice_id virtio_sandbox1_ids[] = {
 194        { .compatible = "sandbox,virtio1" },
 195        { }
 196};
 197
 198U_BOOT_DRIVER(virtio_sandbox1) = {
 199        .name   = "virtio-sandbox1",
 200        .id     = UCLASS_VIRTIO,
 201        .of_match = virtio_sandbox1_ids,
 202        .ops    = &virtio_sandbox1_ops,
 203        .probe  = virtio_sandbox_probe,
 204        .child_post_remove = virtio_sandbox_child_post_remove,
 205        .priv_auto_alloc_size = sizeof(struct virtio_sandbox_priv),
 206};
 207
 208/* this one without notify op */
 209static const struct dm_virtio_ops virtio_sandbox2_ops = {
 210        .get_config     = virtio_sandbox_get_config,
 211        .set_config     = virtio_sandbox_set_config,
 212        .get_status     = virtio_sandbox_get_status,
 213        .set_status     = virtio_sandbox_set_status,
 214        .reset          = virtio_sandbox_reset,
 215        .get_features   = virtio_sandbox_get_features,
 216        .set_features   = virtio_sandbox_set_features,
 217        .find_vqs       = virtio_sandbox_find_vqs,
 218        .del_vqs        = virtio_sandbox_del_vqs,
 219};
 220
 221static const struct udevice_id virtio_sandbox2_ids[] = {
 222        { .compatible = "sandbox,virtio2" },
 223        { }
 224};
 225
 226U_BOOT_DRIVER(virtio_sandbox2) = {
 227        .name   = "virtio-sandbox2",
 228        .id     = UCLASS_VIRTIO,
 229        .of_match = virtio_sandbox2_ids,
 230        .ops    = &virtio_sandbox2_ops,
 231        .probe  = virtio_sandbox_probe,
 232        .priv_auto_alloc_size = sizeof(struct virtio_sandbox_priv),
 233};
 234