On Friday, July 18, 2008 10:24 am Jesse Barnes wrote:
> On Friday, July 18, 2008 10:15 am Jesse Barnes wrote:
> > On Friday, July 18, 2008 10:09 am Michel Dänzer wrote:
> > > On Fri, 2008-07-18 at 09:41 -0700, Jesse Barnes wrote:
> > > > On Friday, July 18, 2008 1:12 am Michel Dänzer wrote:
> > > > > On Thu, 2008-07-17 at 09:32 -0700, Jesse Barnes wrote:
> > > > > > On Wednesday, July 16, 2008 11:51 pm Michel Dänzer wrote:
> > > > > > > On Wed, 2008-07-16 at 16:01 -0700, Jesse Barnes wrote:
> > > > > > > > @@ -528,7 +550,6 @@ int drm_wait_vblank(struct drm_device
> > > > > > > > *dev, void *data, if (crtc >= dev->num_crtcs)
> > > > > > > >                 return -EINVAL;
> > > > > > > >
> > > > > > > > -       drm_update_vblank_count(dev, crtc);
> > > > > > > >         seq = drm_vblank_count(dev, crtc);
> > > > > > > >
> > > > > > > >         switch (vblwait->request.type &
> > > > > > > > _DRM_VBLANK_TYPES_MASK) {
> > > > > > >
> > > > > > > I don't think this can be removed altogether, or seq will be
> > > > > > > stale if the interrupt is disabled when drm_wait_vblank() is
> > > > > > > called. So I guess call drm_update_vblank_count() when the
> > > > > > > interrupt is disabled, or just bail inside
> > > > > > > drm_update_vblank_count() when it is enabled.
> > > > > >
> > > > > > Yeah, I think just a get_vblank_counter() in vblank_disable_fn()
> > > > > > is sufficient, since we'll hit the wraparound logic again when we
> > > > > > re-enable. Look ok?
> > > > >
> > > > > I'm afraid not. Again, the wraparound logic is irrelevant for this,
> > > > > it's in drm_update_vblank_count() after all...
> > > > >
> > > > > What's wrong with
> > > > >
> > > > >       if (!dev->vblank_enabled[crtc])
> > > > >               drm_update_vblank_count(dev, crtc);
> > > > >       seq = drm_vblank_count(dev, crtc);
> > > > >       ...
> > > >
> > > > That's one way of addressing the interrupts-are-off counter update,
> > > > but really I had intended to get rid of drm_update_vblank_count() as
> > > > part of the API since it led to the spurious wraparound problem in
> > > > the first place, and isolate all the update logic to
> > > > drm_vblank_get().  My thinking was that get/put around any API usage
> > > > would be simpler, but maybe keeping the update_vblank_count() call in
> > > > place is better, I dunno.
> > >
> > > While it may be possible to fix the problems of your change in the long
> > > run, I think it's a pretty bad idea to make such fundamental changes to
> > > a basically mature implementation this shortly before submitting the
> > > functionality to the kernel. Maybe we can try your approach again once
> > > it's made it into a kernel release.
> >
> > FWIW here's the patch for the get/put change.  I'm still working on the
> > other one you suggested, but it's not trivial either...
>
> And here's the other one.

Oops, missed a few things in the last one.

Jesse
diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index 75e53da..9f09221 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -343,29 +343,10 @@ u32 drm_vblank_count(struct drm_device *dev, int crtc)
 }
 EXPORT_SYMBOL(drm_vblank_count);
 
-/**
- * drm_update_vblank_count - update the master vblank counter
- * @dev: DRM device
- * @crtc: counter to update
- *
- * Call back into the driver to update the appropriate vblank counter
- * (specified by @crtc).  Deal with wraparound, if it occurred, and
- * update the last read value so we can deal with wraparound on the next
- * call if necessary.
- *
- * Only necessary when going from off->on, to account for frames we
- * didn't get an interrupt for.
- *
- * Note: caller must hold dev->vbl_lock since this reads & writes
- * device vblank fields.
- */
-void drm_update_vblank_count(struct drm_device *dev, int crtc)
+void do_update_vblank_count(struct drm_device *dev, int crtc)
 {
 	u32 cur_vblank, diff;
 
-	if (dev->vblank_suspend[crtc])
-		return;
-
 	/*
 	 * Interrupts were disabled prior to this call, so deal with counter
 	 * wrap if needed.
@@ -392,11 +373,39 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc)
 
 	DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n",
 		  crtc, diff);
-
 	atomic_add(diff, &dev->_vblank_count[crtc]);
 }
 
 /**
+ * drm_update_vblank_count - update the master vblank counter
+ * @dev: DRM device
+ * @crtc: counter to update
+ *
+ * Call back into the driver to update the appropriate vblank counter
+ * (specified by @crtc).  Deal with wraparound, if it occurred, and
+ * update the last read value so we can deal with wraparound on the next
+ * call if necessary.
+ *
+ * Only necessary when going from off->on, to account for frames we
+ * didn't get an interrupt for.
+ *
+ * Note: caller must hold dev->vbl_lock since this reads & writes
+ * device vblank fields.
+ */
+void drm_update_vblank_count(struct drm_device *dev, int crtc)
+{
+	unsigned long irqflags;
+
+	if (dev->vblank_suspend[crtc] || dev->vblank_enabled[crtc])
+		return;
+
+	spin_lock_irqsave(&dev->vbl_lock, irqflags);
+	do_update_vblank_count(dev, crtc);
+	spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+}
+EXPORT_SYMBOL(drm_update_vblank_count);
+
+/**
  * drm_vblank_get - get a reference count on vblank events
  * @dev: DRM device
  * @crtc: which CRTC to own
@@ -420,8 +429,8 @@ int drm_vblank_get(struct drm_device *dev, int crtc)
 		if (ret)
 			atomic_dec(&dev->vblank_refcount[crtc]);
 		else {
+			do_update_vblank_count(dev, crtc);
 			dev->vblank_enabled[crtc] = 1;
-			drm_update_vblank_count(dev, crtc);
 		}
 	}
 	spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
@@ -462,8 +471,6 @@ int drm_modeset_ctl(struct drm_device *dev, void *data,
 		    struct drm_file *file_priv)
 {
 	struct drm_modeset_ctl *modeset = data;
-	unsigned long irqflags;
-	u32 new, diff;
 	int crtc, ret = 0;
 
 	crtc = modeset->crtc;
@@ -474,28 +481,26 @@ int drm_modeset_ctl(struct drm_device *dev, void *data,
 
 	switch (modeset->cmd) {
 	case _DRM_PRE_MODESET:
-		spin_lock_irqsave(&dev->vbl_lock, irqflags);
-		dev->vblank_disable_allowed = 1;
-		if (!dev->vblank_enabled[crtc]) {
-			dev->vblank_premodeset[crtc] =
-				dev->driver->get_vblank_counter(dev, crtc);
-			dev->vblank_suspend[crtc] = 1;
-		}
-		spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+		dev->vblank_premodeset[crtc] =
+			dev->driver->get_vblank_counter(dev, crtc);
+		dev->vblank_suspend[crtc] = 1;
 		break;
 	case _DRM_POST_MODESET:
-		spin_lock_irqsave(&dev->vbl_lock, irqflags);
-		dev->vblank_disable_allowed = 1;
-		new = dev->driver->get_vblank_counter(dev, crtc);
-		if (dev->vblank_suspend[crtc] && !dev->vblank_enabled[crtc]) {
-			if (new > dev->vblank_premodeset[crtc])
-				diff = dev->vblank_premodeset[crtc] - new;
-			else
-				diff = new;
-			atomic_add(diff, &dev->_vblank_count[crtc]);
+		if (dev->vblank_suspend[crtc]) {
+			u32 new = dev->driver->get_vblank_counter(dev, crtc);
+
+			/* Compensate for spurious wraparound */
+			if (new < dev->vblank_premodeset[crtc]) {
+				atomic_sub(dev->max_vblank_count + new -
+					   dev->vblank_premodeset[crtc],
+					   &dev->_vblank_count[crtc]);
+				DRM_DEBUG("vblank_premodeset[%d]=0x%x, new=0x%x"
+					  " => _vblank_count[%d]-=0x%x\n", crtc,
+					  dev->vblank_premodeset[crtc], new,
+					  crtc, dev->max_vblank_count + new -
+					  dev->vblank_premodeset[crtc]);
+			}
 		}
-		dev->vblank_suspend[crtc] = 0;
-		spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 		break;
 	default:
 		ret = -EINVAL;
@@ -549,6 +554,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
 	if (crtc >= dev->num_crtcs)
 		return -EINVAL;
 
+	drm_update_vblank_count(dev, crtc);
 	seq = drm_vblank_count(dev, crtc);
 
 	switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) {
diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index ecb2d7f..713759e 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -769,6 +769,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
 
 	DRM_SPINUNLOCK_IRQRESTORE(&dev->drw_lock, irqflags);
 
+	drm_update_vblank_count(dev, pipe);
 	curseq = drm_vblank_count(dev, pipe);
 
 	if (seqtype == _DRM_VBLANK_RELATIVE)
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
--
_______________________________________________
Dri-devel mailing list
Dri-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel

Reply via email to