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 /drivers/gpu/drm/i915 | |
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>
Diffstat (limited to 'drivers/gpu/drm/i915')
-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); |