diff options
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3242-drm-amd-display-Don-t-replace-the-dc_state-for-fast-.patch')
-rw-r--r-- | meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3242-drm-amd-display-Don-t-replace-the-dc_state-for-fast-.patch | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3242-drm-amd-display-Don-t-replace-the-dc_state-for-fast-.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3242-drm-amd-display-Don-t-replace-the-dc_state-for-fast-.patch new file mode 100644 index 00000000..397f8968 --- /dev/null +++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3242-drm-amd-display-Don-t-replace-the-dc_state-for-fast-.patch @@ -0,0 +1,102 @@ +From f7ff7c11108290d5c87009a1d43c532a20260d46 Mon Sep 17 00:00:00 2001 +From: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com> +Date: Wed, 31 Jul 2019 10:33:54 -0400 +Subject: [PATCH 3242/4256] drm/amd/display: Don't replace the dc_state for + fast updates + +[Why] +DRM private objects have no hw_done/flip_done fencing mechanism on their +own and cannot be used to sequence commits accordingly. + +When issuing commits that don't touch the same set of hardware resources +like page-flips on different CRTCs we can run into the issue below +because of this: + +1. Client requests non-blocking Commit #1, has a new dc_state #1, +state is swapped, commit tail is deferred to work queue + +2. Client requests non-blocking Commit #2, has a new dc_state #2, +state is swapped, commit tail is deferred to work queue + +3. Commit #2 work starts, commit tail finishes, +atomic state is cleared, dc_state #1 is freed + +4. Commit #1 work starts, +commit tail encounters null pointer deref on dc_state #1 + +In order to change the DC state as in the private object we need to +ensure that we wait for all outstanding commits to finish and that +any other pending commits must wait for the current one to finish as +well. + +We do this for MEDIUM and FULL updates. But not for FAST updates, nor +would we want to since it would cause stuttering from the delays. + +FAST updates that go through dm_determine_update_type_for_commit always +create a new dc_state and lock the DRM private object if there are +any changed planes. + +We need the old state to validate, but we don't actually need the new +state here. + +[How] +If the commit isn't a full update then the use after free can be +resolved by simply discarding the new state entirely and retaining +the existing one instead. + +With this change the sequence above can be reexamined. Commit #2 will +still free Commit #1's reference, but before this happens we actually +added an additional reference as part of Commit #2. + +If an update comes in during this that needs to change the dc_state +it will need to wait on Commit #1 and Commit #2 to finish. Then it'll +swap the state, finish the work in commit tail and drop the last +reference on Commit #2's dc_state. + +Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=204181 +Fixes: 004b3938e637 ("drm/amd/display: Check scaling info when determing update type") + +Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com> +Acked-by: Alex Deucher <alexander.deucher@amd.com> +Reviewed-by: David Francis <david.francis@amd.com> +--- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 23 +++++++++++++++++++ + 1 file changed, 23 insertions(+) + +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 2d408b614ee0..3ec42eb79ec9 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -7297,6 +7297,29 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, + ret = -EINVAL; + goto fail; + } ++ } else { ++ /* ++ * The commit is a fast update. Fast updates shouldn't change ++ * the DC context, affect global validation, and can have their ++ * commit work done in parallel with other commits not touching ++ * the same resource. If we have a new DC context as part of ++ * the DM atomic state from validation we need to free it and ++ * retain the existing one instead. ++ */ ++ struct dm_atomic_state *new_dm_state, *old_dm_state; ++ ++ new_dm_state = dm_atomic_get_new_state(state); ++ old_dm_state = dm_atomic_get_old_state(state); ++ ++ if (new_dm_state && old_dm_state) { ++ if (new_dm_state->context) ++ dc_release_state(new_dm_state->context); ++ ++ new_dm_state->context = old_dm_state->context; ++ ++ if (old_dm_state->context) ++ dc_retain_state(old_dm_state->context); ++ } + } + + /* Must be success */ +-- +2.17.1 + |