diff options
| author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2015-04-09 10:44:15 -0400 |
|---|---|---|
| committer | Jani Nikula <jani.nikula@intel.com> | 2015-04-10 07:29:27 -0400 |
| commit | 9da7d69357389ea63893434fe3b17b9fbc2c2d2d (patch) | |
| tree | 6ef4b8b6cc08a3b62915c3d95585fadd2db8a839 | |
| parent | 6e0aa8018f9c676b115b7ca6c20a056fc57c68a9 (diff) | |
drm/i915: Fix locking in DRRS flush/invalidate hooks
We must acquire the mutex before we can check drrs.dp, otherwise
someone might sneak in with a modeset, clear the pointer after we've
checked it and then the code will Oops.
This issue has been introduced in
commit a93fad0f7fb8a3ff12e8814b630648f6d187954c
Author: Vandana Kannan <vandana.kannan@intel.com>
Date: Sat Jan 10 02:25:59 2015 +0530
drm/i915: DRRS calls based on frontbuffer
v2: Don't blow up on uninitialized mutex and work item by checking
whether DRRS is support or not first. Also unconditionally initialize
the mutex/work item to avoid future trouble.
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Ramalingam C <ramalingam.c@intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Vandana Kannan <vandana.kannan@intel.com>
Cc: stable@vger.kernel.org (4.0+ only)
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Tested-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
| -rw-r--r-- | drivers/gpu/drm/i915/intel_dp.c | 22 |
1 files changed, 15 insertions, 7 deletions
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index b70e635ccaf4..5e60473d08fe 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c | |||
| @@ -5157,7 +5157,6 @@ static void intel_edp_drrs_downclock_work(struct work_struct *work) | |||
| 5157 | downclock_mode->vrefresh); | 5157 | downclock_mode->vrefresh); |
| 5158 | 5158 | ||
| 5159 | unlock: | 5159 | unlock: |
| 5160 | |||
| 5161 | mutex_unlock(&dev_priv->drrs.mutex); | 5160 | mutex_unlock(&dev_priv->drrs.mutex); |
| 5162 | } | 5161 | } |
| 5163 | 5162 | ||
| @@ -5179,12 +5178,17 @@ void intel_edp_drrs_invalidate(struct drm_device *dev, | |||
| 5179 | struct drm_crtc *crtc; | 5178 | struct drm_crtc *crtc; |
| 5180 | enum pipe pipe; | 5179 | enum pipe pipe; |
| 5181 | 5180 | ||
| 5182 | if (!dev_priv->drrs.dp) | 5181 | if (dev_priv->drrs.type == DRRS_NOT_SUPPORTED) |
| 5183 | return; | 5182 | return; |
| 5184 | 5183 | ||
| 5185 | cancel_delayed_work_sync(&dev_priv->drrs.work); | 5184 | cancel_delayed_work_sync(&dev_priv->drrs.work); |
| 5186 | 5185 | ||
| 5187 | mutex_lock(&dev_priv->drrs.mutex); | 5186 | mutex_lock(&dev_priv->drrs.mutex); |
| 5187 | if (!dev_priv->drrs.dp) { | ||
| 5188 | mutex_unlock(&dev_priv->drrs.mutex); | ||
| 5189 | return; | ||
| 5190 | } | ||
| 5191 | |||
| 5188 | crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc; | 5192 | crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc; |
| 5189 | pipe = to_intel_crtc(crtc)->pipe; | 5193 | pipe = to_intel_crtc(crtc)->pipe; |
| 5190 | 5194 | ||
| @@ -5218,12 +5222,17 @@ void intel_edp_drrs_flush(struct drm_device *dev, | |||
| 5218 | struct drm_crtc *crtc; | 5222 | struct drm_crtc *crtc; |
| 5219 | enum pipe pipe; | 5223 | enum pipe pipe; |
| 5220 | 5224 | ||
| 5221 | if (!dev_priv->drrs.dp) | 5225 | if (dev_priv->drrs.type == DRRS_NOT_SUPPORTED) |
| 5222 | return; | 5226 | return; |
| 5223 | 5227 | ||
| 5224 | cancel_delayed_work_sync(&dev_priv->drrs.work); | 5228 | cancel_delayed_work_sync(&dev_priv->drrs.work); |
| 5225 | 5229 | ||
| 5226 | mutex_lock(&dev_priv->drrs.mutex); | 5230 | mutex_lock(&dev_priv->drrs.mutex); |
| 5231 | if (!dev_priv->drrs.dp) { | ||
| 5232 | mutex_unlock(&dev_priv->drrs.mutex); | ||
| 5233 | return; | ||
| 5234 | } | ||
| 5235 | |||
| 5227 | crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc; | 5236 | crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc; |
| 5228 | pipe = to_intel_crtc(crtc)->pipe; | 5237 | pipe = to_intel_crtc(crtc)->pipe; |
| 5229 | dev_priv->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits; | 5238 | dev_priv->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits; |
| @@ -5294,6 +5303,9 @@ intel_dp_drrs_init(struct intel_connector *intel_connector, | |||
| 5294 | struct drm_i915_private *dev_priv = dev->dev_private; | 5303 | struct drm_i915_private *dev_priv = dev->dev_private; |
| 5295 | struct drm_display_mode *downclock_mode = NULL; | 5304 | struct drm_display_mode *downclock_mode = NULL; |
| 5296 | 5305 | ||
| 5306 | INIT_DELAYED_WORK(&dev_priv->drrs.work, intel_edp_drrs_downclock_work); | ||
| 5307 | mutex_init(&dev_priv->drrs.mutex); | ||
| 5308 | |||
| 5297 | if (INTEL_INFO(dev)->gen <= 6) { | 5309 | if (INTEL_INFO(dev)->gen <= 6) { |
| 5298 | DRM_DEBUG_KMS("DRRS supported for Gen7 and above\n"); | 5310 | DRM_DEBUG_KMS("DRRS supported for Gen7 and above\n"); |
| 5299 | return NULL; | 5311 | return NULL; |
| @@ -5312,10 +5324,6 @@ intel_dp_drrs_init(struct intel_connector *intel_connector, | |||
| 5312 | return NULL; | 5324 | return NULL; |
| 5313 | } | 5325 | } |
| 5314 | 5326 | ||
| 5315 | INIT_DELAYED_WORK(&dev_priv->drrs.work, intel_edp_drrs_downclock_work); | ||
| 5316 | |||
| 5317 | mutex_init(&dev_priv->drrs.mutex); | ||
| 5318 | |||
| 5319 | dev_priv->drrs.type = dev_priv->vbt.drrs_type; | 5327 | dev_priv->drrs.type = dev_priv->vbt.drrs_type; |
| 5320 | 5328 | ||
| 5321 | dev_priv->drrs.refresh_rate_type = DRRS_HIGH_RR; | 5329 | dev_priv->drrs.refresh_rate_type = DRRS_HIGH_RR; |
