diff options
author | Ville Syrjälä <ville.syrjala@linux.intel.com> | 2014-08-11 13:15:35 +0300 |
---|---|---|
committer | Jani Nikula <jani.nikula@intel.com> | 2014-08-18 10:42:40 +0300 |
commit | 208bf9fdcd3575aa4a5d48b3e0295f7cdaf6fc44 (patch) | |
tree | b33603d0c3129b59cc5b3d695e3bee8ea9d06354 | |
parent | 7d1311b93e58ed55f3a31cc8f94c4b8fe988a2b9 (diff) |
drm/i915: Fix locking for intel_enable_pipe_a()
intel_enable_pipe_a() gets called with all the modeset locks already
held (by drm_modeset_lock_all()), so trying to grab the same
locks using another drm_modeset_acquire_ctx is going to fail miserably.
Move most of the drm_modeset_acquire_ctx handling (init/drop/fini)
out from intel_{get,release}_load_detect_pipe() into the callers
(intel_{crt,tv}_detect()). Only the actual locking and backoff
handling is left in intel_get_load_detect_pipe(). And in
intel_enable_pipe_a() we just share the mode_config.acquire_ctx from
drm_modeset_lock_all() which is already holding all the relevant locks.
It's perfectly legal to lock the same ww_mutex multiple times using the
same ww_acquire_ctx. drm_modeset_lock() will convert the returned
-EALREADY into 0, so the caller doesn't need to do antyhing special.
Fixes a hang on resume on my 830.
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: stable@vger.kernel.org
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
-rw-r--r-- | drivers/gpu/drm/i915/intel_crt.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 21 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_tv.c | 7 |
4 files changed, 17 insertions, 21 deletions
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 2efaf8e8d9c4..e8abfce40976 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -699,16 +699,21 @@ intel_crt_detect(struct drm_connector *connector, bool force) goto out; } + drm_modeset_acquire_init(&ctx, 0); + /* for pre-945g platforms use load detect */ if (intel_get_load_detect_pipe(connector, NULL, &tmp, &ctx)) { if (intel_crt_detect_ddc(connector)) status = connector_status_connected; else status = intel_crt_load_detect(crt); - intel_release_load_detect_pipe(connector, &tmp, &ctx); + intel_release_load_detect_pipe(connector, &tmp); } else status = connector_status_unknown; + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + out: intel_display_power_put(dev_priv, power_domain); return status; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 018fb7222f60..f02c80d4039c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8462,8 +8462,6 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, connector->base.id, connector->name, encoder->base.id, encoder->name); - drm_modeset_acquire_init(ctx, 0); - retry: ret = drm_modeset_lock(&config->connection_mutex, ctx); if (ret) @@ -8574,15 +8572,11 @@ fail_unlock: goto retry; } - drm_modeset_drop_locks(ctx); - drm_modeset_acquire_fini(ctx); - return false; } void intel_release_load_detect_pipe(struct drm_connector *connector, - struct intel_load_detect_pipe *old, - struct drm_modeset_acquire_ctx *ctx) + struct intel_load_detect_pipe *old) { struct intel_encoder *intel_encoder = intel_attached_encoder(connector); @@ -8606,17 +8600,12 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, drm_framebuffer_unreference(old->release_fb); } - goto unlock; return; } /* Switch crtc and encoder back off if necessary */ if (old->dpms_mode != DRM_MODE_DPMS_ON) connector->funcs->dpms(connector, old->dpms_mode); - -unlock: - drm_modeset_drop_locks(ctx); - drm_modeset_acquire_fini(ctx); } static int i9xx_pll_refclk(struct drm_device *dev, @@ -12659,7 +12648,7 @@ static void intel_enable_pipe_a(struct drm_device *dev) struct intel_connector *connector; struct drm_connector *crt = NULL; struct intel_load_detect_pipe load_detect_temp; - struct drm_modeset_acquire_ctx ctx; + struct drm_modeset_acquire_ctx *ctx = dev->mode_config.acquire_ctx; /* We can't just switch on the pipe A, we need to set things up with a * proper mode and output configuration. As a gross hack, enable pipe A @@ -12676,10 +12665,8 @@ static void intel_enable_pipe_a(struct drm_device *dev) if (!crt) return; - if (intel_get_load_detect_pipe(crt, NULL, &load_detect_temp, &ctx)) - intel_release_load_detect_pipe(crt, &load_detect_temp, &ctx); - - + if (intel_get_load_detect_pipe(crt, NULL, &load_detect_temp, ctx)) + intel_release_load_detect_pipe(crt, &load_detect_temp); } static bool diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 4b2664bd5b81..fe3431f96900 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -830,8 +830,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, struct intel_load_detect_pipe *old, struct drm_modeset_acquire_ctx *ctx); void intel_release_load_detect_pipe(struct drm_connector *connector, - struct intel_load_detect_pipe *old, - struct drm_modeset_acquire_ctx *ctx); + struct intel_load_detect_pipe *old); int intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_i915_gem_object *obj, struct intel_engine_cs *pipelined); diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index e211eef4b7e4..32186a656816 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1323,11 +1323,16 @@ intel_tv_detect(struct drm_connector *connector, bool force) struct intel_load_detect_pipe tmp; struct drm_modeset_acquire_ctx ctx; + drm_modeset_acquire_init(&ctx, 0); + if (intel_get_load_detect_pipe(connector, &mode, &tmp, &ctx)) { type = intel_tv_detect_type(intel_tv, connector); - intel_release_load_detect_pipe(connector, &tmp, &ctx); + intel_release_load_detect_pipe(connector, &tmp); } else return connector_status_unknown; + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); } else return connector->status; |