diff options
Diffstat (limited to 'drivers/gpu/drm/drm_irq.c')
-rw-r--r-- | drivers/gpu/drm/drm_irq.c | 56 |
1 files changed, 46 insertions, 10 deletions
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index c9f5453f20e7..c8a34476570a 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c | |||
@@ -276,7 +276,6 @@ static void vblank_disable_fn(unsigned long arg) | |||
276 | void drm_vblank_cleanup(struct drm_device *dev) | 276 | void drm_vblank_cleanup(struct drm_device *dev) |
277 | { | 277 | { |
278 | int crtc; | 278 | int crtc; |
279 | unsigned long irqflags; | ||
280 | 279 | ||
281 | /* Bail if the driver didn't call drm_vblank_init() */ | 280 | /* Bail if the driver didn't call drm_vblank_init() */ |
282 | if (dev->num_crtcs == 0) | 281 | if (dev->num_crtcs == 0) |
@@ -285,11 +284,10 @@ void drm_vblank_cleanup(struct drm_device *dev) | |||
285 | for (crtc = 0; crtc < dev->num_crtcs; crtc++) { | 284 | for (crtc = 0; crtc < dev->num_crtcs; crtc++) { |
286 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; | 285 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; |
287 | 286 | ||
288 | del_timer_sync(&vblank->disable_timer); | 287 | WARN_ON(vblank->enabled && |
288 | drm_core_check_feature(dev, DRIVER_MODESET)); | ||
289 | 289 | ||
290 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 290 | del_timer_sync(&vblank->disable_timer); |
291 | vblank_disable_and_save(dev, crtc); | ||
292 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | ||
293 | } | 291 | } |
294 | 292 | ||
295 | kfree(dev->vblank); | 293 | kfree(dev->vblank); |
@@ -475,17 +473,23 @@ int drm_irq_uninstall(struct drm_device *dev) | |||
475 | dev->irq_enabled = false; | 473 | dev->irq_enabled = false; |
476 | 474 | ||
477 | /* | 475 | /* |
478 | * Wake up any waiters so they don't hang. | 476 | * Wake up any waiters so they don't hang. This is just to paper over |
477 | * isssues for UMS drivers which aren't in full control of their | ||
478 | * vblank/irq handling. KMS drivers must ensure that vblanks are all | ||
479 | * disabled when uninstalling the irq handler. | ||
479 | */ | 480 | */ |
480 | if (dev->num_crtcs) { | 481 | if (dev->num_crtcs) { |
481 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 482 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
482 | for (i = 0; i < dev->num_crtcs; i++) { | 483 | for (i = 0; i < dev->num_crtcs; i++) { |
483 | struct drm_vblank_crtc *vblank = &dev->vblank[i]; | 484 | struct drm_vblank_crtc *vblank = &dev->vblank[i]; |
484 | 485 | ||
486 | if (!vblank->enabled) | ||
487 | continue; | ||
488 | |||
489 | WARN_ON(drm_core_check_feature(dev, DRIVER_MODESET)); | ||
490 | |||
491 | vblank_disable_and_save(dev, i); | ||
485 | wake_up(&vblank->queue); | 492 | wake_up(&vblank->queue); |
486 | vblank->enabled = false; | ||
487 | vblank->last = | ||
488 | dev->driver->get_vblank_counter(dev, i); | ||
489 | } | 493 | } |
490 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | 494 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); |
491 | } | 495 | } |
@@ -1233,6 +1237,38 @@ void drm_crtc_vblank_off(struct drm_crtc *crtc) | |||
1233 | EXPORT_SYMBOL(drm_crtc_vblank_off); | 1237 | EXPORT_SYMBOL(drm_crtc_vblank_off); |
1234 | 1238 | ||
1235 | /** | 1239 | /** |
1240 | * drm_crtc_vblank_reset - reset vblank state to off on a CRTC | ||
1241 | * @crtc: CRTC in question | ||
1242 | * | ||
1243 | * Drivers can use this function to reset the vblank state to off at load time. | ||
1244 | * Drivers should use this together with the drm_crtc_vblank_off() and | ||
1245 | * drm_crtc_vblank_on() functions. The difference compared to | ||
1246 | * drm_crtc_vblank_off() is that this function doesn't save the vblank counter | ||
1247 | * and hence doesn't need to call any driver hooks. | ||
1248 | */ | ||
1249 | void drm_crtc_vblank_reset(struct drm_crtc *drm_crtc) | ||
1250 | { | ||
1251 | struct drm_device *dev = drm_crtc->dev; | ||
1252 | unsigned long irqflags; | ||
1253 | int crtc = drm_crtc_index(drm_crtc); | ||
1254 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; | ||
1255 | |||
1256 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | ||
1257 | /* | ||
1258 | * Prevent subsequent drm_vblank_get() from enabling the vblank | ||
1259 | * interrupt by bumping the refcount. | ||
1260 | */ | ||
1261 | if (!vblank->inmodeset) { | ||
1262 | atomic_inc(&vblank->refcount); | ||
1263 | vblank->inmodeset = 1; | ||
1264 | } | ||
1265 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | ||
1266 | |||
1267 | WARN_ON(!list_empty(&dev->vblank_event_list)); | ||
1268 | } | ||
1269 | EXPORT_SYMBOL(drm_crtc_vblank_reset); | ||
1270 | |||
1271 | /** | ||
1236 | * drm_vblank_on - enable vblank events on a CRTC | 1272 | * drm_vblank_on - enable vblank events on a CRTC |
1237 | * @dev: DRM device | 1273 | * @dev: DRM device |
1238 | * @crtc: CRTC in question | 1274 | * @crtc: CRTC in question |
@@ -1653,7 +1689,7 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) | |||
1653 | struct timeval tvblank; | 1689 | struct timeval tvblank; |
1654 | unsigned long irqflags; | 1690 | unsigned long irqflags; |
1655 | 1691 | ||
1656 | if (!dev->num_crtcs) | 1692 | if (WARN_ON_ONCE(!dev->num_crtcs)) |
1657 | return false; | 1693 | return false; |
1658 | 1694 | ||
1659 | if (WARN_ON(crtc >= dev->num_crtcs)) | 1695 | if (WARN_ON(crtc >= dev->num_crtcs)) |