mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 15:07:32 -04:00
The drm_exec component uses a variable with scope limited to the for() and
an indirect goto to allow instantiating multiple macros in the same
function.
This unfortunately doesn't work well with certain compilers when the
indirect goto can't be lowered to a direct jump.
Switch the indirect goto to a direct goto, the drawback is that we now
can't use the dma_exec_until_all_locked() macro in the same function
multiple times.
The is currently only one user of this and only as a hacky workaround
which is about to be removed.
So document that the __label__ statement should be used when the macro is
used multiple times and fix the tests and the only use case where that is
necessary.
Suggested-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Christian König <christian.koenig@amd.com>
Fixes: 9920249a52 ("drm/amdgpu: convert amdgpu_vm_lock_by_pasid() to drm_exec")
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202606231854.7LeCtlLe-lkp@intel.com/
Closes: https://lore.kernel.org/oe-kbuild-all/202606232356.gwHMAJAW-lkp@intel.com/
Closes: https://lore.kernel.org/oe-kbuild-all/202606240753.kYjobJVl-lkp@intel.com/
Closes: https://lore.kernel.org/oe-kbuild-all/202606241110.iUga5vVw-lkp@intel.com/
Closes: https://lore.kernel.org/oe-kbuild-all/202607031446.1PWG18mN-lkp@intel.com/
Closes: https://lore.kernel.org/oe-kbuild-all/202607031837.HSmBj8pr-lkp@intel.com/
Closes: https://lore.kernel.org/oe-kbuild-all/202607040159.GopyEswS-lkp@intel.com/
Tested-by: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
Reviewed-by: Dave Airlie <airlied@redhat.com>
Link: https://lore.kernel.org/r/20260704084133.122053-1-christian.koenig@amd.com
190 lines
5.6 KiB
C
190 lines
5.6 KiB
C
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
|
|
|
|
#ifndef __DRM_EXEC_H__
|
|
#define __DRM_EXEC_H__
|
|
|
|
#include <linux/compiler.h>
|
|
#include <linux/ww_mutex.h>
|
|
|
|
#define DRM_EXEC_INTERRUPTIBLE_WAIT BIT(0)
|
|
#define DRM_EXEC_IGNORE_DUPLICATES BIT(1)
|
|
|
|
/*
|
|
* Dummy value used to initially enter the retry loop.
|
|
* internal use only.
|
|
*/
|
|
#define DRM_EXEC_DUMMY ((void *)~0)
|
|
|
|
struct drm_gem_object;
|
|
|
|
/**
|
|
* struct drm_exec - Execution context
|
|
*/
|
|
struct drm_exec {
|
|
/**
|
|
* @flags: Flags to control locking behavior
|
|
*/
|
|
u32 flags;
|
|
|
|
/**
|
|
* @ticket: WW ticket used for acquiring locks
|
|
*/
|
|
struct ww_acquire_ctx ticket;
|
|
|
|
/**
|
|
* @num_objects: number of objects locked
|
|
*/
|
|
unsigned int num_objects;
|
|
|
|
/**
|
|
* @max_objects: maximum objects in array
|
|
*/
|
|
unsigned int max_objects;
|
|
|
|
/**
|
|
* @objects: array of the locked objects
|
|
*/
|
|
struct drm_gem_object **objects;
|
|
|
|
/**
|
|
* @contended: contended GEM object we backed off for
|
|
*/
|
|
struct drm_gem_object *contended;
|
|
|
|
/**
|
|
* @prelocked: already locked GEM object due to contention
|
|
*/
|
|
struct drm_gem_object *prelocked;
|
|
};
|
|
|
|
/**
|
|
* drm_exec_obj() - Return the object for a give drm_exec index
|
|
* @exec: Pointer to the drm_exec context
|
|
* @index: The index.
|
|
*
|
|
* Return: Pointer to the locked object corresponding to @index if
|
|
* index is within the number of locked objects. NULL otherwise.
|
|
*/
|
|
static inline struct drm_gem_object *
|
|
drm_exec_obj(struct drm_exec *exec, unsigned long index)
|
|
{
|
|
return index < exec->num_objects ? exec->objects[index] : NULL;
|
|
}
|
|
|
|
/* Helper for drm_exec_for_each_locked_object(). Internal use only. */
|
|
#define __drm_exec_for_each_locked_object(exec, obj, __index) \
|
|
for (unsigned long __index = 0; ((obj) = drm_exec_obj(exec, __index)); ++__index)
|
|
/**
|
|
* drm_exec_for_each_locked_object - iterate over all the locked objects
|
|
* @exec: drm_exec object
|
|
* @obj: the current GEM object
|
|
*
|
|
* Iterate over all the locked GEM objects inside the drm_exec object.
|
|
*/
|
|
#define drm_exec_for_each_locked_object(exec, obj) \
|
|
__drm_exec_for_each_locked_object(exec, obj, __UNIQUE_ID(drm_exec))
|
|
|
|
/* Helper for drm_exec_for_each_locked_object_reverse(). Internal use only. */
|
|
#define __drm_exec_for_each_locked_object_reverse(exec, obj, __index) \
|
|
for (unsigned long __index = (exec)->num_objects - 1; \
|
|
((obj) = drm_exec_obj(exec, __index)); --__index)
|
|
/**
|
|
* drm_exec_for_each_locked_object_reverse - iterate over all the locked
|
|
* objects in reverse locking order
|
|
* @exec: drm_exec object
|
|
* @obj: the current GEM object
|
|
*
|
|
* Iterate over all the locked GEM objects inside the drm_exec object in
|
|
* reverse locking order. Note that the internal index may wrap around,
|
|
* but that will be caught by drm_exec_obj(), returning a NULL object.
|
|
*/
|
|
#define drm_exec_for_each_locked_object_reverse(exec, obj) \
|
|
__drm_exec_for_each_locked_object_reverse(exec, obj, __UNIQUE_ID(drm_exec))
|
|
|
|
/**
|
|
* drm_exec_until_all_locked - loop until all GEM objects are locked
|
|
* @exec: drm_exec object
|
|
*
|
|
* Core functionality of the drm_exec object. Loops until all GEM objects are
|
|
* locked and no more contention exists. At the beginning of the loop it is
|
|
* guaranteed that no GEM object is locked.
|
|
*
|
|
* A global label name drm_exec_retry is used, if you need to use more than one
|
|
* instance of this macro in the same function the label needs to be made local
|
|
* to the block with the __label__ keyword.
|
|
*/
|
|
#define drm_exec_until_all_locked(exec) \
|
|
for (bool const __maybe_unused __drm_exec_loop = false; \
|
|
drm_exec_cleanup(exec);) \
|
|
if (false) { \
|
|
drm_exec_retry: __maybe_unused; \
|
|
continue; \
|
|
} else
|
|
|
|
/**
|
|
* drm_exec_retry_on_contention - restart the loop to grap all locks
|
|
* @exec: drm_exec object
|
|
*
|
|
* Control flow helper to continue when a contention was detected and we need to
|
|
* clean up and re-start the loop to prepare all GEM objects.
|
|
* The __drm_exec_loop check exists to prevent usage outside of an
|
|
* drm_exec_until_all_locked() loop.
|
|
*/
|
|
#define drm_exec_retry_on_contention(exec) \
|
|
do { \
|
|
if (unlikely(drm_exec_is_contended(exec))) \
|
|
goto drm_exec_retry; \
|
|
} while (__drm_exec_loop)
|
|
|
|
/**
|
|
* drm_exec_is_contended - check for contention
|
|
* @exec: drm_exec object
|
|
*
|
|
* Returns true if the drm_exec object has run into some contention while
|
|
* locking a GEM object and needs to clean up.
|
|
*/
|
|
static inline bool drm_exec_is_contended(struct drm_exec *exec)
|
|
{
|
|
return !!exec->contended;
|
|
}
|
|
|
|
/**
|
|
* drm_exec_retry() - Unconditionally restart the loop to grab all locks.
|
|
* @exec: drm_exec object
|
|
*
|
|
* Unconditionally retry the loop to lock all objects. For consistency,
|
|
* the exec object needs to be newly initialized.
|
|
* The __drm_exec_loop check exists to prevent usage outside of an
|
|
* drm_exec_until_all_locked() loop.
|
|
*/
|
|
#define drm_exec_retry(_exec) \
|
|
do { \
|
|
WARN_ON((_exec)->contended != DRM_EXEC_DUMMY); \
|
|
goto drm_exec_retry; \
|
|
} while (__drm_exec_loop)
|
|
|
|
/**
|
|
* drm_exec_ticket - return the ww_acquire_ctx for this exec context
|
|
* @exec: drm_exec object
|
|
*
|
|
* Return: Pointer to the ww_acquire_ctx embedded in @exec.
|
|
*/
|
|
static inline struct ww_acquire_ctx *drm_exec_ticket(struct drm_exec *exec)
|
|
{
|
|
return &exec->ticket;
|
|
}
|
|
|
|
void drm_exec_init(struct drm_exec *exec, u32 flags, unsigned nr);
|
|
void drm_exec_fini(struct drm_exec *exec);
|
|
bool drm_exec_cleanup(struct drm_exec *exec);
|
|
int drm_exec_lock_obj(struct drm_exec *exec, struct drm_gem_object *obj);
|
|
void drm_exec_unlock_obj(struct drm_exec *exec, struct drm_gem_object *obj);
|
|
int drm_exec_prepare_obj(struct drm_exec *exec, struct drm_gem_object *obj,
|
|
unsigned int num_fences);
|
|
int drm_exec_prepare_array(struct drm_exec *exec,
|
|
struct drm_gem_object **objects,
|
|
unsigned int num_objects,
|
|
unsigned int num_fences);
|
|
|
|
#endif
|