diff options
| -rw-r--r-- | drivers/gpu/drm/vc4/vc4_crtc.c | 8 | ||||
| -rw-r--r-- | drivers/gpu/drm/vc4/vc4_drv.h | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/vc4/vc4_kms.c | 33 |
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 */ | ||
| 673 | bool 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 | |||
| 672 | static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) | 680 | static 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); | |||
| 442 | extern struct platform_driver vc4_crtc_driver; | 442 | extern struct platform_driver vc4_crtc_driver; |
| 443 | int vc4_enable_vblank(struct drm_device *dev, unsigned int crtc_id); | 443 | int vc4_enable_vblank(struct drm_device *dev, unsigned int crtc_id); |
| 444 | void vc4_disable_vblank(struct drm_device *dev, unsigned int crtc_id); | 444 | void vc4_disable_vblank(struct drm_device *dev, unsigned int crtc_id); |
| 445 | bool vc4_event_pending(struct drm_crtc *crtc); | ||
| 445 | int vc4_crtc_debugfs_regs(struct seq_file *m, void *arg); | 446 | int vc4_crtc_debugfs_regs(struct seq_file *m, void *arg); |
| 446 | int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, | 447 | int 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); |
