Browse Source

drm/i915: fix up _wait_for macro

As Thomas Gleixner spotted, it's rather horrible racy:
- We can miss almost a full tick, so need to compensate by 1 jiffy.
- We need to re-check the condition when having timed-out, since a
  the last check could have been before the timeout expired. E.g. when
  we've been preempted or a long irq happened.

Cc: Thomas Gleixner <tglx@linutronix.de>
Reported-by: Jack Winter <jbh@alchemy.lu>
Cc: Jack Winter <jbh@alchemy.lu>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Daniel Vetter 12 years ago
parent
commit
1d5bfac96f
1 changed files with 11 additions and 2 deletions
  1. 11 2
      drivers/gpu/drm/i915/intel_drv.h

+ 11 - 2
drivers/gpu/drm/i915/intel_drv.h

@@ -33,12 +33,21 @@
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_dp_helper.h>
 
+/**
+ * _wait_for - magic (register) wait macro
+ *
+ * Does the right thing for modeset paths when run under kdgb or similar atomic
+ * contexts. Note that it's important that we check the condition again after
+ * having timed out, since the timeout could be due to preemption or similar and
+ * we've never had a chance to check the condition before the timeout.
+ */
 #define _wait_for(COND, MS, W) ({ \
-	unsigned long timeout__ = jiffies + msecs_to_jiffies(MS);	\
+	unsigned long timeout__ = jiffies + msecs_to_jiffies(MS) + 1;	\
 	int ret__ = 0;							\
 	while (!(COND)) {						\
 		if (time_after(jiffies, timeout__)) {			\
-			ret__ = -ETIMEDOUT;				\
+			if (!(COND))					\
+				ret__ = -ETIMEDOUT;			\
 			break;						\
 		}							\
 		if (W && drm_can_sleep())  {				\