diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index 7e15ce02fad0..c91ef4255d66 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -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); diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c index 82baf1b3717e..9601f310875d 100644 --- a/drivers/gpu/drm/virtio/virtgpu_kms.c +++ b/drivers/gpu/drm/virtio/virtgpu_kms.c @@ -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) diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c index ec9efacc6919..3545831c5a54 100644 --- a/drivers/gpu/drm/virtio/virtgpu_object.c +++ b/drivers/gpu/drm/virtio/virtgpu_object.c @@ -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; +} diff --git a/drivers/gpu/drm/virtio/virtgpu_prime.c b/drivers/gpu/drm/virtio/virtgpu_prime.c index 70b3b836e1c9..6611b21f6e7e 100644 --- a/drivers/gpu/drm/virtio/virtgpu_prime.c +++ b/drivers/gpu/drm/virtio/virtgpu_prime.c @@ -23,6 +23,7 @@ */ #include +#include #include #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; diff --git a/drivers/gpu/drm/virtio/virtgpu_vram.c b/drivers/gpu/drm/virtio/virtgpu_vram.c index 4ae3cbc35dd3..9ad11c7f1194 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vram.c +++ b/drivers/gpu/drm/virtio/virtgpu_vram.c @@ -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);