瀏覽代碼

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>
Ville Syrjälä 11 年之前
父節點
當前提交
208bf9fdcd

+ 6 - 1
drivers/gpu/drm/i915/intel_crt.c

@@ -699,16 +699,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);
 	return status;
 	return status;

+ 4 - 17
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,
 		      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)
@@ -8574,15 +8572,11 @@ fail_unlock:
 		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 drm_modeset_acquire_ctx *ctx)
+				    struct intel_load_detect_pipe *old)
 {
 {
 	struct intel_encoder *intel_encoder =
 	struct intel_encoder *intel_encoder =
 		intel_attached_encoder(connector);
 		intel_attached_encoder(connector);
@@ -8606,17 +8600,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,
@@ -12659,7 +12648,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
@@ -12676,10 +12665,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))
-		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
 static bool

+ 1 - 2
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 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 drm_modeset_acquire_ctx *ctx);
+				    struct intel_load_detect_pipe *old);
 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);

+ 6 - 1
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 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;