diff options
Diffstat (limited to 'drivers/gpu/drm/omapdrm/omap_drv.c')
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_drv.c | 30 |
1 files changed, 27 insertions, 3 deletions
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 72a5a88a6419..2e7706355eb6 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -118,6 +118,7 @@ static int omap_atomic_commit(struct drm_device *dev, { struct omap_drm_private *priv = dev->dev_private; struct omap_atomic_state_commit *commit; + unsigned long flags; unsigned int i; int ret; @@ -150,6 +151,17 @@ static int omap_atomic_commit(struct drm_device *dev, priv->commit.pending |= commit->crtcs; spin_unlock(&priv->commit.lock); + /* Keep track of all CRTC events to unlink them in preclose(). */ + spin_lock_irqsave(&dev->event_lock, flags); + for (i = 0; i < dev->mode_config.num_crtc; ++i) { + struct drm_crtc_state *cstate = state->crtc_states[i]; + + if (cstate && cstate->event) + list_add_tail(&cstate->event->base.link, + &priv->commit.events); + } + spin_unlock_irqrestore(&dev->event_lock, flags); + /* Swap the state, this is the point of no return. */ drm_atomic_helper_swap_state(dev, state); @@ -632,6 +644,7 @@ static int dev_load(struct drm_device *dev, unsigned long flags) priv->wq = alloc_ordered_workqueue("omapdrm", 0); init_waitqueue_head(&priv->commit.wait); spin_lock_init(&priv->commit.lock); + INIT_LIST_HEAD(&priv->commit.events); spin_lock_init(&priv->list_lock); INIT_LIST_HEAD(&priv->obj_list); @@ -752,12 +765,23 @@ static void dev_lastclose(struct drm_device *dev) static void dev_preclose(struct drm_device *dev, struct drm_file *file) { struct omap_drm_private *priv = dev->dev_private; - unsigned int i; + struct drm_pending_event *event; + unsigned long flags; DBG("preclose: dev=%p", dev); - for (i = 0; i < priv->num_crtcs; ++i) - omap_crtc_cancel_page_flip(priv->crtcs[i], file); + /* + * Unlink all pending CRTC events to make sure they won't be queued up + * by a pending asynchronous commit. + */ + spin_lock_irqsave(&dev->event_lock, flags); + list_for_each_entry(event, &priv->commit.events, link) { + if (event->file_priv == file) { + file->event_space += event->event->length; + event->file_priv = NULL; + } + } + spin_unlock_irqrestore(&dev->event_lock, flags); } static void dev_postclose(struct drm_device *dev, struct drm_file *file) |