diff options
Diffstat (limited to 'drivers/gpu/drm/drm_irq.c')
-rw-r--r-- | drivers/gpu/drm/drm_irq.c | 64 |
1 files changed, 45 insertions, 19 deletions
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 1e787f894b3c..1608f8dbfda0 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c | |||
@@ -305,6 +305,8 @@ int drm_control(struct drm_device *dev, void *data, | |||
305 | case DRM_INST_HANDLER: | 305 | case DRM_INST_HANDLER: |
306 | if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) | 306 | if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) |
307 | return 0; | 307 | return 0; |
308 | if (drm_core_check_feature(dev, DRIVER_MODESET)) | ||
309 | return 0; | ||
308 | if (dev->if_version < DRM_IF_VERSION(1, 2) && | 310 | if (dev->if_version < DRM_IF_VERSION(1, 2) && |
309 | ctl->irq != dev->pdev->irq) | 311 | ctl->irq != dev->pdev->irq) |
310 | return -EINVAL; | 312 | return -EINVAL; |
@@ -312,6 +314,8 @@ int drm_control(struct drm_device *dev, void *data, | |||
312 | case DRM_UNINST_HANDLER: | 314 | case DRM_UNINST_HANDLER: |
313 | if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) | 315 | if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) |
314 | return 0; | 316 | return 0; |
317 | if (drm_core_check_feature(dev, DRIVER_MODESET)) | ||
318 | return 0; | ||
315 | return drm_irq_uninstall(dev); | 319 | return drm_irq_uninstall(dev); |
316 | default: | 320 | default: |
317 | return -EINVAL; | 321 | return -EINVAL; |
@@ -427,6 +431,45 @@ void drm_vblank_put(struct drm_device *dev, int crtc) | |||
427 | EXPORT_SYMBOL(drm_vblank_put); | 431 | EXPORT_SYMBOL(drm_vblank_put); |
428 | 432 | ||
429 | /** | 433 | /** |
434 | * drm_vblank_pre_modeset - account for vblanks across mode sets | ||
435 | * @dev: DRM device | ||
436 | * @crtc: CRTC in question | ||
437 | * @post: post or pre mode set? | ||
438 | * | ||
439 | * Account for vblank events across mode setting events, which will likely | ||
440 | * reset the hardware frame counter. | ||
441 | */ | ||
442 | void drm_vblank_pre_modeset(struct drm_device *dev, int crtc) | ||
443 | { | ||
444 | /* | ||
445 | * To avoid all the problems that might happen if interrupts | ||
446 | * were enabled/disabled around or between these calls, we just | ||
447 | * have the kernel take a reference on the CRTC (just once though | ||
448 | * to avoid corrupting the count if multiple, mismatch calls occur), | ||
449 | * so that interrupts remain enabled in the interim. | ||
450 | */ | ||
451 | if (!dev->vblank_inmodeset[crtc]) { | ||
452 | dev->vblank_inmodeset[crtc] = 1; | ||
453 | drm_vblank_get(dev, crtc); | ||
454 | } | ||
455 | } | ||
456 | EXPORT_SYMBOL(drm_vblank_pre_modeset); | ||
457 | |||
458 | void drm_vblank_post_modeset(struct drm_device *dev, int crtc) | ||
459 | { | ||
460 | unsigned long irqflags; | ||
461 | |||
462 | if (dev->vblank_inmodeset[crtc]) { | ||
463 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | ||
464 | dev->vblank_disable_allowed = 1; | ||
465 | dev->vblank_inmodeset[crtc] = 0; | ||
466 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | ||
467 | drm_vblank_put(dev, crtc); | ||
468 | } | ||
469 | } | ||
470 | EXPORT_SYMBOL(drm_vblank_post_modeset); | ||
471 | |||
472 | /** | ||
430 | * drm_modeset_ctl - handle vblank event counter changes across mode switch | 473 | * drm_modeset_ctl - handle vblank event counter changes across mode switch |
431 | * @DRM_IOCTL_ARGS: standard ioctl arguments | 474 | * @DRM_IOCTL_ARGS: standard ioctl arguments |
432 | * | 475 | * |
@@ -441,7 +484,6 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, | |||
441 | struct drm_file *file_priv) | 484 | struct drm_file *file_priv) |
442 | { | 485 | { |
443 | struct drm_modeset_ctl *modeset = data; | 486 | struct drm_modeset_ctl *modeset = data; |
444 | unsigned long irqflags; | ||
445 | int crtc, ret = 0; | 487 | int crtc, ret = 0; |
446 | 488 | ||
447 | /* If drm_vblank_init() hasn't been called yet, just no-op */ | 489 | /* If drm_vblank_init() hasn't been called yet, just no-op */ |
@@ -454,28 +496,12 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, | |||
454 | goto out; | 496 | goto out; |
455 | } | 497 | } |
456 | 498 | ||
457 | /* | ||
458 | * To avoid all the problems that might happen if interrupts | ||
459 | * were enabled/disabled around or between these calls, we just | ||
460 | * have the kernel take a reference on the CRTC (just once though | ||
461 | * to avoid corrupting the count if multiple, mismatch calls occur), | ||
462 | * so that interrupts remain enabled in the interim. | ||
463 | */ | ||
464 | switch (modeset->cmd) { | 499 | switch (modeset->cmd) { |
465 | case _DRM_PRE_MODESET: | 500 | case _DRM_PRE_MODESET: |
466 | if (!dev->vblank_inmodeset[crtc]) { | 501 | drm_vblank_pre_modeset(dev, crtc); |
467 | dev->vblank_inmodeset[crtc] = 1; | ||
468 | drm_vblank_get(dev, crtc); | ||
469 | } | ||
470 | break; | 502 | break; |
471 | case _DRM_POST_MODESET: | 503 | case _DRM_POST_MODESET: |
472 | if (dev->vblank_inmodeset[crtc]) { | 504 | drm_vblank_post_modeset(dev, crtc); |
473 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | ||
474 | dev->vblank_disable_allowed = 1; | ||
475 | dev->vblank_inmodeset[crtc] = 0; | ||
476 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | ||
477 | drm_vblank_put(dev, crtc); | ||
478 | } | ||
479 | break; | 505 | break; |
480 | default: | 506 | default: |
481 | ret = -EINVAL; | 507 | ret = -EINVAL; |