aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/vc4/vc4_crtc.c8
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.h1
-rw-r--r--drivers/gpu/drm/vc4/vc4_kms.c33
3 files changed, 34 insertions, 8 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 7f08d681a74b..82f914af4156 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -669,6 +669,14 @@ void vc4_disable_vblank(struct drm_device *dev, unsigned int crtc_id)
669 CRTC_WRITE(PV_INTEN, 0); 669 CRTC_WRITE(PV_INTEN, 0);
670} 670}
671 671
672/* Must be called with the event lock held */
673bool vc4_event_pending(struct drm_crtc *crtc)
674{
675 struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
676
677 return !!vc4_crtc->event;
678}
679
672static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) 680static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
673{ 681{
674 struct drm_crtc *crtc = &vc4_crtc->base; 682 struct drm_crtc *crtc = &vc4_crtc->base;
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index fef172804345..b3064e2e79c1 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -442,6 +442,7 @@ int vc4_bo_stats_debugfs(struct seq_file *m, void *arg);
442extern struct platform_driver vc4_crtc_driver; 442extern struct platform_driver vc4_crtc_driver;
443int vc4_enable_vblank(struct drm_device *dev, unsigned int crtc_id); 443int vc4_enable_vblank(struct drm_device *dev, unsigned int crtc_id);
444void vc4_disable_vblank(struct drm_device *dev, unsigned int crtc_id); 444void vc4_disable_vblank(struct drm_device *dev, unsigned int crtc_id);
445bool vc4_event_pending(struct drm_crtc *crtc);
445int vc4_crtc_debugfs_regs(struct seq_file *m, void *arg); 446int vc4_crtc_debugfs_regs(struct seq_file *m, void *arg);
446int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, 447int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
447 unsigned int flags, int *vpos, int *hpos, 448 unsigned int flags, int *vpos, int *hpos,
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
index c1f65c6c8e60..67af2af70af0 100644
--- a/drivers/gpu/drm/vc4/vc4_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
@@ -119,17 +119,34 @@ static int vc4_atomic_commit(struct drm_device *dev,
119 119
120 /* Make sure that any outstanding modesets have finished. */ 120 /* Make sure that any outstanding modesets have finished. */
121 if (nonblock) { 121 if (nonblock) {
122 ret = down_trylock(&vc4->async_modeset); 122 struct drm_crtc *crtc;
123 if (ret) { 123 struct drm_crtc_state *crtc_state;
124 unsigned long flags;
125 bool busy = false;
126
127 /*
128 * If there's an undispatched event to send then we're
129 * obviously still busy. If there isn't, then we can
130 * unconditionally wait for the semaphore because it
131 * shouldn't be contended (for long).
132 *
133 * This is to prevent a race where queuing a new flip
134 * from userspace immediately on receipt of an event
135 * beats our clean-up and returns EBUSY.
136 */
137 spin_lock_irqsave(&dev->event_lock, flags);
138 for_each_crtc_in_state(state, crtc, crtc_state, i)
139 busy |= vc4_event_pending(crtc);
140 spin_unlock_irqrestore(&dev->event_lock, flags);
141 if (busy) {
124 kfree(c); 142 kfree(c);
125 return -EBUSY; 143 return -EBUSY;
126 } 144 }
127 } else { 145 }
128 ret = down_interruptible(&vc4->async_modeset); 146 ret = down_interruptible(&vc4->async_modeset);
129 if (ret) { 147 if (ret) {
130 kfree(c); 148 kfree(c);
131 return ret; 149 return ret;
132 }
133 } 150 }
134 151
135 ret = drm_atomic_helper_prepare_planes(dev, state); 152 ret = drm_atomic_helper_prepare_planes(dev, state);