diff options
Diffstat (limited to 'drivers/gpu/drm/imagination/pvr_vm.c')
-rw-r--r-- | drivers/gpu/drm/imagination/pvr_vm.c | 131 |
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); |