diff options
Diffstat (limited to 'target/linux/brcm2708/patches-4.9/0166-drm-vc4-Fix-race-between-page-flip-completion-event-.patch')
-rw-r--r-- | target/linux/brcm2708/patches-4.9/0166-drm-vc4-Fix-race-between-page-flip-completion-event-.patch | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.9/0166-drm-vc4-Fix-race-between-page-flip-completion-event-.patch b/target/linux/brcm2708/patches-4.9/0166-drm-vc4-Fix-race-between-page-flip-completion-event-.patch new file mode 100644 index 0000000000..3c66fefafd --- /dev/null +++ b/target/linux/brcm2708/patches-4.9/0166-drm-vc4-Fix-race-between-page-flip-completion-event-.patch @@ -0,0 +1,93 @@ +From d7f32f81cf7579ac7d13127db88e789ea864824c Mon Sep 17 00:00:00 2001 +From: Derek Foreman <derekf@osg.samsung.com> +Date: Thu, 24 Nov 2016 12:11:55 -0600 +Subject: [PATCH] drm/vc4: Fix race between page flip completion event and + clean-up + +There was a small window where a userspace program could submit +a pageflip after receiving a pageflip completion event yet still +receive EBUSY. + +Signed-off-by: Derek Foreman <derekf@osg.samsung.com> +Signed-off-by: Eric Anholt <eric@anholt.net> +Reviewed-by: Eric Anholt <eric@anholt.net> +Reviewed-by: Daniel Stone <daniels@collabora.com> +(cherry picked from commit 26fc78f6fef39b9d7a15def5e7e9826ff68303f4) +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 8 ++++++++ + drivers/gpu/drm/vc4/vc4_drv.h | 1 + + drivers/gpu/drm/vc4/vc4_kms.c | 33 +++++++++++++++++++++++++-------- + 3 files changed, 34 insertions(+), 8 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -682,6 +682,14 @@ void vc4_disable_vblank(struct drm_devic + CRTC_WRITE(PV_INTEN, 0); + } + ++/* Must be called with the event lock held */ ++bool vc4_event_pending(struct drm_crtc *crtc) ++{ ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ ++ return !!vc4_crtc->event; ++} ++ + static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) + { + struct drm_crtc *crtc = &vc4_crtc->base; +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -445,6 +445,7 @@ int vc4_bo_stats_debugfs(struct seq_file + extern struct platform_driver vc4_crtc_driver; + int vc4_enable_vblank(struct drm_device *dev, unsigned int crtc_id); + void vc4_disable_vblank(struct drm_device *dev, unsigned int crtc_id); ++bool vc4_event_pending(struct drm_crtc *crtc); + int vc4_crtc_debugfs_regs(struct seq_file *m, void *arg); + int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, + unsigned int flags, int *vpos, int *hpos, +--- 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_ + + /* 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); |