[PATCH 3/3] drm: Add DRM_MODESET_LOCK_BEGIN/END helpers
Sean Paul
sean at poorly.run
Wed Nov 28 16:59:48 UTC 2018
On Wed, Nov 28, 2018 at 10:01:07AM +0100, Daniel Vetter wrote:
> 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.
This isn't a function, but a series of flags prefixed with DRM_MODESET_ACQUIRE_
(currently only one there, but perhaps more could come).
>
> 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
--
Sean Paul, Software Engineer, Google / Chromium OS
More information about the dri-devel
mailing list