|
@@ -588,6 +588,46 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
|
|
|
ida_simple_remove(&vd_index_ida, index);
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_PM
|
|
|
+static int virtblk_freeze(struct virtio_device *vdev)
|
|
|
+{
|
|
|
+ struct virtio_blk *vblk = vdev->priv;
|
|
|
+
|
|
|
+ /* Ensure we don't receive any more interrupts */
|
|
|
+ vdev->config->reset(vdev);
|
|
|
+
|
|
|
+ /* Prevent config work handler from accessing the device. */
|
|
|
+ mutex_lock(&vblk->config_lock);
|
|
|
+ vblk->config_enable = false;
|
|
|
+ mutex_unlock(&vblk->config_lock);
|
|
|
+
|
|
|
+ flush_work(&vblk->config_work);
|
|
|
+
|
|
|
+ spin_lock_irq(vblk->disk->queue->queue_lock);
|
|
|
+ blk_stop_queue(vblk->disk->queue);
|
|
|
+ spin_unlock_irq(vblk->disk->queue->queue_lock);
|
|
|
+ blk_sync_queue(vblk->disk->queue);
|
|
|
+
|
|
|
+ vdev->config->del_vqs(vdev);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int virtblk_restore(struct virtio_device *vdev)
|
|
|
+{
|
|
|
+ struct virtio_blk *vblk = vdev->priv;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ vblk->config_enable = true;
|
|
|
+ ret = init_vq(vdev->priv);
|
|
|
+ if (!ret) {
|
|
|
+ spin_lock_irq(vblk->disk->queue->queue_lock);
|
|
|
+ blk_start_queue(vblk->disk->queue);
|
|
|
+ spin_unlock_irq(vblk->disk->queue->queue_lock);
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
static const struct virtio_device_id id_table[] = {
|
|
|
{ VIRTIO_ID_BLOCK, VIRTIO_DEV_ANY_ID },
|
|
|
{ 0 },
|
|
@@ -613,6 +653,10 @@ static struct virtio_driver __refdata virtio_blk = {
|
|
|
.probe = virtblk_probe,
|
|
|
.remove = __devexit_p(virtblk_remove),
|
|
|
.config_changed = virtblk_config_changed,
|
|
|
+#ifdef CONFIG_PM
|
|
|
+ .freeze = virtblk_freeze,
|
|
|
+ .restore = virtblk_restore,
|
|
|
+#endif
|
|
|
};
|
|
|
|
|
|
static int __init init(void)
|