aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/drm/i915_irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/drm/i915_irq.c')
-rw-r--r--drivers/char/drm/i915_irq.c43
1 files changed, 38 insertions, 5 deletions
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c
index a93f1f37ec6a..d56455666312 100644
--- a/drivers/char/drm/i915_irq.c
+++ b/drivers/char/drm/i915_irq.c
@@ -375,7 +375,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
375 drm_i915_private_t *dev_priv = dev->dev_private; 375 drm_i915_private_t *dev_priv = dev->dev_private;
376 drm_i915_vblank_swap_t swap; 376 drm_i915_vblank_swap_t swap;
377 drm_i915_vbl_swap_t *vbl_swap; 377 drm_i915_vbl_swap_t *vbl_swap;
378 unsigned int irqflags; 378 unsigned int pipe, seqtype, irqflags, curseq;
379 struct list_head *list; 379 struct list_head *list;
380 380
381 if (!dev_priv) { 381 if (!dev_priv) {
@@ -396,8 +396,23 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
396 DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data, 396 DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data,
397 sizeof(swap)); 397 sizeof(swap));
398 398
399 if (swap.pipe > 1 || !(dev_priv->vblank_pipe & (1 << swap.pipe))) { 399 if (swap.seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE |
400 DRM_ERROR("Invalid pipe %d\n", swap.pipe); 400 _DRM_VBLANK_SECONDARY)) {
401 DRM_ERROR("Invalid sequence type 0x%x\n", swap.seqtype);
402 return DRM_ERR(EINVAL);
403 }
404
405 pipe = (swap.seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
406
407 seqtype = swap.seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
408
409 if (seqtype == _DRM_VBLANK_RELATIVE && swap.sequence == 0) {
410 DRM_DEBUG("Not scheduling swap for current sequence\n");
411 return DRM_ERR(EINVAL);
412 }
413
414 if (!(dev_priv->vblank_pipe & (1 << pipe))) {
415 DRM_ERROR("Invalid pipe %d\n", pipe);
401 return DRM_ERR(EINVAL); 416 return DRM_ERR(EINVAL);
402 } 417 }
403 418
@@ -411,13 +426,28 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
411 426
412 spin_unlock_irqrestore(&dev->drw_lock, irqflags); 427 spin_unlock_irqrestore(&dev->drw_lock, irqflags);
413 428
429 curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received);
430
414 spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); 431 spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
415 432
433 switch (seqtype) {
434 case _DRM_VBLANK_RELATIVE:
435 swap.sequence += curseq;
436 break;
437 case _DRM_VBLANK_ABSOLUTE:
438 if ((curseq - swap.sequence) > (1<<23)) {
439 spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
440 DRM_DEBUG("Missed target sequence\n");
441 return DRM_ERR(EINVAL);
442 }
443 break;
444 }
445
416 list_for_each(list, &dev_priv->vbl_swaps.head) { 446 list_for_each(list, &dev_priv->vbl_swaps.head) {
417 vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); 447 vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);
418 448
419 if (vbl_swap->drw_id == swap.drawable && 449 if (vbl_swap->drw_id == swap.drawable &&
420 vbl_swap->pipe == swap.pipe && 450 vbl_swap->pipe == pipe &&
421 vbl_swap->sequence == swap.sequence) { 451 vbl_swap->sequence == swap.sequence) {
422 spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); 452 spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
423 DRM_DEBUG("Already scheduled\n"); 453 DRM_DEBUG("Already scheduled\n");
@@ -437,7 +467,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
437 DRM_DEBUG("\n"); 467 DRM_DEBUG("\n");
438 468
439 vbl_swap->drw_id = swap.drawable; 469 vbl_swap->drw_id = swap.drawable;
440 vbl_swap->pipe = swap.pipe; 470 vbl_swap->pipe = pipe;
441 vbl_swap->sequence = swap.sequence; 471 vbl_swap->sequence = swap.sequence;
442 472
443 spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); 473 spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
@@ -447,6 +477,9 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
447 477
448 spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); 478 spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
449 479
480 DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_swap_t __user *) data, swap,
481 sizeof(swap));
482
450 return 0; 483 return 0;
451} 484}
452 485