[PATCH 3/3] drm: Add DRM_MODESET_LOCK_BEGIN/END helpers
Daniel Vetter
daniel at ffwll.ch
Wed Nov 28 09:01:07 UTC 2018
On Tue, Nov 27, 2018 at 05:46:40PM -0500, Sean Paul wrote:
> From: Sean Paul <seanpaul at chromium.org>
>
> This patch adds a couple of helpers to remove the boilerplate involved
> in grabbing all of the modeset locks.
>
> I've also converted the obvious cases in drm core to use the helpers.
>
> The only remaining instance of drm_modeset_lock_all_ctx() is in
> drm_framebuffer. It's complicated by the state clear that occurs on
> deadlock. ATM, there's no way to inject code in the deadlock path with
> the helpers, so it's unfit for conversion.
>
> Cc: Daniel Vetter <daniel at ffwll.ch>
> Signed-off-by: Sean Paul <seanpaul at chromium.org>
> ---
> drivers/gpu/drm/drm_atomic_helper.c | 52 ++++++---------------------
> drivers/gpu/drm/drm_color_mgmt.c | 14 ++------
> drivers/gpu/drm/drm_crtc.c | 15 ++------
> drivers/gpu/drm/drm_plane.c | 16 ++-------
> include/drm/drm_modeset_lock.h | 54 +++++++++++++++++++++++++++++
> 5 files changed, 72 insertions(+), 79 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 15a75b9f185fa..997735eea9abc 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -3124,23 +3124,13 @@ void drm_atomic_helper_shutdown(struct drm_device *dev)
> struct drm_modeset_acquire_ctx ctx;
> int ret;
>
> - drm_modeset_acquire_init(&ctx, 0);
> - while (1) {
> - ret = drm_modeset_lock_all_ctx(dev, &ctx);
> - if (!ret)
> - ret = __drm_atomic_helper_disable_all(dev, &ctx, true);
> -
> - if (ret != -EDEADLK)
> - break;
> -
> - drm_modeset_backoff(&ctx);
> - }
> + DRM_MODESET_LOCK_ALL_BEGIN(dev, ret, ctx, 0);
>
> + ret = __drm_atomic_helper_disable_all(dev, &ctx, true);
> if (ret)
> DRM_ERROR("Disabling all crtc's during unload failed with %i\n", ret);
>
> - drm_modeset_drop_locks(&ctx);
> - drm_modeset_acquire_fini(&ctx);
> + DRM_MODESET_LOCK_ALL_END(ret, ctx);
> }
> EXPORT_SYMBOL(drm_atomic_helper_shutdown);
>
> @@ -3175,14 +3165,7 @@ struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev)
> struct drm_atomic_state *state;
> int err;
>
> - drm_modeset_acquire_init(&ctx, 0);
> -
> -retry:
> - err = drm_modeset_lock_all_ctx(dev, &ctx);
> - if (err < 0) {
> - state = ERR_PTR(err);
> - goto unlock;
> - }
> + DRM_MODESET_LOCK_ALL_BEGIN(dev, err, ctx, 0);
>
> state = drm_atomic_helper_duplicate_state(dev, &ctx);
> if (IS_ERR(state))
> @@ -3191,18 +3174,14 @@ struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev)
> err = drm_atomic_helper_disable_all(dev, &ctx);
> if (err < 0) {
> drm_atomic_state_put(state);
> - state = ERR_PTR(err);
> goto unlock;
> }
>
> unlock:
> - if (PTR_ERR(state) == -EDEADLK) {
> - drm_modeset_backoff(&ctx);
> - goto retry;
> - }
> + DRM_MODESET_LOCK_ALL_END(err, ctx);
> + if (err)
> + return ERR_PTR(err);
>
> - drm_modeset_drop_locks(&ctx);
> - drm_modeset_acquire_fini(&ctx);
> return state;
> }
> EXPORT_SYMBOL(drm_atomic_helper_suspend);
> @@ -3272,23 +3251,12 @@ int drm_atomic_helper_resume(struct drm_device *dev,
>
> drm_mode_config_reset(dev);
>
> - drm_modeset_acquire_init(&ctx, 0);
> - while (1) {
> - err = drm_modeset_lock_all_ctx(dev, &ctx);
> - if (err)
> - goto out;
> + DRM_MODESET_LOCK_ALL_BEGIN(dev, err, ctx, 0);
>
> - err = drm_atomic_helper_commit_duplicated_state(state, &ctx);
> -out:
> - if (err != -EDEADLK)
> - break;
> -
> - drm_modeset_backoff(&ctx);
> - }
> + err = drm_atomic_helper_commit_duplicated_state(state, &ctx);
>
> state->acquire_ctx = NULL;
> - drm_modeset_drop_locks(&ctx);
> - drm_modeset_acquire_fini(&ctx);
> + DRM_MODESET_LOCK_ALL_END(err, ctx);
> drm_atomic_state_put(state);
>
> return err;
> diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c
> index 581cc37882230..9c6827171d795 100644
> --- a/drivers/gpu/drm/drm_color_mgmt.c
> +++ b/drivers/gpu/drm/drm_color_mgmt.c
> @@ -255,11 +255,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
> if (crtc_lut->gamma_size != crtc->gamma_size)
> return -EINVAL;
>
> - drm_modeset_acquire_init(&ctx, 0);
> -retry:
> - ret = drm_modeset_lock_all_ctx(dev, &ctx);
> - if (ret)
> - goto out;
> + DRM_MODESET_LOCK_ALL_BEGIN(dev, ret, ctx, 0);
>
> size = crtc_lut->gamma_size * (sizeof(uint16_t));
> r_base = crtc->gamma_store;
> @@ -284,13 +280,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
> crtc->gamma_size, &ctx);
>
> out:
> - if (ret == -EDEADLK) {
> - drm_modeset_backoff(&ctx);
> - goto retry;
> - }
> - drm_modeset_drop_locks(&ctx);
> - drm_modeset_acquire_fini(&ctx);
> -
> + DRM_MODESET_LOCK_ALL_END(ret, ctx);
> return ret;
>
> }
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index af4b94ce8e942..4b3d45239407e 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -599,11 +599,8 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
> plane = crtc->primary;
>
> mutex_lock(&crtc->dev->mode_config.mutex);
> - drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
> -retry:
> - ret = drm_modeset_lock_all_ctx(crtc->dev, &ctx);
> - if (ret)
> - goto out;
> + DRM_MODESET_LOCK_ALL_BEGIN(dev, ret, ctx,
> + DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
>
> if (crtc_req->mode_valid) {
> /* If we have a mode we need a framebuffer. */
> @@ -768,13 +765,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
> fb = NULL;
> mode = NULL;
>
> - if (ret == -EDEADLK) {
> - ret = drm_modeset_backoff(&ctx);
> - if (!ret)
> - goto retry;
> - }
> - drm_modeset_drop_locks(&ctx);
> - drm_modeset_acquire_fini(&ctx);
> + DRM_MODESET_LOCK_ALL_END(ret, ctx);
> mutex_unlock(&crtc->dev->mode_config.mutex);
>
> return ret;
> diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c
> index 679455e368298..37472edb4f303 100644
> --- a/drivers/gpu/drm/drm_plane.c
> +++ b/drivers/gpu/drm/drm_plane.c
> @@ -767,11 +767,8 @@ static int setplane_internal(struct drm_plane *plane,
> struct drm_modeset_acquire_ctx ctx;
> int ret;
>
> - drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
> -retry:
> - ret = drm_modeset_lock_all_ctx(plane->dev, &ctx);
> - if (ret)
> - goto fail;
> + DRM_MODESET_LOCK_ALL_BEGIN(plane->dev, ret, ctx,
> + DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
>
> if (drm_drv_uses_atomic_modeset(plane->dev))
> ret = __setplane_atomic(plane, crtc, fb,
> @@ -782,14 +779,7 @@ static int setplane_internal(struct drm_plane *plane,
> crtc_x, crtc_y, crtc_w, crtc_h,
> src_x, src_y, src_w, src_h, &ctx);
>
> -fail:
> - if (ret == -EDEADLK) {
> - ret = drm_modeset_backoff(&ctx);
> - if (!ret)
> - goto retry;
> - }
> - drm_modeset_drop_locks(&ctx);
> - drm_modeset_acquire_fini(&ctx);
> + DRM_MODESET_LOCK_ALL_END(ret, ctx);
>
> return ret;
> }
> diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h
> index a685d1bb21f26..6213a11445633 100644
> --- a/include/drm/drm_modeset_lock.h
> +++ b/include/drm/drm_modeset_lock.h
> @@ -130,4 +130,58 @@ void drm_warn_on_modeset_not_all_locked(struct drm_device *dev);
> int drm_modeset_lock_all_ctx(struct drm_device *dev,
> struct drm_modeset_acquire_ctx *ctx);
>
> +/**
> + * DRM_MODESET_LOCK_ALL_BEGIN - Helper to acquire modeset locks
> + * @dev: drm device
> + * @ret: local ret/err/etc variable to track error status
> + * @ctx: local modeset acquire context, will be dereferenced
> + * @flags: DRM_MODESET_ACQUIRE_* flags to pass to acquire_init()
Full function name for the nice hyperlink. Needs a continuation line,
which just needs to be indentend.
And a bikeshed: I'd put ret last in both macros, I think that's where
usually the cursors/output variables are.
> + *
> + * Use these macros to simplify grabbing all modeset locks using a local
> + * context. This has the advantage of reducing boilerplate, but also properly
> + * checking return values where appropriate.
> + *
> + * Any code run between BEGIN and END will be holding the modeset locks.
> + *
> + * This must be paired with DRM_MODESET_LOCAL_ALL_END. We will jump back and
_END() for the hyperlink. Also s/LOCAL/LOCK/
> + * forth between the labels on deadlock and error conditions.
Maybe add:
"Drivers can acquire additional modeset locks. If any lock acquisition
fails the control flow needs to jump to DRM_MODESET_LOCK_ALL_END(), with
the @ret parameter containing the return value of drm_modeset_lock()."
Since making that possible was the entire point of this exercise.
> + *
> + * Returns: The only possible value of ret immediately after
> + * DRM_MODESET_LOCK_ALL_BEGIN is 0, so no error checking is necessary.
Looks pretty in the generated html I guess, but inconsistent with the
usual style, which is empty line after Returns: and then no indenting.
> + */
> +#define DRM_MODESET_LOCK_ALL_BEGIN(dev, ret, ctx, flags) \
> + drm_modeset_acquire_init(&ctx, flags); \
> +modeset_lock_retry: \
> + ret = drm_modeset_lock_all_ctx(dev, &ctx); \
> + if (ret) \
> + goto modeset_lock_fail;
> +
> +/**
> + * DRM_MODESET_LOCK_ALL_END - Helper to release and cleanup modeset locks
> + * @ret: local ret/err/etc variable to track error status
> + * @ctx: local modeset acquire context, will be dereferenced
> + *
> + * The other side of DRM_MODESET_LOCK_ALL_BEGIN. It will bounce back to BEGIN if
()
> + * ret is -EDEADLK.
> + *
> + * It's important that you use the same ret variable for begin and end so
> + * deadlock conditions are properly handled.
> + *
> + * Returns: ret will be untouched unless it is -EDEADLK. That means that if you
> + * successfully acquire the locks, ret will be whatever your code sets
> + * it to. If there is a deadlock or other failure with acquire or
> + * backoff, ret will be set to that failure. In both of these cases the
> + * code between BEGIN/END will not be run, so the failure will reflect
> + * the inability to grab the locks.
> + */
> +#define DRM_MODESET_LOCK_ALL_END(ret, ctx) \
> +modeset_lock_fail: \
> + if (ret == -EDEADLK) { \
> + ret = drm_modeset_backoff(&ctx); \
> + if (!ret) \
> + goto modeset_lock_retry; \
> + } \
> + drm_modeset_drop_locks(&ctx); \
> + drm_modeset_acquire_fini(&ctx);
> +
> #endif /* DRM_MODESET_LOCK_H_ */
Please reference these two convenience macros at the end of the DOC:
overview comment in drm_modeset_lock.c, e.g.
"For convenience this control flow is implemented in the
DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END() for the case
where all modeset locks need to be taken through
drm_modeset_lock_all_ctx()."
And maybe in the _lock_all_ctx() function add:
"See also DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END()."
With the doc bikesheds:
Reviewed-by: Daniel Vetter <daniel.vetter at ffwll.ch>
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
More information about the dri-devel
mailing list