aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/virtio/virtio.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/virtio/virtio.c')
-rw-r--r--drivers/virtio/virtio.c103
1 files changed, 103 insertions, 0 deletions
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
index fed0ce198ae3..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,6 +284,64 @@ void unregister_virtio_device(struct virtio_device *dev)
239} 284}
240EXPORT_SYMBOL_GPL(unregister_virtio_device); 285EXPORT_SYMBOL_GPL(unregister_virtio_device);
241 286
287#ifdef CONFIG_PM_SLEEP
288int virtio_device_freeze(struct virtio_device *dev)
289{
290 struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
291
292 virtio_config_disable(dev);
293
294 dev->failed = dev->config->get_status(dev) & VIRTIO_CONFIG_S_FAILED;
295
296 if (drv && drv->freeze)
297 return drv->freeze(dev);
298
299 return 0;
300}
301EXPORT_SYMBOL_GPL(virtio_device_freeze);
302
303int virtio_device_restore(struct virtio_device *dev)
304{
305 struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
306
307 /* We always start by resetting the device, in case a previous
308 * driver messed it up. */
309 dev->config->reset(dev);
310
311 /* Acknowledge that we've seen the device. */
312 add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
313
314 /* Maybe driver failed before freeze.
315 * Restore the failed status, for debugging. */
316 if (dev->failed)
317 add_status(dev, VIRTIO_CONFIG_S_FAILED);
318
319 if (!drv)
320 return 0;
321
322 /* We have a driver! */
323 add_status(dev, VIRTIO_CONFIG_S_DRIVER);
324
325 dev->config->finalize_features(dev);
326
327 if (drv->restore) {
328 int ret = drv->restore(dev);
329 if (ret) {
330 add_status(dev, VIRTIO_CONFIG_S_FAILED);
331 return ret;
332 }
333 }
334
335 /* Finally, tell the device we're all set */
336 add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
337
338 virtio_config_enable(dev);
339
340 return 0;
341}
342EXPORT_SYMBOL_GPL(virtio_device_restore);
343#endif
344
242static int virtio_init(void) 345static int virtio_init(void)
243{ 346{
244 if (bus_register(&virtio_bus) != 0) 347 if (bus_register(&virtio_bus) != 0)