diff options
Diffstat (limited to 'drivers/virtio')
-rw-r--r-- | drivers/virtio/virtio.c | 103 | ||||
-rw-r--r-- | drivers/virtio/virtio_balloon.c | 2 | ||||
-rw-r--r-- | drivers/virtio/virtio_mmio.c | 7 | ||||
-rw-r--r-- | drivers/virtio/virtio_pci.c | 33 |
4 files changed, 110 insertions, 35 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 | } |
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,6 +284,64 @@ 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 | ||
287 | #ifdef CONFIG_PM_SLEEP | ||
288 | int 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 | } | ||
301 | EXPORT_SYMBOL_GPL(virtio_device_freeze); | ||
302 | |||
303 | int 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 | } | ||
342 | EXPORT_SYMBOL_GPL(virtio_device_restore); | ||
343 | #endif | ||
344 | |||
242 | static int virtio_init(void) | 345 | static int virtio_init(void) |
243 | { | 346 | { |
244 | if (bus_register(&virtio_bus) != 0) | 347 | if (bus_register(&virtio_bus) != 0) |
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index f893148a107b..c9703d4d6f67 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c | |||
@@ -504,6 +504,8 @@ static int virtballoon_restore(struct virtio_device *vdev) | |||
504 | if (ret) | 504 | if (ret) |
505 | return ret; | 505 | return ret; |
506 | 506 | ||
507 | virtio_device_ready(vdev); | ||
508 | |||
507 | fill_balloon(vb, towards_target(vb)); | 509 | fill_balloon(vb, towards_target(vb)); |
508 | update_balloon_size(vb); | 510 | update_balloon_size(vb); |
509 | return 0; | 511 | return 0; |
diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c index c600ccfd6922..ef9a1650bb80 100644 --- a/drivers/virtio/virtio_mmio.c +++ b/drivers/virtio/virtio_mmio.c | |||
@@ -234,8 +234,6 @@ static irqreturn_t vm_interrupt(int irq, void *opaque) | |||
234 | { | 234 | { |
235 | struct virtio_mmio_device *vm_dev = opaque; | 235 | struct virtio_mmio_device *vm_dev = opaque; |
236 | struct virtio_mmio_vq_info *info; | 236 | struct virtio_mmio_vq_info *info; |
237 | struct virtio_driver *vdrv = container_of(vm_dev->vdev.dev.driver, | ||
238 | struct virtio_driver, driver); | ||
239 | unsigned long status; | 237 | unsigned long status; |
240 | unsigned long flags; | 238 | unsigned long flags; |
241 | irqreturn_t ret = IRQ_NONE; | 239 | irqreturn_t ret = IRQ_NONE; |
@@ -244,9 +242,8 @@ static irqreturn_t vm_interrupt(int irq, void *opaque) | |||
244 | status = readl(vm_dev->base + VIRTIO_MMIO_INTERRUPT_STATUS); | 242 | status = readl(vm_dev->base + VIRTIO_MMIO_INTERRUPT_STATUS); |
245 | writel(status, vm_dev->base + VIRTIO_MMIO_INTERRUPT_ACK); | 243 | writel(status, vm_dev->base + VIRTIO_MMIO_INTERRUPT_ACK); |
246 | 244 | ||
247 | if (unlikely(status & VIRTIO_MMIO_INT_CONFIG) | 245 | if (unlikely(status & VIRTIO_MMIO_INT_CONFIG)) { |
248 | && vdrv && vdrv->config_changed) { | 246 | virtio_config_changed(&vm_dev->vdev); |
249 | vdrv->config_changed(&vm_dev->vdev); | ||
250 | ret = IRQ_HANDLED; | 247 | ret = IRQ_HANDLED; |
251 | } | 248 | } |
252 | 249 | ||
diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c index 3d1463c6b120..d34ebfa604f3 100644 --- a/drivers/virtio/virtio_pci.c +++ b/drivers/virtio/virtio_pci.c | |||
@@ -57,9 +57,6 @@ struct virtio_pci_device | |||
57 | /* Vectors allocated, excluding per-vq vectors if any */ | 57 | /* Vectors allocated, excluding per-vq vectors if any */ |
58 | unsigned msix_used_vectors; | 58 | unsigned msix_used_vectors; |
59 | 59 | ||
60 | /* Status saved during hibernate/restore */ | ||
61 | u8 saved_status; | ||
62 | |||
63 | /* Whether we have vector per vq */ | 60 | /* Whether we have vector per vq */ |
64 | bool per_vq_vectors; | 61 | bool per_vq_vectors; |
65 | }; | 62 | }; |
@@ -211,12 +208,8 @@ static bool vp_notify(struct virtqueue *vq) | |||
211 | static irqreturn_t vp_config_changed(int irq, void *opaque) | 208 | static irqreturn_t vp_config_changed(int irq, void *opaque) |
212 | { | 209 | { |
213 | struct virtio_pci_device *vp_dev = opaque; | 210 | struct virtio_pci_device *vp_dev = opaque; |
214 | struct virtio_driver *drv; | ||
215 | drv = container_of(vp_dev->vdev.dev.driver, | ||
216 | struct virtio_driver, driver); | ||
217 | 211 | ||
218 | if (drv && drv->config_changed) | 212 | virtio_config_changed(&vp_dev->vdev); |
219 | drv->config_changed(&vp_dev->vdev); | ||
220 | return IRQ_HANDLED; | 213 | return IRQ_HANDLED; |
221 | } | 214 | } |
222 | 215 | ||
@@ -768,16 +761,9 @@ static int virtio_pci_freeze(struct device *dev) | |||
768 | { | 761 | { |
769 | struct pci_dev *pci_dev = to_pci_dev(dev); | 762 | struct pci_dev *pci_dev = to_pci_dev(dev); |
770 | struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); | 763 | struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); |
771 | struct virtio_driver *drv; | ||
772 | int ret; | 764 | int ret; |
773 | 765 | ||
774 | drv = container_of(vp_dev->vdev.dev.driver, | 766 | ret = virtio_device_freeze(&vp_dev->vdev); |
775 | struct virtio_driver, driver); | ||
776 | |||
777 | ret = 0; | ||
778 | vp_dev->saved_status = vp_get_status(&vp_dev->vdev); | ||
779 | if (drv && drv->freeze) | ||
780 | ret = drv->freeze(&vp_dev->vdev); | ||
781 | 767 | ||
782 | if (!ret) | 768 | if (!ret) |
783 | pci_disable_device(pci_dev); | 769 | pci_disable_device(pci_dev); |
@@ -788,27 +774,14 @@ static int virtio_pci_restore(struct device *dev) | |||
788 | { | 774 | { |
789 | struct pci_dev *pci_dev = to_pci_dev(dev); | 775 | struct pci_dev *pci_dev = to_pci_dev(dev); |
790 | struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); | 776 | struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); |
791 | struct virtio_driver *drv; | ||
792 | int ret; | 777 | int ret; |
793 | 778 | ||
794 | drv = container_of(vp_dev->vdev.dev.driver, | ||
795 | struct virtio_driver, driver); | ||
796 | |||
797 | ret = pci_enable_device(pci_dev); | 779 | ret = pci_enable_device(pci_dev); |
798 | if (ret) | 780 | if (ret) |
799 | return ret; | 781 | return ret; |
800 | 782 | ||
801 | pci_set_master(pci_dev); | 783 | pci_set_master(pci_dev); |
802 | vp_finalize_features(&vp_dev->vdev); | 784 | return virtio_device_restore(&vp_dev->vdev); |
803 | |||
804 | if (drv && drv->restore) | ||
805 | ret = drv->restore(&vp_dev->vdev); | ||
806 | |||
807 | /* Finally, tell the device we're all set */ | ||
808 | if (!ret) | ||
809 | vp_set_status(&vp_dev->vdev, vp_dev->saved_status); | ||
810 | |||
811 | return ret; | ||
812 | } | 785 | } |
813 | 786 | ||
814 | static const struct dev_pm_ops virtio_pci_pm_ops = { | 787 | static const struct dev_pm_ops virtio_pci_pm_ops = { |