aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
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
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')
-rw-r--r--drivers/block/virtio_blk.c8
-rw-r--r--drivers/lguest/lguest_device.c48
-rw-r--r--drivers/net/virtio_net.c22
-rw-r--r--drivers/virtio/virtio.c38
-rw-r--r--drivers/virtio/virtio_balloon.c6
-rw-r--r--drivers/virtio/virtio_pci.c30
6 files changed, 106 insertions, 46 deletions
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index cc6d39383a3f..78be6b8c89e0 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -242,7 +242,7 @@ static int virtblk_probe(struct virtio_device *vdev)
242 index++; 242 index++;
243 243
244 /* If barriers are supported, tell block layer that queue is ordered */ 244 /* If barriers are supported, tell block layer that queue is ordered */
245 if (vdev->config->feature(vdev, VIRTIO_BLK_F_BARRIER)) 245 if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER))
246 blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL); 246 blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL);
247 247
248 /* Host must always specify the capacity. */ 248 /* Host must always specify the capacity. */
@@ -308,7 +308,13 @@ static struct virtio_device_id id_table[] = {
308 { 0 }, 308 { 0 },
309}; 309};
310 310
311static unsigned int features[] = {
312 VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX,
313};
314
311static struct virtio_driver virtio_blk = { 315static struct virtio_driver virtio_blk = {
316 .feature_table = features,
317 .feature_table_size = ARRAY_SIZE(features),
312 .driver.name = KBUILD_MODNAME, 318 .driver.name = KBUILD_MODNAME,
313 .driver.owner = THIS_MODULE, 319 .driver.owner = THIS_MODULE,
314 .id_table = id_table, 320 .id_table = id_table,
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,
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index ad43421ab6f1..f926b5ab3d09 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -378,26 +378,26 @@ static int virtnet_probe(struct virtio_device *vdev)
378 SET_NETDEV_DEV(dev, &vdev->dev); 378 SET_NETDEV_DEV(dev, &vdev->dev);
379 379
380 /* Do we support "hardware" checksums? */ 380 /* Do we support "hardware" checksums? */
381 if (csum && vdev->config->feature(vdev, VIRTIO_NET_F_CSUM)) { 381 if (csum && virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) {
382 /* This opens up the world of extra features. */ 382 /* This opens up the world of extra features. */
383 dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; 383 dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
384 if (gso && vdev->config->feature(vdev, VIRTIO_NET_F_GSO)) { 384 if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
385 dev->features |= NETIF_F_TSO | NETIF_F_UFO 385 dev->features |= NETIF_F_TSO | NETIF_F_UFO
386 | NETIF_F_TSO_ECN | NETIF_F_TSO6; 386 | NETIF_F_TSO_ECN | NETIF_F_TSO6;
387 } 387 }
388 /* Individual feature bits: what can host handle? */ 388 /* Individual feature bits: what can host handle? */
389 if (gso && vdev->config->feature(vdev, VIRTIO_NET_F_HOST_TSO4)) 389 if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO4))
390 dev->features |= NETIF_F_TSO; 390 dev->features |= NETIF_F_TSO;
391 if (gso && vdev->config->feature(vdev, VIRTIO_NET_F_HOST_TSO6)) 391 if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO6))
392 dev->features |= NETIF_F_TSO6; 392 dev->features |= NETIF_F_TSO6;
393 if (gso && vdev->config->feature(vdev, VIRTIO_NET_F_HOST_ECN)) 393 if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
394 dev->features |= NETIF_F_TSO_ECN; 394 dev->features |= NETIF_F_TSO_ECN;
395 if (gso && vdev->config->feature(vdev, VIRTIO_NET_F_HOST_UFO)) 395 if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UFO))
396 dev->features |= NETIF_F_UFO; 396 dev->features |= NETIF_F_UFO;
397 } 397 }
398 398
399 /* Configuration may specify what MAC to use. Otherwise random. */ 399 /* Configuration may specify what MAC to use. Otherwise random. */
400 if (vdev->config->feature(vdev, VIRTIO_NET_F_MAC)) { 400 if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC)) {
401 vdev->config->get(vdev, 401 vdev->config->get(vdev,
402 offsetof(struct virtio_net_config, mac), 402 offsetof(struct virtio_net_config, mac),
403 dev->dev_addr, dev->addr_len); 403 dev->dev_addr, dev->addr_len);
@@ -486,7 +486,15 @@ static struct virtio_device_id id_table[] = {
486 { 0 }, 486 { 0 },
487}; 487};
488 488
489static unsigned int features[] = {
490 VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC,
491 VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6,
492 VIRTIO_NET_F_HOST_ECN,
493};
494
489static struct virtio_driver virtio_net = { 495static struct virtio_driver virtio_net = {
496 .feature_table = features,
497 .feature_table_size = ARRAY_SIZE(features),
490 .driver.name = KBUILD_MODNAME, 498 .driver.name = KBUILD_MODNAME,
491 .driver.owner = THIS_MODULE, 499 .driver.owner = THIS_MODULE,
492 .id_table = id_table, 500 .id_table = id_table,
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
index b535483bc556..13866789b356 100644
--- a/drivers/virtio/virtio.c
+++ b/drivers/virtio/virtio.c
@@ -80,19 +80,51 @@ static void add_status(struct virtio_device *dev, unsigned status)
80 dev->config->set_status(dev, dev->config->get_status(dev) | status); 80 dev->config->set_status(dev, dev->config->get_status(dev) | status);
81} 81}
82 82
83void virtio_check_driver_offered_feature(const struct virtio_device *vdev,
84 unsigned int fbit)
85{
86 unsigned int i;
87 struct virtio_driver *drv = container_of(vdev->dev.driver,
88 struct virtio_driver, driver);
89
90 for (i = 0; i < drv->feature_table_size; i++)
91 if (drv->feature_table[i] == fbit)
92 return;
93 BUG();
94}
95EXPORT_SYMBOL_GPL(virtio_check_driver_offered_feature);
96
83static int virtio_dev_probe(struct device *_d) 97static int virtio_dev_probe(struct device *_d)
84{ 98{
85 int err; 99 int err, i;
86 struct virtio_device *dev = container_of(_d,struct virtio_device,dev); 100 struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
87 struct virtio_driver *drv = container_of(dev->dev.driver, 101 struct virtio_driver *drv = container_of(dev->dev.driver,
88 struct virtio_driver, driver); 102 struct virtio_driver, driver);
103 u32 device_features;
89 104
105 /* We have a driver! */
90 add_status(dev, VIRTIO_CONFIG_S_DRIVER); 106 add_status(dev, VIRTIO_CONFIG_S_DRIVER);
107
108 /* Figure out what features the device supports. */
109 device_features = dev->config->get_features(dev);
110
111 /* Features supported by both device and driver into dev->features. */
112 memset(dev->features, 0, sizeof(dev->features));
113 for (i = 0; i < drv->feature_table_size; i++) {
114 unsigned int f = drv->feature_table[i];
115 BUG_ON(f >= 32);
116 if (device_features & (1 << f))
117 set_bit(f, dev->features);
118 }
119
91 err = drv->probe(dev); 120 err = drv->probe(dev);
92 if (err) 121 if (err)
93 add_status(dev, VIRTIO_CONFIG_S_FAILED); 122 add_status(dev, VIRTIO_CONFIG_S_FAILED);
94 else 123 else {
95 add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK); 124 add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
125 /* They should never have set feature bits beyond 32 */
126 dev->config->set_features(dev, dev->features[0]);
127 }
96 return err; 128 return err;
97} 129}
98 130
@@ -114,6 +146,8 @@ static int virtio_dev_remove(struct device *_d)
114 146
115int register_virtio_driver(struct virtio_driver *driver) 147int register_virtio_driver(struct virtio_driver *driver)
116{ 148{
149 /* Catch this early. */
150 BUG_ON(driver->feature_table_size && !driver->feature_table);
117 driver->driver.bus = &virtio_bus; 151 driver->driver.bus = &virtio_bus;
118 driver->driver.probe = virtio_dev_probe; 152 driver->driver.probe = virtio_dev_probe;
119 driver->driver.remove = virtio_dev_remove; 153 driver->driver.remove = virtio_dev_remove;
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index fef88d84cef6..bfef604160d1 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -227,7 +227,7 @@ static int virtballoon_probe(struct virtio_device *vdev)
227 } 227 }
228 228
229 vb->tell_host_first 229 vb->tell_host_first
230 = vdev->config->feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST); 230 = virtio_has_feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
231 231
232 return 0; 232 return 0;
233 233
@@ -259,7 +259,11 @@ static void virtballoon_remove(struct virtio_device *vdev)
259 kfree(vb); 259 kfree(vb);
260} 260}
261 261
262static unsigned int features[] = { VIRTIO_BALLOON_F_MUST_TELL_HOST };
263
262static struct virtio_driver virtio_balloon = { 264static struct virtio_driver virtio_balloon = {
265 .feature_table = features,
266 .feature_table_size = ARRAY_SIZE(features),
263 .driver.name = KBUILD_MODNAME, 267 .driver.name = KBUILD_MODNAME,
264 .driver.owner = THIS_MODULE, 268 .driver.owner = THIS_MODULE,
265 .id_table = id_table, 269 .id_table = id_table,
diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c
index de102a614e97..27e9fc9117cd 100644
--- a/drivers/virtio/virtio_pci.c
+++ b/drivers/virtio/virtio_pci.c
@@ -87,23 +87,22 @@ static struct virtio_pci_device *to_vp_device(struct virtio_device *vdev)
87 return container_of(vdev, struct virtio_pci_device, vdev); 87 return container_of(vdev, struct virtio_pci_device, vdev);
88} 88}
89 89
90/* virtio config->feature() implementation */ 90/* virtio config->get_features() implementation */
91static bool vp_feature(struct virtio_device *vdev, unsigned bit) 91static u32 vp_get_features(struct virtio_device *vdev)
92{
93 struct virtio_pci_device *vp_dev = to_vp_device(vdev);
94
95 /* When someone needs more than 32 feature bits, we'll need to
96 * steal a bit to indicate that the rest are somewhere else. */
97 return ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES);
98}
99
100/* virtio config->set_features() implementation */
101static void vp_set_features(struct virtio_device *vdev, u32 features)
92{ 102{
93 struct virtio_pci_device *vp_dev = to_vp_device(vdev); 103 struct virtio_pci_device *vp_dev = to_vp_device(vdev);
94 u32 mask;
95
96 /* Since this function is supposed to have the side effect of
97 * enabling a queried feature, we simulate that by doing a read
98 * from the host feature bitmask and then writing to the guest
99 * feature bitmask */
100 mask = ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES);
101 if (mask & (1 << bit)) {
102 mask |= (1 << bit);
103 iowrite32(mask, vp_dev->ioaddr + VIRTIO_PCI_GUEST_FEATURES);
104 }
105 104
106 return !!(mask & (1 << bit)); 105 iowrite32(features, vp_dev->ioaddr + VIRTIO_PCI_GUEST_FEATURES);
107} 106}
108 107
109/* virtio config->get() implementation */ 108/* virtio config->get() implementation */
@@ -293,7 +292,6 @@ static void vp_del_vq(struct virtqueue *vq)
293} 292}
294 293
295static struct virtio_config_ops virtio_pci_config_ops = { 294static struct virtio_config_ops virtio_pci_config_ops = {
296 .feature = vp_feature,
297 .get = vp_get, 295 .get = vp_get,
298 .set = vp_set, 296 .set = vp_set,
299 .get_status = vp_get_status, 297 .get_status = vp_get_status,
@@ -301,6 +299,8 @@ static struct virtio_config_ops virtio_pci_config_ops = {
301 .reset = vp_reset, 299 .reset = vp_reset,
302 .find_vq = vp_find_vq, 300 .find_vq = vp_find_vq,
303 .del_vq = vp_del_vq, 301 .del_vq = vp_del_vq,
302 .get_features = vp_get_features,
303 .set_features = vp_set_features,
304}; 304};
305 305
306/* the PCI probing function */ 306/* the PCI probing function */