aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/virtio
diff options
context:
space:
mode:
authorMichael S. Tsirkin <mst@redhat.com>2014-10-14 19:51:55 -0400
committerRusty Russell <rusty@rustcorp.com.au>2014-10-14 19:54:56 -0400
commit22b7050a024d7deb0c9ef1e14ed73e3b1e369f24 (patch)
treebe21b9a75aa1b5a95d8bb3ab7bf9470669e643bb /drivers/virtio
parentc6716bae52f97347e25166c6270aa98693d9212c (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.c58
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}
118EXPORT_SYMBOL_GPL(virtio_check_driver_offered_feature); 118EXPORT_SYMBOL_GPL(virtio_check_driver_offered_feature);
119 119
120static 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
130void 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}
138EXPORT_SYMBOL_GPL(virtio_config_changed);
139
140static 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
147static 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
120static int virtio_dev_probe(struct device *_d) 157static 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}
240EXPORT_SYMBOL_GPL(unregister_virtio_device); 285EXPORT_SYMBOL_GPL(unregister_virtio_device);
241 286
242void 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}
249EXPORT_SYMBOL_GPL(virtio_config_changed);
250
251#ifdef CONFIG_PM_SLEEP 287#ifdef CONFIG_PM_SLEEP
252int virtio_device_freeze(struct virtio_device *dev) 288int 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}
302EXPORT_SYMBOL_GPL(virtio_device_restore); 342EXPORT_SYMBOL_GPL(virtio_device_restore);