aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/lguest
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2008-05-02 22:50:50 -0400
committerRusty Russell <rusty@rustcorp.com.au>2008-05-02 07:50:50 -0400
commitc45a6816c19dee67b8f725e6646d428901a6dc24 (patch)
tree096e3263fd14e140685bcc3082394ff15f5aeddb /drivers/lguest
parent72e61eb40b55dd57031ec5971e810649f82b0259 (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')
-rw-r--r--drivers/lguest/lguest_device.c48
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. */
89static bool lg_feature(struct virtio_device *vdev, unsigned fbit) 89static 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
104static 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. */
288static struct virtio_config_ops lguest_config_ops = { 295static 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,