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
