From a586d4f6016f7139d8c26df0e6927131168d3b5b Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 4 Feb 2008 23:49:56 -0500 Subject: virtio: simplify config mechanism. Previously we used a type/len pair within the config space, but this seems overkill. We now simply define a structure which represents the layout in the config space: the config space can now only be extended at the end. The main driver-visible changes: 1) We indicate what fields are present with an explicit feature bit. 2) Virtqueues are explicitly numbered, and not in the config space. Signed-off-by: Rusty Russell --- include/linux/lguest_launcher.h | 9 +++- include/linux/virtio_blk.h | 22 +++++---- include/linux/virtio_config.h | 98 +++++++++++++++++++---------------------- include/linux/virtio_net.h | 11 +++-- 4 files changed, 73 insertions(+), 67 deletions(-) (limited to 'include/linux') diff --git a/include/linux/lguest_launcher.h b/include/linux/lguest_launcher.h index 697104da91f..589be3e1f3a 100644 --- a/include/linux/lguest_launcher.h +++ b/include/linux/lguest_launcher.h @@ -23,7 +23,12 @@ struct lguest_device_desc { /* The device type: console, network, disk etc. Type 0 terminates. */ __u8 type; - /* The number of bytes of the config array. */ + /* The number of virtqueues (first in config array) */ + __u8 num_vq; + /* The number of bytes of feature bits. Multiply by 2: one for host + * features and one for guest acknowledgements. */ + __u8 feature_len; + /* The number of bytes of the config array after virtqueues. */ __u8 config_len; /* A status byte, written by the Guest. */ __u8 status; @@ -31,7 +36,7 @@ struct lguest_device_desc { }; /*D:135 This is how we expect the device configuration field for a virtqueue - * (type VIRTIO_CONFIG_F_VIRTQUEUE) to be laid out: */ + * to be laid out in config space. */ struct lguest_vqconfig { /* The number of entries in the virtio_ring */ __u16 num; diff --git a/include/linux/virtio_blk.h b/include/linux/virtio_blk.h index 7bd2bce0cfd..e54635666f2 100644 --- a/include/linux/virtio_blk.h +++ b/include/linux/virtio_blk.h @@ -6,15 +6,19 @@ #define VIRTIO_ID_BLOCK 2 /* Feature bits */ -#define VIRTIO_CONFIG_BLK_F 0x40 -#define VIRTIO_BLK_F_BARRIER 1 /* Does host support barriers? */ - -/* The capacity (in 512-byte sectors). */ -#define VIRTIO_CONFIG_BLK_F_CAPACITY 0x41 -/* The maximum segment size. */ -#define VIRTIO_CONFIG_BLK_F_SIZE_MAX 0x42 -/* The maximum number of segments. */ -#define VIRTIO_CONFIG_BLK_F_SEG_MAX 0x43 +#define VIRTIO_BLK_F_BARRIER 0 /* Does host support barriers? */ +#define VIRTIO_BLK_F_SIZE_MAX 1 /* Indicates maximum segment size */ +#define VIRTIO_BLK_F_SEG_MAX 2 /* Indicates maximum # of segments */ + +struct virtio_blk_config +{ + /* The capacity (in 512-byte sectors). */ + __le64 capacity; + /* The maximum segment size (if VIRTIO_BLK_F_SIZE_MAX) */ + __le32 size_max; + /* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */ + __le32 seg_max; +} __attribute__((packed)); /* These two define direction. */ #define VIRTIO_BLK_T_IN 0 diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index bcc01888df7..70bb26062d7 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -5,7 +5,7 @@ * store and access that space differently. */ #include -/* Status byte for guest to report progress, and synchronize config. */ +/* Status byte for guest to report progress, and synchronize features. */ /* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */ #define VIRTIO_CONFIG_S_ACKNOWLEDGE 1 /* We have found a driver for the device. */ @@ -15,34 +15,27 @@ /* We've given up on this device. */ #define VIRTIO_CONFIG_S_FAILED 0x80 -/* Feature byte (actually 7 bits availabe): */ -/* Requirements/features of the virtio implementation. */ -#define VIRTIO_CONFIG_F_VIRTIO 1 -/* Requirements/features of the virtqueue (may have more than one). */ -#define VIRTIO_CONFIG_F_VIRTQUEUE 2 - #ifdef __KERNEL__ struct virtio_device; /** * virtio_config_ops - operations for configuring a virtio device - * @find: search for the next configuration field of the given type. + * @feature: search for a feature in this config * vdev: the virtio_device - * type: the feature type - * len: the (returned) length of the field if found. - * Returns a token if found, or NULL. Never returnes the same field twice - * (ie. it's used up). - * @get: read the value of a configuration field after find(). + * bit: the feature bit + * Returns true if the feature is supported. Acknowledges the feature + * so the host can see it. + * @get: read the value of a configuration field * vdev: the virtio_device - * token: the token returned from find(). + * offset: the offset of the configuration field * buf: the buffer to write the field value into. - * len: the length of the buffer (given by find()). + * len: the length of the buffer * Note that contents are conventionally little-endian. - * @set: write the value of a configuration field after find(). + * @set: write the value of a configuration field * vdev: the virtio_device - * token: the token returned from find(). + * offset: the offset of the configuration field * buf: the buffer to read the field value from. - * len: the length of the buffer (given by find()). + * len: the length of the buffer * Note that contents are conventionally little-endian. * @get_status: read the status byte * vdev: the virtio_device @@ -50,62 +43,63 @@ struct virtio_device; * @set_status: write the status byte * vdev: the virtio_device * status: the new status byte - * @find_vq: find the first VIRTIO_CONFIG_F_VIRTQUEUE and create a virtqueue. + * @find_vq: find a virtqueue and instantiate it. * vdev: the virtio_device + * index: the 0-based virtqueue number in case there's more than one. * callback: the virqtueue callback - * Returns the new virtqueue or ERR_PTR(). + * Returns the new virtqueue or ERR_PTR() (eg. -ENOENT). * @del_vq: free a virtqueue found by find_vq(). */ struct virtio_config_ops { - void *(*find)(struct virtio_device *vdev, u8 type, unsigned *len); - void (*get)(struct virtio_device *vdev, void *token, + bool (*feature)(struct virtio_device *vdev, unsigned bit); + void (*get)(struct virtio_device *vdev, unsigned offset, void *buf, unsigned len); - void (*set)(struct virtio_device *vdev, void *token, + void (*set)(struct virtio_device *vdev, unsigned offset, const void *buf, unsigned len); u8 (*get_status)(struct virtio_device *vdev); void (*set_status)(struct virtio_device *vdev, u8 status); struct virtqueue *(*find_vq)(struct virtio_device *vdev, + unsigned index, bool (*callback)(struct virtqueue *)); void (*del_vq)(struct virtqueue *vq); }; /** - * virtio_config_val - get a single virtio config and mark it used. - * @config: the virtio config space - * @type: the type to search for. + * virtio_config_val - look for a feature and get a single virtio config. + * @vdev: the virtio device + * @fbit: the feature bit + * @offset: the type to search for. * @val: a pointer to the value to fill in. * - * Once used, the config type is marked with VIRTIO_CONFIG_F_USED so it can't - * be found again. This version does endian conversion. */ -#define virtio_config_val(vdev, type, v) ({ \ - int _err = __virtio_config_val((vdev),(type),(v),sizeof(*(v))); \ - \ - BUILD_BUG_ON(sizeof(*(v)) != 1 && sizeof(*(v)) != 2 \ - && sizeof(*(v)) != 4 && sizeof(*(v)) != 8); \ - if (!_err) { \ - switch (sizeof(*(v))) { \ - case 2: le16_to_cpus((__u16 *) v); break; \ - case 4: le32_to_cpus((__u32 *) v); break; \ - case 8: le64_to_cpus((__u64 *) v); break; \ - } \ - } \ + * The return value is -ENOENT if the feature doesn't exist. Otherwise + * the value is endian-corrected and returned in v. */ +#define virtio_config_val(vdev, fbit, offset, v) ({ \ + int _err; \ + if ((vdev)->config->feature((vdev), (fbit))) { \ + __virtio_config_val((vdev), (offset), (v)); \ + _err = 0; \ + } else \ + _err = -ENOENT; \ _err; \ }) -int __virtio_config_val(struct virtio_device *dev, - u8 type, void *val, size_t size); - /** - * virtio_use_bit - helper to use a feature bit in a bitfield value. - * @dev: the virtio device - * @token: the token as returned from vdev->config->find(). - * @len: the length of the field. - * @bitnum: the bit to test. + * __virtio_config_val - get a single virtio config without feature check. + * @vdev: the virtio device + * @offset: the type to search for. + * @val: a pointer to the value to fill in. * - * If handed a NULL token, it returns false, otherwise returns bit status. - * If it's one, it sets the mirroring acknowledgement bit. */ -int virtio_use_bit(struct virtio_device *vdev, - void *token, unsigned int len, unsigned int bitnum); + * The value is endian-corrected and returned in v. */ +#define __virtio_config_val(vdev, offset, v) do { \ + BUILD_BUG_ON(sizeof(*(v)) != 1 && sizeof(*(v)) != 2 \ + && sizeof(*(v)) != 4 && sizeof(*(v)) != 8); \ + (vdev)->config->get((vdev), (offset), (v), sizeof(*(v))); \ + switch (sizeof(*(v))) { \ + case 2: le16_to_cpus((__u16 *) v); break; \ + case 4: le32_to_cpus((__u32 *) v); break; \ + case 8: le64_to_cpus((__u64 *) v); break; \ + } \ +} while(0) #endif /* __KERNEL__ */ #endif /* _LINUX_VIRTIO_CONFIG_H */ diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h index ae469ae55d3..6e8fdfea8cd 100644 --- a/include/linux/virtio_net.h +++ b/include/linux/virtio_net.h @@ -5,16 +5,19 @@ /* The ID for virtio_net */ #define VIRTIO_ID_NET 1 -/* The bitmap of config for virtio net */ -#define VIRTIO_CONFIG_NET_F 0x40 +/* The feature bitmap for virtio net */ #define VIRTIO_NET_F_NO_CSUM 0 #define VIRTIO_NET_F_TSO4 1 #define VIRTIO_NET_F_UFO 2 #define VIRTIO_NET_F_TSO4_ECN 3 #define VIRTIO_NET_F_TSO6 4 +#define VIRTIO_NET_F_MAC 5 -/* The config defining mac address. */ -#define VIRTIO_CONFIG_NET_MAC_F 0x41 +struct virtio_net_config +{ + /* The config defining mac address (if VIRTIO_NET_F_MAC) */ + __u8 mac[6]; +} __attribute__((packed)); /* This is the first element of the scatter-gather list. If you don't * specify GSO or CSUM features, you can simply ignore the header. */ -- cgit v1.2.3