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/virtio/virtio.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/virtio/virtio.c')
-rw-r--r-- | drivers/virtio/virtio.c | 38 |
1 files changed, 36 insertions, 2 deletions
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 | ||
83 | void 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 | } | ||
95 | EXPORT_SYMBOL_GPL(virtio_check_driver_offered_feature); | ||
96 | |||
83 | static int virtio_dev_probe(struct device *_d) | 97 | static 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 | ||
115 | int register_virtio_driver(struct virtio_driver *driver) | 147 | int 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; |