Re: [PATCH v2] drm: Block fb changes for async plane updates

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On 2/14/19 6:21 AM, Daniel Vetter wrote:
> 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

Indeed, there was a missing drm_atomic_helper_cleanup_planes() call in
intel_atomic_commit(), now it is working fine.

Thanks and sorry for the noise on this.
Helen

> 
>>
>> 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




[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux