| From f6675adc2421c21c8060e4f1ff1eb720ca61b66a Mon Sep 17 00:00:00 2001 |
| From: Jani Nikula <jani.nikula@intel.com> |
| Date: Fri, 12 Apr 2013 15:18:37 +0300 |
| Subject: drm/i915: protect backlight registers and data with a spinlock |
| |
| Backlight data and registers are fiddled through LVDS/eDP modeset |
| enable/disable hooks, backlight sysfs files, asle interrupts, and register |
| save/restore. Protect the backlight related registers and driver private |
| fields using a spinlock. |
| |
| The locking in register save/restore covers a little more than is strictly |
| necessary, including non-modeset case, for simplicity. |
| |
| v2: Cover register access, save/restore, i915_read_blc_pwm_ctl() and code |
| paths leading there. |
| |
| Signed-off-by: Jani Nikula <jani.nikula@intel.com> |
| Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> |
| (cherry picked from commit 8ba2d18520ce380cf572e9902d9b3b91ece6c2c0) |
| [dbasehore: Fixed simple conflict] |
| Signed-off-by: Derek Basehore <dbasehore@chromium.org> |
| |
| Conflicts: |
| drivers/gpu/drm/i915/i915_dma.c |
| Signed-off-by: Darren Hart <dvhart@linux.intel.com> |
| --- |
| drivers/gpu/drm/i915/i915_dma.c | 1 + |
| drivers/gpu/drm/i915/i915_drv.h | 1 + |
| drivers/gpu/drm/i915/i915_suspend.c | 10 ++++++++++ |
| drivers/gpu/drm/i915/intel_panel.c | 30 +++++++++++++++++++++++++++++- |
| 4 files changed, 41 insertions(+), 1 deletion(-) |
| |
| --- a/drivers/gpu/drm/i915/i915_dma.c |
| +++ b/drivers/gpu/drm/i915/i915_dma.c |
| @@ -1527,6 +1527,7 @@ int i915_driver_load(struct drm_device * |
| spin_lock_init(&dev_priv->gpu_error.lock); |
| spin_lock_init(&dev_priv->rps.lock); |
| spin_lock_init(&dev_priv->gt_lock); |
| + spin_lock_init(&dev_priv->backlight.lock); |
| mutex_init(&dev_priv->dpio_lock); |
| mutex_init(&dev_priv->rps.hw_lock); |
| mutex_init(&dev_priv->modeset_restore_lock); |
| --- a/drivers/gpu/drm/i915/i915_drv.h |
| +++ b/drivers/gpu/drm/i915/i915_drv.h |
| @@ -961,6 +961,7 @@ typedef struct drm_i915_private { |
| struct { |
| int level; |
| bool enabled; |
| + spinlock_t lock; /* bl registers and the above bl fields */ |
| struct backlight_device *device; |
| } backlight; |
| |
| --- a/drivers/gpu/drm/i915/i915_suspend.c |
| +++ b/drivers/gpu/drm/i915/i915_suspend.c |
| @@ -192,6 +192,7 @@ static void i915_restore_vga(struct drm_ |
| static void i915_save_display(struct drm_device *dev) |
| { |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| + unsigned long flags; |
| |
| /* Display arbitration control */ |
| if (INTEL_INFO(dev)->gen <= 4) |
| @@ -202,6 +203,8 @@ static void i915_save_display(struct drm |
| if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
| i915_save_display_reg(dev); |
| |
| + spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
| + |
| /* LVDS state */ |
| if (HAS_PCH_SPLIT(dev)) { |
| dev_priv->regfile.savePP_CONTROL = I915_READ(PCH_PP_CONTROL); |
| @@ -222,6 +225,8 @@ static void i915_save_display(struct drm |
| dev_priv->regfile.saveLVDS = I915_READ(LVDS); |
| } |
| |
| + spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
| + |
| if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev)) |
| dev_priv->regfile.savePFIT_CONTROL = I915_READ(PFIT_CONTROL); |
| |
| @@ -257,6 +262,7 @@ static void i915_restore_display(struct |
| { |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| u32 mask = 0xffffffff; |
| + unsigned long flags; |
| |
| /* Display arbitration */ |
| if (INTEL_INFO(dev)->gen <= 4) |
| @@ -265,6 +271,8 @@ static void i915_restore_display(struct |
| if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
| i915_restore_display_reg(dev); |
| |
| + spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
| + |
| /* LVDS state */ |
| if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) |
| I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2); |
| @@ -304,6 +312,8 @@ static void i915_restore_display(struct |
| I915_WRITE(PP_CONTROL, dev_priv->regfile.savePP_CONTROL); |
| } |
| |
| + spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
| + |
| /* only restore FBC info on the platform that supports FBC*/ |
| intel_disable_fbc(dev); |
| if (I915_HAS_FBC(dev)) { |
| --- a/drivers/gpu/drm/i915/intel_panel.c |
| +++ b/drivers/gpu/drm/i915/intel_panel.c |
| @@ -138,6 +138,8 @@ static u32 i915_read_blc_pwm_ctl(struct |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| u32 val; |
| |
| + WARN_ON(!spin_is_locked(&dev_priv->backlight.lock)); |
| + |
| /* Restore the CTL value if it lost, e.g. GPU reset */ |
| |
| if (HAS_PCH_SPLIT(dev_priv->dev)) { |
| @@ -218,6 +220,9 @@ static u32 intel_panel_get_backlight(str |
| { |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| u32 val; |
| + unsigned long flags; |
| + |
| + spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
| |
| if (HAS_PCH_SPLIT(dev)) { |
| val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; |
| @@ -235,6 +240,9 @@ static u32 intel_panel_get_backlight(str |
| } |
| |
| val = intel_panel_compute_brightness(dev, val); |
| + |
| + spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
| + |
| DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val); |
| return val; |
| } |
| @@ -282,11 +290,14 @@ void intel_panel_set_backlight(struct dr |
| { |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| u32 freq; |
| + unsigned long flags; |
| + |
| + spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
| |
| freq = intel_panel_get_max_backlight(dev); |
| if (!freq) { |
| /* we are screwed, bail out */ |
| - return; |
| + goto out; |
| } |
| |
| /* scale to hardware */ |
| @@ -298,11 +309,16 @@ void intel_panel_set_backlight(struct dr |
| |
| if (dev_priv->backlight.enabled) |
| intel_panel_actually_set_backlight(dev, level); |
| +out: |
| + spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
| } |
| |
| void intel_panel_disable_backlight(struct drm_device *dev) |
| { |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| + unsigned long flags; |
| + |
| + spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
| |
| dev_priv->backlight.enabled = false; |
| intel_panel_actually_set_backlight(dev, 0); |
| @@ -320,12 +336,17 @@ void intel_panel_disable_backlight(struc |
| I915_WRITE(BLC_PWM_PCH_CTL1, tmp); |
| } |
| } |
| + |
| + spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
| } |
| |
| void intel_panel_enable_backlight(struct drm_device *dev, |
| enum pipe pipe) |
| { |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| + unsigned long flags; |
| + |
| + spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
| |
| if (dev_priv->backlight.level == 0) { |
| dev_priv->backlight.level = intel_panel_get_max_backlight(dev); |
| @@ -376,6 +397,8 @@ set_level: |
| */ |
| dev_priv->backlight.enabled = true; |
| intel_panel_actually_set_backlight(dev, dev_priv->backlight.level); |
| + |
| + spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
| } |
| |
| static void intel_panel_init_backlight(struct drm_device *dev) |
| @@ -433,6 +456,7 @@ int intel_panel_setup_backlight(struct d |
| struct drm_device *dev = connector->dev; |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| struct backlight_properties props; |
| + unsigned long flags; |
| |
| intel_panel_init_backlight(dev); |
| |
| @@ -442,7 +466,11 @@ int intel_panel_setup_backlight(struct d |
| memset(&props, 0, sizeof(props)); |
| props.type = BACKLIGHT_RAW; |
| props.brightness = dev_priv->backlight.level; |
| + |
| + spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
| props.max_brightness = intel_panel_get_max_backlight(dev); |
| + spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
| + |
| if (props.max_brightness == 0) { |
| DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n"); |
| return -ENODEV; |