blob: 13fd1dd8babf21c76d030ffc34b8182d3015310c [file] [log] [blame]
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;