Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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/

Rob Clark 471920ce 9d712c50

+134
+126
drivers/gpu/drm/drm_gpuvm.c
··· 2391 2391 } 2392 2392 EXPORT_SYMBOL_GPL(drm_gpuvm_sm_unmap); 2393 2393 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 + 2394 2520 static struct drm_gpuva_op * 2395 2521 gpuva_op_alloc(struct drm_gpuvm *gpuvm) 2396 2522 {
+8
include/drm/drm_gpuvm.h
··· 1211 1211 int drm_gpuvm_sm_unmap(struct drm_gpuvm *gpuvm, void *priv, 1212 1212 u64 addr, u64 range); 1213 1213 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 + 1214 1222 void drm_gpuva_map(struct drm_gpuvm *gpuvm, 1215 1223 struct drm_gpuva *va, 1216 1224 struct drm_gpuva_op_map *op);