Commit ecc68a4b authored by Ville Syrjälä's avatar Ville Syrjälä Committed by Greg Kroah-Hartman

drm/i915: Fix locking for intel_enable_pipe_a()

commit 208bf9fd upstream.

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: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: default avatarJani Nikula <jani.nikula@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent e7797932
...@@ -673,16 +673,21 @@ intel_crt_detect(struct drm_connector *connector, bool force) ...@@ -673,16 +673,21 @@ intel_crt_detect(struct drm_connector *connector, bool force)
goto out; goto out;
} }
drm_modeset_acquire_init(&ctx, 0);
/* for pre-945g platforms use load detect */ /* for pre-945g platforms use load detect */
if (intel_get_load_detect_pipe(connector, NULL, &tmp, &ctx)) { if (intel_get_load_detect_pipe(connector, NULL, &tmp, &ctx)) {
if (intel_crt_detect_ddc(connector)) if (intel_crt_detect_ddc(connector))
status = connector_status_connected; status = connector_status_connected;
else else
status = intel_crt_load_detect(crt); status = intel_crt_load_detect(crt);
intel_release_load_detect_pipe(connector, &tmp, &ctx); intel_release_load_detect_pipe(connector, &tmp);
} else } else
status = connector_status_unknown; status = connector_status_unknown;
drm_modeset_drop_locks(&ctx);
drm_modeset_acquire_fini(&ctx);
out: out:
intel_display_power_put(dev_priv, power_domain); intel_display_power_put(dev_priv, power_domain);
intel_runtime_pm_put(dev_priv); intel_runtime_pm_put(dev_priv);
......
...@@ -8319,8 +8319,6 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, ...@@ -8319,8 +8319,6 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
connector->base.id, connector->name, connector->base.id, connector->name,
encoder->base.id, encoder->name); encoder->base.id, encoder->name);
drm_modeset_acquire_init(ctx, 0);
retry: retry:
ret = drm_modeset_lock(&config->connection_mutex, ctx); ret = drm_modeset_lock(&config->connection_mutex, ctx);
if (ret) if (ret)
...@@ -8435,15 +8433,11 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, ...@@ -8435,15 +8433,11 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
goto retry; goto retry;
} }
drm_modeset_drop_locks(ctx);
drm_modeset_acquire_fini(ctx);
return false; return false;
} }
void intel_release_load_detect_pipe(struct drm_connector *connector, void intel_release_load_detect_pipe(struct drm_connector *connector,
struct intel_load_detect_pipe *old, struct intel_load_detect_pipe *old)
struct drm_modeset_acquire_ctx *ctx)
{ {
struct intel_encoder *intel_encoder = struct intel_encoder *intel_encoder =
intel_attached_encoder(connector); intel_attached_encoder(connector);
...@@ -8467,17 +8461,12 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, ...@@ -8467,17 +8461,12 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
drm_framebuffer_unreference(old->release_fb); drm_framebuffer_unreference(old->release_fb);
} }
goto unlock;
return; return;
} }
/* Switch crtc and encoder back off if necessary */ /* Switch crtc and encoder back off if necessary */
if (old->dpms_mode != DRM_MODE_DPMS_ON) if (old->dpms_mode != DRM_MODE_DPMS_ON)
connector->funcs->dpms(connector, old->dpms_mode); 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, static int i9xx_pll_refclk(struct drm_device *dev,
...@@ -11846,7 +11835,7 @@ static void intel_enable_pipe_a(struct drm_device *dev) ...@@ -11846,7 +11835,7 @@ static void intel_enable_pipe_a(struct drm_device *dev)
struct intel_connector *connector; struct intel_connector *connector;
struct drm_connector *crt = NULL; struct drm_connector *crt = NULL;
struct intel_load_detect_pipe load_detect_temp; 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 /* 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 * proper mode and output configuration. As a gross hack, enable pipe A
...@@ -11863,10 +11852,8 @@ static void intel_enable_pipe_a(struct drm_device *dev) ...@@ -11863,10 +11852,8 @@ static void intel_enable_pipe_a(struct drm_device *dev)
if (!crt) if (!crt)
return; return;
if (intel_get_load_detect_pipe(crt, NULL, &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, &ctx); intel_release_load_detect_pipe(crt, &load_detect_temp);
} }
static bool static bool
......
...@@ -754,8 +754,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, ...@@ -754,8 +754,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
struct intel_load_detect_pipe *old, struct intel_load_detect_pipe *old,
struct drm_modeset_acquire_ctx *ctx); struct drm_modeset_acquire_ctx *ctx);
void intel_release_load_detect_pipe(struct drm_connector *connector, void intel_release_load_detect_pipe(struct drm_connector *connector,
struct intel_load_detect_pipe *old, struct intel_load_detect_pipe *old);
struct drm_modeset_acquire_ctx *ctx);
int intel_pin_and_fence_fb_obj(struct drm_device *dev, int intel_pin_and_fence_fb_obj(struct drm_device *dev,
struct drm_i915_gem_object *obj, struct drm_i915_gem_object *obj,
struct intel_engine_cs *pipelined); struct intel_engine_cs *pipelined);
......
...@@ -1323,11 +1323,16 @@ intel_tv_detect(struct drm_connector *connector, bool force) ...@@ -1323,11 +1323,16 @@ intel_tv_detect(struct drm_connector *connector, bool force)
struct intel_load_detect_pipe tmp; struct intel_load_detect_pipe tmp;
struct drm_modeset_acquire_ctx ctx; struct drm_modeset_acquire_ctx ctx;
drm_modeset_acquire_init(&ctx, 0);
if (intel_get_load_detect_pipe(connector, &mode, &tmp, &ctx)) { if (intel_get_load_detect_pipe(connector, &mode, &tmp, &ctx)) {
type = intel_tv_detect_type(intel_tv, connector); type = intel_tv_detect_type(intel_tv, connector);
intel_release_load_detect_pipe(connector, &tmp, &ctx); intel_release_load_detect_pipe(connector, &tmp);
} else } else
return connector_status_unknown; return connector_status_unknown;
drm_modeset_drop_locks(&ctx);
drm_modeset_acquire_fini(&ctx);
} else } else
return connector->status; return connector->status;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment