On 9/24/25 22:47, [email protected] wrote:
> From: Dongwon Kim <[email protected]>
> 
> Implementing functions for .freeze and .restore hooks for virtio-gpu driver
> Just like other virtio-devices, all virtio gueues are removed then recreated
> during suspend/hiberation and resume cycle.
> 
> v2: 10ms sleep was added in virtgpu_freeze to avoid the situation
>     the driver is locked up during resumption.
> 
> v3: Plain 10ms delay was replaced with wait calls which wait until
>     the virtio queue is empty.
>     (Dmitry Osipenko)
> 
> Suggested-by: Dmitry Osipenko <[email protected]>
> Cc: Vivek Kasireddy <[email protected]>
> Signed-off-by: Dongwon Kim <[email protected]>
> ---
>  drivers/gpu/drm/virtio/virtgpu_drv.c | 60 +++++++++++++++++++++++++++-
>  drivers/gpu/drm/virtio/virtgpu_drv.h |  1 +
>  drivers/gpu/drm/virtio/virtgpu_kms.c | 23 ++++++++---
>  3 files changed, 77 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c 
> b/drivers/gpu/drm/virtio/virtgpu_drv.c
> index 71c6ccad4b99..676893e90a9f 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)
> 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 1c15cbf326b7..cbebe19c3fb3 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");

Tested-by: Dmitry Osipenko <[email protected]>

-- 
Best regards,
Dmitry

Reply via email to