summaryrefslogtreecommitdiff
path: root/shared-core/i915_irq.c
diff options
context:
space:
mode:
authorMichel Dänzer <michel@tungstengraphics.com>2006-08-30 19:33:28 +0200
committerMichel Dänzer <michel@tungstengraphics.com>2006-09-29 12:55:08 +0200
commit1f3493f65ba0959e401191c648f57501216eeb0a (patch)
tree6160a8e45d1d1ab4878e536d8c7c2ae690f950c4 /shared-core/i915_irq.c
parent00531cecad3cf9a1ec230f7f33535d153b9d9bd0 (diff)
DRM_I915_VBLANK_SWAP ioctl: Take drm_vblank_seq_type_t instead of pipe number.
Handle relative as well as absolute target sequence numbers. Return error if target sequence has already passed, so userspace can deal with this situation as it sees fit. On success, return the sequence number of the vertical blank when the buffer swap is expected to take place. Also add DRM_IOCTL_I915_VBLANK_SWAP definition for userspace code that may want to use ioctl() instead of drmCommandWriteRead(). (cherry picked from d5a0f107511e128658e2d5e15bd7e6215c507f29 commit)
Diffstat (limited to 'shared-core/i915_irq.c')
-rw-r--r--shared-core/i915_irq.c43
1 files changed, 38 insertions, 5 deletions
diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index 667a9ca8..3c562fdd 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -411,7 +411,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_vblank_swap_t swap;
drm_i915_vbl_swap_t *vbl_swap;
- unsigned int irqflags;
+ unsigned int pipe, seqtype, irqflags, curseq;
struct list_head *list;
if (!dev_priv) {
@@ -432,8 +432,23 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data,
sizeof(swap));
- if (swap.pipe > 1 || !(dev_priv->vblank_pipe & (1 << swap.pipe))) {
- DRM_ERROR("Invalid pipe %d\n", swap.pipe);
+ if (swap.seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE |
+ _DRM_VBLANK_SECONDARY)) {
+ DRM_ERROR("Invalid sequence type 0x%x\n", swap.seqtype);
+ return DRM_ERR(EINVAL);
+ }
+
+ pipe = (swap.seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
+
+ 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);
}
@@ -447,13 +462,28 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+ curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received);
+
spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
+ switch (seqtype) {
+ case _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);
+ DRM_DEBUG("Missed target sequence\n");
+ return DRM_ERR(EINVAL);
+ }
+ break;
+ }
+
list_for_each(list, &dev_priv->vbl_swaps.head) {
vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);
if (vbl_swap->drw_id == swap.drawable &&
- vbl_swap->pipe == swap.pipe &&
+ vbl_swap->pipe == pipe &&
vbl_swap->sequence == swap.sequence) {
spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
DRM_DEBUG("Already scheduled\n");
@@ -473,7 +503,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
DRM_DEBUG("\n");
vbl_swap->drw_id = swap.drawable;
- vbl_swap->pipe = swap.pipe;
+ vbl_swap->pipe = pipe;
vbl_swap->sequence = swap.sequence;
spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
@@ -483,6 +513,9 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+ DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_swap_t __user *) data, swap,
+ sizeof(swap));
+
return 0;
}