Skip to content

Commit 471920c

Browse files
author
Rob Clark
committed
drm/gpuvm: Add locking helpers
For UNMAP/REMAP steps we could be needing to lock objects that are not explicitly listed in the VM_BIND ioctl in order to tear-down unmapped VAs. These helpers handle locking/preparing the needed objects. Note that these functions do not strictly require the VM changes to be applied before the next drm_gpuvm_sm_map_lock()/_unmap_lock() call. In the case that VM changes from an earlier drm_gpuvm_sm_map()/_unmap() call result in a differing sequence of steps when the VM changes are actually applied, it will be the same set of GEM objects involved, so the locking is still correct. v2: Rename to drm_gpuvm_sm_*_exec_locked() [Danilo] v3: Expand comments to show expected usage, and explain how the usage is safe in the case of overlapping driver VM_BIND ops. Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com> Tested-by: Antonino Maniscalco <antomani103@gmail.com> Reviewed-by: Antonino Maniscalco <antomani103@gmail.com> Acked-by: Danilo Krummrich <dakr@kernel.org> Patchwork: https://patchwork.freedesktop.org/patch/661458/
1 parent 9d712c5 commit 471920c

File tree

2 files changed

+134
-0
lines changed

2 files changed

+134
-0
lines changed

drivers/gpu/drm/drm_gpuvm.c

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2391,6 +2391,132 @@ drm_gpuvm_sm_unmap(struct drm_gpuvm *gpuvm, void *priv,
23912391
}
23922392
EXPORT_SYMBOL_GPL(drm_gpuvm_sm_unmap);
23932393

2394+
static int
2395+
drm_gpuva_sm_step_lock(struct drm_gpuva_op *op, void *priv)
2396+
{
2397+
struct drm_exec *exec = priv;
2398+
2399+
switch (op->op) {
2400+
case DRM_GPUVA_OP_REMAP:
2401+
if (op->remap.unmap->va->gem.obj)
2402+
return drm_exec_lock_obj(exec, op->remap.unmap->va->gem.obj);
2403+
return 0;
2404+
case DRM_GPUVA_OP_UNMAP:
2405+
if (op->unmap.va->gem.obj)
2406+
return drm_exec_lock_obj(exec, op->unmap.va->gem.obj);
2407+
return 0;
2408+
default:
2409+
return 0;
2410+
}
2411+
}
2412+
2413+
static const struct drm_gpuvm_ops lock_ops = {
2414+
.sm_step_map = drm_gpuva_sm_step_lock,
2415+
.sm_step_remap = drm_gpuva_sm_step_lock,
2416+
.sm_step_unmap = drm_gpuva_sm_step_lock,
2417+
};
2418+
2419+
/**
2420+
* drm_gpuvm_sm_map_exec_lock() - locks the objects touched by a drm_gpuvm_sm_map()
2421+
* @gpuvm: the &drm_gpuvm representing the GPU VA space
2422+
* @exec: the &drm_exec locking context
2423+
* @num_fences: for newly mapped objects, the # of fences to reserve
2424+
* @req_addr: the start address of the range to unmap
2425+
* @req_range: the range of the mappings to unmap
2426+
* @req_obj: the &drm_gem_object to map
2427+
* @req_offset: the offset within the &drm_gem_object
2428+
*
2429+
* This function locks (drm_exec_lock_obj()) objects that will be unmapped/
2430+
* remapped, and locks+prepares (drm_exec_prepare_object()) objects that
2431+
* will be newly mapped.
2432+
*
2433+
* The expected usage is:
2434+
*
2435+
* vm_bind {
2436+
* struct drm_exec exec;
2437+
*
2438+
* // IGNORE_DUPLICATES is required, INTERRUPTIBLE_WAIT is recommended:
2439+
* drm_exec_init(&exec, IGNORE_DUPLICATES | INTERRUPTIBLE_WAIT, 0);
2440+
*
2441+
* drm_exec_until_all_locked (&exec) {
2442+
* for_each_vm_bind_operation {
2443+
* switch (op->op) {
2444+
* case DRIVER_OP_UNMAP:
2445+
* ret = drm_gpuvm_sm_unmap_exec_lock(gpuvm, &exec, op->addr, op->range);
2446+
* break;
2447+
* case DRIVER_OP_MAP:
2448+
* ret = drm_gpuvm_sm_map_exec_lock(gpuvm, &exec, num_fences,
2449+
* op->addr, op->range,
2450+
* obj, op->obj_offset);
2451+
* break;
2452+
* }
2453+
*
2454+
* drm_exec_retry_on_contention(&exec);
2455+
* if (ret)
2456+
* return ret;
2457+
* }
2458+
* }
2459+
* }
2460+
*
2461+
* This enables all locking to be performed before the driver begins modifying
2462+
* the VM. This is safe to do in the case of overlapping DRIVER_VM_BIND_OPs,
2463+
* where an earlier op can alter the sequence of steps generated for a later
2464+
* op, because the later altered step will involve the same GEM object(s)
2465+
* already seen in the earlier locking step. For example:
2466+
*
2467+
* 1) An earlier driver DRIVER_OP_UNMAP op removes the need for a
2468+
* DRM_GPUVA_OP_REMAP/UNMAP step. This is safe because we've already
2469+
* locked the GEM object in the earlier DRIVER_OP_UNMAP op.
2470+
*
2471+
* 2) An earlier DRIVER_OP_MAP op overlaps with a later DRIVER_OP_MAP/UNMAP
2472+
* op, introducing a DRM_GPUVA_OP_REMAP/UNMAP that wouldn't have been
2473+
* required without the earlier DRIVER_OP_MAP. This is safe because we've
2474+
* already locked the GEM object in the earlier DRIVER_OP_MAP step.
2475+
*
2476+
* Returns: 0 on success or a negative error codec
2477+
*/
2478+
int
2479+
drm_gpuvm_sm_map_exec_lock(struct drm_gpuvm *gpuvm,
2480+
struct drm_exec *exec, unsigned int num_fences,
2481+
u64 req_addr, u64 req_range,
2482+
struct drm_gem_object *req_obj, u64 req_offset)
2483+
{
2484+
if (req_obj) {
2485+
int ret = drm_exec_prepare_obj(exec, req_obj, num_fences);
2486+
if (ret)
2487+
return ret;
2488+
}
2489+
2490+
return __drm_gpuvm_sm_map(gpuvm, &lock_ops, exec,
2491+
req_addr, req_range,
2492+
req_obj, req_offset);
2493+
2494+
}
2495+
EXPORT_SYMBOL_GPL(drm_gpuvm_sm_map_exec_lock);
2496+
2497+
/**
2498+
* drm_gpuvm_sm_unmap_exec_lock() - locks the objects touched by drm_gpuvm_sm_unmap()
2499+
* @gpuvm: the &drm_gpuvm representing the GPU VA space
2500+
* @exec: the &drm_exec locking context
2501+
* @req_addr: the start address of the range to unmap
2502+
* @req_range: the range of the mappings to unmap
2503+
*
2504+
* This function locks (drm_exec_lock_obj()) objects that will be unmapped/
2505+
* remapped by drm_gpuvm_sm_unmap().
2506+
*
2507+
* See drm_gpuvm_sm_map_exec_lock() for expected usage.
2508+
*
2509+
* Returns: 0 on success or a negative error code
2510+
*/
2511+
int
2512+
drm_gpuvm_sm_unmap_exec_lock(struct drm_gpuvm *gpuvm, struct drm_exec *exec,
2513+
u64 req_addr, u64 req_range)
2514+
{
2515+
return __drm_gpuvm_sm_unmap(gpuvm, &lock_ops, exec,
2516+
req_addr, req_range);
2517+
}
2518+
EXPORT_SYMBOL_GPL(drm_gpuvm_sm_unmap_exec_lock);
2519+
23942520
static struct drm_gpuva_op *
23952521
gpuva_op_alloc(struct drm_gpuvm *gpuvm)
23962522
{

include/drm/drm_gpuvm.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,6 +1211,14 @@ int drm_gpuvm_sm_map(struct drm_gpuvm *gpuvm, void *priv,
12111211
int drm_gpuvm_sm_unmap(struct drm_gpuvm *gpuvm, void *priv,
12121212
u64 addr, u64 range);
12131213

1214+
int drm_gpuvm_sm_map_exec_lock(struct drm_gpuvm *gpuvm,
1215+
struct drm_exec *exec, unsigned int num_fences,
1216+
u64 req_addr, u64 req_range,
1217+
struct drm_gem_object *obj, u64 offset);
1218+
1219+
int drm_gpuvm_sm_unmap_exec_lock(struct drm_gpuvm *gpuvm, struct drm_exec *exec,
1220+
u64 req_addr, u64 req_range);
1221+
12141222
void drm_gpuva_map(struct drm_gpuvm *gpuvm,
12151223
struct drm_gpuva *va,
12161224
struct drm_gpuva_op_map *op);

0 commit comments

Comments
 (0)