summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/vc4/vc4_kms.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2016-12-13 12:05:12 +1000
committerDave Airlie <airlied@redhat.com>2016-12-13 12:05:12 +1000
commit2601a15d5d9b7f262e94b88784b1e1cf28ec020d (patch)
tree52a5434ad72100759552f18c706dc44598fa6dbc /drivers/gpu/drm/vc4/vc4_kms.c
parent25dfd7cfefeea5bddd48da5763ecbe686579c922 (diff)
parentc167df443b4a8d97d25a8e69bd9f490a1e3fe646 (diff)
downloadlinux-2601a15d5d9b7f262e94b88784b1e1cf28ec020d.tar.bz2
Merge tag 'drm-vc4-next-2016-12-09' of https://github.com/anholt/linux into drm-next
This pull request brings in VEC (TV-out) support for vc4, along with a pageflipping race fix. * tag 'drm-vc4-next-2016-12-09' of https://github.com/anholt/linux: drm/vc4: Don't use drm_put_dev drm/vc4: Document VEC DT binding drm/vc4: Add support for the VEC (Video Encoder) IP drm: Add TV connector states to drm_connector_state drm: Turn DRM_MODE_SUBCONNECTOR_xx definitions into an enum drm/vc4: Fix ->clock_select setting for the VEC encoder drm/vc4: Fix race between page flip completion event and clean-up
Diffstat (limited to 'drivers/gpu/drm/vc4/vc4_kms.c')
-rw-r--r--drivers/gpu/drm/vc4/vc4_kms.c33
1 files changed, 25 insertions, 8 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
index f31f72af8551..be8dd8262f27 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,
/* Make sure that any outstanding modesets have finished. */
if (nonblock) {
- ret = down_trylock(&vc4->async_modeset);
- if (ret) {
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *crtc_state;
+ unsigned long flags;
+ bool busy = false;
+
+ /*
+ * If there's an undispatched event to send then we're
+ * obviously still busy. If there isn't, then we can
+ * unconditionally wait for the semaphore because it
+ * shouldn't be contended (for long).
+ *
+ * This is to prevent a race where queuing a new flip
+ * from userspace immediately on receipt of an event
+ * beats our clean-up and returns EBUSY.
+ */
+ spin_lock_irqsave(&dev->event_lock, flags);
+ for_each_crtc_in_state(state, crtc, crtc_state, i)
+ busy |= vc4_event_pending(crtc);
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ if (busy) {
kfree(c);
return -EBUSY;
}
- } else {
- ret = down_interruptible(&vc4->async_modeset);
- if (ret) {
- kfree(c);
- return ret;
- }
+ }
+ ret = down_interruptible(&vc4->async_modeset);
+ if (ret) {
+ kfree(c);
+ return ret;
}
ret = drm_atomic_helper_prepare_planes(dev, state);