mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
drm/virtio: Add support for saving and restoring virtio_gpu_objects
When the host KVM/QEMU resumes from hibernation, it loses all graphics resources previously submitted by the guest OS, as the QEMU process is terminated during the suspend-resume cycle. This leads to invalid resource errors when the guest OS attempts to interact with the host using those resources after resumption. To resolve this, the virtio-gpu driver now tracks all active virtio_gpu_objects and provides a mechanism to restore them by re-submitting the objects to QEMU when needed (e.g., during resume from hibernation). Cc: Dmitry Osipenko <dmitry.osipenko@collabora.com> Cc: Vivek Kasireddy <vivek.kasireddy@intel.com> Cc: Nirmoy Das <nirmoyd@nvidia.com> Signed-off-by: Dongwon Kim <dongwon.kim@intel.com> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com> Link: https://patch.msgid.link/20260526192814.179673-3-dongwon.kim@intel.com [dmitry.osipenko@collabora.com: remove extra blank line] [dmitry.osipenko@collabora.com: move err msg to virtio_gpu_object_restore_all]
This commit is contained in:
parent
cad6a879a7
commit
54a9700482
|
|
@ -99,6 +99,10 @@ struct virtio_gpu_object {
|
|||
|
||||
int uuid_state;
|
||||
uuid_t uuid;
|
||||
|
||||
/* for restoration of objects after hibernation */
|
||||
struct virtio_gpu_object_params params;
|
||||
struct list_head restore_node;
|
||||
};
|
||||
#define gem_to_virtio_gpu_obj(gobj) \
|
||||
container_of((gobj), struct virtio_gpu_object, base.base)
|
||||
|
|
@ -267,6 +271,8 @@ struct virtio_gpu_device {
|
|||
struct work_struct obj_free_work;
|
||||
spinlock_t obj_free_lock;
|
||||
struct list_head obj_free_list;
|
||||
struct mutex obj_restore_lock;
|
||||
struct list_head obj_restore_list;
|
||||
|
||||
struct virtio_gpu_drv_capset *capsets;
|
||||
uint32_t num_capsets;
|
||||
|
|
@ -472,6 +478,7 @@ void virtio_gpu_fence_event_process(struct virtio_gpu_device *vdev,
|
|||
u64 fence_id);
|
||||
|
||||
/* virtgpu_object.c */
|
||||
void virtio_gpu_remove_from_restore_list(struct virtio_gpu_object *bo);
|
||||
void virtio_gpu_cleanup_object(struct virtio_gpu_object *bo);
|
||||
struct drm_gem_object *virtio_gpu_create_object(struct drm_device *dev,
|
||||
size_t size);
|
||||
|
|
@ -484,6 +491,12 @@ bool virtio_gpu_is_shmem(struct virtio_gpu_object *bo);
|
|||
|
||||
int virtio_gpu_resource_id_get(struct virtio_gpu_device *vgdev,
|
||||
uint32_t *resid);
|
||||
|
||||
void virtio_gpu_add_object_to_restore_list(struct virtio_gpu_device *vgdev,
|
||||
struct virtio_gpu_object *bo);
|
||||
|
||||
int virtio_gpu_object_restore_all(struct virtio_gpu_device *vgdev);
|
||||
|
||||
/* virtgpu_prime.c */
|
||||
int virtio_gpu_resource_assign_uuid(struct virtio_gpu_device *vgdev,
|
||||
struct virtio_gpu_object *bo);
|
||||
|
|
@ -498,6 +511,8 @@ int virtgpu_dma_buf_import_sgt(struct virtio_gpu_mem_entry **ents,
|
|||
unsigned int *nents,
|
||||
struct virtio_gpu_object *bo,
|
||||
struct dma_buf_attachment *attach);
|
||||
int virtgpu_dma_buf_obj_resubmit(struct virtio_gpu_device *vgdev,
|
||||
struct virtio_gpu_object *bo);
|
||||
|
||||
/* virtgpu_debugfs.c */
|
||||
void virtio_gpu_debugfs_init(struct drm_minor *minor);
|
||||
|
|
|
|||
|
|
@ -171,6 +171,8 @@ int virtio_gpu_init(struct virtio_device *vdev, struct drm_device *dev)
|
|||
virtio_gpu_array_put_free_work);
|
||||
INIT_LIST_HEAD(&vgdev->obj_free_list);
|
||||
spin_lock_init(&vgdev->obj_free_lock);
|
||||
INIT_LIST_HEAD(&vgdev->obj_restore_list);
|
||||
mutex_init(&vgdev->obj_restore_lock);
|
||||
|
||||
#ifdef __LITTLE_ENDIAN
|
||||
if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_VIRGL))
|
||||
|
|
@ -307,6 +309,7 @@ void virtio_gpu_deinit(struct drm_device *dev)
|
|||
flush_work(&vgdev->config_changed_work);
|
||||
virtio_reset_device(vgdev->vdev);
|
||||
vgdev->vdev->config->del_vqs(vgdev->vdev);
|
||||
mutex_destroy(&vgdev->obj_restore_lock);
|
||||
}
|
||||
|
||||
void virtio_gpu_release(struct drm_device *dev)
|
||||
|
|
|
|||
|
|
@ -63,6 +63,15 @@ static void virtio_gpu_resource_id_put(struct virtio_gpu_device *vgdev, uint32_t
|
|||
ida_free(&vgdev->resource_ida, id - 1);
|
||||
}
|
||||
|
||||
void virtio_gpu_remove_from_restore_list(struct virtio_gpu_object *bo)
|
||||
{
|
||||
struct virtio_gpu_device *vgdev = bo->base.base.dev->dev_private;
|
||||
|
||||
mutex_lock(&vgdev->obj_restore_lock);
|
||||
list_del_init(&bo->restore_node);
|
||||
mutex_unlock(&vgdev->obj_restore_lock);
|
||||
}
|
||||
|
||||
void virtio_gpu_cleanup_object(struct virtio_gpu_object *bo)
|
||||
{
|
||||
struct virtio_gpu_device *vgdev = bo->base.base.dev->dev_private;
|
||||
|
|
@ -94,6 +103,7 @@ static void virtio_gpu_free_object(struct drm_gem_object *obj)
|
|||
struct virtio_gpu_device *vgdev = bo->base.base.dev->dev_private;
|
||||
|
||||
if (bo->created) {
|
||||
virtio_gpu_remove_from_restore_list(bo);
|
||||
virtio_gpu_cmd_unref_resource(vgdev, bo);
|
||||
virtio_gpu_notify(vgdev);
|
||||
/* completion handler calls virtio_gpu_cleanup_object() */
|
||||
|
|
@ -220,6 +230,8 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev,
|
|||
return PTR_ERR(shmem_obj);
|
||||
bo = gem_to_virtio_gpu_obj(&shmem_obj->base);
|
||||
|
||||
INIT_LIST_HEAD(&bo->restore_node);
|
||||
|
||||
ret = virtio_gpu_resource_id_get(vgdev, &bo->hw_res_handle);
|
||||
if (ret < 0)
|
||||
goto err_free_gem;
|
||||
|
|
@ -258,6 +270,12 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev,
|
|||
virtio_gpu_object_attach(vgdev, bo, ents, nents);
|
||||
}
|
||||
|
||||
if (!params->virgl) {
|
||||
/* store non-virgl object with its param to the restore list */
|
||||
bo->params = *params;
|
||||
virtio_gpu_add_object_to_restore_list(vgdev, bo);
|
||||
}
|
||||
|
||||
*bo_ptr = bo;
|
||||
return 0;
|
||||
|
||||
|
|
@ -271,3 +289,58 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev,
|
|||
drm_gem_shmem_free(shmem_obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void virtio_gpu_add_object_to_restore_list(struct virtio_gpu_device *vgdev,
|
||||
struct virtio_gpu_object *bo)
|
||||
{
|
||||
mutex_lock(&vgdev->obj_restore_lock);
|
||||
list_add_tail(&bo->restore_node, &vgdev->obj_restore_list);
|
||||
mutex_unlock(&vgdev->obj_restore_lock);
|
||||
}
|
||||
|
||||
int virtio_gpu_object_restore_all(struct virtio_gpu_device *vgdev)
|
||||
{
|
||||
struct virtio_gpu_object *bo, *tmp;
|
||||
struct virtio_gpu_mem_entry *ents;
|
||||
unsigned int nents;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&vgdev->obj_restore_lock);
|
||||
list_for_each_entry_safe(bo, tmp, &vgdev->obj_restore_list,
|
||||
restore_node) {
|
||||
if (drm_gem_is_imported(&bo->base.base)) {
|
||||
ret = virtgpu_dma_buf_obj_resubmit(vgdev, bo);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bo->params.blob || bo->attached) {
|
||||
ret = virtio_gpu_object_shmem_init(vgdev, bo, &ents,
|
||||
&nents);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
if (bo->params.blob) {
|
||||
virtio_gpu_cmd_resource_create_blob(vgdev, bo,
|
||||
&bo->params,
|
||||
ents, nents);
|
||||
} else {
|
||||
virtio_gpu_cmd_create_resource(vgdev, bo, &bo->params,
|
||||
NULL, NULL);
|
||||
if (bo->attached) {
|
||||
bo->attached = false;
|
||||
virtio_gpu_object_attach(vgdev, bo, ents,
|
||||
nents);
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&vgdev->obj_restore_lock);
|
||||
|
||||
if (ret)
|
||||
DRM_ERROR("failed to restore virtio-gpu objects: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
|
||||
#include <drm/drm_prime.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <linux/virtio_dma_buf.h>
|
||||
|
||||
#include "virtgpu_drv.h"
|
||||
|
|
@ -216,6 +217,7 @@ static void virtgpu_dma_buf_free_obj(struct drm_gem_object *obj)
|
|||
}
|
||||
|
||||
if (bo->created) {
|
||||
virtio_gpu_remove_from_restore_list(bo);
|
||||
virtio_gpu_cmd_unref_resource(vgdev, bo);
|
||||
virtio_gpu_notify(vgdev);
|
||||
return;
|
||||
|
|
@ -262,6 +264,13 @@ static int virtgpu_dma_buf_init_obj(struct drm_device *dev,
|
|||
dma_buf_unpin(attach);
|
||||
dma_resv_unlock(resv);
|
||||
|
||||
/*
|
||||
* Store the dmabuf imported object with its params to the
|
||||
* restore list.
|
||||
*/
|
||||
bo->params = params;
|
||||
virtio_gpu_add_object_to_restore_list(vgdev, bo);
|
||||
|
||||
return 0;
|
||||
|
||||
err_import:
|
||||
|
|
@ -272,6 +281,38 @@ static int virtgpu_dma_buf_init_obj(struct drm_device *dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int virtgpu_dma_buf_obj_resubmit(struct virtio_gpu_device *vgdev,
|
||||
struct virtio_gpu_object *bo)
|
||||
{
|
||||
struct virtio_gpu_mem_entry *ents;
|
||||
struct scatterlist *sl;
|
||||
int i;
|
||||
|
||||
if (!bo->sgt) {
|
||||
DRM_ERROR("no sgt bound to virtio_gpu_object\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ents = kvmalloc_array(bo->sgt->nents,
|
||||
sizeof(struct virtio_gpu_mem_entry),
|
||||
GFP_KERNEL);
|
||||
if (!ents) {
|
||||
DRM_ERROR("failed to allocate ent list\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for_each_sgtable_dma_sg(bo->sgt, sl, i) {
|
||||
ents[i].addr = cpu_to_le64(sg_dma_address(sl));
|
||||
ents[i].length = cpu_to_le32(sg_dma_len(sl));
|
||||
ents[i].padding = 0;
|
||||
}
|
||||
|
||||
virtio_gpu_cmd_resource_create_blob(vgdev, bo, &bo->params,
|
||||
ents, bo->sgt->nents);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_gem_object_funcs virtgpu_gem_dma_buf_funcs = {
|
||||
.free = virtgpu_dma_buf_free_obj,
|
||||
};
|
||||
|
|
@ -317,6 +358,8 @@ struct drm_gem_object *virtgpu_gem_prime_import(struct drm_device *dev,
|
|||
if (!bo)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
INIT_LIST_HEAD(&bo->restore_node);
|
||||
|
||||
obj = &bo->base.base;
|
||||
obj->resv = buf->resv;
|
||||
obj->funcs = &virtgpu_gem_dma_buf_funcs;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ static void virtio_gpu_vram_free(struct drm_gem_object *obj)
|
|||
if (unmap)
|
||||
virtio_gpu_cmd_unmap(vgdev, bo);
|
||||
|
||||
virtio_gpu_remove_from_restore_list(bo);
|
||||
virtio_gpu_cmd_unref_resource(vgdev, bo);
|
||||
virtio_gpu_notify(vgdev);
|
||||
return;
|
||||
|
|
@ -207,6 +208,8 @@ int virtio_gpu_vram_create(struct virtio_gpu_device *vgdev,
|
|||
obj = &vram->base.base.base;
|
||||
obj->funcs = &virtio_gpu_vram_funcs;
|
||||
|
||||
INIT_LIST_HEAD(&vram->base.restore_node);
|
||||
|
||||
params->size = PAGE_ALIGN(params->size);
|
||||
drm_gem_private_object_init(vgdev->ddev, obj, params->size);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user