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. 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 > _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel