Merge tag 'drm-misc-fixes-2019-06-05' of git://anongit.freedesktop.org/drm/drm-misc...
authorDave Airlie <airlied@redhat.com>
Thu, 6 Jun 2019 01:56:00 +0000 (11:56 +1000)
committerDave Airlie <airlied@redhat.com>
Thu, 6 Jun 2019 01:57:13 +0000 (11:57 +1000)
- Allow fb changes in async commits (fixes igt failures) (Helen)
- Actually unmap the scatterlist when unmapping udmabuf (Lucas)

Cc: Lucas Stach <l.stach@pengutronix.de>
Cc: Helen Koike <helen.koike@collabora.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Sean Paul <sean@poorly.run>
Link: https://patchwork.freedesktop.org/patch/msgid/20190605210335.GA35431@art_vandelay
drivers/dma-buf/udmabuf.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
drivers/gpu/drm/rockchip/rockchip_drm_vop.c
drivers/gpu/drm/vc4/vc4_plane.c
include/drm/drm_modeset_helper_vtables.h

index cd57747..9635897 100644 (file)
@@ -77,6 +77,7 @@ static void unmap_udmabuf(struct dma_buf_attachment *at,
                          struct sg_table *sg,
                          enum dma_data_direction direction)
 {
+       dma_unmap_sg(at->dev, sg->sgl, sg->nents, direction);
        sg_free_table(sg);
        kfree(sg);
 }
index bcb1a93..ab7c5c3 100644 (file)
@@ -4232,8 +4232,7 @@ static void dm_plane_atomic_async_update(struct drm_plane *plane,
        struct drm_plane_state *old_state =
                drm_atomic_get_old_plane_state(new_state->state, plane);
 
-       if (plane->state->fb != new_state->fb)
-               drm_atomic_set_fb_for_plane(plane->state, new_state->fb);
+       swap(plane->state->fb, new_state->fb);
 
        plane->state->src_x = new_state->src_x;
        plane->state->src_y = new_state->src_y;
index 2e0cb42..22a5c61 100644 (file)
@@ -1607,15 +1607,6 @@ int drm_atomic_helper_async_check(struct drm_device *dev,
            old_plane_state->crtc != new_plane_state->crtc)
                return -EINVAL;
 
-       /*
-        * FIXME: Since prepare_fb and cleanup_fb are always called on
-        * the new_plane_state for async updates we need to block framebuffer
-        * changes. This prevents use of a fb that's been cleaned up and
-        * double cleanups from occuring.
-        */
-       if (old_plane_state->fb != new_plane_state->fb)
-               return -EINVAL;
-
        funcs = plane->helper_private;
        if (!funcs->atomic_async_update)
                return -EINVAL;
@@ -1646,6 +1637,8 @@ EXPORT_SYMBOL(drm_atomic_helper_async_check);
  * drm_atomic_async_check() succeeds. Async commits are not supposed to swap
  * the states like normal sync commits, but just do in-place changes on the
  * current state.
+ *
+ * TODO: Implement full swap instead of doing in-place changes.
  */
 void drm_atomic_helper_async_commit(struct drm_device *dev,
                                    struct drm_atomic_state *state)
@@ -1656,6 +1649,9 @@ void drm_atomic_helper_async_commit(struct drm_device *dev,
        int i;
 
        for_each_new_plane_in_state(state, plane, plane_state, i) {
+               struct drm_framebuffer *new_fb = plane_state->fb;
+               struct drm_framebuffer *old_fb = plane->state->fb;
+
                funcs = plane->helper_private;
                funcs->atomic_async_update(plane, plane_state);
 
@@ -1664,11 +1660,17 @@ void drm_atomic_helper_async_commit(struct drm_device *dev,
                 * plane->state in-place, make sure at least common
                 * properties have been properly updated.
                 */
-               WARN_ON_ONCE(plane->state->fb != plane_state->fb);
+               WARN_ON_ONCE(plane->state->fb != new_fb);
                WARN_ON_ONCE(plane->state->crtc_x != plane_state->crtc_x);
                WARN_ON_ONCE(plane->state->crtc_y != plane_state->crtc_y);
                WARN_ON_ONCE(plane->state->src_x != plane_state->src_x);
                WARN_ON_ONCE(plane->state->src_y != plane_state->src_y);
+
+               /*
+                * Make sure the FBs have been swapped so that cleanups in the
+                * new_state performs a cleanup in the old FB.
+                */
+               WARN_ON_ONCE(plane_state->fb != old_fb);
        }
 }
 EXPORT_SYMBOL(drm_atomic_helper_async_commit);
index be13140..b854f47 100644 (file)
@@ -502,6 +502,8 @@ static int mdp5_plane_atomic_async_check(struct drm_plane *plane,
 static void mdp5_plane_atomic_async_update(struct drm_plane *plane,
                                           struct drm_plane_state *new_state)
 {
+       struct drm_framebuffer *old_fb = plane->state->fb;
+
        plane->state->src_x = new_state->src_x;
        plane->state->src_y = new_state->src_y;
        plane->state->crtc_x = new_state->crtc_x;
@@ -524,6 +526,8 @@ static void mdp5_plane_atomic_async_update(struct drm_plane *plane,
 
        *to_mdp5_plane_state(plane->state) =
                *to_mdp5_plane_state(new_state);
+
+       new_state->fb = old_fb;
 }
 
 static const struct drm_plane_helper_funcs mdp5_plane_helper_funcs = {
index 20a9c29..3bb242f 100644 (file)
@@ -924,29 +924,17 @@ static void vop_plane_atomic_async_update(struct drm_plane *plane,
                                          struct drm_plane_state *new_state)
 {
        struct vop *vop = to_vop(plane->state->crtc);
-       struct drm_plane_state *plane_state;
-
-       plane_state = plane->funcs->atomic_duplicate_state(plane);
-       plane_state->crtc_x = new_state->crtc_x;
-       plane_state->crtc_y = new_state->crtc_y;
-       plane_state->crtc_h = new_state->crtc_h;
-       plane_state->crtc_w = new_state->crtc_w;
-       plane_state->src_x = new_state->src_x;
-       plane_state->src_y = new_state->src_y;
-       plane_state->src_h = new_state->src_h;
-       plane_state->src_w = new_state->src_w;
-
-       if (plane_state->fb != new_state->fb)
-               drm_atomic_set_fb_for_plane(plane_state, new_state->fb);
-
-       swap(plane_state, plane->state);
-
-       if (plane->state->fb && plane->state->fb != new_state->fb) {
-               drm_framebuffer_get(plane->state->fb);
-               WARN_ON(drm_crtc_vblank_get(plane->state->crtc) != 0);
-               drm_flip_work_queue(&vop->fb_unref_work, plane->state->fb);
-               set_bit(VOP_PENDING_FB_UNREF, &vop->pending);
-       }
+       struct drm_framebuffer *old_fb = plane->state->fb;
+
+       plane->state->crtc_x = new_state->crtc_x;
+       plane->state->crtc_y = new_state->crtc_y;
+       plane->state->crtc_h = new_state->crtc_h;
+       plane->state->crtc_w = new_state->crtc_w;
+       plane->state->src_x = new_state->src_x;
+       plane->state->src_y = new_state->src_y;
+       plane->state->src_h = new_state->src_h;
+       plane->state->src_w = new_state->src_w;
+       swap(plane->state->fb, new_state->fb);
 
        if (vop->is_enabled) {
                rockchip_drm_psr_inhibit_get_state(new_state->state);
@@ -955,9 +943,22 @@ static void vop_plane_atomic_async_update(struct drm_plane *plane,
                vop_cfg_done(vop);
                spin_unlock(&vop->reg_lock);
                rockchip_drm_psr_inhibit_put_state(new_state->state);
-       }
 
-       plane->funcs->atomic_destroy_state(plane, plane_state);
+               /*
+                * A scanout can still be occurring, so we can't drop the
+                * reference to the old framebuffer. To solve this we get a
+                * reference to old_fb and set a worker to release it later.
+                * FIXME: if we perform 500 async_update calls before the
+                * vblank, then we can have 500 different framebuffers waiting
+                * to be released.
+                */
+               if (old_fb && plane->state->fb != old_fb) {
+                       drm_framebuffer_get(old_fb);
+                       WARN_ON(drm_crtc_vblank_get(plane->state->crtc) != 0);
+                       drm_flip_work_queue(&vop->fb_unref_work, old_fb);
+                       set_bit(VOP_PENDING_FB_UNREF, &vop->pending);
+               }
+       }
 }
 
 static const struct drm_plane_helper_funcs plane_helper_funcs = {
index 4d918d3..afc80b2 100644 (file)
@@ -1025,7 +1025,7 @@ static void vc4_plane_atomic_async_update(struct drm_plane *plane,
 {
        struct vc4_plane_state *vc4_state, *new_vc4_state;
 
-       drm_atomic_set_fb_for_plane(plane->state, state->fb);
+       swap(plane->state->fb, state->fb);
        plane->state->crtc_x = state->crtc_x;
        plane->state->crtc_y = state->crtc_y;
        plane->state->crtc_w = state->crtc_w;
index f9c94c2..f7bbd0b 100644 (file)
@@ -1185,6 +1185,14 @@ struct drm_plane_helper_funcs {
         * current one with the new plane configurations in the new
         * plane_state.
         *
+        * Drivers should also swap the framebuffers between current plane
+        * state (&drm_plane.state) and new_state.
+        * This is required since cleanup for async commits is performed on
+        * the new state, rather than old state like for traditional commits.
+        * Since we want to give up the reference on the current (old) fb
+        * instead of our brand new one, swap them in the driver during the
+        * async commit.
+        *
         * FIXME:
         *  - It only works for single plane updates
         *  - Async Pageflips are not supported yet