diff options
Diffstat (limited to 'drivers/char/drm/i915_irq.c')
-rw-r--r-- | drivers/char/drm/i915_irq.c | 43 |
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 | ||