The TTM eviction path has some additional requirements which make it necessary to trylock an object and then eventually keep or drop the lock again. Signed-off-by: Christian König <christian.koenig@xxxxxxx> --- drivers/gpu/drm/drm_exec.c | 77 ++++++++++++++++++++++++++++++++++++++ include/drm/drm_exec.h | 5 +++ 2 files changed, 82 insertions(+) diff --git a/drivers/gpu/drm/drm_exec.c b/drivers/gpu/drm/drm_exec.c index 220df336fbd9..b81bf5a92d97 100644 --- a/drivers/gpu/drm/drm_exec.c +++ b/drivers/gpu/drm/drm_exec.c @@ -336,5 +336,82 @@ int drm_exec_prepare_array(struct drm_exec *exec, } EXPORT_SYMBOL(drm_exec_prepare_array); +/** + * drm_exec_trylock_obj - try to lock a GEM object + * @exec: the drm_exec object with the state + * @obj: the GEM object to trylock + * + * Try to lock a GEM object but don't grab a reference yet. + * + * Since we can't handle contention here it's illegal to trylock the first + * object. + * + * This function is suposed to be used from atomic context and we don't + * know if the GEM object will actually be used or not. So we don't grab a + * reference yet. + * + * Returns: True if the object could be locked, false otherwise. + */ +bool drm_exec_trylock_obj(struct drm_exec *exec, struct drm_gem_object *obj) +{ + if (WARN_ON(!exec->num_objects)) + return false; + + if (exec->prelocked == obj) + return true; + + return dma_resv_trylock_ctx(obj->resv, &exec->ticket); +} +EXPORT_SYMBOL(drm_exec_trylock_obj); + +/** + * drm_exec_keep_trylocked_obj - keep the trylocked obj + * @exec: the drm_exec object with the state + * @obj: the GEM object to trylock + * + * Keep a trylocked object in the drm_exec state object. Grabs a reference to + * the object and adds it to the container of locked objects. + */ +int drm_exec_keep_trylocked_obj(struct drm_exec *exec, + struct drm_gem_object *obj) +{ + int ret; + + ret = drm_exec_obj_locked(exec, obj); + if (ret) { + dma_resv_unlock(obj->resv); + return ret; + } + + if (exec->prelocked == obj) { + drm_gem_object_put(exec->prelocked); + exec->prelocked = NULL; + } + + return ret; +} +EXPORT_SYMBOL(drm_exec_keep_trylocked_obj); + +/** + * drm_exec_drop_trylocked_obj - drop the trylocked obj + * @exec: the drm_exec object with the state + * @obj: the GEM object to trylock + * + * Used to drop a trylocked object in the drm_exec state object, drop the + * reservation lock again and cleanup all references. + */ +void drm_exec_drop_trylocked_obj(struct drm_exec *exec, + struct drm_gem_object *obj) +{ + /* + * We can't drop the reference of prelocked objects since we might still + * be in atomic context. Additionally it makes sense to keep the + * prelocked object around since we might need it again later on. + */ + if (exec->prelocked != obj) + dma_resv_unlock(obj->resv); +} +EXPORT_SYMBOL(drm_exec_drop_trylocked_obj); + MODULE_DESCRIPTION("DRM execution context"); MODULE_LICENSE("Dual MIT/GPL"); diff --git a/include/drm/drm_exec.h b/include/drm/drm_exec.h index aa786b828a0a..a3943057a3e8 100644 --- a/include/drm/drm_exec.h +++ b/include/drm/drm_exec.h @@ -146,5 +146,10 @@ int drm_exec_prepare_array(struct drm_exec *exec, struct drm_gem_object **objects, unsigned int num_objects, unsigned int num_fences); +bool drm_exec_trylock_obj(struct drm_exec *exec, struct drm_gem_object *obj); +int drm_exec_keep_trylocked_obj(struct drm_exec *exec, + struct drm_gem_object *obj); +void drm_exec_drop_trylocked_obj(struct drm_exec *exec, + struct drm_gem_object *obj); #endif -- 2.34.1