]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - queue-5.1/drm-rockchip-fix-fb-references-in-async-update.patch
4.4-stable patches
[thirdparty/kernel/stable-queue.git] / queue-5.1 / drm-rockchip-fix-fb-references-in-async-update.patch
1 From d985a3533274ef7dd1ccb25cb05a72259b25268f Mon Sep 17 00:00:00 2001
2 From: Helen Koike <helen.koike@collabora.com>
3 Date: Mon, 3 Jun 2019 13:56:06 -0300
4 Subject: drm/rockchip: fix fb references in async update
5
6 From: Helen Koike <helen.koike@collabora.com>
7
8 commit d985a3533274ef7dd1ccb25cb05a72259b25268f upstream.
9
10 In the case of async update, modifications are done in place, i.e. in the
11 current plane state, so the new_state is prepared and the new_state is
12 cleaned up (instead of the old_state, unlike what happens in a
13 normal sync update).
14 To cleanup the old_fb properly, it needs to be placed in the new_state
15 in the end of async_update, so cleanup call will unreference the old_fb
16 correctly.
17
18 Also, the previous code had a:
19
20 plane_state = plane->funcs->atomic_duplicate_state(plane);
21 ...
22 swap(plane_state, plane->state);
23
24 if (plane->state->fb && plane->state->fb != new_state->fb) {
25 ...
26 }
27
28 Which was wrong, as the fb were just assigned to be equal, so this if
29 statement nevers evaluates to true.
30
31 Another details is that the function drm_crtc_vblank_get() can only be
32 called when vop->is_enabled is true, otherwise it has no effect and
33 trows a WARN_ON().
34
35 Calling drm_atomic_set_fb_for_plane() (which get a referent of the new
36 fb and pus the old fb) is not required, as it is taken care by
37 drm_mode_cursor_universal() when calling
38 drm_atomic_helper_update_plane().
39
40 Fixes: 15609559a834 ("drm/rockchip: update cursors asynchronously through atomic.")
41 Cc: <stable@vger.kernel.org> # v4.20+
42 Signed-off-by: Helen Koike <helen.koike@collabora.com>
43 Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
44 Link: https://patchwork.freedesktop.org/patch/msgid/20190603165610.24614-2-helen.koike@collabora.com
45 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
46
47 ---
48 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 49 ++++++++++++++--------------
49 1 file changed, 25 insertions(+), 24 deletions(-)
50
51 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
52 +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
53 @@ -924,29 +924,17 @@ static void vop_plane_atomic_async_updat
54 struct drm_plane_state *new_state)
55 {
56 struct vop *vop = to_vop(plane->state->crtc);
57 - struct drm_plane_state *plane_state;
58 + struct drm_framebuffer *old_fb = plane->state->fb;
59
60 - plane_state = plane->funcs->atomic_duplicate_state(plane);
61 - plane_state->crtc_x = new_state->crtc_x;
62 - plane_state->crtc_y = new_state->crtc_y;
63 - plane_state->crtc_h = new_state->crtc_h;
64 - plane_state->crtc_w = new_state->crtc_w;
65 - plane_state->src_x = new_state->src_x;
66 - plane_state->src_y = new_state->src_y;
67 - plane_state->src_h = new_state->src_h;
68 - plane_state->src_w = new_state->src_w;
69 -
70 - if (plane_state->fb != new_state->fb)
71 - drm_atomic_set_fb_for_plane(plane_state, new_state->fb);
72 -
73 - swap(plane_state, plane->state);
74 -
75 - if (plane->state->fb && plane->state->fb != new_state->fb) {
76 - drm_framebuffer_get(plane->state->fb);
77 - WARN_ON(drm_crtc_vblank_get(plane->state->crtc) != 0);
78 - drm_flip_work_queue(&vop->fb_unref_work, plane->state->fb);
79 - set_bit(VOP_PENDING_FB_UNREF, &vop->pending);
80 - }
81 + plane->state->crtc_x = new_state->crtc_x;
82 + plane->state->crtc_y = new_state->crtc_y;
83 + plane->state->crtc_h = new_state->crtc_h;
84 + plane->state->crtc_w = new_state->crtc_w;
85 + plane->state->src_x = new_state->src_x;
86 + plane->state->src_y = new_state->src_y;
87 + plane->state->src_h = new_state->src_h;
88 + plane->state->src_w = new_state->src_w;
89 + swap(plane->state->fb, new_state->fb);
90
91 if (vop->is_enabled) {
92 rockchip_drm_psr_inhibit_get_state(new_state->state);
93 @@ -955,9 +943,22 @@ static void vop_plane_atomic_async_updat
94 vop_cfg_done(vop);
95 spin_unlock(&vop->reg_lock);
96 rockchip_drm_psr_inhibit_put_state(new_state->state);
97 - }
98
99 - plane->funcs->atomic_destroy_state(plane, plane_state);
100 + /*
101 + * A scanout can still be occurring, so we can't drop the
102 + * reference to the old framebuffer. To solve this we get a
103 + * reference to old_fb and set a worker to release it later.
104 + * FIXME: if we perform 500 async_update calls before the
105 + * vblank, then we can have 500 different framebuffers waiting
106 + * to be released.
107 + */
108 + if (old_fb && plane->state->fb != old_fb) {
109 + drm_framebuffer_get(old_fb);
110 + WARN_ON(drm_crtc_vblank_get(plane->state->crtc) != 0);
111 + drm_flip_work_queue(&vop->fb_unref_work, old_fb);
112 + set_bit(VOP_PENDING_FB_UNREF, &vop->pending);
113 + }
114 + }
115 }
116
117 static const struct drm_plane_helper_funcs plane_helper_funcs = {