Skip to content

Commit a0ea4ff

Browse files
lynxeye-devpH5
authored andcommitted
drm/imx: only send commit done event when all state has been applied
Currently there is a small race window where we could manage to arm the vblank event from atomic flush, but programming the hardware was too close to the frame end, so the hardware will only apply the current state on the next vblank. In this case we will send out the commit done event too early causing userspace to reuse framebuffes that are still in use. Instead of using the event arming mechnism, just remember the pending event and send it from the vblank IRQ handler, once we are sure that all state has been applied successfully. Signed-off-by: Lucas Stach <[email protected]> [[email protected]: inverted logic: done -> pending, added back spinlock in atomic_flush, commit message typo fix] Signed-off-by: Philipp Zabel <[email protected]>
1 parent f601970 commit a0ea4ff

File tree

1 file changed

+28
-2
lines changed

1 file changed

+28
-2
lines changed

drivers/gpu/drm/imx/ipuv3-crtc.c

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ struct ipu_crtc {
3434
struct ipu_dc *dc;
3535
struct ipu_di *di;
3636
int irq;
37+
struct drm_pending_vblank_event *event;
3738
};
3839

3940
static inline struct ipu_crtc *to_ipu_crtc(struct drm_crtc *crtc)
@@ -173,8 +174,31 @@ static const struct drm_crtc_funcs ipu_crtc_funcs = {
173174
static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
174175
{
175176
struct ipu_crtc *ipu_crtc = dev_id;
177+
struct drm_crtc *crtc = &ipu_crtc->base;
178+
unsigned long flags;
179+
int i;
180+
181+
drm_crtc_handle_vblank(crtc);
182+
183+
if (ipu_crtc->event) {
184+
for (i = 0; i < ARRAY_SIZE(ipu_crtc->plane); i++) {
185+
struct ipu_plane *plane = ipu_crtc->plane[i];
176186

177-
drm_crtc_handle_vblank(&ipu_crtc->base);
187+
if (!plane)
188+
continue;
189+
190+
if (ipu_plane_atomic_update_pending(&plane->base))
191+
break;
192+
}
193+
194+
if (i == ARRAY_SIZE(ipu_crtc->plane)) {
195+
spin_lock_irqsave(&crtc->dev->event_lock, flags);
196+
drm_crtc_send_vblank_event(crtc, ipu_crtc->event);
197+
ipu_crtc->event = NULL;
198+
drm_crtc_vblank_put(crtc);
199+
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
200+
}
201+
}
178202

179203
return IRQ_HANDLED;
180204
}
@@ -223,8 +247,10 @@ static void ipu_crtc_atomic_flush(struct drm_crtc *crtc,
223247
{
224248
spin_lock_irq(&crtc->dev->event_lock);
225249
if (crtc->state->event) {
250+
struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
251+
226252
WARN_ON(drm_crtc_vblank_get(crtc));
227-
drm_crtc_arm_vblank_event(crtc, crtc->state->event);
253+
ipu_crtc->event = crtc->state->event;
228254
crtc->state->event = NULL;
229255
}
230256
spin_unlock_irq(&crtc->dev->event_lock);

0 commit comments

Comments
 (0)