diff options
| author | Rusty Russell <rusty@rustcorp.com.au> | 2008-05-02 22:50:50 -0400 |
|---|---|---|
| committer | Rusty Russell <rusty@rustcorp.com.au> | 2008-05-02 07:50:50 -0400 |
| commit | c45a6816c19dee67b8f725e6646d428901a6dc24 (patch) | |
| tree | 096e3263fd14e140685bcc3082394ff15f5aeddb /include/linux | |
| parent | 72e61eb40b55dd57031ec5971e810649f82b0259 (diff) | |
virtio: explicit advertisement of driver features
A recent proposed feature addition to the virtio block driver revealed
some flaws in the API: in particular, we assume that feature
negotiation is complete once a driver's probe function returns.
There is nothing in the API to require this, however, and even I
didn't notice when it was violated.
So instead, we require the driver to specify what features it supports
in a table, we can then move the feature negotiation into the virtio
core. The intersection of device and driver features are presented in
a new 'features' bitmap in the struct virtio_device.
Note that this highlights the difference between Linux unsigned-long
bitmaps where each unsigned long is in native endian, and a
straight-forward little-endian array of bytes.
Drivers can still remove feature bits in their probe routine if they
really have to.
API changes:
- dev->config->feature() no longer gets and acks a feature.
- drivers should advertise their features in the 'feature_table' field
- use virtio_has_feature() for extra sanity when checking feature bits
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/virtio.h | 7 | ||||
| -rw-r--r-- | include/linux/virtio_config.h | 36 |
2 files changed, 36 insertions, 7 deletions
diff --git a/include/linux/virtio.h b/include/linux/virtio.h index e7d10845b3c1..06005fa9e982 100644 --- a/include/linux/virtio.h +++ b/include/linux/virtio.h | |||
| @@ -76,6 +76,7 @@ struct virtqueue_ops { | |||
| 76 | * @dev: underlying device. | 76 | * @dev: underlying device. |
| 77 | * @id: the device type identification (used to match it with a driver). | 77 | * @id: the device type identification (used to match it with a driver). |
| 78 | * @config: the configuration ops for this device. | 78 | * @config: the configuration ops for this device. |
| 79 | * @features: the features supported by both driver and device. | ||
| 79 | * @priv: private pointer for the driver's use. | 80 | * @priv: private pointer for the driver's use. |
| 80 | */ | 81 | */ |
| 81 | struct virtio_device | 82 | struct virtio_device |
| @@ -84,6 +85,8 @@ struct virtio_device | |||
| 84 | struct device dev; | 85 | struct device dev; |
| 85 | struct virtio_device_id id; | 86 | struct virtio_device_id id; |
| 86 | struct virtio_config_ops *config; | 87 | struct virtio_config_ops *config; |
| 88 | /* Note that this is a Linux set_bit-style bitmap. */ | ||
| 89 | unsigned long features[1]; | ||
| 87 | void *priv; | 90 | void *priv; |
| 88 | }; | 91 | }; |
| 89 | 92 | ||
| @@ -94,6 +97,8 @@ void unregister_virtio_device(struct virtio_device *dev); | |||
| 94 | * virtio_driver - operations for a virtio I/O driver | 97 | * virtio_driver - operations for a virtio I/O driver |
| 95 | * @driver: underlying device driver (populate name and owner). | 98 | * @driver: underlying device driver (populate name and owner). |
| 96 | * @id_table: the ids serviced by this driver. | 99 | * @id_table: the ids serviced by this driver. |
| 100 | * @feature_table: an array of feature numbers supported by this device. | ||
| 101 | * @feature_table_size: number of entries in the feature table array. | ||
| 97 | * @probe: the function to call when a device is found. Returns a token for | 102 | * @probe: the function to call when a device is found. Returns a token for |
| 98 | * remove, or PTR_ERR(). | 103 | * remove, or PTR_ERR(). |
| 99 | * @remove: the function when a device is removed. | 104 | * @remove: the function when a device is removed. |
| @@ -103,6 +108,8 @@ void unregister_virtio_device(struct virtio_device *dev); | |||
| 103 | struct virtio_driver { | 108 | struct virtio_driver { |
| 104 | struct device_driver driver; | 109 | struct device_driver driver; |
| 105 | const struct virtio_device_id *id_table; | 110 | const struct virtio_device_id *id_table; |
| 111 | const unsigned int *feature_table; | ||
| 112 | unsigned int feature_table_size; | ||
| 106 | int (*probe)(struct virtio_device *dev); | 113 | int (*probe)(struct virtio_device *dev); |
| 107 | void (*remove)(struct virtio_device *dev); | 114 | void (*remove)(struct virtio_device *dev); |
| 108 | void (*config_changed)(struct virtio_device *dev); | 115 | void (*config_changed)(struct virtio_device *dev); |
diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index 475572e976fe..50db245c81ad 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h | |||
| @@ -20,11 +20,6 @@ | |||
| 20 | 20 | ||
| 21 | /** | 21 | /** |
| 22 | * virtio_config_ops - operations for configuring a virtio device | 22 | * virtio_config_ops - operations for configuring a virtio device |
| 23 | * @feature: search for a feature in this config | ||
| 24 | * vdev: the virtio_device | ||
| 25 | * bit: the feature bit | ||
| 26 | * Returns true if the feature is supported. Acknowledges the feature | ||
| 27 | * so the host can see it. | ||
| 28 | * @get: read the value of a configuration field | 23 | * @get: read the value of a configuration field |
| 29 | * vdev: the virtio_device | 24 | * vdev: the virtio_device |
| 30 | * offset: the offset of the configuration field | 25 | * offset: the offset of the configuration field |
| @@ -50,10 +45,15 @@ | |||
| 50 | * callback: the virqtueue callback | 45 | * callback: the virqtueue callback |
| 51 | * Returns the new virtqueue or ERR_PTR() (eg. -ENOENT). | 46 | * Returns the new virtqueue or ERR_PTR() (eg. -ENOENT). |
| 52 | * @del_vq: free a virtqueue found by find_vq(). | 47 | * @del_vq: free a virtqueue found by find_vq(). |
| 48 | * @get_features: get the array of feature bits for this device. | ||
| 49 | * vdev: the virtio_device | ||
| 50 | * Returns the first 32 feature bits (all we currently need). | ||
| 51 | * @set_features: confirm what device features we'll be using. | ||
| 52 | * vdev: the virtio_device | ||
| 53 | * feature: the first 32 feature bits | ||
| 53 | */ | 54 | */ |
| 54 | struct virtio_config_ops | 55 | struct virtio_config_ops |
| 55 | { | 56 | { |
| 56 | bool (*feature)(struct virtio_device *vdev, unsigned bit); | ||
| 57 | void (*get)(struct virtio_device *vdev, unsigned offset, | 57 | void (*get)(struct virtio_device *vdev, unsigned offset, |
| 58 | void *buf, unsigned len); | 58 | void *buf, unsigned len); |
| 59 | void (*set)(struct virtio_device *vdev, unsigned offset, | 59 | void (*set)(struct virtio_device *vdev, unsigned offset, |
| @@ -65,8 +65,30 @@ struct virtio_config_ops | |||
| 65 | unsigned index, | 65 | unsigned index, |
| 66 | void (*callback)(struct virtqueue *)); | 66 | void (*callback)(struct virtqueue *)); |
| 67 | void (*del_vq)(struct virtqueue *vq); | 67 | void (*del_vq)(struct virtqueue *vq); |
| 68 | u32 (*get_features)(struct virtio_device *vdev); | ||
| 69 | void (*set_features)(struct virtio_device *vdev, u32 features); | ||
| 68 | }; | 70 | }; |
| 69 | 71 | ||
| 72 | /* If driver didn't advertise the feature, it will never appear. */ | ||
| 73 | void virtio_check_driver_offered_feature(const struct virtio_device *vdev, | ||
| 74 | unsigned int fbit); | ||
| 75 | |||
| 76 | /** | ||
| 77 | * virtio_has_feature - helper to determine if this device has this feature. | ||
| 78 | * @vdev: the device | ||
| 79 | * @fbit: the feature bit | ||
| 80 | */ | ||
| 81 | static inline bool virtio_has_feature(const struct virtio_device *vdev, | ||
| 82 | unsigned int fbit) | ||
| 83 | { | ||
| 84 | /* Did you forget to fix assumptions on max features? */ | ||
| 85 | if (__builtin_constant_p(fbit)) | ||
| 86 | BUILD_BUG_ON(fbit >= 32); | ||
| 87 | |||
| 88 | virtio_check_driver_offered_feature(vdev, fbit); | ||
| 89 | return test_bit(fbit, vdev->features); | ||
| 90 | } | ||
| 91 | |||
| 70 | /** | 92 | /** |
| 71 | * virtio_config_val - look for a feature and get a virtio config entry. | 93 | * virtio_config_val - look for a feature and get a virtio config entry. |
| 72 | * @vdev: the virtio device | 94 | * @vdev: the virtio device |
| @@ -84,7 +106,7 @@ static inline int virtio_config_buf(struct virtio_device *vdev, | |||
| 84 | unsigned int offset, | 106 | unsigned int offset, |
| 85 | void *buf, unsigned len) | 107 | void *buf, unsigned len) |
| 86 | { | 108 | { |
| 87 | if (!vdev->config->feature(vdev, fbit)) | 109 | if (!virtio_has_feature(vdev, fbit)) |
| 88 | return -ENOENT; | 110 | return -ENOENT; |
| 89 | 111 | ||
| 90 | vdev->config->get(vdev, offset, buf, len); | 112 | vdev->config->get(vdev, offset, buf, len); |
