|
@@ -760,6 +760,7 @@ static irqreturn_t vc4_crtc_irq_handler(int irq, void *data)
|
|
struct vc4_async_flip_state {
|
|
struct vc4_async_flip_state {
|
|
struct drm_crtc *crtc;
|
|
struct drm_crtc *crtc;
|
|
struct drm_framebuffer *fb;
|
|
struct drm_framebuffer *fb;
|
|
|
|
+ struct drm_framebuffer *old_fb;
|
|
struct drm_pending_vblank_event *event;
|
|
struct drm_pending_vblank_event *event;
|
|
|
|
|
|
struct vc4_seqno_cb cb;
|
|
struct vc4_seqno_cb cb;
|
|
@@ -789,6 +790,23 @@ vc4_async_page_flip_complete(struct vc4_seqno_cb *cb)
|
|
|
|
|
|
drm_crtc_vblank_put(crtc);
|
|
drm_crtc_vblank_put(crtc);
|
|
drm_framebuffer_put(flip_state->fb);
|
|
drm_framebuffer_put(flip_state->fb);
|
|
|
|
+
|
|
|
|
+ /* Decrement the BO usecnt in order to keep the inc/dec calls balanced
|
|
|
|
+ * when the planes are updated through the async update path.
|
|
|
|
+ * FIXME: we should move to generic async-page-flip when it's
|
|
|
|
+ * available, so that we can get rid of this hand-made cleanup_fb()
|
|
|
|
+ * logic.
|
|
|
|
+ */
|
|
|
|
+ if (flip_state->old_fb) {
|
|
|
|
+ struct drm_gem_cma_object *cma_bo;
|
|
|
|
+ struct vc4_bo *bo;
|
|
|
|
+
|
|
|
|
+ cma_bo = drm_fb_cma_get_gem_obj(flip_state->old_fb, 0);
|
|
|
|
+ bo = to_vc4_bo(&cma_bo->base);
|
|
|
|
+ vc4_bo_dec_usecnt(bo);
|
|
|
|
+ drm_framebuffer_put(flip_state->old_fb);
|
|
|
|
+ }
|
|
|
|
+
|
|
kfree(flip_state);
|
|
kfree(flip_state);
|
|
|
|
|
|
up(&vc4->async_modeset);
|
|
up(&vc4->async_modeset);
|
|
@@ -813,9 +831,22 @@ static int vc4_async_page_flip(struct drm_crtc *crtc,
|
|
struct drm_gem_cma_object *cma_bo = drm_fb_cma_get_gem_obj(fb, 0);
|
|
struct drm_gem_cma_object *cma_bo = drm_fb_cma_get_gem_obj(fb, 0);
|
|
struct vc4_bo *bo = to_vc4_bo(&cma_bo->base);
|
|
struct vc4_bo *bo = to_vc4_bo(&cma_bo->base);
|
|
|
|
|
|
|
|
+ /* Increment the BO usecnt here, so that we never end up with an
|
|
|
|
+ * unbalanced number of vc4_bo_{dec,inc}_usecnt() calls when the
|
|
|
|
+ * plane is later updated through the non-async path.
|
|
|
|
+ * FIXME: we should move to generic async-page-flip when it's
|
|
|
|
+ * available, so that we can get rid of this hand-made prepare_fb()
|
|
|
|
+ * logic.
|
|
|
|
+ */
|
|
|
|
+ ret = vc4_bo_inc_usecnt(bo);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
flip_state = kzalloc(sizeof(*flip_state), GFP_KERNEL);
|
|
flip_state = kzalloc(sizeof(*flip_state), GFP_KERNEL);
|
|
- if (!flip_state)
|
|
|
|
|
|
+ if (!flip_state) {
|
|
|
|
+ vc4_bo_dec_usecnt(bo);
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
|
|
+ }
|
|
|
|
|
|
drm_framebuffer_get(fb);
|
|
drm_framebuffer_get(fb);
|
|
flip_state->fb = fb;
|
|
flip_state->fb = fb;
|
|
@@ -826,10 +857,23 @@ static int vc4_async_page_flip(struct drm_crtc *crtc,
|
|
ret = down_interruptible(&vc4->async_modeset);
|
|
ret = down_interruptible(&vc4->async_modeset);
|
|
if (ret) {
|
|
if (ret) {
|
|
drm_framebuffer_put(fb);
|
|
drm_framebuffer_put(fb);
|
|
|
|
+ vc4_bo_dec_usecnt(bo);
|
|
kfree(flip_state);
|
|
kfree(flip_state);
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* Save the current FB before it's replaced by the new one in
|
|
|
|
+ * drm_atomic_set_fb_for_plane(). We'll need the old FB in
|
|
|
|
+ * vc4_async_page_flip_complete() to decrement the BO usecnt and keep
|
|
|
|
+ * it consistent.
|
|
|
|
+ * FIXME: we should move to generic async-page-flip when it's
|
|
|
|
+ * available, so that we can get rid of this hand-made cleanup_fb()
|
|
|
|
+ * logic.
|
|
|
|
+ */
|
|
|
|
+ flip_state->old_fb = plane->state->fb;
|
|
|
|
+ if (flip_state->old_fb)
|
|
|
|
+ drm_framebuffer_get(flip_state->old_fb);
|
|
|
|
+
|
|
WARN_ON(drm_crtc_vblank_get(crtc) != 0);
|
|
WARN_ON(drm_crtc_vblank_get(crtc) != 0);
|
|
|
|
|
|
/* Immediately update the plane's legacy fb pointer, so that later
|
|
/* Immediately update the plane's legacy fb pointer, so that later
|