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 /drivers/lguest/lguest_device.c | |
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 'drivers/lguest/lguest_device.c')
-rw-r--r-- | drivers/lguest/lguest_device.c | 48 |
1 files changed, 28 insertions, 20 deletions
diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c index 2bc9bf7e88e5..7a643a6ee9a1 100644 --- a/drivers/lguest/lguest_device.c +++ b/drivers/lguest/lguest_device.c | |||
@@ -85,27 +85,34 @@ static unsigned desc_size(const struct lguest_device_desc *desc) | |||
85 | + desc->config_len; | 85 | + desc->config_len; |
86 | } | 86 | } |
87 | 87 | ||
88 | /* This tests (and acknowleges) a feature bit. */ | 88 | /* This gets the device's feature bits. */ |
89 | static bool lg_feature(struct virtio_device *vdev, unsigned fbit) | 89 | static u32 lg_get_features(struct virtio_device *vdev) |
90 | { | 90 | { |
91 | unsigned int i; | ||
92 | u32 features = 0; | ||
93 | struct lguest_device_desc *desc = to_lgdev(vdev)->desc; | ||
94 | u8 *in_features = lg_features(desc); | ||
95 | |||
96 | /* We do this the slow but generic way. */ | ||
97 | for (i = 0; i < min(desc->feature_len * 8, 32); i++) | ||
98 | if (in_features[i / 8] & (1 << (i % 8))) | ||
99 | features |= (1 << i); | ||
100 | |||
101 | return features; | ||
102 | } | ||
103 | |||
104 | static void lg_set_features(struct virtio_device *vdev, u32 features) | ||
105 | { | ||
106 | unsigned int i; | ||
91 | struct lguest_device_desc *desc = to_lgdev(vdev)->desc; | 107 | struct lguest_device_desc *desc = to_lgdev(vdev)->desc; |
92 | u8 *features; | 108 | /* Second half of bitmap is features we accept. */ |
93 | 109 | u8 *out_features = lg_features(desc) + desc->feature_len; | |
94 | /* Obviously if they ask for a feature off the end of our feature | 110 | |
95 | * bitmap, it's not set. */ | 111 | memset(out_features, 0, desc->feature_len); |
96 | if (fbit / 8 > desc->feature_len) | 112 | for (i = 0; i < min(desc->feature_len * 8, 32); i++) { |
97 | return false; | 113 | if (features & (1 << i)) |
98 | 114 | out_features[i / 8] |= (1 << (i % 8)); | |
99 | /* The feature bitmap comes after the virtqueues. */ | 115 | } |
100 | features = lg_features(desc); | ||
101 | if (!(features[fbit / 8] & (1 << (fbit % 8)))) | ||
102 | return false; | ||
103 | |||
104 | /* We set the matching bit in the other half of the bitmap to tell the | ||
105 | * Host we want to use this feature. We don't use this yet, but we | ||
106 | * could in future. */ | ||
107 | features[desc->feature_len + fbit / 8] |= (1 << (fbit % 8)); | ||
108 | return true; | ||
109 | } | 116 | } |
110 | 117 | ||
111 | /* Once they've found a field, getting a copy of it is easy. */ | 118 | /* Once they've found a field, getting a copy of it is easy. */ |
@@ -286,7 +293,8 @@ static void lg_del_vq(struct virtqueue *vq) | |||
286 | 293 | ||
287 | /* The ops structure which hooks everything together. */ | 294 | /* The ops structure which hooks everything together. */ |
288 | static struct virtio_config_ops lguest_config_ops = { | 295 | static struct virtio_config_ops lguest_config_ops = { |
289 | .feature = lg_feature, | 296 | .get_features = lg_get_features, |
297 | .set_features = lg_set_features, | ||
290 | .get = lg_get, | 298 | .get = lg_get, |
291 | .set = lg_set, | 299 | .set = lg_set, |
292 | .get_status = lg_get_status, | 300 | .get_status = lg_get_status, |