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