diff options
| -rw-r--r-- | drivers/block/virtio_blk.c | 8 | ||||
| -rw-r--r-- | drivers/lguest/lguest_device.c | 48 | ||||
| -rw-r--r-- | drivers/net/virtio_net.c | 22 | ||||
| -rw-r--r-- | drivers/virtio/virtio.c | 38 | ||||
| -rw-r--r-- | drivers/virtio/virtio_balloon.c | 6 | ||||
| -rw-r--r-- | drivers/virtio/virtio_pci.c | 30 | ||||
| -rw-r--r-- | include/linux/virtio.h | 7 | ||||
| -rw-r--r-- | include/linux/virtio_config.h | 36 |
8 files changed, 142 insertions, 53 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 | ||
| 311 | static unsigned int features[] = { | ||
| 312 | VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, | ||
| 313 | }; | ||
| 314 | |||
| 311 | static struct virtio_driver virtio_blk = { | 315 | static 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. */ |
| 89 | static bool lg_feature(struct virtio_device *vdev, unsigned fbit) | 89 | static 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 | |||
| 104 | static 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. */ |
| 288 | static struct virtio_config_ops lguest_config_ops = { | 295 | static 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 | ||
| 489 | static 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 | |||
| 489 | static struct virtio_driver virtio_net = { | 495 | static 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 | ||
| 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; |
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 | ||
| 262 | static unsigned int features[] = { VIRTIO_BALLOON_F_MUST_TELL_HOST }; | ||
| 263 | |||
| 262 | static struct virtio_driver virtio_balloon = { | 264 | static 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 */ |
| 91 | static bool vp_feature(struct virtio_device *vdev, unsigned bit) | 91 | static 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 */ | ||
| 101 | static 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 | ||
| 295 | static struct virtio_config_ops virtio_pci_config_ops = { | 294 | static 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 */ |
diff --git a/include/linux/virtio.h b/include/linux/virtio.h index e7d10845b3c1..06005fa9e982 100644 --- a/include/linux/virtio.h +++ b/include/linux/virtio.h | |||
| @@ -76,6 +76,7 @@ struct virtqueue_ops { | |||
| 76 | * @dev: underlying device. | 76 | * @dev: underlying device. |
| 77 | * @id: the device type identification (used to match it with a driver). | 77 | * @id: the device type identification (used to match it with a driver). |
| 78 | * @config: the configuration ops for this device. | 78 | * @config: the configuration ops for this device. |
| 79 | * @features: the features supported by both driver and device. | ||
| 79 | * @priv: private pointer for the driver's use. | 80 | * @priv: private pointer for the driver's use. |
| 80 | */ | 81 | */ |
| 81 | struct virtio_device | 82 | struct virtio_device |
| @@ -84,6 +85,8 @@ struct virtio_device | |||
| 84 | struct device dev; | 85 | struct device dev; |
| 85 | struct virtio_device_id id; | 86 | struct virtio_device_id id; |
| 86 | struct virtio_config_ops *config; | 87 | struct virtio_config_ops *config; |
| 88 | /* Note that this is a Linux set_bit-style bitmap. */ | ||
| 89 | unsigned long features[1]; | ||
| 87 | void *priv; | 90 | void *priv; |
| 88 | }; | 91 | }; |
| 89 | 92 | ||
| @@ -94,6 +97,8 @@ void unregister_virtio_device(struct virtio_device *dev); | |||
| 94 | * virtio_driver - operations for a virtio I/O driver | 97 | * virtio_driver - operations for a virtio I/O driver |
| 95 | * @driver: underlying device driver (populate name and owner). | 98 | * @driver: underlying device driver (populate name and owner). |
| 96 | * @id_table: the ids serviced by this driver. | 99 | * @id_table: the ids serviced by this driver. |
| 100 | * @feature_table: an array of feature numbers supported by this device. | ||
| 101 | * @feature_table_size: number of entries in the feature table array. | ||
| 97 | * @probe: the function to call when a device is found. Returns a token for | 102 | * @probe: the function to call when a device is found. Returns a token for |
| 98 | * remove, or PTR_ERR(). | 103 | * remove, or PTR_ERR(). |
| 99 | * @remove: the function when a device is removed. | 104 | * @remove: the function when a device is removed. |
| @@ -103,6 +108,8 @@ void unregister_virtio_device(struct virtio_device *dev); | |||
| 103 | struct virtio_driver { | 108 | struct virtio_driver { |
| 104 | struct device_driver driver; | 109 | struct device_driver driver; |
| 105 | const struct virtio_device_id *id_table; | 110 | const struct virtio_device_id *id_table; |
| 111 | const unsigned int *feature_table; | ||
| 112 | unsigned int feature_table_size; | ||
| 106 | int (*probe)(struct virtio_device *dev); | 113 | int (*probe)(struct virtio_device *dev); |
| 107 | void (*remove)(struct virtio_device *dev); | 114 | void (*remove)(struct virtio_device *dev); |
| 108 | void (*config_changed)(struct virtio_device *dev); | 115 | void (*config_changed)(struct virtio_device *dev); |
diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index 475572e976fe..50db245c81ad 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h | |||
| @@ -20,11 +20,6 @@ | |||
| 20 | 20 | ||
| 21 | /** | 21 | /** |
| 22 | * virtio_config_ops - operations for configuring a virtio device | 22 | * virtio_config_ops - operations for configuring a virtio device |
| 23 | * @feature: search for a feature in this config | ||
| 24 | * vdev: the virtio_device | ||
| 25 | * bit: the feature bit | ||
| 26 | * Returns true if the feature is supported. Acknowledges the feature | ||
| 27 | * so the host can see it. | ||
| 28 | * @get: read the value of a configuration field | 23 | * @get: read the value of a configuration field |
| 29 | * vdev: the virtio_device | 24 | * vdev: the virtio_device |
| 30 | * offset: the offset of the configuration field | 25 | * offset: the offset of the configuration field |
| @@ -50,10 +45,15 @@ | |||
| 50 | * callback: the virqtueue callback | 45 | * callback: the virqtueue callback |
| 51 | * Returns the new virtqueue or ERR_PTR() (eg. -ENOENT). | 46 | * Returns the new virtqueue or ERR_PTR() (eg. -ENOENT). |
| 52 | * @del_vq: free a virtqueue found by find_vq(). | 47 | * @del_vq: free a virtqueue found by find_vq(). |
| 48 | * @get_features: get the array of feature bits for this device. | ||
| 49 | * vdev: the virtio_device | ||
| 50 | * Returns the first 32 feature bits (all we currently need). | ||
| 51 | * @set_features: confirm what device features we'll be using. | ||
| 52 | * vdev: the virtio_device | ||
| 53 | * feature: the first 32 feature bits | ||
| 53 | */ | 54 | */ |
| 54 | struct virtio_config_ops | 55 | struct virtio_config_ops |
| 55 | { | 56 | { |
| 56 | bool (*feature)(struct virtio_device *vdev, unsigned bit); | ||
| 57 | void (*get)(struct virtio_device *vdev, unsigned offset, | 57 | void (*get)(struct virtio_device *vdev, unsigned offset, |
| 58 | void *buf, unsigned len); | 58 | void *buf, unsigned len); |
| 59 | void (*set)(struct virtio_device *vdev, unsigned offset, | 59 | void (*set)(struct virtio_device *vdev, unsigned offset, |
| @@ -65,8 +65,30 @@ struct virtio_config_ops | |||
| 65 | unsigned index, | 65 | unsigned index, |
| 66 | void (*callback)(struct virtqueue *)); | 66 | void (*callback)(struct virtqueue *)); |
| 67 | void (*del_vq)(struct virtqueue *vq); | 67 | void (*del_vq)(struct virtqueue *vq); |
| 68 | u32 (*get_features)(struct virtio_device *vdev); | ||
| 69 | void (*set_features)(struct virtio_device *vdev, u32 features); | ||
| 68 | }; | 70 | }; |
| 69 | 71 | ||
| 72 | /* If driver didn't advertise the feature, it will never appear. */ | ||
| 73 | void virtio_check_driver_offered_feature(const struct virtio_device *vdev, | ||
| 74 | unsigned int fbit); | ||
| 75 | |||
| 76 | /** | ||
| 77 | * virtio_has_feature - helper to determine if this device has this feature. | ||
| 78 | * @vdev: the device | ||
| 79 | * @fbit: the feature bit | ||
| 80 | */ | ||
| 81 | static inline bool virtio_has_feature(const struct virtio_device *vdev, | ||
| 82 | unsigned int fbit) | ||
| 83 | { | ||
| 84 | /* Did you forget to fix assumptions on max features? */ | ||
| 85 | if (__builtin_constant_p(fbit)) | ||
| 86 | BUILD_BUG_ON(fbit >= 32); | ||
| 87 | |||
| 88 | virtio_check_driver_offered_feature(vdev, fbit); | ||
| 89 | return test_bit(fbit, vdev->features); | ||
| 90 | } | ||
| 91 | |||
| 70 | /** | 92 | /** |
| 71 | * virtio_config_val - look for a feature and get a virtio config entry. | 93 | * virtio_config_val - look for a feature and get a virtio config entry. |
| 72 | * @vdev: the virtio device | 94 | * @vdev: the virtio device |
| @@ -84,7 +106,7 @@ static inline int virtio_config_buf(struct virtio_device *vdev, | |||
| 84 | unsigned int offset, | 106 | unsigned int offset, |
| 85 | void *buf, unsigned len) | 107 | void *buf, unsigned len) |
| 86 | { | 108 | { |
| 87 | if (!vdev->config->feature(vdev, fbit)) | 109 | if (!virtio_has_feature(vdev, fbit)) |
| 88 | return -ENOENT; | 110 | return -ENOENT; |
| 89 | 111 | ||
| 90 | vdev->config->get(vdev, offset, buf, len); | 112 | vdev->config->get(vdev, offset, buf, len); |
