aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2010-08-07 06:01:35 -0400
committerEric Anholt <eric@anholt.net>2010-08-09 14:24:35 -0400
commit913d8d110078788c14812dce8bb62c37946821d2 (patch)
tree982a622078194b438bf75d0ee4c77cf1e4f0260e /drivers/gpu/drm/i915
parentdd785e35cb3c430c2290d351e67715864f7e5db5 (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.c17
-rw-r--r--drivers/gpu/drm/i915/intel_display.c58
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c25
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h14
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c12
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)
1037void i8xx_disable_fbc(struct drm_device *dev) 1037void 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,
759static void ironlake_edp_panel_on (struct drm_device *dev) 759static 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)
783static void ironlake_edp_panel_off (struct drm_device *dev) 779static 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)
96static void intel_lvds_set_power(struct drm_device *dev, bool on) 96static 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);