aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/virtio
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/virtio
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/virtio')
-rw-r--r--drivers/virtio/virtio.c38
-rw-r--r--drivers/virtio/virtio_balloon.c6
-rw-r--r--drivers/virtio/virtio_pci.c30
3 files changed, 56 insertions, 18 deletions
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
index b535483bc55..13866789b35 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 fef88d84cef..bfef604160d 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 de102a614e9..27e9fc9117c 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 */