diff options
| author | Chris Wilson <chris@chris-wilson.co.uk> | 2010-08-07 06:01:35 -0400 |
|---|---|---|
| committer | Eric Anholt <eric@anholt.net> | 2010-08-09 14:24:35 -0400 |
| commit | 913d8d110078788c14812dce8bb62c37946821d2 (patch) | |
| tree | 982a622078194b438bf75d0ee4c77cf1e4f0260e | |
| parent | dd785e35cb3c430c2290d351e67715864f7e5db5 (diff) | |
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: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Eric Anholt <eric@anholt.net>
| -rw-r--r-- | drivers/gpu/drm/i915/intel_crt.c | 17 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 58 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_dp.c | 25 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 14 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_lvds.c | 12 |
5 files changed, 48 insertions, 78 deletions
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index cfcf85496e30..c43176d77549 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c | |||
| @@ -185,8 +185,9 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) | |||
| 185 | DRM_DEBUG_KMS("pch crt adpa 0x%x", adpa); | 185 | DRM_DEBUG_KMS("pch crt adpa 0x%x", adpa); |
| 186 | I915_WRITE(PCH_ADPA, adpa); | 186 | I915_WRITE(PCH_ADPA, adpa); |
| 187 | 187 | ||
| 188 | while ((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) != 0) | 188 | if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, |
| 189 | ; | 189 | 1000, 1)) |
| 190 | DRM_ERROR("timed out waiting for FORCE_TRIGGER"); | ||
| 190 | 191 | ||
| 191 | if (HAS_PCH_CPT(dev)) { | 192 | if (HAS_PCH_CPT(dev)) { |
| 192 | I915_WRITE(PCH_ADPA, temp); | 193 | I915_WRITE(PCH_ADPA, temp); |
| @@ -237,17 +238,13 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) | |||
| 237 | hotplug_en |= CRT_HOTPLUG_FORCE_DETECT; | 238 | hotplug_en |= CRT_HOTPLUG_FORCE_DETECT; |
| 238 | 239 | ||
| 239 | for (i = 0; i < tries ; i++) { | 240 | for (i = 0; i < tries ; i++) { |
| 240 | unsigned long timeout; | ||
| 241 | /* turn on the FORCE_DETECT */ | 241 | /* turn on the FORCE_DETECT */ |
| 242 | I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); | 242 | I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); |
| 243 | timeout = jiffies + msecs_to_jiffies(1000); | ||
| 244 | /* wait for FORCE_DETECT to go off */ | 243 | /* wait for FORCE_DETECT to go off */ |
| 245 | do { | 244 | if (wait_for((I915_READ(PORT_HOTPLUG_EN) & |
| 246 | if (!(I915_READ(PORT_HOTPLUG_EN) & | 245 | CRT_HOTPLUG_FORCE_DETECT) == 0, |
| 247 | CRT_HOTPLUG_FORCE_DETECT)) | 246 | 1000, 1)) |
| 248 | break; | 247 | DRM_ERROR("timed out waiting for FORCE_DETECT to go off"); |
| 249 | msleep(1); | ||
| 250 | } while (time_after(timeout, jiffies)); | ||
| 251 | } | 248 | } |
| 252 | 249 | ||
| 253 | stat = I915_READ(PORT_HOTPLUG_STAT); | 250 | stat = I915_READ(PORT_HOTPLUG_STAT); |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1eae234ff485..0bf683dd512c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
| @@ -1037,7 +1037,6 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) | |||
| 1037 | void i8xx_disable_fbc(struct drm_device *dev) | 1037 | void i8xx_disable_fbc(struct drm_device *dev) |
| 1038 | { | 1038 | { |
| 1039 | struct drm_i915_private *dev_priv = dev->dev_private; | 1039 | struct drm_i915_private *dev_priv = dev->dev_private; |
| 1040 | unsigned long timeout = jiffies + msecs_to_jiffies(1); | ||
| 1041 | u32 fbc_ctl; | 1040 | u32 fbc_ctl; |
| 1042 | 1041 | ||
| 1043 | if (!I915_HAS_FBC(dev)) | 1042 | if (!I915_HAS_FBC(dev)) |
| @@ -1052,12 +1051,9 @@ void i8xx_disable_fbc(struct drm_device *dev) | |||
| 1052 | I915_WRITE(FBC_CONTROL, fbc_ctl); | 1051 | I915_WRITE(FBC_CONTROL, fbc_ctl); |
| 1053 | 1052 | ||
| 1054 | /* Wait for compressing bit to clear */ | 1053 | /* Wait for compressing bit to clear */ |
| 1055 | while (I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) { | 1054 | if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10, 0)) { |
| 1056 | if (time_after(jiffies, timeout)) { | 1055 | DRM_DEBUG_KMS("FBC idle timed out\n"); |
| 1057 | DRM_DEBUG_DRIVER("FBC idle timed out\n"); | 1056 | return; |
| 1058 | break; | ||
| 1059 | } | ||
| 1060 | ; /* do nothing */ | ||
| 1061 | } | 1057 | } |
| 1062 | 1058 | ||
| 1063 | intel_wait_for_vblank(dev); | 1059 | intel_wait_for_vblank(dev); |
| @@ -1943,7 +1939,6 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) | |||
| 1943 | int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B; | 1939 | int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B; |
| 1944 | int trans_dpll_sel = (pipe == 0) ? 0 : 1; | 1940 | int trans_dpll_sel = (pipe == 0) ? 0 : 1; |
| 1945 | u32 temp; | 1941 | u32 temp; |
| 1946 | int n; | ||
| 1947 | u32 pipe_bpc; | 1942 | u32 pipe_bpc; |
| 1948 | 1943 | ||
| 1949 | temp = I915_READ(pipeconf_reg); | 1944 | temp = I915_READ(pipeconf_reg); |
| @@ -2134,9 +2129,8 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) | |||
| 2134 | I915_WRITE(transconf_reg, temp | TRANS_ENABLE); | 2129 | I915_WRITE(transconf_reg, temp | TRANS_ENABLE); |
| 2135 | I915_READ(transconf_reg); | 2130 | I915_READ(transconf_reg); |
| 2136 | 2131 | ||
| 2137 | while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0) | 2132 | if (wait_for(I915_READ(transconf_reg) & TRANS_STATE_ENABLE, 10, 0)) |
| 2138 | ; | 2133 | DRM_ERROR("failed to enable transcoder\n"); |
| 2139 | |||
| 2140 | } | 2134 | } |
| 2141 | 2135 | ||
| 2142 | intel_crtc_load_lut(crtc); | 2136 | intel_crtc_load_lut(crtc); |
| @@ -2167,20 +2161,10 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) | |||
| 2167 | temp = I915_READ(pipeconf_reg); | 2161 | temp = I915_READ(pipeconf_reg); |
| 2168 | if ((temp & PIPEACONF_ENABLE) != 0) { | 2162 | if ((temp & PIPEACONF_ENABLE) != 0) { |
| 2169 | I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE); | 2163 | I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE); |
| 2170 | I915_READ(pipeconf_reg); | 2164 | |
| 2171 | n = 0; | ||
| 2172 | /* wait for cpu pipe off, pipe state */ | 2165 | /* wait for cpu pipe off, pipe state */ |
| 2173 | while ((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) != 0) { | 2166 | if (wait_for((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) == 0, 50, 1)) |
| 2174 | n++; | 2167 | DRM_ERROR("failed to turn off cpu pipe\n"); |
| 2175 | if (n < 60) { | ||
| 2176 | udelay(500); | ||
| 2177 | continue; | ||
| 2178 | } else { | ||
| 2179 | DRM_DEBUG_KMS("pipe %d off delay\n", | ||
| 2180 | pipe); | ||
| 2181 | break; | ||
| 2182 | } | ||
| 2183 | } | ||
| 2184 | } else | 2168 | } else |
| 2185 | DRM_DEBUG_KMS("crtc %d is disabled\n", pipe); | 2169 | DRM_DEBUG_KMS("crtc %d is disabled\n", pipe); |
| 2186 | 2170 | ||
| @@ -2241,20 +2225,10 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) | |||
| 2241 | temp = I915_READ(transconf_reg); | 2225 | temp = I915_READ(transconf_reg); |
| 2242 | if ((temp & TRANS_ENABLE) != 0) { | 2226 | if ((temp & TRANS_ENABLE) != 0) { |
| 2243 | I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE); | 2227 | I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE); |
| 2244 | I915_READ(transconf_reg); | 2228 | |
| 2245 | n = 0; | ||
| 2246 | /* wait for PCH transcoder off, transcoder state */ | 2229 | /* wait for PCH transcoder off, transcoder state */ |
| 2247 | while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) != 0) { | 2230 | if (wait_for((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0, 50, 1)) |
| 2248 | n++; | 2231 | DRM_ERROR("failed to disable transcoder\n"); |
| 2249 | if (n < 60) { | ||
| 2250 | udelay(500); | ||
| 2251 | continue; | ||
| 2252 | } else { | ||
| 2253 | DRM_DEBUG_KMS("transcoder %d off " | ||
| 2254 | "delay\n", pipe); | ||
| 2255 | break; | ||
| 2256 | } | ||
| 2257 | } | ||
| 2258 | } | 2232 | } |
| 2259 | 2233 | ||
| 2260 | temp = I915_READ(transconf_reg); | 2234 | temp = I915_READ(transconf_reg); |
| @@ -5521,7 +5495,6 @@ void ironlake_enable_drps(struct drm_device *dev) | |||
| 5521 | struct drm_i915_private *dev_priv = dev->dev_private; | 5495 | struct drm_i915_private *dev_priv = dev->dev_private; |
| 5522 | u32 rgvmodectl = I915_READ(MEMMODECTL); | 5496 | u32 rgvmodectl = I915_READ(MEMMODECTL); |
| 5523 | u8 fmax, fmin, fstart, vstart; | 5497 | u8 fmax, fmin, fstart, vstart; |
| 5524 | int i = 0; | ||
| 5525 | 5498 | ||
| 5526 | /* 100ms RC evaluation intervals */ | 5499 | /* 100ms RC evaluation intervals */ |
| 5527 | I915_WRITE(RCUPEI, 100000); | 5500 | I915_WRITE(RCUPEI, 100000); |
| @@ -5565,13 +5538,8 @@ void ironlake_enable_drps(struct drm_device *dev) | |||
| 5565 | rgvmodectl |= MEMMODE_SWMODE_EN; | 5538 | rgvmodectl |= MEMMODE_SWMODE_EN; |
| 5566 | I915_WRITE(MEMMODECTL, rgvmodectl); | 5539 | I915_WRITE(MEMMODECTL, rgvmodectl); |
| 5567 | 5540 | ||
| 5568 | while (I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) { | 5541 | if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 1, 0)) |
| 5569 | if (i++ > 100) { | 5542 | DRM_ERROR("stuck trying to change perf mode\n"); |
| 5570 | DRM_ERROR("stuck trying to change perf mode\n"); | ||
| 5571 | break; | ||
| 5572 | } | ||
| 5573 | msleep(1); | ||
| 5574 | } | ||
| 5575 | msleep(1); | 5543 | msleep(1); |
| 5576 | 5544 | ||
| 5577 | ironlake_set_drps(dev, fstart); | 5545 | ironlake_set_drps(dev, fstart); |
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index cee5d9ceb3b8..c6629bd9430f 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c | |||
| @@ -759,22 +759,18 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, | |||
| 759 | static void ironlake_edp_panel_on (struct drm_device *dev) | 759 | static void ironlake_edp_panel_on (struct drm_device *dev) |
| 760 | { | 760 | { |
| 761 | struct drm_i915_private *dev_priv = dev->dev_private; | 761 | struct drm_i915_private *dev_priv = dev->dev_private; |
| 762 | unsigned long timeout = jiffies + msecs_to_jiffies(5000); | 762 | u32 pp; |
| 763 | u32 pp, pp_status; | ||
| 764 | 763 | ||
| 765 | pp_status = I915_READ(PCH_PP_STATUS); | 764 | if (I915_READ(PCH_PP_STATUS) & PP_ON) |
| 766 | if (pp_status & PP_ON) | ||
| 767 | return; | 765 | return; |
| 768 | 766 | ||
| 769 | pp = I915_READ(PCH_PP_CONTROL); | 767 | pp = I915_READ(PCH_PP_CONTROL); |
| 770 | pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON; | 768 | pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON; |
| 771 | I915_WRITE(PCH_PP_CONTROL, pp); | 769 | I915_WRITE(PCH_PP_CONTROL, pp); |
| 772 | do { | ||
| 773 | pp_status = I915_READ(PCH_PP_STATUS); | ||
| 774 | } while (((pp_status & PP_ON) == 0) && !time_after(jiffies, timeout)); | ||
| 775 | 770 | ||
| 776 | if (time_after(jiffies, timeout)) | 771 | if (wait_for(I915_READ(PCH_PP_STATUS) & PP_ON, 5000, 10)) |
| 777 | DRM_DEBUG_KMS("panel on wait timed out: 0x%08x\n", pp_status); | 772 | DRM_ERROR("panel on wait timed out: 0x%08x\n", |
| 773 | I915_READ(PCH_PP_STATUS)); | ||
| 778 | 774 | ||
| 779 | pp &= ~(PANEL_UNLOCK_REGS | EDP_FORCE_VDD); | 775 | pp &= ~(PANEL_UNLOCK_REGS | EDP_FORCE_VDD); |
| 780 | I915_WRITE(PCH_PP_CONTROL, pp); | 776 | I915_WRITE(PCH_PP_CONTROL, pp); |
| @@ -783,18 +779,15 @@ static void ironlake_edp_panel_on (struct drm_device *dev) | |||
| 783 | static void ironlake_edp_panel_off (struct drm_device *dev) | 779 | static void ironlake_edp_panel_off (struct drm_device *dev) |
| 784 | { | 780 | { |
| 785 | struct drm_i915_private *dev_priv = dev->dev_private; | 781 | struct drm_i915_private *dev_priv = dev->dev_private; |
| 786 | unsigned long timeout = jiffies + msecs_to_jiffies(5000); | 782 | u32 pp; |
| 787 | u32 pp, pp_status; | ||
| 788 | 783 | ||
| 789 | pp = I915_READ(PCH_PP_CONTROL); | 784 | pp = I915_READ(PCH_PP_CONTROL); |
| 790 | pp &= ~POWER_TARGET_ON; | 785 | pp &= ~POWER_TARGET_ON; |
| 791 | I915_WRITE(PCH_PP_CONTROL, pp); | 786 | I915_WRITE(PCH_PP_CONTROL, pp); |
| 792 | do { | ||
| 793 | pp_status = I915_READ(PCH_PP_STATUS); | ||
| 794 | } while ((pp_status & PP_ON) && !time_after(jiffies, timeout)); | ||
| 795 | 787 | ||
| 796 | if (time_after(jiffies, timeout)) | 788 | if (wait_for((I915_READ(PCH_PP_STATUS) & PP_ON) == 0, 5000, 10)) |
| 797 | DRM_DEBUG_KMS("panel off wait timed out\n"); | 789 | DRM_ERROR("panel off wait timed out: 0x%08x\n", |
| 790 | I915_READ(PCH_PP_STATUS)); | ||
| 798 | 791 | ||
| 799 | /* Make sure VDD is enabled so DP AUX will work */ | 792 | /* Make sure VDD is enabled so DP AUX will work */ |
| 800 | pp |= EDP_FORCE_VDD; | 793 | pp |= EDP_FORCE_VDD; |
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index c552b06e5d21..2a3eaaf64b24 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
| @@ -32,6 +32,20 @@ | |||
| 32 | #include "drm_crtc.h" | 32 | #include "drm_crtc.h" |
| 33 | 33 | ||
| 34 | #include "drm_crtc_helper.h" | 34 | #include "drm_crtc_helper.h" |
| 35 | |||
| 36 | #define wait_for(COND, MS, W) ({ \ | ||
| 37 | unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \ | ||
| 38 | int ret__ = 0; \ | ||
| 39 | while (! (COND)) { \ | ||
| 40 | if (time_after(jiffies, timeout__)) { \ | ||
| 41 | ret__ = -ETIMEDOUT; \ | ||
| 42 | break; \ | ||
| 43 | } \ | ||
| 44 | if (W) msleep(W); \ | ||
| 45 | } \ | ||
| 46 | ret__; \ | ||
| 47 | }) | ||
| 48 | |||
| 35 | /* | 49 | /* |
| 36 | * Display related stuff | 50 | * Display related stuff |
| 37 | */ | 51 | */ |
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index cb5821eb59b6..b819c1081147 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c | |||
| @@ -96,7 +96,7 @@ static u32 intel_lvds_get_max_backlight(struct drm_device *dev) | |||
| 96 | static void intel_lvds_set_power(struct drm_device *dev, bool on) | 96 | static void intel_lvds_set_power(struct drm_device *dev, bool on) |
| 97 | { | 97 | { |
| 98 | struct drm_i915_private *dev_priv = dev->dev_private; | 98 | struct drm_i915_private *dev_priv = dev->dev_private; |
| 99 | u32 pp_status, ctl_reg, status_reg, lvds_reg; | 99 | u32 ctl_reg, status_reg, lvds_reg; |
| 100 | 100 | ||
| 101 | if (HAS_PCH_SPLIT(dev)) { | 101 | if (HAS_PCH_SPLIT(dev)) { |
| 102 | ctl_reg = PCH_PP_CONTROL; | 102 | ctl_reg = PCH_PP_CONTROL; |
| @@ -114,9 +114,8 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on) | |||
| 114 | 114 | ||
| 115 | I915_WRITE(ctl_reg, I915_READ(ctl_reg) | | 115 | I915_WRITE(ctl_reg, I915_READ(ctl_reg) | |
| 116 | POWER_TARGET_ON); | 116 | POWER_TARGET_ON); |
| 117 | do { | 117 | if (wait_for(I915_READ(status_reg) & PP_ON, 1000, 0)) |
| 118 | pp_status = I915_READ(status_reg); | 118 | DRM_ERROR("timed out waiting to enable LVDS pipe"); |
| 119 | } while ((pp_status & PP_ON) == 0); | ||
| 120 | 119 | ||
| 121 | intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle); | 120 | intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle); |
| 122 | } else { | 121 | } else { |
| @@ -124,9 +123,8 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on) | |||
| 124 | 123 | ||
| 125 | I915_WRITE(ctl_reg, I915_READ(ctl_reg) & | 124 | I915_WRITE(ctl_reg, I915_READ(ctl_reg) & |
| 126 | ~POWER_TARGET_ON); | 125 | ~POWER_TARGET_ON); |
| 127 | do { | 126 | if (wait_for((I915_READ(status_reg) & PP_ON) == 0, 1000, 0)) |
| 128 | pp_status = I915_READ(status_reg); | 127 | DRM_ERROR("timed out waiting for LVDS pipe to turn off"); |
| 129 | } while (pp_status & PP_ON); | ||
| 130 | 128 | ||
| 131 | I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN); | 129 | I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN); |
| 132 | POSTING_READ(lvds_reg); | 130 | POSTING_READ(lvds_reg); |
