drm/i915: Ensure that while(INREG()) are bounded (v2)
authorChris Wilson <chris@chris-wilson.co.uk>
Sat, 7 Aug 2010 10:01:35 +0000 (11:01 +0100)
committerEric Anholt <eric@anholt.net>
Mon, 9 Aug 2010 18:24:35 +0000 (11:24 -0700)
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>
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_lvds.c

index cfcf85496e305d8e3c75f12d7a490162d4d7ec47..c43176d77549b36801ce0a5a7dbed9848f3d2abc 100644 (file)
@@ -185,8 +185,9 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
        DRM_DEBUG_KMS("pch crt adpa 0x%x", 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)) {
                I915_WRITE(PCH_ADPA, temp);
@@ -237,17 +238,13 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
        hotplug_en |= CRT_HOTPLUG_FORCE_DETECT;
 
        for (i = 0; i < tries ; i++) {
-               unsigned long timeout;
                /* turn on the FORCE_DETECT */
                I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
-               timeout = jiffies + msecs_to_jiffies(1000);
                /* wait for FORCE_DETECT to go off */
-               do {
-                       if (!(I915_READ(PORT_HOTPLUG_EN) &
-                                       CRT_HOTPLUG_FORCE_DETECT))
-                               break;
-                       msleep(1);
-               } while (time_after(timeout, jiffies));
+               if (wait_for((I915_READ(PORT_HOTPLUG_EN) &
+                             CRT_HOTPLUG_FORCE_DETECT) == 0,
+                            1000, 1))
+                       DRM_ERROR("timed out waiting for FORCE_DETECT to go off");
        }
 
        stat = I915_READ(PORT_HOTPLUG_STAT);
index 1eae234ff485699c198a26cc757d3d70d9b4204f..0bf683dd512c65c4bb3f7cf57bdd1597d5639c72 100644 (file)
@@ -1037,7 +1037,6 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 void i8xx_disable_fbc(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       unsigned long timeout = jiffies + msecs_to_jiffies(1);
        u32 fbc_ctl;
 
        if (!I915_HAS_FBC(dev))
@@ -1052,12 +1051,9 @@ void i8xx_disable_fbc(struct drm_device *dev)
        I915_WRITE(FBC_CONTROL, fbc_ctl);
 
        /* Wait for compressing bit to clear */
-       while (I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) {
-               if (time_after(jiffies, timeout)) {
-                       DRM_DEBUG_DRIVER("FBC idle timed out\n");
-                       break;
-               }
-               ; /* do nothing */
+       if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10, 0)) {
+               DRM_DEBUG_KMS("FBC idle timed out\n");
+               return;
        }
 
        intel_wait_for_vblank(dev);
@@ -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_dpll_sel = (pipe == 0) ? 0 : 1;
        u32 temp;
-       int n;
        u32 pipe_bpc;
 
        temp = I915_READ(pipeconf_reg);
@@ -2134,9 +2129,8 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                        I915_WRITE(transconf_reg, temp | TRANS_ENABLE);
                        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);
@@ -2167,20 +2161,10 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                temp = I915_READ(pipeconf_reg);
                if ((temp & PIPEACONF_ENABLE) != 0) {
                        I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
-                       I915_READ(pipeconf_reg);
-                       n = 0;
+
                        /* wait for cpu pipe off, pipe state */
-                       while ((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) != 0) {
-                               n++;
-                               if (n < 60) {
-                                       udelay(500);
-                                       continue;
-                               } else {
-                                       DRM_DEBUG_KMS("pipe %d off delay\n",
-                                                               pipe);
-                                       break;
-                               }
-                       }
+                       if (wait_for((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) == 0, 50, 1))
+                               DRM_ERROR("failed to turn off cpu pipe\n");
                } else
                        DRM_DEBUG_KMS("crtc %d is disabled\n", pipe);
 
@@ -2241,20 +2225,10 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                temp = I915_READ(transconf_reg);
                if ((temp & TRANS_ENABLE) != 0) {
                        I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE);
-                       I915_READ(transconf_reg);
-                       n = 0;
+
                        /* wait for PCH transcoder off, transcoder state */
-                       while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) != 0) {
-                               n++;
-                               if (n < 60) {
-                                       udelay(500);
-                                       continue;
-                               } else {
-                                       DRM_DEBUG_KMS("transcoder %d off "
-                                                       "delay\n", pipe);
-                                       break;
-                               }
-                       }
+                       if (wait_for((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0, 50, 1))
+                               DRM_ERROR("failed to disable transcoder\n");
                }
 
                temp = I915_READ(transconf_reg);
@@ -5521,7 +5495,6 @@ void ironlake_enable_drps(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 rgvmodectl = I915_READ(MEMMODECTL);
        u8 fmax, fmin, fstart, vstart;
-       int i = 0;
 
        /* 100ms RC evaluation intervals */
        I915_WRITE(RCUPEI, 100000);
@@ -5565,13 +5538,8 @@ void ironlake_enable_drps(struct drm_device *dev)
        rgvmodectl |= MEMMODE_SWMODE_EN;
        I915_WRITE(MEMMODECTL, rgvmodectl);
 
-       while (I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) {
-               if (i++ > 100) {
-                       DRM_ERROR("stuck trying to change perf mode\n");
-                       break;
-               }
-               msleep(1);
-       }
+       if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 1, 0))
+               DRM_ERROR("stuck trying to change perf mode\n");
        msleep(1);
 
        ironlake_set_drps(dev, fstart);
index cee5d9ceb3b86625eabf6338d5662cbae8095b27..c6629bd9430f03276b2566d3ba0a4cc5258f66f7 100644 (file)
@@ -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)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       unsigned long timeout = jiffies + msecs_to_jiffies(5000);
-       u32 pp, pp_status;
+       u32 pp;
 
-       pp_status = I915_READ(PCH_PP_STATUS);
-       if (pp_status & PP_ON)
+       if (I915_READ(PCH_PP_STATUS) & PP_ON)
                return;
 
        pp = I915_READ(PCH_PP_CONTROL);
        pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON;
        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))
-               DRM_DEBUG_KMS("panel on wait timed out: 0x%08x\n", pp_status);
+       if (wait_for(I915_READ(PCH_PP_STATUS) & PP_ON, 5000, 10))
+               DRM_ERROR("panel on wait timed out: 0x%08x\n",
+                         I915_READ(PCH_PP_STATUS));
 
        pp &= ~(PANEL_UNLOCK_REGS | EDP_FORCE_VDD);
        I915_WRITE(PCH_PP_CONTROL, pp);
@@ -783,18 +779,15 @@ static void ironlake_edp_panel_on (struct drm_device *dev)
 static void ironlake_edp_panel_off (struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       unsigned long timeout = jiffies + msecs_to_jiffies(5000);
-       u32 pp, pp_status;
+       u32 pp;
 
        pp = I915_READ(PCH_PP_CONTROL);
        pp &= ~POWER_TARGET_ON;
        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))
-               DRM_DEBUG_KMS("panel off wait timed out\n");
+       if (wait_for((I915_READ(PCH_PP_STATUS) & PP_ON) == 0, 5000, 10))
+               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 */
        pp |= EDP_FORCE_VDD;
index c552b06e5d213bccaa3d31f025baa130f5d39fad..2a3eaaf64b24efd88a249dc8f325646f0b521eaa 100644 (file)
 #include "drm_crtc.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
  */
index cb5821eb59b635593103e896f4ac11abc20ba969..b819c10811470775b19826e407ba75fffd6a9b68 100644 (file)
@@ -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)
 {
        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)) {
                ctl_reg = PCH_PP_CONTROL;
@@ -114,9 +114,8 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on)
 
                I915_WRITE(ctl_reg, I915_READ(ctl_reg) |
                           POWER_TARGET_ON);
-               do {
-                       pp_status = I915_READ(status_reg);
-               } while ((pp_status & PP_ON) == 0);
+               if (wait_for(I915_READ(status_reg) & PP_ON, 1000, 0))
+                       DRM_ERROR("timed out waiting to enable LVDS pipe");
 
                intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle);
        } else {
@@ -124,9 +123,8 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on)
 
                I915_WRITE(ctl_reg, I915_READ(ctl_reg) &
                           ~POWER_TARGET_ON);
-               do {
-                       pp_status = I915_READ(status_reg);
-               } while (pp_status & PP_ON);
+               if (wait_for((I915_READ(status_reg) & PP_ON) == 0, 1000, 0))
+                       DRM_ERROR("timed out waiting for LVDS pipe to turn off");
 
                I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN);
                POSTING_READ(lvds_reg);