[PATCH v2] drm/amd/display: Signal hw_done() after waiting for flip_done()

Harry Wentland harry.wentland at amd.com
Tue Oct 2 14:41:14 UTC 2018



On 2018-10-01 07:26 PM, sunpeng.li at amd.com wrote:
> From: Shirish S <shirish.s at amd.com>
> 
> In amdgpu_dm_commit_tail(), wait until flip_done() is signaled before
> we signal hw_done().
> 
> [Why]
> 
> This is to temporary address a paging error that occurs when a

s/temporary/temporarily/g

> nonblocking commit contends with another commit, particularly in a
> mirrored multi-display configuration. The error occurs in
> drm_atomic_helper_wait_for_flip_done(), when we attempt to access the
> contents of new_crtc_state->commit.
> 
> Here's the sequence for a mirrored 2 display setup (irrelevant steps
> left out for clarity):
> 
> **THREAD 1**                        | **THREAD 2**
>                                     |
> Initialize atomic state for flip    |
>                                     |
> Queue worker                        |
>                                    ...
> 
>                                     | Do work for flip
>                                     |
>                                     | Signal hw_done() on CRTC 1
>                                     | Signal hw_done() on CRTC 2
>                                     |
>                                     | Wait for flip_done() on CRTC 1
> 
>                                 <---- **PREEMPTED BY THREAD 1**
> 
> Initialize atomic state for cursor
> update (1)                          |
>                                     |
> Do cursor update worker             |
>                                     |
> Clear atomic state (2)              |
> **DONE**                            |
>                                    ...
>                                     |
>                                     | Wait for flip_done() on CRTC 2
>                                     | *ERROR*
>                                     |
> 
> The issue starts with (1). When the atomic state is initialized, the
> current CRTC states are duplicated to be the new_crtc_states, and
> referenced to be the old_crtc_states. (The new_crtc_states are to be
> filled with update data.)
> 
> Some things to note:
> 
> * Due to the mirrored configuration, the cursor updates on both CRTCs.
> 
> * At this point, the pflip IRQ has already been handled, and flip_done
>   signaled on all CRTCs. The cursor commit can therefore continue.
> 
> * The old_crtc_states used by the cursor update are the **same states**
>   as the new_crtc_states used by the flip worker.
> 
> At (2), the old_crtc_state is freed (*), and the cursor commit
> completes. We then context switch back to the flip worker, where we
> attempt to access the new_crtc_state->commit object. This is
> problematic, as this state has already been freed.
> 
> (*) Technically, 'state->crtcs[i].state' is freed, which was made to
>     reference old_crtc_state in drm_atomic_helper_swap_state()
> 
> [How]
> 
> By moving hw_done() after wait_for_flip_done(), we're guaranteed that
> the new_crtc_state (from the flip worker's perspective) still exists.
> This is because any other commit will be blocked, waiting for the
> hw_done() signal.
> 
> Note that both the i915 and imx drivers have this sequence flipped
> already, masking this problem.
> 
> Signed-off-by: Shirish S <shirish.s at amd.com>
> Signed-off-by: Leo Li <sunpeng.li at amd.com>

Thanks for the additional explanation. Took me a while to understand what was happening here. Let's keep pursuing a proper solution that allows us to flip hw_done and wait_for_flip_done again but since that might be non-trivial this change is

Reviewed-by: Harry Wentland <harry.wentland at amd.com>

Harry

> ---
> 
> Hi Shirish,
> 
> Sorry for the late reply. I took some time to dig at this issue, and found
> that a proper fix will need more thought. I'm OK with this fix for now, until
> we can address it with a proper fix.
> 
> I've updated the commit message and comments below to reflect the underlying
> issue.
> 
> Thanks,
> Leo
> 
>  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> index 774db34..bbfffaf 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -4755,12 +4755,18 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
>  	}
>  	spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
>  
> -	/* Signal HW programming completion */
> -	drm_atomic_helper_commit_hw_done(state);
>  
>  	if (wait_for_vblank)
>  		drm_atomic_helper_wait_for_flip_done(dev, state);
>  
> +	/*
> +	 * FIXME:
> +	 * Delay hw_done() until flip_done() is signaled. This is to block
> +	 * another commit from freeing the CRTC state while we're still
> +	 * waiting on flip_done.
> +	 */
> +	drm_atomic_helper_commit_hw_done(state);
> +
>  	drm_atomic_helper_cleanup_planes(dev, state);
>  
>  	/*
> 


More information about the amd-gfx mailing list