diff options
Diffstat (limited to 'drivers/virtio/virtio.c')
-rw-r--r-- | drivers/virtio/virtio.c | 59 |
1 files changed, 46 insertions, 13 deletions
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index bc1f962e483b..b9095751e43b 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -127,10 +127,12 @@ static void __virtio_config_changed(struct virtio_device *dev) { struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); - if (!dev->config_enabled) + if (!dev->config_core_enabled || dev->config_driver_disabled) dev->config_change_pending = true; - else if (drv && drv->config_changed) + else if (drv && drv->config_changed) { drv->config_changed(dev); + dev->config_change_pending = false; + } } void virtio_config_changed(struct virtio_device *dev) @@ -143,20 +145,51 @@ void virtio_config_changed(struct virtio_device *dev) } EXPORT_SYMBOL_GPL(virtio_config_changed); -static void virtio_config_disable(struct virtio_device *dev) +/** + * virtio_config_driver_disable - disable config change reporting by drivers + * @dev: the device to reset + * + * This is only allowed to be called by a driver and disabling can't + * be nested. + */ +void virtio_config_driver_disable(struct virtio_device *dev) { spin_lock_irq(&dev->config_lock); - dev->config_enabled = false; + dev->config_driver_disabled = true; spin_unlock_irq(&dev->config_lock); } +EXPORT_SYMBOL_GPL(virtio_config_driver_disable); -static void virtio_config_enable(struct virtio_device *dev) +/** + * virtio_config_driver_enable - enable config change reporting by drivers + * @dev: the device to reset + * + * This is only allowed to be called by a driver and enabling can't + * be nested. + */ +void virtio_config_driver_enable(struct virtio_device *dev) { spin_lock_irq(&dev->config_lock); - dev->config_enabled = true; + dev->config_driver_disabled = false; + if (dev->config_change_pending) + __virtio_config_changed(dev); + spin_unlock_irq(&dev->config_lock); +} +EXPORT_SYMBOL_GPL(virtio_config_driver_enable); + +static void virtio_config_core_disable(struct virtio_device *dev) +{ + spin_lock_irq(&dev->config_lock); + dev->config_core_enabled = false; + spin_unlock_irq(&dev->config_lock); +} + +static void virtio_config_core_enable(struct virtio_device *dev) +{ + spin_lock_irq(&dev->config_lock); + dev->config_core_enabled = true; if (dev->config_change_pending) __virtio_config_changed(dev); - dev->config_change_pending = false; spin_unlock_irq(&dev->config_lock); } @@ -316,7 +349,7 @@ static int virtio_dev_probe(struct device *_d) if (drv->scan) drv->scan(dev); - virtio_config_enable(dev); + virtio_config_core_enable(dev); return 0; @@ -331,7 +364,7 @@ static void virtio_dev_remove(struct device *_d) struct virtio_device *dev = dev_to_virtio(_d); struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); - virtio_config_disable(dev); + virtio_config_core_disable(dev); drv->remove(dev); @@ -443,7 +476,7 @@ int register_virtio_device(struct virtio_device *dev) goto out_ida_remove; spin_lock_init(&dev->config_lock); - dev->config_enabled = false; + dev->config_core_enabled = false; dev->config_change_pending = false; INIT_LIST_HEAD(&dev->vqs); @@ -500,14 +533,14 @@ int virtio_device_freeze(struct virtio_device *dev) struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); int ret; - virtio_config_disable(dev); + virtio_config_core_disable(dev); dev->failed = dev->config->get_status(dev) & VIRTIO_CONFIG_S_FAILED; if (drv && drv->freeze) { ret = drv->freeze(dev); if (ret) { - virtio_config_enable(dev); + virtio_config_core_enable(dev); return ret; } } @@ -557,7 +590,7 @@ int virtio_device_restore(struct virtio_device *dev) if (!(dev->config->get_status(dev) & VIRTIO_CONFIG_S_DRIVER_OK)) virtio_device_ready(dev); - virtio_config_enable(dev); + virtio_config_core_enable(dev); return 0; |