uboot/drivers/virtio/virtio-uclass.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2018, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
   4 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
   5 *
   6 * VirtIO is a virtualization standard for network and disk device drivers
   7 * where just the guest's device driver "knows" it is running in a virtual
   8 * environment, and cooperates with the hypervisor. This enables guests to
   9 * get high performance network and disk operations, and gives most of the
  10 * performance benefits of paravirtualization. In the U-Boot case, the guest
  11 * is U-Boot itself, while the virtual environment are normally QEMU targets
  12 * like ARM, RISC-V and x86.
  13 *
  14 * See http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.pdf for
  15 * the VirtIO specification v1.0.
  16 */
  17
  18#include <common.h>
  19#include <dm.h>
  20#include <log.h>
  21#include <malloc.h>
  22#include <virtio_types.h>
  23#include <virtio.h>
  24#include <dm/lists.h>
  25#include <linux/bug.h>
  26
  27static const char *const virtio_drv_name[VIRTIO_ID_MAX_NUM] = {
  28        [VIRTIO_ID_NET]         = VIRTIO_NET_DRV_NAME,
  29        [VIRTIO_ID_BLOCK]       = VIRTIO_BLK_DRV_NAME,
  30        [VIRTIO_ID_RNG]         = VIRTIO_RNG_DRV_NAME,
  31};
  32
  33int virtio_get_config(struct udevice *vdev, unsigned int offset,
  34                      void *buf, unsigned int len)
  35{
  36        struct dm_virtio_ops *ops;
  37
  38        ops = virtio_get_ops(vdev->parent);
  39
  40        return ops->get_config(vdev->parent, offset, buf, len);
  41}
  42
  43int virtio_set_config(struct udevice *vdev, unsigned int offset,
  44                      void *buf, unsigned int len)
  45{
  46        struct dm_virtio_ops *ops;
  47
  48        ops = virtio_get_ops(vdev->parent);
  49
  50        return ops->set_config(vdev->parent, offset, buf, len);
  51}
  52
  53int virtio_generation(struct udevice *vdev, u32 *counter)
  54{
  55        struct dm_virtio_ops *ops;
  56
  57        ops = virtio_get_ops(vdev->parent);
  58        if (!ops->generation)
  59                return -ENOSYS;
  60
  61        return ops->generation(vdev->parent, counter);
  62}
  63
  64int virtio_get_status(struct udevice *vdev, u8 *status)
  65{
  66        struct dm_virtio_ops *ops;
  67
  68        ops = virtio_get_ops(vdev->parent);
  69
  70        return ops->get_status(vdev->parent, status);
  71}
  72
  73int virtio_set_status(struct udevice *vdev, u8 status)
  74{
  75        struct dm_virtio_ops *ops;
  76
  77        ops = virtio_get_ops(vdev->parent);
  78
  79        return ops->set_status(vdev->parent, status);
  80}
  81
  82int virtio_reset(struct udevice *vdev)
  83{
  84        struct dm_virtio_ops *ops;
  85
  86        ops = virtio_get_ops(vdev->parent);
  87
  88        return ops->reset(vdev->parent);
  89}
  90
  91int virtio_get_features(struct udevice *vdev, u64 *features)
  92{
  93        struct dm_virtio_ops *ops;
  94
  95        ops = virtio_get_ops(vdev->parent);
  96
  97        return ops->get_features(vdev->parent, features);
  98}
  99
 100int virtio_set_features(struct udevice *vdev)
 101{
 102        struct dm_virtio_ops *ops;
 103
 104        ops = virtio_get_ops(vdev->parent);
 105
 106        return ops->set_features(vdev->parent);
 107}
 108
 109int virtio_find_vqs(struct udevice *vdev, unsigned int nvqs,
 110                    struct virtqueue *vqs[])
 111{
 112        struct dm_virtio_ops *ops;
 113
 114        ops = virtio_get_ops(vdev->parent);
 115
 116        return ops->find_vqs(vdev->parent, nvqs, vqs);
 117}
 118
 119int virtio_del_vqs(struct udevice *vdev)
 120{
 121        struct dm_virtio_ops *ops;
 122
 123        ops = virtio_get_ops(vdev->parent);
 124
 125        return ops->del_vqs(vdev->parent);
 126}
 127
 128int virtio_notify(struct udevice *vdev, struct virtqueue *vq)
 129{
 130        struct dm_virtio_ops *ops;
 131
 132        ops = virtio_get_ops(vdev->parent);
 133
 134        return ops->notify(vdev->parent, vq);
 135}
 136
 137void virtio_add_status(struct udevice *vdev, u8 status)
 138{
 139        u8 old;
 140
 141        if (!virtio_get_status(vdev, &old))
 142                virtio_set_status(vdev, old | status);
 143}
 144
 145int virtio_finalize_features(struct udevice *vdev)
 146{
 147        struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(vdev->parent);
 148        u8 status;
 149        int ret;
 150
 151        ret = virtio_set_features(vdev);
 152        if (ret)
 153                return ret;
 154
 155        if (uc_priv->legacy)
 156                return 0;
 157
 158        virtio_add_status(vdev, VIRTIO_CONFIG_S_FEATURES_OK);
 159        ret = virtio_get_status(vdev, &status);
 160        if (ret)
 161                return ret;
 162        if (!(status & VIRTIO_CONFIG_S_FEATURES_OK)) {
 163                debug("(%s): device refuses features %x\n", vdev->name, status);
 164                return -ENODEV;
 165        }
 166
 167        return 0;
 168}
 169
 170void virtio_driver_features_init(struct virtio_dev_priv *priv,
 171                                 const u32 *feature,
 172                                 u32 feature_size,
 173                                 const u32 *feature_legacy,
 174                                 u32 feature_legacy_size)
 175{
 176        priv->feature_table = feature;
 177        priv->feature_table_size = feature_size;
 178        priv->feature_table_legacy = feature_legacy;
 179        priv->feature_table_size_legacy = feature_legacy_size;
 180}
 181
 182int virtio_init(void)
 183{
 184        struct udevice *bus;
 185        int ret;
 186
 187        /* Enumerate all known virtio devices */
 188        ret = uclass_first_device(UCLASS_VIRTIO, &bus);
 189        if (ret)
 190                return ret;
 191
 192        while (bus) {
 193                ret = uclass_next_device(&bus);
 194                if (ret)
 195                        break;
 196        }
 197
 198        return ret;
 199}
 200
 201static int virtio_uclass_pre_probe(struct udevice *udev)
 202{
 203        struct dm_virtio_ops *ops;
 204
 205        ops = (struct dm_virtio_ops *)(udev->driver->ops);
 206
 207        /*
 208         * Check virtio transport driver ops here so that we don't need
 209         * check these ops each time when the virtio_xxx APIs are called.
 210         *
 211         * Only generation op is optional. All other ops are must-have.
 212         */
 213        if (!ops->get_config || !ops->set_config ||
 214            !ops->get_status || !ops->set_status ||
 215            !ops->get_features || !ops->set_features ||
 216            !ops->find_vqs || !ops->del_vqs ||
 217            !ops->reset || !ops->notify)
 218                return -ENOENT;
 219
 220        return 0;
 221}
 222
 223static int virtio_uclass_post_probe(struct udevice *udev)
 224{
 225        struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
 226        char dev_name[30], *str;
 227        struct udevice *vdev;
 228        int ret;
 229
 230        if (uc_priv->device > VIRTIO_ID_MAX_NUM) {
 231                debug("(%s): virtio device ID %d exceeds maximum num\n",
 232                      udev->name, uc_priv->device);
 233                return 0;
 234        }
 235
 236        if (!virtio_drv_name[uc_priv->device]) {
 237                debug("(%s): underlying virtio device driver unavailable\n",
 238                      udev->name);
 239                return 0;
 240        }
 241
 242        snprintf(dev_name, sizeof(dev_name), "%s#%d",
 243                 virtio_drv_name[uc_priv->device], udev->seq);
 244        str = strdup(dev_name);
 245        if (!str)
 246                return -ENOMEM;
 247
 248        ret = device_bind_driver(udev, virtio_drv_name[uc_priv->device],
 249                                 str, &vdev);
 250        if (ret == -ENOENT) {
 251                debug("(%s): no driver configured\n", udev->name);
 252                return 0;
 253        }
 254        if (ret) {
 255                free(str);
 256                return ret;
 257        }
 258        device_set_name_alloced(vdev);
 259
 260        INIT_LIST_HEAD(&uc_priv->vqs);
 261
 262        return 0;
 263}
 264
 265static int virtio_uclass_child_post_bind(struct udevice *vdev)
 266{
 267        /* Acknowledge that we've seen the device */
 268        virtio_add_status(vdev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
 269
 270        return 0;
 271}
 272
 273static int virtio_uclass_child_pre_probe(struct udevice *vdev)
 274{
 275        struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(vdev->parent);
 276        u64 device_features;
 277        u64 driver_features;
 278        u64 driver_features_legacy;
 279        int i;
 280        int ret;
 281
 282        /*
 283         * Save the real virtio device (eg: virtio-net, virtio-blk) to
 284         * the transport (parent) device's uclass priv for future use.
 285         */
 286        uc_priv->vdev = vdev;
 287
 288        /*
 289         * We always start by resetting the device, in case a previous driver
 290         * messed it up. This also tests that code path a little.
 291         */
 292        ret = virtio_reset(vdev);
 293        if (ret)
 294                goto err;
 295
 296        /* We have a driver! */
 297        virtio_add_status(vdev, VIRTIO_CONFIG_S_DRIVER);
 298
 299        /* Figure out what features the device supports */
 300        virtio_get_features(vdev, &device_features);
 301        debug("(%s) plain device features supported %016llx\n",
 302              vdev->name, device_features);
 303        if (!(device_features & (1ULL << VIRTIO_F_VERSION_1)))
 304                uc_priv->legacy = true;
 305
 306        /* Figure out what features the driver supports */
 307        driver_features = 0;
 308        for (i = 0; i < uc_priv->feature_table_size; i++) {
 309                unsigned int f = uc_priv->feature_table[i];
 310
 311                WARN_ON(f >= 64);
 312                driver_features |= (1ULL << f);
 313        }
 314
 315        /* Some drivers have a separate feature table for virtio v1.0 */
 316        if (uc_priv->feature_table_legacy) {
 317                driver_features_legacy = 0;
 318                for (i = 0; i < uc_priv->feature_table_size_legacy; i++) {
 319                        unsigned int f = uc_priv->feature_table_legacy[i];
 320
 321                        WARN_ON(f >= 64);
 322                        driver_features_legacy |= (1ULL << f);
 323                }
 324        } else {
 325                driver_features_legacy = driver_features;
 326        }
 327
 328        if (uc_priv->legacy) {
 329                debug("(%s): legacy virtio device\n", vdev->name);
 330                uc_priv->features = driver_features_legacy & device_features;
 331        } else {
 332                debug("(%s): v1.0 complaint virtio device\n", vdev->name);
 333                uc_priv->features = driver_features & device_features;
 334        }
 335
 336        /* Transport features always preserved to pass to finalize_features */
 337        for (i = VIRTIO_TRANSPORT_F_START; i < VIRTIO_TRANSPORT_F_END; i++)
 338                if ((device_features & (1ULL << i)) &&
 339                    (i == VIRTIO_F_VERSION_1))
 340                        __virtio_set_bit(vdev->parent, i);
 341
 342        debug("(%s) final negotiated features supported %016llx\n",
 343              vdev->name, uc_priv->features);
 344        ret = virtio_finalize_features(vdev);
 345        if (ret)
 346                goto err;
 347
 348        return 0;
 349
 350err:
 351        virtio_add_status(vdev, VIRTIO_CONFIG_S_FAILED);
 352        return ret;
 353}
 354
 355static int virtio_uclass_child_post_probe(struct udevice *vdev)
 356{
 357        /* Indicates that the driver is set up and ready to drive the device */
 358        virtio_add_status(vdev, VIRTIO_CONFIG_S_DRIVER_OK);
 359
 360        return 0;
 361}
 362
 363UCLASS_DRIVER(virtio) = {
 364        .name   = "virtio",
 365        .id     = UCLASS_VIRTIO,
 366        .flags  = DM_UC_FLAG_SEQ_ALIAS,
 367        .pre_probe = virtio_uclass_pre_probe,
 368        .post_probe = virtio_uclass_post_probe,
 369        .child_post_bind = virtio_uclass_child_post_bind,
 370        .child_pre_probe = virtio_uclass_child_pre_probe,
 371        .child_post_probe = virtio_uclass_child_post_probe,
 372        .per_device_auto_alloc_size = sizeof(struct virtio_dev_priv),
 373};
 374