@@ -254,30 +254,6 @@ static const struct dss_mgr_ops mgr_ops = {
* Setup, Flush and Page Flip
*/
-void omap_crtc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file)
-{
- struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
- struct drm_pending_vblank_event *event;
- struct drm_device *dev = crtc->dev;
- unsigned long flags;
-
- /* Destroy the pending vertical blanking event associated with the
- * pending page flip, if any, and disable vertical blanking interrupts.
- */
-
- spin_lock_irqsave(&dev->event_lock, flags);
-
- event = omap_crtc->event;
- omap_crtc->event = NULL;
-
- if (event && event->base.file_priv == file) {
- event->base.destroy(&event->base);
- drm_crtc_vblank_put(crtc);
- }
-
- spin_unlock_irqrestore(&dev->event_lock, flags);
-}
-
static void omap_crtc_complete_page_flip(struct drm_crtc *crtc)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
@@ -291,7 +267,17 @@ static void omap_crtc_complete_page_flip(struct drm_crtc *crtc)
omap_crtc->event = NULL;
if (event) {
- drm_crtc_send_vblank_event(crtc, event);
+ list_del(&event->base.link);
+
+ /*
+ * Queue the event for delivery if it's still linked to a file
+ * handle, otherwise just destroy it.
+ */
+ if (event->base.file_priv)
+ drm_crtc_send_vblank_event(crtc, event);
+ else
+ event->base.destroy(&event->base);
+
wake_up(&omap_crtc->flip_wait);
drm_crtc_vblank_put(crtc);
}
@@ -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)
@@ -109,6 +109,7 @@ struct omap_drm_private {
/* atomic commit */
struct {
+ struct list_head events;
wait_queue_head_t wait;
u32 pending;
spinlock_t lock; /* Protects commit.pending */
@@ -142,7 +143,6 @@ void omap_fbdev_free(struct drm_device *dev);
const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc);
enum omap_channel omap_crtc_channel(struct drm_crtc *crtc);
-void omap_crtc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file);
void omap_crtc_pre_init(void);
void omap_crtc_pre_uninit(void);
struct drm_crtc *omap_crtc_init(struct drm_device *dev,