drm: i915 updates
author=?utf-8?q?Michel_D=C3=A4nzer?= <michel@tungstengraphics.com>
Tue, 24 Oct 2006 15:05:09 +0000 (01:05 +1000)
committerairlied <airlied@linux.ie>
Thu, 7 Dec 2006 04:53:31 +0000 (15:53 +1100)
Add support for DRM_VBLANK_NEXTONMISS.
Bump minor for swap scheduling ioctl and secondary vblank support.
Avoid mis-counting vblank interrupts when they're only enabled for pipe A.
Only schedule vblank tasklet if there are scheduled swaps pending.

Signed-off-by: Dave Airlie <airlied@linux.ie>
drivers/char/drm/i915_drv.h
drivers/char/drm/i915_irq.c

index 334b0ce..93cdcfe 100644 (file)
  * 1.3: Add vblank support
  * 1.4: Fix cmdbuffer path, add heap destroy
  * 1.5: Add vblank pipe configuration
+ * 1.6: - New ioctl for scheduling buffer swaps on vertical blank
+ *      - Support vertical blank on secondary display pipe
  */
 #define DRIVER_MAJOR           1
-#define DRIVER_MINOR           5
+#define DRIVER_MINOR           6
 #define DRIVER_PATCHLEVEL      0
 
 typedef struct _drm_i915_ring_buffer {
index 1a5edec..e5463b1 100644 (file)
@@ -153,20 +153,26 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
                DRM_WAKEUP(&dev_priv->irq_queue);
 
        if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
-               if ((dev_priv->vblank_pipe &
+               int vblank_pipe = dev_priv->vblank_pipe;
+
+               if ((vblank_pipe &
                     (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B))
                    == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) {
                        if (temp & VSYNC_PIPEA_FLAG)
                                atomic_inc(&dev->vbl_received);
                        if (temp & VSYNC_PIPEB_FLAG)
                                atomic_inc(&dev->vbl_received2);
-               } else
+               } else if (((temp & VSYNC_PIPEA_FLAG) &&
+                           (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) ||
+                          ((temp & VSYNC_PIPEB_FLAG) &&
+                           (vblank_pipe & DRM_I915_VBLANK_PIPE_B)))
                        atomic_inc(&dev->vbl_received);
 
                DRM_WAKEUP(&dev->vbl_queue);
                drm_vbl_send_signals(dev);
 
-               drm_locked_tasklet(dev, i915_vblank_tasklet);
+               if (dev_priv->swaps_pending > 0)
+                       drm_locked_tasklet(dev, i915_vblank_tasklet);
        }
 
        return IRQ_HANDLED;
@@ -397,7 +403,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
                                 sizeof(swap));
 
        if (swap.seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE |
-                            _DRM_VBLANK_SECONDARY)) {
+                            _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) {
                DRM_ERROR("Invalid sequence type 0x%x\n", swap.seqtype);
                return DRM_ERR(EINVAL);
        }
@@ -406,11 +412,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 
        seqtype = swap.seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
 
-       if (seqtype == _DRM_VBLANK_RELATIVE && swap.sequence == 0) {
-               DRM_DEBUG("Not scheduling swap for current sequence\n");
-               return DRM_ERR(EINVAL);
-       }
-
        if (!(dev_priv->vblank_pipe & (1 << pipe))) {
                DRM_ERROR("Invalid pipe %d\n", pipe);
                return DRM_ERR(EINVAL);
@@ -428,21 +429,20 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 
        curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received);
 
-       spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
-
-       switch (seqtype) {
-       case _DRM_VBLANK_RELATIVE:
+       if (seqtype == _DRM_VBLANK_RELATIVE)
                swap.sequence += curseq;
-               break;
-       case _DRM_VBLANK_ABSOLUTE:
-               if ((curseq - swap.sequence) <= (1<<23)) {
-                       spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+
+       if ((curseq - swap.sequence) <= (1<<23)) {
+               if (swap.seqtype & _DRM_VBLANK_NEXTONMISS) {
+                       swap.sequence = curseq + 1;
+               } else {
                        DRM_DEBUG("Missed target sequence\n");
                        return DRM_ERR(EINVAL);
                }
-               break;
        }
 
+       spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
+
        list_for_each(list, &dev_priv->vbl_swaps.head) {
                vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);