diff options
author | Michael S. Tsirkin <mst@redhat.com> | 2014-10-14 19:51:55 -0400 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2014-10-14 19:54:56 -0400 |
commit | 22b7050a024d7deb0c9ef1e14ed73e3b1e369f24 (patch) | |
tree | be21b9a75aa1b5a95d8bb3ab7bf9470669e643bb /drivers/virtio | |
parent | c6716bae52f97347e25166c6270aa98693d9212c (diff) |
virtio: defer config changed notifications
Defer config changed notifications that arrive during
probe/scan/freeze/restore.
This will allow drivers to set DRIVER_OK earlier, without worrying about
racing with config change interrupts.
This change will also benefit old hypervisors (before 2009)
that send interrupts without checking DRIVER_OK: previously,
the callback could race with driver-specific initialization.
This will also help simplify drivers.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (cosmetic changes)
Diffstat (limited to 'drivers/virtio')
-rw-r--r-- | drivers/virtio/virtio.c | 58 |
1 files changed, 49 insertions, 9 deletions
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index 8216b7311092..df598dd8c5c8 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c | |||
@@ -117,6 +117,43 @@ void virtio_check_driver_offered_feature(const struct virtio_device *vdev, | |||
117 | } | 117 | } |
118 | EXPORT_SYMBOL_GPL(virtio_check_driver_offered_feature); | 118 | EXPORT_SYMBOL_GPL(virtio_check_driver_offered_feature); |
119 | 119 | ||
120 | static void __virtio_config_changed(struct virtio_device *dev) | ||
121 | { | ||
122 | struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); | ||
123 | |||
124 | if (!dev->config_enabled) | ||
125 | dev->config_change_pending = true; | ||
126 | else if (drv && drv->config_changed) | ||
127 | drv->config_changed(dev); | ||
128 | } | ||
129 | |||
130 | void virtio_config_changed(struct virtio_device *dev) | ||
131 | { | ||
132 | unsigned long flags; | ||
133 | |||
134 | spin_lock_irqsave(&dev->config_lock, flags); | ||
135 | __virtio_config_changed(dev); | ||
136 | spin_unlock_irqrestore(&dev->config_lock, flags); | ||
137 | } | ||
138 | EXPORT_SYMBOL_GPL(virtio_config_changed); | ||
139 | |||
140 | static void virtio_config_disable(struct virtio_device *dev) | ||
141 | { | ||
142 | spin_lock_irq(&dev->config_lock); | ||
143 | dev->config_enabled = false; | ||
144 | spin_unlock_irq(&dev->config_lock); | ||
145 | } | ||
146 | |||
147 | static void virtio_config_enable(struct virtio_device *dev) | ||
148 | { | ||
149 | spin_lock_irq(&dev->config_lock); | ||
150 | dev->config_enabled = true; | ||
151 | if (dev->config_change_pending) | ||
152 | __virtio_config_changed(dev); | ||
153 | dev->config_change_pending = false; | ||
154 | spin_unlock_irq(&dev->config_lock); | ||
155 | } | ||
156 | |||
120 | static int virtio_dev_probe(struct device *_d) | 157 | static int virtio_dev_probe(struct device *_d) |
121 | { | 158 | { |
122 | int err, i; | 159 | int err, i; |
@@ -153,6 +190,8 @@ static int virtio_dev_probe(struct device *_d) | |||
153 | add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK); | 190 | add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK); |
154 | if (drv->scan) | 191 | if (drv->scan) |
155 | drv->scan(dev); | 192 | drv->scan(dev); |
193 | |||
194 | virtio_config_enable(dev); | ||
156 | } | 195 | } |
157 | 196 | ||
158 | return err; | 197 | return err; |
@@ -163,6 +202,8 @@ static int virtio_dev_remove(struct device *_d) | |||
163 | struct virtio_device *dev = dev_to_virtio(_d); | 202 | struct virtio_device *dev = dev_to_virtio(_d); |
164 | struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); | 203 | struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); |
165 | 204 | ||
205 | virtio_config_disable(dev); | ||
206 | |||
166 | drv->remove(dev); | 207 | drv->remove(dev); |
167 | 208 | ||
168 | /* Driver should have reset device. */ | 209 | /* Driver should have reset device. */ |
@@ -211,6 +252,10 @@ int register_virtio_device(struct virtio_device *dev) | |||
211 | dev->index = err; | 252 | dev->index = err; |
212 | dev_set_name(&dev->dev, "virtio%u", dev->index); | 253 | dev_set_name(&dev->dev, "virtio%u", dev->index); |
213 | 254 | ||
255 | spin_lock_init(&dev->config_lock); | ||
256 | dev->config_enabled = false; | ||
257 | dev->config_change_pending = false; | ||
258 | |||
214 | /* We always start by resetting the device, in case a previous | 259 | /* We always start by resetting the device, in case a previous |
215 | * driver messed it up. This also tests that code path a little. */ | 260 | * driver messed it up. This also tests that code path a little. */ |
216 | dev->config->reset(dev); | 261 | dev->config->reset(dev); |
@@ -239,20 +284,13 @@ void unregister_virtio_device(struct virtio_device *dev) | |||
239 | } | 284 | } |
240 | EXPORT_SYMBOL_GPL(unregister_virtio_device); | 285 | EXPORT_SYMBOL_GPL(unregister_virtio_device); |
241 | 286 | ||
242 | void virtio_config_changed(struct virtio_device *dev) | ||
243 | { | ||
244 | struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); | ||
245 | |||
246 | if (drv && drv->config_changed) | ||
247 | drv->config_changed(dev); | ||
248 | } | ||
249 | EXPORT_SYMBOL_GPL(virtio_config_changed); | ||
250 | |||
251 | #ifdef CONFIG_PM_SLEEP | 287 | #ifdef CONFIG_PM_SLEEP |
252 | int virtio_device_freeze(struct virtio_device *dev) | 288 | int virtio_device_freeze(struct virtio_device *dev) |
253 | { | 289 | { |
254 | struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); | 290 | struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); |
255 | 291 | ||
292 | virtio_config_disable(dev); | ||
293 | |||
256 | dev->failed = dev->config->get_status(dev) & VIRTIO_CONFIG_S_FAILED; | 294 | dev->failed = dev->config->get_status(dev) & VIRTIO_CONFIG_S_FAILED; |
257 | 295 | ||
258 | if (drv && drv->freeze) | 296 | if (drv && drv->freeze) |
@@ -297,6 +335,8 @@ int virtio_device_restore(struct virtio_device *dev) | |||
297 | /* Finally, tell the device we're all set */ | 335 | /* Finally, tell the device we're all set */ |
298 | add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK); | 336 | add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK); |
299 | 337 | ||
338 | virtio_config_enable(dev); | ||
339 | |||
300 | return 0; | 340 | return 0; |
301 | } | 341 | } |
302 | EXPORT_SYMBOL_GPL(virtio_device_restore); | 342 | EXPORT_SYMBOL_GPL(virtio_device_restore); |