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>
This commit is contained in:
Rusty Russell
2008-05-02 21:50:50 -05:00
parent 72e61eb40b
commit c45a6816c1
8 changed files with 138 additions and 49 deletions
+14 -14
View File
@@ -87,23 +87,22 @@ static struct virtio_pci_device *to_vp_device(struct virtio_device *vdev)
return container_of(vdev, struct virtio_pci_device, vdev);
}
/* virtio config->feature() implementation */
static bool vp_feature(struct virtio_device *vdev, unsigned bit)
/* virtio config->get_features() implementation */
static u32 vp_get_features(struct virtio_device *vdev)
{
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
u32 mask;
/* Since this function is supposed to have the side effect of
* enabling a queried feature, we simulate that by doing a read
* from the host feature bitmask and then writing to the guest
* feature bitmask */
mask = ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES);
if (mask & (1 << bit)) {
mask |= (1 << bit);
iowrite32(mask, vp_dev->ioaddr + VIRTIO_PCI_GUEST_FEATURES);
}
/* When someone needs more than 32 feature bits, we'll need to
* steal a bit to indicate that the rest are somewhere else. */
return ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES);
}
return !!(mask & (1 << bit));
/* virtio config->set_features() implementation */
static void vp_set_features(struct virtio_device *vdev, u32 features)
{
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
iowrite32(features, vp_dev->ioaddr + VIRTIO_PCI_GUEST_FEATURES);
}
/* virtio config->get() implementation */
@@ -293,7 +292,6 @@ static void vp_del_vq(struct virtqueue *vq)
}
static struct virtio_config_ops virtio_pci_config_ops = {
.feature = vp_feature,
.get = vp_get,
.set = vp_set,
.get_status = vp_get_status,
@@ -301,6 +299,8 @@ static struct virtio_config_ops virtio_pci_config_ops = {
.reset = vp_reset,
.find_vq = vp_find_vq,
.del_vq = vp_del_vq,
.get_features = vp_get_features,
.set_features = vp_set_features,
};
/* the PCI probing function */