summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/imagination/pvr_vm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/imagination/pvr_vm.c')
-rw-r--r--drivers/gpu/drm/imagination/pvr_vm.c131
1 files changed, 58 insertions, 73 deletions
diff --git a/drivers/gpu/drm/imagination/pvr_vm.c b/drivers/gpu/drm/imagination/pvr_vm.c
index 3ad1366294b9..f42345fbe4bf 100644
--- a/drivers/gpu/drm/imagination/pvr_vm.c
+++ b/drivers/gpu/drm/imagination/pvr_vm.c
@@ -42,7 +42,7 @@ struct pvr_vm_context {
/** @mmu_ctx: The context for binding to physical memory. */
struct pvr_mmu_context *mmu_ctx;
- /** @gpuva_mgr: GPUVA manager object associated with this context. */
+ /** @gpuvm_mgr: GPUVM object associated with this context. */
struct drm_gpuvm gpuvm_mgr;
/** @lock: Global lock on this VM. */
@@ -64,6 +64,12 @@ struct pvr_vm_context {
struct drm_gem_object dummy_gem;
};
+static inline
+struct pvr_vm_context *to_pvr_vm_context(struct drm_gpuvm *gpuvm)
+{
+ return container_of(gpuvm, struct pvr_vm_context, gpuvm_mgr);
+}
+
struct pvr_vm_context *pvr_vm_context_get(struct pvr_vm_context *vm_ctx)
{
if (vm_ctx)
@@ -108,12 +114,6 @@ struct pvr_vm_gpuva {
struct drm_gpuva base;
};
-static __always_inline
-struct pvr_vm_gpuva *to_pvr_vm_gpuva(struct drm_gpuva *gpuva)
-{
- return container_of(gpuva, struct pvr_vm_gpuva, base);
-}
-
enum pvr_vm_bind_type {
PVR_VM_BIND_TYPE_MAP,
PVR_VM_BIND_TYPE_UNMAP,
@@ -224,6 +224,7 @@ pvr_vm_bind_op_map_init(struct pvr_vm_bind_op *bind_op,
struct pvr_gem_object *pvr_obj, u64 offset,
u64 device_addr, u64 size)
{
+ struct drm_gem_object *obj = gem_from_pvr_gem(pvr_obj);
const bool is_user = vm_ctx == vm_ctx->pvr_dev->kernel_vm_ctx;
const u64 pvr_obj_size = pvr_gem_object_size(pvr_obj);
struct sg_table *sgt;
@@ -238,17 +239,18 @@ pvr_vm_bind_op_map_init(struct pvr_vm_bind_op *bind_op,
return -EINVAL;
}
- if (!pvr_device_addr_and_size_are_valid(device_addr, size) ||
+ if (!pvr_device_addr_and_size_are_valid(vm_ctx, device_addr, size) ||
offset & ~PAGE_MASK || size & ~PAGE_MASK ||
offset >= pvr_obj_size || offset_plus_size > pvr_obj_size)
return -EINVAL;
bind_op->type = PVR_VM_BIND_TYPE_MAP;
- bind_op->gpuvm_bo = drm_gpuvm_bo_create(&vm_ctx->gpuvm_mgr,
- gem_from_pvr_gem(pvr_obj));
- if (!bind_op->gpuvm_bo)
- return -ENOMEM;
+ dma_resv_lock(obj->resv, NULL);
+ bind_op->gpuvm_bo = drm_gpuvm_bo_obtain(&vm_ctx->gpuvm_mgr, obj);
+ dma_resv_unlock(obj->resv);
+ if (IS_ERR(bind_op->gpuvm_bo))
+ return PTR_ERR(bind_op->gpuvm_bo);
bind_op->new_va = kzalloc(sizeof(*bind_op->new_va), GFP_KERNEL);
bind_op->prev_va = kzalloc(sizeof(*bind_op->prev_va), GFP_KERNEL);
@@ -293,7 +295,7 @@ pvr_vm_bind_op_unmap_init(struct pvr_vm_bind_op *bind_op,
{
int err;
- if (!pvr_device_addr_and_size_are_valid(device_addr, size))
+ if (!pvr_device_addr_and_size_are_valid(vm_ctx, device_addr, size))
return -EINVAL;
bind_op->type = PVR_VM_BIND_TYPE_UNMAP;
@@ -325,48 +327,6 @@ err_bind_op_fini:
return err;
}
-static int
-pvr_vm_bind_op_lock_resvs(struct drm_exec *exec, struct pvr_vm_bind_op *bind_op)
-{
- drm_exec_until_all_locked(exec) {
- struct drm_gem_object *r_obj = &bind_op->vm_ctx->dummy_gem;
- struct drm_gpuvm *gpuvm = &bind_op->vm_ctx->gpuvm_mgr;
- struct pvr_gem_object *pvr_obj = bind_op->pvr_obj;
- struct drm_gpuvm_bo *gpuvm_bo;
-
- /* Acquire lock on the vm_context's reserve object. */
- int err = drm_exec_lock_obj(exec, r_obj);
-
- drm_exec_retry_on_contention(exec);
- if (err)
- return err;
-
- /* Acquire lock on all BOs in the context. */
- list_for_each_entry(gpuvm_bo, &gpuvm->extobj.list,
- list.entry.extobj) {
- err = drm_exec_lock_obj(exec, gpuvm_bo->obj);
-
- drm_exec_retry_on_contention(exec);
- if (err)
- return err;
- }
-
- /* Unmap operations don't have an object to lock. */
- if (!pvr_obj)
- break;
-
- /* Acquire lock on the GEM being mapped. */
- err = drm_exec_lock_obj(exec,
- gem_from_pvr_gem(bind_op->pvr_obj));
-
- drm_exec_retry_on_contention(exec);
- if (err)
- return err;
- }
-
- return 0;
-}
-
/**
* pvr_vm_gpuva_map() - Insert a mapping into a memory context.
* @op: gpuva op containing the remap details.
@@ -503,6 +463,7 @@ pvr_device_addr_is_valid(u64 device_addr)
/**
* pvr_device_addr_and_size_are_valid() - Tests whether a device-virtual
* address and associated size are both valid.
+ * @vm_ctx: Target VM context.
* @device_addr: Virtual device address to test.
* @size: Size of the range based at @device_addr to test.
*
@@ -521,16 +482,18 @@ pvr_device_addr_is_valid(u64 device_addr)
* * %false otherwise.
*/
bool
-pvr_device_addr_and_size_are_valid(u64 device_addr, u64 size)
+pvr_device_addr_and_size_are_valid(struct pvr_vm_context *vm_ctx,
+ u64 device_addr, u64 size)
{
return pvr_device_addr_is_valid(device_addr) &&
+ drm_gpuvm_range_valid(&vm_ctx->gpuvm_mgr, device_addr, size) &&
size != 0 && (size & ~PVR_DEVICE_PAGE_MASK) == 0 &&
(device_addr + size <= PVR_PAGE_TABLE_ADDR_SPACE_SIZE);
}
-void pvr_gpuvm_free(struct drm_gpuvm *gpuvm)
+static void pvr_gpuvm_free(struct drm_gpuvm *gpuvm)
{
-
+ kfree(to_pvr_vm_context(gpuvm));
}
static const struct drm_gpuvm_ops pvr_vm_gpuva_ops = {
@@ -650,12 +613,11 @@ pvr_vm_context_release(struct kref *ref_count)
WARN_ON(pvr_vm_unmap(vm_ctx, vm_ctx->gpuvm_mgr.mm_start,
vm_ctx->gpuvm_mgr.mm_range));
- drm_gpuvm_put(&vm_ctx->gpuvm_mgr);
pvr_mmu_context_destroy(vm_ctx->mmu_ctx);
drm_gem_private_object_fini(&vm_ctx->dummy_gem);
mutex_destroy(&vm_ctx->lock);
- kfree(vm_ctx);
+ drm_gpuvm_put(&vm_ctx->gpuvm_mgr);
}
/**
@@ -721,6 +683,20 @@ void pvr_destroy_vm_contexts_for_file(struct pvr_file *pvr_file)
}
}
+static int
+pvr_vm_lock_extra(struct drm_gpuvm_exec *vm_exec)
+{
+ struct pvr_vm_bind_op *bind_op = vm_exec->extra.priv;
+ struct pvr_gem_object *pvr_obj = bind_op->pvr_obj;
+
+ /* Unmap operations don't have an object to lock. */
+ if (!pvr_obj)
+ return 0;
+
+ /* Acquire lock on the GEM being mapped. */
+ return drm_exec_lock_obj(&vm_exec->exec, gem_from_pvr_gem(pvr_obj));
+}
+
/**
* pvr_vm_map() - Map a section of physical memory into a section of
* device-virtual memory.
@@ -748,7 +724,15 @@ pvr_vm_map(struct pvr_vm_context *vm_ctx, struct pvr_gem_object *pvr_obj,
u64 pvr_obj_offset, u64 device_addr, u64 size)
{
struct pvr_vm_bind_op bind_op = {0};
- struct drm_exec exec;
+ struct drm_gpuvm_exec vm_exec = {
+ .vm = &vm_ctx->gpuvm_mgr,
+ .flags = DRM_EXEC_INTERRUPTIBLE_WAIT |
+ DRM_EXEC_IGNORE_DUPLICATES,
+ .extra = {
+ .fn = pvr_vm_lock_extra,
+ .priv = &bind_op,
+ },
+ };
int err = pvr_vm_bind_op_map_init(&bind_op, vm_ctx, pvr_obj,
pvr_obj_offset, device_addr,
@@ -757,18 +741,15 @@ pvr_vm_map(struct pvr_vm_context *vm_ctx, struct pvr_gem_object *pvr_obj,
if (err)
return err;
- drm_exec_init(&exec,
- DRM_EXEC_INTERRUPTIBLE_WAIT | DRM_EXEC_IGNORE_DUPLICATES);
-
pvr_gem_object_get(pvr_obj);
- err = pvr_vm_bind_op_lock_resvs(&exec, &bind_op);
+ err = drm_gpuvm_exec_lock(&vm_exec);
if (err)
goto err_cleanup;
err = pvr_vm_bind_op_exec(&bind_op);
- drm_exec_fini(&exec);
+ drm_gpuvm_exec_unlock(&vm_exec);
err_cleanup:
pvr_vm_bind_op_fini(&bind_op);
@@ -794,24 +775,28 @@ int
pvr_vm_unmap(struct pvr_vm_context *vm_ctx, u64 device_addr, u64 size)
{
struct pvr_vm_bind_op bind_op = {0};
- struct drm_exec exec;
+ struct drm_gpuvm_exec vm_exec = {
+ .vm = &vm_ctx->gpuvm_mgr,
+ .flags = DRM_EXEC_INTERRUPTIBLE_WAIT |
+ DRM_EXEC_IGNORE_DUPLICATES,
+ .extra = {
+ .fn = pvr_vm_lock_extra,
+ .priv = &bind_op,
+ },
+ };
int err = pvr_vm_bind_op_unmap_init(&bind_op, vm_ctx, device_addr,
size);
-
if (err)
return err;
- drm_exec_init(&exec,
- DRM_EXEC_INTERRUPTIBLE_WAIT | DRM_EXEC_IGNORE_DUPLICATES);
-
- err = pvr_vm_bind_op_lock_resvs(&exec, &bind_op);
+ err = drm_gpuvm_exec_lock(&vm_exec);
if (err)
goto err_cleanup;
err = pvr_vm_bind_op_exec(&bind_op);
- drm_exec_fini(&exec);
+ drm_gpuvm_exec_unlock(&vm_exec);
err_cleanup:
pvr_vm_bind_op_fini(&bind_op);