From: Dongwon Kim <dongwon....@intel.com>

virtio device needs to delete before VM suspend happens
then reinitialize all virtqueues again upon resume

v2: 10ms sleep is added in virtgpu_freeze to avoid the situation
    the driver is locked up during resumption.

v3: Plain 10ms delay (v2) is replaced with wait calls which wait until
    the virtio queue is empty.
    (Dmitry Osipenko)

Suggested-by: Dmitry Osipenko <dmitry.osipe...@collabora.com>
Tested-by: Dmitry Osipenko <dmitry.osipe...@collabora.com>
Cc: Vivek Kasireddy <vivek.kasire...@intel.com>
Signed-off-by: Dongwon Kim <dongwon....@intel.com>
---
 drivers/gpu/drm/virtio/virtgpu_drv.c | 61 +++++++++++++++++++++++++++-
 drivers/gpu/drm/virtio/virtgpu_drv.h |  1 +
 drivers/gpu/drm/virtio/virtgpu_kms.c | 23 ++++++++---
 3 files changed, 78 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c 
b/drivers/gpu/drm/virtio/virtgpu_drv.c
index e32e680c7197..bcdd6e37db3e 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.c
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.c
@@ -163,6 +163,60 @@ static unsigned int features[] = {
        VIRTIO_GPU_F_RESOURCE_BLOB,
        VIRTIO_GPU_F_CONTEXT_INIT,
 };
+
+#ifdef CONFIG_PM_SLEEP
+static int virtgpu_freeze(struct virtio_device *vdev)
+{
+       struct drm_device *dev = vdev->priv;
+       struct virtio_gpu_device *vgdev = dev->dev_private;
+       int error;
+
+       error = drm_mode_config_helper_suspend(dev);
+       if (error) {
+               DRM_ERROR("suspend error %d\n", error);
+               return error;
+       }
+
+       flush_work(&vgdev->obj_free_work);
+       flush_work(&vgdev->ctrlq.dequeue_work);
+       flush_work(&vgdev->cursorq.dequeue_work);
+       flush_work(&vgdev->config_changed_work);
+
+       wait_event(vgdev->ctrlq.ack_queue,
+                  vgdev->ctrlq.vq->num_free == vgdev->ctrlq.vq->num_max);
+
+       wait_event(vgdev->cursorq.ack_queue,
+                  vgdev->cursorq.vq->num_free == vgdev->cursorq.vq->num_max);
+
+       vdev->config->del_vqs(vdev);
+
+       return 0;
+}
+
+static int virtgpu_restore(struct virtio_device *vdev)
+{
+       struct drm_device *dev = vdev->priv;
+       struct virtio_gpu_device *vgdev = dev->dev_private;
+       int error;
+
+       error = virtio_gpu_find_vqs(vgdev);
+       if (error) {
+               DRM_ERROR("failed to find virt queues\n");
+               return error;
+       }
+
+       virtio_device_ready(vdev);
+
+       error = drm_mode_config_helper_resume(dev);
+       if (error) {
+               DRM_ERROR("resume error %d\n", error);
+               return error;
+       }
+
+       return 0;
+}
+#endif
+
 static struct virtio_driver virtio_gpu_driver = {
        .feature_table = features,
        .feature_table_size = ARRAY_SIZE(features),
@@ -171,7 +225,11 @@ static struct virtio_driver virtio_gpu_driver = {
        .probe = virtio_gpu_probe,
        .remove = virtio_gpu_remove,
        .shutdown = virtio_gpu_shutdown,
-       .config_changed = virtio_gpu_config_changed
+       .config_changed = virtio_gpu_config_changed,
+#ifdef CONFIG_PM_SLEEP
+       .freeze = virtgpu_freeze,
+       .restore = virtgpu_restore,
+#endif
 };
 
 static int __init virtio_gpu_driver_init(void)
@@ -193,6 +251,7 @@ static int __init virtio_gpu_driver_init(void)
 
        ret = register_virtio_driver(&virtio_gpu_driver);
 
+       printk("**dw_debug:: virtio-init\n");
        if (pdev) {
                if (pci_is_vga(pdev))
                        vga_put(pdev,
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h 
b/drivers/gpu/drm/virtio/virtgpu_drv.h
index f17660a71a3e..1279f998c8e0 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.h
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.h
@@ -300,6 +300,7 @@ void virtio_gpu_deinit(struct drm_device *dev);
 void virtio_gpu_release(struct drm_device *dev);
 int virtio_gpu_driver_open(struct drm_device *dev, struct drm_file *file);
 void virtio_gpu_driver_postclose(struct drm_device *dev, struct drm_file 
*file);
+int virtio_gpu_find_vqs(struct virtio_gpu_device *vgdev);
 
 /* virtgpu_gem.c */
 int virtio_gpu_gem_object_open(struct drm_gem_object *obj,
diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c 
b/drivers/gpu/drm/virtio/virtgpu_kms.c
index 7dfb2006c561..6c1af77ea083 100644
--- a/drivers/gpu/drm/virtio/virtgpu_kms.c
+++ b/drivers/gpu/drm/virtio/virtgpu_kms.c
@@ -114,15 +114,28 @@ static void virtio_gpu_get_capsets(struct 
virtio_gpu_device *vgdev,
        vgdev->num_capsets = num_capsets;
 }
 
-int virtio_gpu_init(struct virtio_device *vdev, struct drm_device *dev)
+int virtio_gpu_find_vqs(struct virtio_gpu_device *vgdev)
 {
        struct virtqueue_info vqs_info[] = {
                { "control", virtio_gpu_ctrl_ack },
                { "cursor", virtio_gpu_cursor_ack },
        };
-       struct virtio_gpu_device *vgdev;
-       /* this will expand later */
        struct virtqueue *vqs[2];
+       int ret;
+
+       ret = virtio_find_vqs(vgdev->vdev, 2, vqs, vqs_info, NULL);
+       if (ret)
+               return ret;
+
+       vgdev->ctrlq.vq = vqs[0];
+       vgdev->cursorq.vq = vqs[1];
+
+       return 0;
+}
+
+int virtio_gpu_init(struct virtio_device *vdev, struct drm_device *dev)
+{
+       struct virtio_gpu_device *vgdev;
        u32 num_scanouts, num_capsets;
        int ret = 0;
 
@@ -206,13 +219,11 @@ int virtio_gpu_init(struct virtio_device *vdev, struct 
drm_device *dev)
        DRM_INFO("features: %ccontext_init\n",
                 vgdev->has_context_init ? '+' : '-');
 
-       ret = virtio_find_vqs(vgdev->vdev, 2, vqs, vqs_info, NULL);
+       ret = virtio_gpu_find_vqs(vgdev);
        if (ret) {
                DRM_ERROR("failed to find virt queues\n");
                goto err_vqs;
        }
-       vgdev->ctrlq.vq = vqs[0];
-       vgdev->cursorq.vq = vqs[1];
        ret = virtio_gpu_alloc_vbufs(vgdev);
        if (ret) {
                DRM_ERROR("failed to alloc vbufs\n");
-- 
2.34.1

Reply via email to