On Wed, Feb 13, 2019 at 09:32:43PM -0200, Helen Koike wrote: > > > On 2/13/19 7:21 PM, Helen Koike wrote: > > > > > > On 2/13/19 5:18 PM, Nicholas Kazlauskas wrote: > >> The prepare_fb call always happens on new_plane_state. > >> > >> The drm_atomic_helper_cleanup_planes checks to see if > >> plane state pointer has changed when deciding to call cleanup_fb on > >> either the new_plane_state or the old_plane_state. > >> > >> For a non-async atomic commit the state pointer is swapped, so this > >> helper calls prepare_fb on the new_plane_state and cleanup_fb on the > >> old_plane_state. This makes sense, since we want to prepare the > >> framebuffer we are going to use and cleanup the the framebuffer we are > >> no longer using. > >> > >> For the async atomic update helpers this differs. The async atomic > >> update helpers perform in-place updates on the existing state. They call > >> drm_atomic_helper_cleanup_planes but the state pointer is not swapped. > >> This means that prepare_fb is called on the new_plane_state and > >> cleanup_fb is called on the new_plane_state (not the old). > >> > >> In the case where old_plane_state->fb == new_plane_state->fb then > >> there should be no behavioral difference between an async update > >> and a non-async commit. But there are issues that arise when > >> old_plane_state->fb != new_plane_state->fb. > >> > >> The first is that the new_plane_state->fb is immediately cleaned up > >> after it has been prepared, so we're using a fb that we shouldn't > >> be. > >> > >> The second occurs during a sequence of async atomic updates and > >> non-async regular atomic commits. Suppose there are two framebuffers > >> being interleaved in a double-buffering scenario, fb1 and fb2: > >> > >> - Async update, oldfb = NULL, newfb = fb1, prepare fb1, cleanup fb1 > >> - Async update, oldfb = fb1, newfb = fb2, prepare fb2, cleanup fb2 > >> - Non-async commit, oldfb = fb2, newfb = fb1, prepare fb1, cleanup fb2 > >> > >> We call cleanup_fb on fb2 twice in this example scenario, and any > >> further use will result in use-after-free. > >> > >> The simple fix to this problem is to block framebuffer changes > >> in the drm_atomic_helper_async_check function for now. > >> > >> Cc: Daniel Vetter <daniel.vetter@xxxxxxxx> > >> Cc: Harry Wentland <harry.wentland@xxxxxxx> > >> Cc: Andrey Grodzovsky <andrey.grodzovsky@xxxxxxx> > >> Cc: <stable@xxxxxxxxxxxxxxx> # v4.14+ > >> Fixes: fef9df8b5945 ("drm/atomic: initial support for asynchronous plane update") > >> Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@xxxxxxx> > >> --- > >> drivers/gpu/drm/drm_atomic_helper.c | 9 +++++++++ > >> 1 file changed, 9 insertions(+) > >> > >> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c > >> index 54e2ae614dcc..f4290f6b0c38 100644 > >> --- a/drivers/gpu/drm/drm_atomic_helper.c > >> +++ b/drivers/gpu/drm/drm_atomic_helper.c > >> @@ -1602,6 +1602,15 @@ 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; > >> > > > > Hi, > > > > Thank you for working on this. > > > > I have two points I would like to raise: > > > > 1) cursor update is too slow: > > > > I am working on the v8 of > > https://lore.kernel.org/patchwork/patch/949264/ "drm/i915: update > > cursors asynchronously through atomic". > > > > But with this patch applied, the following tests fails: > > > > cursor-vs-flip-atomic-transitions-varying-size > > cursor-vs-flip-toggle > > cursor-vs-flip-varying-size > > > > with errors of type: > > > > "CRITICAL: completed 97 cursor updated in a period of 30 flips, we > > expect to complete approximately 15360 updates, with the threshold set > > at 7680" > > > > I guess it's because what should be async updates are being turned into > > non-async updates (which is slower). > > > > Well, I guess we need to work on a proper solution for the FIXME above, > > this is just an observation/note. > > > > 2) I have another possibly related issue: > > > > From the tests I am making, unless I did some mistake or miss > > interpretation (which is possible since I am new to drm), it seems that > > there is a problem if an async update re-uses the same fb from a > > previous non-async commit, for example: > > > > - Non-async commit, oldfb = NULL, newfb = fb1, prepare fb1, cleanup fb2, > > - Async commit, oldfb = NULL, newfb = fb1, prepare fb1, cleanup fb1 # > > double prepare fb1 > > Sorry, this is solved by this patch, I meant this: > > - Non-async commit, oldfb = NULL, newfb = fb1, prepare fb1, cleanup fb2, > - Async commit, oldfb = fb1, newfb = fb1, prepare fb1, cleanup fb1 > #double prepare fb1 > > But I was told that async commit should block if there is a pending > commit, so this scenario shouldn't happen, but there is still something > off (please see below). > > > > > The cursor through atomic patch was "solving" this by bypassing the > > prepare call with a: > > > > @@ -13495,6 +13503,9 @@ intel_prepare_plane_fb(struct drm_plane *plane, > > struct drm_i915_gem_object *old_obj = > > intel_fb_obj(plane->state->fb); > > int ret; > > > > + if (new_state->state->async_update) > > + return 0; > > + > > if (old_obj) { > > struct drm_crtc_state *crtc_state = > > drm_atomic_get_new_crtc_state(new_state->state, > > > > > > Which looks really wrong to me, but without it, igt tests > > (plane_cursor_legacy, kms_cursor_legacy) fail, I get lots of > > I915_VMA_PIN_OVERFLOW, which suggest double pinning the frame buffers. > > Please, ignore this error above, when I ran the test this patch (Block > fb changes) wasn't applied when I got this error about pin overflow, but > I still have issues: > > With this patch (Block fb changes) applied I get several dmesg failures > on WARN_ON(to_intel_plane_state(state)->vma) in the > intel_plane_destroy_state() function. > > https://people.collabora.com/~koike/results-5.0.0-rc1+-v8-tmp/html/problems.html > > But I don't get this errors with the hack below (that bypass > intel_prepare_plane_fb if the buffer is already pinned). > > I'm still not sure why, I would really appreciate if any one has any > pointers. i915 largely uses its own modeset framework, so there's a good chance for differences in how we pin/unpin buffers, compared to common atomic helpers. That's about my best guess. -Daniel > > Thanks > Helen > > > > > I did this really ugly test to bypass the prepare call just if the > > buffer is already pinned: > > https://gitlab.collabora.com/koike/linux/commit/2d01d4af30347ff43fbac254d8ec305cd6fe4aeb > > > > With this hack igt tests pass. > > > > As I am new to DRM, I would appreciate if someone could confirm that > > this is a real bug or please clarify if I am miss interpreting anything. > > > > If this is a real bug, then if someone could give me pointers in how to > > properly fix this it would be great. > > > > Thanks a lot > > Helen > > -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel