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