aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/omapdrm/omap_drv.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/omapdrm/omap_drv.c')
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.c30
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)