Commit 913d8d11 authored by Chris Wilson's avatar Chris Wilson Committed by Eric Anholt

drm/i915: Ensure that while(INREG()) are bounded (v2)

Add a new macro, wait_for, to simplify the act of waiting on a register
to change state. wait_for() takes three arguments, the condition to
inspect on every loop, the maximum amount of time to wait and whether to
yield the cpu for a length of time after each check.

v2: Upgrade failure messages to DRM_ERROR on the suggestion of
Eric Anholt. We do not expect to hit these conditions as they reflect
programming errors, so if we do we want to be notified.
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: default avatarEric Anholt <eric@anholt.net>
parent dd785e35
...@@ -185,8 +185,9 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) ...@@ -185,8 +185,9 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
DRM_DEBUG_KMS("pch crt adpa 0x%x", adpa); DRM_DEBUG_KMS("pch crt adpa 0x%x", adpa);
I915_WRITE(PCH_ADPA, adpa); I915_WRITE(PCH_ADPA, adpa);
while ((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) != 0) if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
; 1000, 1))
DRM_ERROR("timed out waiting for FORCE_TRIGGER");
if (HAS_PCH_CPT(dev)) { if (HAS_PCH_CPT(dev)) {
I915_WRITE(PCH_ADPA, temp); I915_WRITE(PCH_ADPA, temp);
...@@ -237,17 +238,13 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) ...@@ -237,17 +238,13 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
hotplug_en |= CRT_HOTPLUG_FORCE_DETECT; hotplug_en |= CRT_HOTPLUG_FORCE_DETECT;
for (i = 0; i < tries ; i++) { for (i = 0; i < tries ; i++) {
unsigned long timeout;
/* turn on the FORCE_DETECT */ /* turn on the FORCE_DETECT */
I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
timeout = jiffies + msecs_to_jiffies(1000);
/* wait for FORCE_DETECT to go off */ /* wait for FORCE_DETECT to go off */
do { if (wait_for((I915_READ(PORT_HOTPLUG_EN) &
if (!(I915_READ(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT) == 0,
CRT_HOTPLUG_FORCE_DETECT)) 1000, 1))
break; DRM_ERROR("timed out waiting for FORCE_DETECT to go off");
msleep(1);
} while (time_after(timeout, jiffies));
} }
stat = I915_READ(PORT_HOTPLUG_STAT); stat = I915_READ(PORT_HOTPLUG_STAT);
......
...@@ -1037,7 +1037,6 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) ...@@ -1037,7 +1037,6 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
void i8xx_disable_fbc(struct drm_device *dev) void i8xx_disable_fbc(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long timeout = jiffies + msecs_to_jiffies(1);
u32 fbc_ctl; u32 fbc_ctl;
if (!I915_HAS_FBC(dev)) if (!I915_HAS_FBC(dev))
...@@ -1052,12 +1051,9 @@ void i8xx_disable_fbc(struct drm_device *dev) ...@@ -1052,12 +1051,9 @@ void i8xx_disable_fbc(struct drm_device *dev)
I915_WRITE(FBC_CONTROL, fbc_ctl); I915_WRITE(FBC_CONTROL, fbc_ctl);
/* Wait for compressing bit to clear */ /* Wait for compressing bit to clear */
while (I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) { if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10, 0)) {
if (time_after(jiffies, timeout)) { DRM_DEBUG_KMS("FBC idle timed out\n");
DRM_DEBUG_DRIVER("FBC idle timed out\n"); return;
break;
}
; /* do nothing */
} }
intel_wait_for_vblank(dev); intel_wait_for_vblank(dev);
...@@ -1943,7 +1939,6 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) ...@@ -1943,7 +1939,6 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B; int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B;
int trans_dpll_sel = (pipe == 0) ? 0 : 1; int trans_dpll_sel = (pipe == 0) ? 0 : 1;
u32 temp; u32 temp;
int n;
u32 pipe_bpc; u32 pipe_bpc;
temp = I915_READ(pipeconf_reg); temp = I915_READ(pipeconf_reg);
...@@ -2134,9 +2129,8 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) ...@@ -2134,9 +2129,8 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
I915_WRITE(transconf_reg, temp | TRANS_ENABLE); I915_WRITE(transconf_reg, temp | TRANS_ENABLE);
I915_READ(transconf_reg); I915_READ(transconf_reg);
while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0) if (wait_for(I915_READ(transconf_reg) & TRANS_STATE_ENABLE, 10, 0))
; DRM_ERROR("failed to enable transcoder\n");
} }
intel_crtc_load_lut(crtc); intel_crtc_load_lut(crtc);
...@@ -2167,20 +2161,10 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) ...@@ -2167,20 +2161,10 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
temp = I915_READ(pipeconf_reg); temp = I915_READ(pipeconf_reg);
if ((temp & PIPEACONF_ENABLE) != 0) { if ((temp & PIPEACONF_ENABLE) != 0) {
I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE); I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
I915_READ(pipeconf_reg);
n = 0;
/* wait for cpu pipe off, pipe state */ /* wait for cpu pipe off, pipe state */
while ((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) != 0) { if (wait_for((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) == 0, 50, 1))
n++; DRM_ERROR("failed to turn off cpu pipe\n");
if (n < 60) {
udelay(500);
continue;
} else {
DRM_DEBUG_KMS("pipe %d off delay\n",
pipe);
break;
}
}
} else } else
DRM_DEBUG_KMS("crtc %d is disabled\n", pipe); DRM_DEBUG_KMS("crtc %d is disabled\n", pipe);
...@@ -2241,20 +2225,10 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) ...@@ -2241,20 +2225,10 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
temp = I915_READ(transconf_reg); temp = I915_READ(transconf_reg);
if ((temp & TRANS_ENABLE) != 0) { if ((temp & TRANS_ENABLE) != 0) {
I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE); I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE);
I915_READ(transconf_reg);
n = 0;
/* wait for PCH transcoder off, transcoder state */ /* wait for PCH transcoder off, transcoder state */
while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) != 0) { if (wait_for((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0, 50, 1))
n++; DRM_ERROR("failed to disable transcoder\n");
if (n < 60) {
udelay(500);
continue;
} else {
DRM_DEBUG_KMS("transcoder %d off "
"delay\n", pipe);
break;
}
}
} }
temp = I915_READ(transconf_reg); temp = I915_READ(transconf_reg);
...@@ -5521,7 +5495,6 @@ void ironlake_enable_drps(struct drm_device *dev) ...@@ -5521,7 +5495,6 @@ void ironlake_enable_drps(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 rgvmodectl = I915_READ(MEMMODECTL); u32 rgvmodectl = I915_READ(MEMMODECTL);
u8 fmax, fmin, fstart, vstart; u8 fmax, fmin, fstart, vstart;
int i = 0;
/* 100ms RC evaluation intervals */ /* 100ms RC evaluation intervals */
I915_WRITE(RCUPEI, 100000); I915_WRITE(RCUPEI, 100000);
...@@ -5565,13 +5538,8 @@ void ironlake_enable_drps(struct drm_device *dev) ...@@ -5565,13 +5538,8 @@ void ironlake_enable_drps(struct drm_device *dev)
rgvmodectl |= MEMMODE_SWMODE_EN; rgvmodectl |= MEMMODE_SWMODE_EN;
I915_WRITE(MEMMODECTL, rgvmodectl); I915_WRITE(MEMMODECTL, rgvmodectl);
while (I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) { if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 1, 0))
if (i++ > 100) {
DRM_ERROR("stuck trying to change perf mode\n"); DRM_ERROR("stuck trying to change perf mode\n");
break;
}
msleep(1);
}
msleep(1); msleep(1);
ironlake_set_drps(dev, fstart); ironlake_set_drps(dev, fstart);
......
...@@ -759,22 +759,18 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, ...@@ -759,22 +759,18 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
static void ironlake_edp_panel_on (struct drm_device *dev) static void ironlake_edp_panel_on (struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long timeout = jiffies + msecs_to_jiffies(5000); u32 pp;
u32 pp, pp_status;
pp_status = I915_READ(PCH_PP_STATUS); if (I915_READ(PCH_PP_STATUS) & PP_ON)
if (pp_status & PP_ON)
return; return;
pp = I915_READ(PCH_PP_CONTROL); pp = I915_READ(PCH_PP_CONTROL);
pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON; pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON;
I915_WRITE(PCH_PP_CONTROL, pp); I915_WRITE(PCH_PP_CONTROL, pp);
do {
pp_status = I915_READ(PCH_PP_STATUS);
} while (((pp_status & PP_ON) == 0) && !time_after(jiffies, timeout));
if (time_after(jiffies, timeout)) if (wait_for(I915_READ(PCH_PP_STATUS) & PP_ON, 5000, 10))
DRM_DEBUG_KMS("panel on wait timed out: 0x%08x\n", pp_status); DRM_ERROR("panel on wait timed out: 0x%08x\n",
I915_READ(PCH_PP_STATUS));
pp &= ~(PANEL_UNLOCK_REGS | EDP_FORCE_VDD); pp &= ~(PANEL_UNLOCK_REGS | EDP_FORCE_VDD);
I915_WRITE(PCH_PP_CONTROL, pp); I915_WRITE(PCH_PP_CONTROL, pp);
...@@ -783,18 +779,15 @@ static void ironlake_edp_panel_on (struct drm_device *dev) ...@@ -783,18 +779,15 @@ static void ironlake_edp_panel_on (struct drm_device *dev)
static void ironlake_edp_panel_off (struct drm_device *dev) static void ironlake_edp_panel_off (struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long timeout = jiffies + msecs_to_jiffies(5000); u32 pp;
u32 pp, pp_status;
pp = I915_READ(PCH_PP_CONTROL); pp = I915_READ(PCH_PP_CONTROL);
pp &= ~POWER_TARGET_ON; pp &= ~POWER_TARGET_ON;
I915_WRITE(PCH_PP_CONTROL, pp); I915_WRITE(PCH_PP_CONTROL, pp);
do {
pp_status = I915_READ(PCH_PP_STATUS);
} while ((pp_status & PP_ON) && !time_after(jiffies, timeout));
if (time_after(jiffies, timeout)) if (wait_for((I915_READ(PCH_PP_STATUS) & PP_ON) == 0, 5000, 10))
DRM_DEBUG_KMS("panel off wait timed out\n"); DRM_ERROR("panel off wait timed out: 0x%08x\n",
I915_READ(PCH_PP_STATUS));
/* Make sure VDD is enabled so DP AUX will work */ /* Make sure VDD is enabled so DP AUX will work */
pp |= EDP_FORCE_VDD; pp |= EDP_FORCE_VDD;
......
...@@ -32,6 +32,20 @@ ...@@ -32,6 +32,20 @@
#include "drm_crtc.h" #include "drm_crtc.h"
#include "drm_crtc_helper.h" #include "drm_crtc_helper.h"
#define wait_for(COND, MS, W) ({ \
unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \
int ret__ = 0; \
while (! (COND)) { \
if (time_after(jiffies, timeout__)) { \
ret__ = -ETIMEDOUT; \
break; \
} \
if (W) msleep(W); \
} \
ret__; \
})
/* /*
* Display related stuff * Display related stuff
*/ */
......
...@@ -96,7 +96,7 @@ static u32 intel_lvds_get_max_backlight(struct drm_device *dev) ...@@ -96,7 +96,7 @@ static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
static void intel_lvds_set_power(struct drm_device *dev, bool on) static void intel_lvds_set_power(struct drm_device *dev, bool on)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp_status, ctl_reg, status_reg, lvds_reg; u32 ctl_reg, status_reg, lvds_reg;
if (HAS_PCH_SPLIT(dev)) { if (HAS_PCH_SPLIT(dev)) {
ctl_reg = PCH_PP_CONTROL; ctl_reg = PCH_PP_CONTROL;
...@@ -114,9 +114,8 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on) ...@@ -114,9 +114,8 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on)
I915_WRITE(ctl_reg, I915_READ(ctl_reg) | I915_WRITE(ctl_reg, I915_READ(ctl_reg) |
POWER_TARGET_ON); POWER_TARGET_ON);
do { if (wait_for(I915_READ(status_reg) & PP_ON, 1000, 0))
pp_status = I915_READ(status_reg); DRM_ERROR("timed out waiting to enable LVDS pipe");
} while ((pp_status & PP_ON) == 0);
intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle); intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle);
} else { } else {
...@@ -124,9 +123,8 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on) ...@@ -124,9 +123,8 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on)
I915_WRITE(ctl_reg, I915_READ(ctl_reg) & I915_WRITE(ctl_reg, I915_READ(ctl_reg) &
~POWER_TARGET_ON); ~POWER_TARGET_ON);
do { if (wait_for((I915_READ(status_reg) & PP_ON) == 0, 1000, 0))
pp_status = I915_READ(status_reg); DRM_ERROR("timed out waiting for LVDS pipe to turn off");
} while (pp_status & PP_ON);
I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN); I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN);
POSTING_READ(lvds_reg); POSTING_READ(lvds_reg);
......
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