Commit 8ba2d185 authored by Jani Nikula's avatar Jani Nikula Committed by Daniel Vetter

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: default avatarJani Nikula <jani.nikula@intel.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent d6540632
...@@ -1633,6 +1633,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) ...@@ -1633,6 +1633,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
spin_lock_init(&dev_priv->irq_lock); spin_lock_init(&dev_priv->irq_lock);
spin_lock_init(&dev_priv->gpu_error.lock); spin_lock_init(&dev_priv->gpu_error.lock);
spin_lock_init(&dev_priv->rps.lock); spin_lock_init(&dev_priv->rps.lock);
spin_lock_init(&dev_priv->backlight.lock);
mutex_init(&dev_priv->dpio_lock); mutex_init(&dev_priv->dpio_lock);
mutex_init(&dev_priv->rps.hw_lock); mutex_init(&dev_priv->rps.hw_lock);
......
...@@ -960,6 +960,7 @@ typedef struct drm_i915_private { ...@@ -960,6 +960,7 @@ typedef struct drm_i915_private {
struct { struct {
int level; int level;
bool enabled; bool enabled;
spinlock_t lock; /* bl registers and the above bl fields */
struct backlight_device *device; struct backlight_device *device;
} backlight; } backlight;
......
...@@ -192,6 +192,7 @@ static void i915_restore_vga(struct drm_device *dev) ...@@ -192,6 +192,7 @@ static void i915_restore_vga(struct drm_device *dev)
static void i915_save_display(struct drm_device *dev) static void i915_save_display(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long flags;
/* Display arbitration control */ /* Display arbitration control */
if (INTEL_INFO(dev)->gen <= 4) if (INTEL_INFO(dev)->gen <= 4)
...@@ -202,6 +203,8 @@ static void i915_save_display(struct drm_device *dev) ...@@ -202,6 +203,8 @@ static void i915_save_display(struct drm_device *dev)
if (!drm_core_check_feature(dev, DRIVER_MODESET)) if (!drm_core_check_feature(dev, DRIVER_MODESET))
i915_save_display_reg(dev); i915_save_display_reg(dev);
spin_lock_irqsave(&dev_priv->backlight.lock, flags);
/* LVDS state */ /* LVDS state */
if (HAS_PCH_SPLIT(dev)) { if (HAS_PCH_SPLIT(dev)) {
dev_priv->regfile.savePP_CONTROL = I915_READ(PCH_PP_CONTROL); dev_priv->regfile.savePP_CONTROL = I915_READ(PCH_PP_CONTROL);
...@@ -222,6 +225,8 @@ static void i915_save_display(struct drm_device *dev) ...@@ -222,6 +225,8 @@ static void i915_save_display(struct drm_device *dev)
dev_priv->regfile.saveLVDS = I915_READ(LVDS); 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)) if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev))
dev_priv->regfile.savePFIT_CONTROL = I915_READ(PFIT_CONTROL); dev_priv->regfile.savePFIT_CONTROL = I915_READ(PFIT_CONTROL);
...@@ -257,6 +262,7 @@ static void i915_restore_display(struct drm_device *dev) ...@@ -257,6 +262,7 @@ static void i915_restore_display(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 mask = 0xffffffff; u32 mask = 0xffffffff;
unsigned long flags;
/* Display arbitration */ /* Display arbitration */
if (INTEL_INFO(dev)->gen <= 4) if (INTEL_INFO(dev)->gen <= 4)
...@@ -265,6 +271,8 @@ static void i915_restore_display(struct drm_device *dev) ...@@ -265,6 +271,8 @@ static void i915_restore_display(struct drm_device *dev)
if (!drm_core_check_feature(dev, DRIVER_MODESET)) if (!drm_core_check_feature(dev, DRIVER_MODESET))
i915_restore_display_reg(dev); i915_restore_display_reg(dev);
spin_lock_irqsave(&dev_priv->backlight.lock, flags);
/* LVDS state */ /* LVDS state */
if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2); I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2);
...@@ -304,6 +312,8 @@ static void i915_restore_display(struct drm_device *dev) ...@@ -304,6 +312,8 @@ static void i915_restore_display(struct drm_device *dev)
I915_WRITE(PP_CONTROL, dev_priv->regfile.savePP_CONTROL); 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*/ /* only restore FBC info on the platform that supports FBC*/
intel_disable_fbc(dev); intel_disable_fbc(dev);
if (I915_HAS_FBC(dev)) { if (I915_HAS_FBC(dev)) {
......
...@@ -138,6 +138,8 @@ static u32 i915_read_blc_pwm_ctl(struct drm_device *dev) ...@@ -138,6 +138,8 @@ static u32 i915_read_blc_pwm_ctl(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 val; u32 val;
WARN_ON(!spin_is_locked(&dev_priv->backlight.lock));
/* Restore the CTL value if it lost, e.g. GPU reset */ /* Restore the CTL value if it lost, e.g. GPU reset */
if (HAS_PCH_SPLIT(dev_priv->dev)) { if (HAS_PCH_SPLIT(dev_priv->dev)) {
...@@ -218,6 +220,9 @@ static u32 intel_panel_get_backlight(struct drm_device *dev) ...@@ -218,6 +220,9 @@ static u32 intel_panel_get_backlight(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 val; u32 val;
unsigned long flags;
spin_lock_irqsave(&dev_priv->backlight.lock, flags);
if (HAS_PCH_SPLIT(dev)) { if (HAS_PCH_SPLIT(dev)) {
val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
...@@ -235,6 +240,9 @@ static u32 intel_panel_get_backlight(struct drm_device *dev) ...@@ -235,6 +240,9 @@ static u32 intel_panel_get_backlight(struct drm_device *dev)
} }
val = intel_panel_compute_brightness(dev, val); val = intel_panel_compute_brightness(dev, val);
spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val); DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
return val; return val;
} }
...@@ -282,11 +290,14 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max) ...@@ -282,11 +290,14 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 freq; u32 freq;
unsigned long flags;
spin_lock_irqsave(&dev_priv->backlight.lock, flags);
freq = intel_panel_get_max_backlight(dev); freq = intel_panel_get_max_backlight(dev);
if (!freq) { if (!freq) {
/* we are screwed, bail out */ /* we are screwed, bail out */
return; goto out;
} }
/* scale to hardware */ /* scale to hardware */
...@@ -298,11 +309,16 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max) ...@@ -298,11 +309,16 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max)
if (dev_priv->backlight.enabled) if (dev_priv->backlight.enabled)
intel_panel_actually_set_backlight(dev, level); 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) void intel_panel_disable_backlight(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; 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; dev_priv->backlight.enabled = false;
intel_panel_actually_set_backlight(dev, 0); intel_panel_actually_set_backlight(dev, 0);
...@@ -320,12 +336,17 @@ void intel_panel_disable_backlight(struct drm_device *dev) ...@@ -320,12 +336,17 @@ void intel_panel_disable_backlight(struct drm_device *dev)
I915_WRITE(BLC_PWM_PCH_CTL1, tmp); I915_WRITE(BLC_PWM_PCH_CTL1, tmp);
} }
} }
spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
} }
void intel_panel_enable_backlight(struct drm_device *dev, void intel_panel_enable_backlight(struct drm_device *dev,
enum pipe pipe) enum pipe pipe)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; 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) { if (dev_priv->backlight.level == 0) {
dev_priv->backlight.level = intel_panel_get_max_backlight(dev); dev_priv->backlight.level = intel_panel_get_max_backlight(dev);
...@@ -375,6 +396,8 @@ void intel_panel_enable_backlight(struct drm_device *dev, ...@@ -375,6 +396,8 @@ void intel_panel_enable_backlight(struct drm_device *dev,
*/ */
dev_priv->backlight.enabled = true; dev_priv->backlight.enabled = true;
intel_panel_actually_set_backlight(dev, dev_priv->backlight.level); 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) static void intel_panel_init_backlight(struct drm_device *dev)
...@@ -432,6 +455,7 @@ int intel_panel_setup_backlight(struct drm_connector *connector) ...@@ -432,6 +455,7 @@ int intel_panel_setup_backlight(struct drm_connector *connector)
struct drm_device *dev = connector->dev; struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct backlight_properties props; struct backlight_properties props;
unsigned long flags;
intel_panel_init_backlight(dev); intel_panel_init_backlight(dev);
...@@ -441,7 +465,11 @@ int intel_panel_setup_backlight(struct drm_connector *connector) ...@@ -441,7 +465,11 @@ int intel_panel_setup_backlight(struct drm_connector *connector)
memset(&props, 0, sizeof(props)); memset(&props, 0, sizeof(props));
props.type = BACKLIGHT_RAW; props.type = BACKLIGHT_RAW;
props.brightness = dev_priv->backlight.level; props.brightness = dev_priv->backlight.level;
spin_lock_irqsave(&dev_priv->backlight.lock, flags);
props.max_brightness = intel_panel_get_max_backlight(dev); props.max_brightness = intel_panel_get_max_backlight(dev);
spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
if (props.max_brightness == 0) { if (props.max_brightness == 0) {
DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n"); DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n");
return -ENODEV; return -ENODEV;
......
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