uboot/include/virtio.h
<<
>>
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 * This file is largely based on Linux kernel virtio_*.h files
  18 */
  19
  20#ifndef __VIRTIO_H__
  21#define __VIRTIO_H__
  22
  23#include <linux/bitops.h>
  24#include <linux/bug.h>
  25#define VIRTIO_ID_NET           1 /* virtio net */
  26#define VIRTIO_ID_BLOCK         2 /* virtio block */
  27#define VIRTIO_ID_RNG           4 /* virtio rng */
  28#define VIRTIO_ID_MAX_NUM       5
  29
  30#define VIRTIO_NET_DRV_NAME     "virtio-net"
  31#define VIRTIO_BLK_DRV_NAME     "virtio-blk"
  32#define VIRTIO_RNG_DRV_NAME     "virtio-rng"
  33
  34/* Status byte for guest to report progress, and synchronize features */
  35
  36/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
  37#define VIRTIO_CONFIG_S_ACKNOWLEDGE     1
  38/* We have found a driver for the device */
  39#define VIRTIO_CONFIG_S_DRIVER          2
  40/* Driver has used its parts of the config, and is happy */
  41#define VIRTIO_CONFIG_S_DRIVER_OK       4
  42/* Driver has finished configuring features */
  43#define VIRTIO_CONFIG_S_FEATURES_OK     8
  44/* Device entered invalid state, driver must reset it */
  45#define VIRTIO_CONFIG_S_NEEDS_RESET     0x40
  46/* We've given up on this device */
  47#define VIRTIO_CONFIG_S_FAILED          0x80
  48
  49/*
  50 * Virtio feature bits VIRTIO_TRANSPORT_F_START through VIRTIO_TRANSPORT_F_END
  51 * are reserved for the transport being used (eg: virtio_ring, virtio_pci etc.),
  52 * the rest are per-device feature bits.
  53 */
  54#define VIRTIO_TRANSPORT_F_START        28
  55#define VIRTIO_TRANSPORT_F_END          38
  56
  57#ifndef VIRTIO_CONFIG_NO_LEGACY
  58/*
  59 * Do we get callbacks when the ring is completely used,
  60 * even if we've suppressed them?
  61 */
  62#define VIRTIO_F_NOTIFY_ON_EMPTY        24
  63
  64/* Can the device handle any descriptor layout? */
  65#define VIRTIO_F_ANY_LAYOUT             27
  66#endif /* VIRTIO_CONFIG_NO_LEGACY */
  67
  68/* v1.0 compliant */
  69#define VIRTIO_F_VERSION_1              32
  70
  71/*
  72 * If clear - device has the IOMMU bypass quirk feature.
  73 * If set - use platform tools to detect the IOMMU.
  74 *
  75 * Note the reverse polarity (compared to most other features),
  76 * this is for compatibility with legacy systems.
  77 */
  78#define VIRTIO_F_IOMMU_PLATFORM         33
  79
  80/* Does the device support Single Root I/O Virtualization? */
  81#define VIRTIO_F_SR_IOV                 37
  82
  83/**
  84 * virtio scatter-gather struct
  85 *
  86 * @addr:               sg buffer address
  87 * @lengh:              sg buffer length
  88 */
  89struct virtio_sg {
  90        void *addr;
  91        size_t length;
  92};
  93
  94struct virtqueue;
  95
  96/* virtio bus operations */
  97struct dm_virtio_ops {
  98        /**
  99         * get_config() - read the value of a configuration field
 100         *
 101         * @vdev:       the real virtio device
 102         * @offset:     the offset of the configuration field
 103         * @buf:        the buffer to write the field value into
 104         * @len:        the length of the buffer
 105         * @return 0 if OK, -ve on error
 106         */
 107        int (*get_config)(struct udevice *vdev, unsigned int offset,
 108                          void *buf, unsigned int len);
 109        /**
 110         * set_config() - write the value of a configuration field
 111         *
 112         * @vdev:       the real virtio device
 113         * @offset:     the offset of the configuration field
 114         * @buf:        the buffer to read the field value from
 115         * @len:        the length of the buffer
 116         * @return 0 if OK, -ve on error
 117         */
 118        int (*set_config)(struct udevice *vdev, unsigned int offset,
 119                          const void *buf, unsigned int len);
 120        /**
 121         * generation() - config generation counter
 122         *
 123         * @vdev:       the real virtio device
 124         * @counter:    the returned config generation counter
 125         * @return 0 if OK, -ve on error
 126         */
 127        int (*generation)(struct udevice *vdev, u32 *counter);
 128        /**
 129         * get_status() - read the status byte
 130         *
 131         * @vdev:       the real virtio device
 132         * @status:     the returned status byte
 133         * @return 0 if OK, -ve on error
 134         */
 135        int (*get_status)(struct udevice *vdev, u8 *status);
 136        /**
 137         * set_status() - write the status byte
 138         *
 139         * @vdev:       the real virtio device
 140         * @status:     the new status byte
 141         * @return 0 if OK, -ve on error
 142         */
 143        int (*set_status)(struct udevice *vdev, u8 status);
 144        /**
 145         * reset() - reset the device
 146         *
 147         * @vdev:       the real virtio device
 148         * @return 0 if OK, -ve on error
 149         */
 150        int (*reset)(struct udevice *vdev);
 151        /**
 152         * get_features() - get the array of feature bits for this device
 153         *
 154         * @vdev:       the real virtio device
 155         * @features:   the first 32 feature bits (all we currently need)
 156         * @return 0 if OK, -ve on error
 157         */
 158        int (*get_features)(struct udevice *vdev, u64 *features);
 159        /**
 160         * set_features() - confirm what device features we'll be using
 161         *
 162         * @vdev:       the real virtio device
 163         * @return 0 if OK, -ve on error
 164         */
 165        int (*set_features)(struct udevice *vdev);
 166        /**
 167         * find_vqs() - find virtqueues and instantiate them
 168         *
 169         * @vdev:       the real virtio device
 170         * @nvqs:       the number of virtqueues to find
 171         * @vqs:        on success, includes new virtqueues
 172         * @return 0 if OK, -ve on error
 173         */
 174        int (*find_vqs)(struct udevice *vdev, unsigned int nvqs,
 175                        struct virtqueue *vqs[]);
 176        /**
 177         * del_vqs() - free virtqueues found by find_vqs()
 178         *
 179         * @vdev:       the real virtio device
 180         * @return 0 if OK, -ve on error
 181         */
 182        int (*del_vqs)(struct udevice *vdev);
 183        /**
 184         * notify() - notify the device to process the queue
 185         *
 186         * @vdev:       the real virtio device
 187         * @vq:         virtqueue to process
 188         * @return 0 if OK, -ve on error
 189         */
 190        int (*notify)(struct udevice *vdev, struct virtqueue *vq);
 191};
 192
 193/* Get access to a virtio bus' operations */
 194#define virtio_get_ops(dev)     ((struct dm_virtio_ops *)(dev)->driver->ops)
 195
 196/**
 197 * virtio uclass per device private data
 198 *
 199 * @vqs:                        virtualqueue for the virtio device
 200 * @vdev:                       the real virtio device underneath
 201 * @legacy:                     is it a legacy device?
 202 * @device:                     virtio device ID
 203 * @vendor:                     virtio vendor ID
 204 * @features:                   negotiated supported features
 205 * @feature_table:              an array of feature supported by the driver
 206 * @feature_table_size:         number of entries in the feature table array
 207 * @feature_table_legacy:       same as feature_table but working in legacy mode
 208 * @feature_table_size_legacy:  number of entries in feature table legacy array
 209 */
 210struct virtio_dev_priv {
 211        struct list_head vqs;
 212        struct udevice *vdev;
 213        bool legacy;
 214        u32 device;
 215        u32 vendor;
 216        u64 features;
 217        const u32 *feature_table;
 218        u32 feature_table_size;
 219        const u32 *feature_table_legacy;
 220        u32 feature_table_size_legacy;
 221};
 222
 223/**
 224 * virtio_get_config() - read the value of a configuration field
 225 *
 226 * @vdev:       the real virtio device
 227 * @offset:     the offset of the configuration field
 228 * @buf:        the buffer to write the field value into
 229 * @len:        the length of the buffer
 230 * @return 0 if OK, -ve on error
 231 */
 232int virtio_get_config(struct udevice *vdev, unsigned int offset,
 233                      void *buf, unsigned int len);
 234
 235/**
 236 * virtio_set_config() - write the value of a configuration field
 237 *
 238 * @vdev:       the real virtio device
 239 * @offset:     the offset of the configuration field
 240 * @buf:        the buffer to read the field value from
 241 * @len:        the length of the buffer
 242 * @return 0 if OK, -ve on error
 243 */
 244int virtio_set_config(struct udevice *vdev, unsigned int offset,
 245                      void *buf, unsigned int len);
 246
 247/**
 248 * virtio_generation() - config generation counter
 249 *
 250 * @vdev:       the real virtio device
 251 * @counter:    the returned config generation counter
 252 * @return 0 if OK, -ve on error
 253 */
 254int virtio_generation(struct udevice *vdev, u32 *counter);
 255
 256/**
 257 * virtio_get_status() - read the status byte
 258 *
 259 * @vdev:       the real virtio device
 260 * @status:     the returned status byte
 261 * @return 0 if OK, -ve on error
 262 */
 263int virtio_get_status(struct udevice *vdev, u8 *status);
 264
 265/**
 266 * virtio_set_status() - write the status byte
 267 *
 268 * @vdev:       the real virtio device
 269 * @status:     the new status byte
 270 * @return 0 if OK, -ve on error
 271 */
 272int virtio_set_status(struct udevice *vdev, u8 status);
 273
 274/**
 275 * virtio_reset() - reset the device
 276 *
 277 * @vdev:       the real virtio device
 278 * @return 0 if OK, -ve on error
 279 */
 280int virtio_reset(struct udevice *vdev);
 281
 282/**
 283 * virtio_get_features() - get the array of feature bits for this device
 284 *
 285 * @vdev:       the real virtio device
 286 * @features:   the first 32 feature bits (all we currently need)
 287 * @return 0 if OK, -ve on error
 288 */
 289int virtio_get_features(struct udevice *vdev, u64 *features);
 290
 291/**
 292 * virtio_set_features() - confirm what device features we'll be using
 293 *
 294 * @vdev:       the real virtio device
 295 * @return 0 if OK, -ve on error
 296 */
 297int virtio_set_features(struct udevice *vdev);
 298
 299/**
 300 * virtio_find_vqs() - find virtqueues and instantiate them
 301 *
 302 * @vdev:       the real virtio device
 303 * @nvqs:       the number of virtqueues to find
 304 * @vqs:        on success, includes new virtqueues
 305 * @return 0 if OK, -ve on error
 306 */
 307int virtio_find_vqs(struct udevice *vdev, unsigned int nvqs,
 308                    struct virtqueue *vqs[]);
 309
 310/**
 311 * virtio_del_vqs() - free virtqueues found by find_vqs()
 312 *
 313 * @vdev:       the real virtio device
 314 * @return 0 if OK, -ve on error
 315 */
 316int virtio_del_vqs(struct udevice *vdev);
 317
 318/**
 319 * virtio_notify() - notify the device to process the queue
 320 *
 321 * @vdev:       the real virtio device
 322 * @vq:         virtqueue to process
 323 * @return 0 if OK, -ve on error
 324 */
 325int virtio_notify(struct udevice *vdev, struct virtqueue *vq);
 326
 327/**
 328 * virtio_add_status() - helper to set a new status code to the device
 329 *
 330 * @vdev:       the real virtio device
 331 * @status:     new status code to be added
 332 */
 333void virtio_add_status(struct udevice *vdev, u8 status);
 334
 335/**
 336 * virtio_finalize_features() - helper to finalize features
 337 *
 338 * @vdev:       the real virtio device
 339 * @return 0 if OK, -ve on error
 340 */
 341int virtio_finalize_features(struct udevice *vdev);
 342
 343/**
 344 * virtio_driver_features_init() - initialize driver supported features
 345 *
 346 * This fills in the virtio device parent per child private data with the given
 347 * information, which contains driver supported features and legacy features.
 348 *
 349 * This API should be called in the virtio device driver's bind method, so that
 350 * later virtio transport uclass driver can utilize the driver supplied features
 351 * to negotiate with the device on the final supported features.
 352 *
 353 * @priv:               virtio uclass per device private data
 354 * @feature:            an array of feature supported by the driver
 355 * @feature_size:       number of entries in the feature table array
 356 * @feature_legacy:     same as feature_table but working in legacy mode
 357 * @feature_legacy_size:number of entries in feature table legacy array
 358 */
 359void virtio_driver_features_init(struct virtio_dev_priv *priv,
 360                                 const u32 *feature,
 361                                 u32 feature_size,
 362                                 const u32 *feature_legacy,
 363                                 u32 feature_legacy_size);
 364
 365/**
 366 * virtio_init() - helper to enumerate all known virtio devices
 367 *
 368 * @return 0 if OK, -ve on error
 369 */
 370int virtio_init(void);
 371
 372static inline u16 __virtio16_to_cpu(bool little_endian, __virtio16 val)
 373{
 374        if (little_endian)
 375                return le16_to_cpu((__force __le16)val);
 376        else
 377                return be16_to_cpu((__force __be16)val);
 378}
 379
 380static inline __virtio16 __cpu_to_virtio16(bool little_endian, u16 val)
 381{
 382        if (little_endian)
 383                return (__force __virtio16)cpu_to_le16(val);
 384        else
 385                return (__force __virtio16)cpu_to_be16(val);
 386}
 387
 388static inline u32 __virtio32_to_cpu(bool little_endian, __virtio32 val)
 389{
 390        if (little_endian)
 391                return le32_to_cpu((__force __le32)val);
 392        else
 393                return be32_to_cpu((__force __be32)val);
 394}
 395
 396static inline __virtio32 __cpu_to_virtio32(bool little_endian, u32 val)
 397{
 398        if (little_endian)
 399                return (__force __virtio32)cpu_to_le32(val);
 400        else
 401                return (__force __virtio32)cpu_to_be32(val);
 402}
 403
 404static inline u64 __virtio64_to_cpu(bool little_endian, __virtio64 val)
 405{
 406        if (little_endian)
 407                return le64_to_cpu((__force __le64)val);
 408        else
 409                return be64_to_cpu((__force __be64)val);
 410}
 411
 412static inline __virtio64 __cpu_to_virtio64(bool little_endian, u64 val)
 413{
 414        if (little_endian)
 415                return (__force __virtio64)cpu_to_le64(val);
 416        else
 417                return (__force __virtio64)cpu_to_be64(val);
 418}
 419
 420/**
 421 * __virtio_test_bit - helper to test feature bits
 422 *
 423 * For use by transports. Devices should normally use virtio_has_feature,
 424 * which includes more checks.
 425 *
 426 * @udev: the transport device
 427 * @fbit: the feature bit
 428 */
 429static inline bool __virtio_test_bit(struct udevice *udev, unsigned int fbit)
 430{
 431        struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
 432
 433        /* Did you forget to fix assumptions on max features? */
 434        if (__builtin_constant_p(fbit))
 435                BUILD_BUG_ON(fbit >= 64);
 436        else
 437                WARN_ON(fbit >= 64);
 438
 439        return uc_priv->features & BIT_ULL(fbit);
 440}
 441
 442/**
 443 * __virtio_set_bit - helper to set feature bits
 444 *
 445 * For use by transports.
 446 *
 447 * @udev: the transport device
 448 * @fbit: the feature bit
 449 */
 450static inline void __virtio_set_bit(struct udevice *udev, unsigned int fbit)
 451{
 452        struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
 453
 454        /* Did you forget to fix assumptions on max features? */
 455        if (__builtin_constant_p(fbit))
 456                BUILD_BUG_ON(fbit >= 64);
 457        else
 458                WARN_ON(fbit >= 64);
 459
 460        uc_priv->features |= BIT_ULL(fbit);
 461}
 462
 463/**
 464 * __virtio_clear_bit - helper to clear feature bits
 465 *
 466 * For use by transports.
 467 *
 468 * @vdev: the transport device
 469 * @fbit: the feature bit
 470 */
 471static inline void __virtio_clear_bit(struct udevice *udev, unsigned int fbit)
 472{
 473        struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
 474
 475        /* Did you forget to fix assumptions on max features? */
 476        if (__builtin_constant_p(fbit))
 477                BUILD_BUG_ON(fbit >= 64);
 478        else
 479                WARN_ON(fbit >= 64);
 480
 481        uc_priv->features &= ~BIT_ULL(fbit);
 482}
 483
 484/**
 485 * virtio_has_feature - helper to determine if this device has this feature
 486 *
 487 * Note this API is only usable after the virtio device driver's bind phase,
 488 * as the feature has been negotiated between the device and the driver.
 489 *
 490 * @vdev: the virtio device
 491 * @fbit: the feature bit
 492 */
 493static inline bool virtio_has_feature(struct udevice *vdev, unsigned int fbit)
 494{
 495        if (!(dev_get_flags(vdev) & DM_FLAG_BOUND))
 496                WARN_ON(true);
 497
 498        return __virtio_test_bit(vdev->parent, fbit);
 499}
 500
 501static inline bool virtio_legacy_is_little_endian(void)
 502{
 503#ifdef __LITTLE_ENDIAN
 504        return true;
 505#else
 506        return false;
 507#endif
 508}
 509
 510static inline bool virtio_is_little_endian(struct udevice *vdev)
 511{
 512        struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(vdev->parent);
 513
 514        return !uc_priv->legacy || virtio_legacy_is_little_endian();
 515}
 516
 517/* Memory accessors */
 518static inline u16 virtio16_to_cpu(struct udevice *vdev, __virtio16 val)
 519{
 520        return __virtio16_to_cpu(virtio_is_little_endian(vdev), val);
 521}
 522
 523static inline __virtio16 cpu_to_virtio16(struct udevice *vdev, u16 val)
 524{
 525        return __cpu_to_virtio16(virtio_is_little_endian(vdev), val);
 526}
 527
 528static inline u32 virtio32_to_cpu(struct udevice *vdev, __virtio32 val)
 529{
 530        return __virtio32_to_cpu(virtio_is_little_endian(vdev), val);
 531}
 532
 533static inline __virtio32 cpu_to_virtio32(struct udevice *vdev, u32 val)
 534{
 535        return __cpu_to_virtio32(virtio_is_little_endian(vdev), val);
 536}
 537
 538static inline u64 virtio64_to_cpu(struct udevice *vdev, __virtio64 val)
 539{
 540        return __virtio64_to_cpu(virtio_is_little_endian(vdev), val);
 541}
 542
 543static inline __virtio64 cpu_to_virtio64(struct udevice *vdev, u64 val)
 544{
 545        return __cpu_to_virtio64(virtio_is_little_endian(vdev), val);
 546}
 547
 548/* Read @count fields, @bytes each */
 549static inline void __virtio_cread_many(struct udevice *vdev,
 550                                       unsigned int offset,
 551                                       void *buf, size_t count, size_t bytes)
 552{
 553        u32 old, gen;
 554        int i;
 555
 556        /* no need to check return value as generation can be optional */
 557        virtio_generation(vdev, &gen);
 558        do {
 559                old = gen;
 560
 561                for (i = 0; i < count; i++)
 562                        virtio_get_config(vdev, offset + bytes * i,
 563                                          buf + i * bytes, bytes);
 564
 565                virtio_generation(vdev, &gen);
 566        } while (gen != old);
 567}
 568
 569static inline void virtio_cread_bytes(struct udevice *vdev,
 570                                      unsigned int offset,
 571                                      void *buf, size_t len)
 572{
 573        __virtio_cread_many(vdev, offset, buf, len, 1);
 574}
 575
 576static inline u8 virtio_cread8(struct udevice *vdev, unsigned int offset)
 577{
 578        u8 ret;
 579
 580        virtio_get_config(vdev, offset, &ret, sizeof(ret));
 581        return ret;
 582}
 583
 584static inline void virtio_cwrite8(struct udevice *vdev,
 585                                  unsigned int offset, u8 val)
 586{
 587        virtio_set_config(vdev, offset, &val, sizeof(val));
 588}
 589
 590static inline u16 virtio_cread16(struct udevice *vdev,
 591                                 unsigned int offset)
 592{
 593        u16 ret;
 594
 595        virtio_get_config(vdev, offset, &ret, sizeof(ret));
 596        return virtio16_to_cpu(vdev, (__force __virtio16)ret);
 597}
 598
 599static inline void virtio_cwrite16(struct udevice *vdev,
 600                                   unsigned int offset, u16 val)
 601{
 602        val = (__force u16)cpu_to_virtio16(vdev, val);
 603        virtio_set_config(vdev, offset, &val, sizeof(val));
 604}
 605
 606static inline u32 virtio_cread32(struct udevice *vdev,
 607                                 unsigned int offset)
 608{
 609        u32 ret;
 610
 611        virtio_get_config(vdev, offset, &ret, sizeof(ret));
 612        return virtio32_to_cpu(vdev, (__force __virtio32)ret);
 613}
 614
 615static inline void virtio_cwrite32(struct udevice *vdev,
 616                                   unsigned int offset, u32 val)
 617{
 618        val = (__force u32)cpu_to_virtio32(vdev, val);
 619        virtio_set_config(vdev, offset, &val, sizeof(val));
 620}
 621
 622static inline u64 virtio_cread64(struct udevice *vdev,
 623                                 unsigned int offset)
 624{
 625        u64 ret;
 626
 627        __virtio_cread_many(vdev, offset, &ret, 1, sizeof(ret));
 628        return virtio64_to_cpu(vdev, (__force __virtio64)ret);
 629}
 630
 631static inline void virtio_cwrite64(struct udevice *vdev,
 632                                   unsigned int offset, u64 val)
 633{
 634        val = (__force u64)cpu_to_virtio64(vdev, val);
 635        virtio_set_config(vdev, offset, &val, sizeof(val));
 636}
 637
 638/* Config space read accessor */
 639#define virtio_cread(vdev, structname, member, ptr)                     \
 640        do {                                                            \
 641                /* Must match the member's type, and be integer */      \
 642                if (!typecheck(typeof((((structname *)0)->member)), *(ptr))) \
 643                        (*ptr) = 1;                                     \
 644                                                                        \
 645                switch (sizeof(*ptr)) {                                 \
 646                case 1:                                                 \
 647                        *(ptr) = virtio_cread8(vdev,                    \
 648                                               offsetof(structname, member)); \
 649                        break;                                          \
 650                case 2:                                                 \
 651                        *(ptr) = virtio_cread16(vdev,                   \
 652                                                offsetof(structname, member)); \
 653                        break;                                          \
 654                case 4:                                                 \
 655                        *(ptr) = virtio_cread32(vdev,                   \
 656                                                offsetof(structname, member)); \
 657                        break;                                          \
 658                case 8:                                                 \
 659                        *(ptr) = virtio_cread64(vdev,                   \
 660                                                offsetof(structname, member)); \
 661                        break;                                          \
 662                default:                                                \
 663                        WARN_ON(true);                                  \
 664                }                                                       \
 665        } while (0)
 666
 667/* Config space write accessor */
 668#define virtio_cwrite(vdev, structname, member, ptr)                    \
 669        do {                                                            \
 670                /* Must match the member's type, and be integer */      \
 671                if (!typecheck(typeof((((structname *)0)->member)), *(ptr))) \
 672                        WARN_ON((*ptr) == 1);                           \
 673                                                                        \
 674                switch (sizeof(*ptr)) {                                 \
 675                case 1:                                                 \
 676                        virtio_cwrite8(vdev,                            \
 677                                       offsetof(structname, member),    \
 678                                       *(ptr));                         \
 679                        break;                                          \
 680                case 2:                                                 \
 681                        virtio_cwrite16(vdev,                           \
 682                                        offsetof(structname, member),   \
 683                                        *(ptr));                        \
 684                        break;                                          \
 685                case 4:                                                 \
 686                        virtio_cwrite32(vdev,                           \
 687                                        offsetof(structname, member),   \
 688                                        *(ptr));                        \
 689                        break;                                          \
 690                case 8:                                                 \
 691                        virtio_cwrite64(vdev,                           \
 692                                        offsetof(structname, member),   \
 693                                        *(ptr));                        \
 694                        break;                                          \
 695                default:                                                \
 696                        WARN_ON(true);                                  \
 697                }                                                       \
 698        } while (0)
 699
 700/* Conditional config space accessors */
 701#define virtio_cread_feature(vdev, fbit, structname, member, ptr)       \
 702        ({                                                              \
 703                int _r = 0;                                             \
 704                if (!virtio_has_feature(vdev, fbit))                    \
 705                        _r = -ENOENT;                                   \
 706                else                                                    \
 707                        virtio_cread(vdev, structname, member, ptr);    \
 708                _r;                                                     \
 709        })
 710
 711#endif /* __VIRTIO_H__ */
 712