drm/atomic: Fix use-after-free with unbound connectors/planes.
Subsystems (3)
Maarten Lankhorst
maintainercover drm/atomic: Fix use-after-free with unbound connectors/planes.
This started out as a small set of 2 patches, but feedback made it 5. :(
Maarten Lankhorst (5):
drm/i915: Always wait for flip_done
drm/atomic: Remove waits in drm_atomic_helper_commit_cleanup_done drm/atomic: Move drm_crtc_commit to drm_crtc_state, v2. drm/atomic: Fix freeing connector/plane state too early by tracking
commits, v2.
drm/atomic: Make async plane update checks work as intended.
drivers/gpu/drm/drm_atomic.c | 11 +- drivers/gpu/drm/drm_atomic_helper.c | 270 ++++++++++++++++++++++------------- drivers/gpu/drm/i915/i915_drv.h | 3 +- drivers/gpu/drm/i915/intel_display.c | 93 +++--------- include/drm/drm_atomic.h | 13 +- include/drm/drm_connector.h | 7 + include/drm/drm_crtc.h | 23 ++- include/drm/drm_plane.h | 8 ++ 8 files changed, 242 insertions(+), 186 deletions(-)
Signature · 6 lines
2.11.0 _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
Maarten Lankhorst
maintainerRFC PATCH 1/5 drm/i915: Always wait for flip_done
The next commit removes the wait for flip_done in in drm_atomic_helper_commit_cleanup_done, but we need it for the tests to pass. Instead of using complicated vblank tracking which ends up being ignored anyway, call the correct atomic helper. :)
RFC because I'm not completely sure what we want to do with the vblank waiting, I think for now this patch is the right way to go until we decide because it preserves the status quo when drm_crtc_commit was introduced.
--- drivers/gpu/drm/i915/i915_drv.h | 3 +- drivers/gpu/drm/i915/intel_display.c | 83 +++--------------------------------- 2 files changed, 8 insertions(+), 78 deletions(-)
drivers/gpu/drm/i915/i915_drv.h +1 -2
@@ -707,8 +707,7 @@ struct drm_i915_display_funcs { struct drm_atomic_state *old_state);void (*crtc_disable)(struct intel_crtc_state *old_crtc_state,struct drm_atomic_state *old_state); -void (*update_crtcs)(struct drm_atomic_state *state, -unsigned int *crtc_vblank_mask); +void (*update_crtcs)(struct drm_atomic_state *state);void (*audio_codec_enable)(struct drm_connector *connector,struct intel_encoder *encoder,const struct drm_display_mode *adjusted_mode);
drivers/gpu/drm/i915/intel_display.c +7 -76
133 lines not on this page · raw message
Signature · 6 lines
2.11.0 _______________________________________________ Intel-gfx mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Re: [RFC PATCH 1/5] drm/i915: Always wait for flip_done
Quoted 165 lines · Maarten Lankhorst
The next commit removes the wait for
flip_donein indrm_atomic_helper_commit_cleanup_done, but we need it for the tests to pass. Instead of using complicated vblank tracking which ends up being ignored anyway, call the correct atomic helper. :)RFC because I'm not completely sure what we want to do with the vblank waiting, I think for now this patch is the right way to go until we decide because it preserves the status quo when
drm_crtc_commitwas introduced.Signed-off-by Maarten Lankhorst <[email protected]>--- drivers/gpu/drm/i915/i915_drv.h | 3 +- drivers/gpu/drm/i915/intel_display.c | 83 +++--------------------------------- 2 files changed, 8 insertions(+), 78 deletions(-)drivers/gpu/drm/i915/i915_drv.h +1
-2@@ -707,8 +707,7 @@ struct drm_i915_display_funcs { struct drm_atomic_state *old_state);void (*crtc_disable)(struct intel_crtc_state *old_crtc_state,struct drm_atomic_state *old_state); -void (*update_crtcs)(struct drm_atomic_state *state, -unsigned int *crtc_vblank_mask); +void (*update_crtcs)(struct drm_atomic_state *state);void (*audio_codec_enable)(struct drm_connector *connector,struct intel_encoder *encoder,const struct drm_display_mode *adjusted_mode);drivers/gpu/drm/i915/intel_display.c +6
-75@@ -12114,73 +12114,10 @@ u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)return dev->driver->get_vblank_counter (dev, crtc->pipe); } -static void intel_atomic_wait_for_vblanks (struct drm_device *dev, -struct drm_i915_private *dev_priv, -unsigned crtc_mask) -{ -unsigned last_vblank_count[I915_MAX_PIPES ]; -enum pipe pipe; -int ret; - -if (!crtc_mask) -return ; - -for_each_pipe (dev_priv, pipe) { -struct intel_crtc *crtc =intel_get_crtc_for_pipe (dev_priv, - pipe); - -if (!((1 << pipe) & crtc_mask)) -continue ; - - ret =drm_crtc_vblank_get (&crtc->base); -if (WARN_ON (ret !=0 )) { - crtc_mask &= ~(1 << pipe); -continue ; - } - - last_vblank_count[pipe] =drm_crtc_vblank_count (&crtc->base); - } - -for_each_pipe (dev_priv, pipe) { -struct intel_crtc *crtc =intel_get_crtc_for_pipe (dev_priv, - pipe); -long lret; - -if (!((1 << pipe) & crtc_mask)) -continue ; - - lret =wait_event_timeout (dev->vblank[pipe].queue, - last_vblank_count[pipe] != -drm_crtc_vblank_count (&crtc->base), -msecs_to_jiffies (50 )); - -WARN (!lret,"pipe %c vblank wait timed out\n" ,pipe_name (pipe)); - -drm_crtc_vblank_put (&crtc->base); - } -} - -static bool needs_vblank_wait (struct intel_crtc_state *crtc_state) -{ -/* fb updated, need to unpin old fb */ -if (crtc_state->fb_changed) -return true; - -/* wm changes, need vblank before final wm's */ -if (crtc_state->update_wm_post) -return true; - -if (crtc_state->wm.need_postvbl_update) -return true; - -return false; -} -static void intel_update_crtc (struct drm_crtc *crtc,struct drm_atomic_state *state,struct drm_crtc_state *old_crtc_state, -struct drm_crtc_state *new_crtc_state, -unsigned int *crtc_vblank_mask) +struct drm_crtc_state *new_crtc_state) {struct drm_device *dev = crtc->dev;struct drm_i915_private *dev_priv =to_i915 (dev);@@ -12203,13 +12140,9 @@ static void intel_update_crtc(struct drm_crtc *crtc, }drm_atomic_helper_commit_planes_on_crtc (old_crtc_state); - -if (needs_vblank_wait (pipe_config)) - *crtc_vblank_mask |=drm_crtc_mask (crtc); } -static void intel_update_crtcs (struct drm_atomic_state *state, -unsigned int *crtc_vblank_mask) +static void intel_update_crtcs (struct drm_atomic_state *state) {struct drm_crtc *crtc;struct drm_crtc_state *old_crtc_state, *new_crtc_state;@@ -12220,12 +12153,11 @@ static void intel_update_crtcs(struct drm_atomic_state *state,continue ;intel_update_crtc (crtc, state, old_crtc_state, - new_crtc_state, crtc_vblank_mask); + new_crtc_state); } } -static void skl_update_crtcs (struct drm_atomic_state *state, -unsigned int *crtc_vblank_mask) +static void skl_update_crtcs (struct drm_atomic_state *state) {struct drm_i915_private *dev_priv =to_i915 (state->dev);struct intel_atomic_state *intel_state =to_intel_atomic_state (state);@@ -12284,7 +12216,7 @@ static void skl_update_crtcs(struct drm_atomic_state *state, vbl_wait = true;intel_update_crtc (crtc, state, old_crtc_state, - new_crtc_state, crtc_vblank_mask); + new_crtc_state);if (vbl_wait)intel_wait_for_vblank (dev_priv, pipe);@@ -12346,7 +12278,6 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)struct intel_crtc_state *intel_cstate;bool hw_check = intel_state->modeset;u64 put_domains[I915_MAX_PIPES ] = {}; -unsigned crtc_vblank_mask =0 ;int i;intel_atomic_commit_fence_wait (intel_state);@@ -12438,7 +12369,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)pm_qos_update_request (&dev_priv->pm_qos_atomic,0 );/* Now enable the clocks, plane, pipe, and connectors that we set up. */ - dev_priv->display.update_crtcs (state, &crtc_vblank_mask); + dev_priv->display.update_crtcs (state);/* FIXME: We should call drm_atomic_helper_commit_hw_done() here * already, but still need the state for the delayed optimization. To
drivers/gpu/drm/i915/intel_display.c static void intel_atomic_commit_tail(struct drm_atomic_state *state) · line 12383
Quoted 3 lines
drivers/gpu/drm/i915/intel_display.c +0
-0@@ -12450,7 +12381,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)* we don't need out special handling any more. */ if (!state->legacy_cursor_update)
I think this if is dead code, since either we use the fastpath in intel_legacy_cursor_update, which means no atomic commit. Or we don't, and then we clear this hack (on most platforms at least) since it just wreaks complete havoc.
We should probably do this logic in the async helpers, i.e. if async helpers reject a cursor update, clear state->legacy_cursor_update.
Since I think we don't necessarily need this patch in this series, I think it'd be better in a separate series to straighten out the async_update story. Which would then include moving i915 over to the core support. -Daniel
Quoted 12 lines
drivers/gpu/drm/i915/intel_display.c +1
-1-intel_atomic_wait_for_vblanks (dev, dev_priv, crtc_vblank_mask); +drm_atomic_helper_wait_for_flip_done (dev, state);/* * Now that the vblank has passed, we can go ahead and program the Signature · 6 lines
2.11.0 _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
Signature · 7 lines
Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
Maarten Lankhorst
maintainerRe: [RFC PATCH 1/5] drm/i915: Always wait for flip_done
Op 30-08-17 om 14:43 schreef Daniel Vetter:
Quoted 174 lines · Maarten Lankhorst
Quoted 165 lines
The next commit removes the wait for
flip_donein indrm_atomic_helper_commit_cleanup_done, but we need it for the tests to pass. Instead of using complicated vblank tracking which ends up being ignored anyway, call the correct atomic helper. :)RFC because I'm not completely sure what we want to do with the vblank waiting, I think for now this patch is the right way to go until we decide because it preserves the status quo when
drm_crtc_commitwas introduced.Signed-off-by Maarten Lankhorst <[email protected]>--- drivers/gpu/drm/i915/i915_drv.h | 3 +- drivers/gpu/drm/i915/intel_display.c | 83 +++--------------------------------- 2 files changed, 8 insertions(+), 78 deletions(-)drivers/gpu/drm/i915/i915_drv.h +1
-2@@ -707,8 +707,7 @@ struct drm_i915_display_funcs { struct drm_atomic_state *old_state);void (*crtc_disable)(struct intel_crtc_state *old_crtc_state,struct drm_atomic_state *old_state); -void (*update_crtcs)(struct drm_atomic_state *state, -unsigned int *crtc_vblank_mask); +void (*update_crtcs)(struct drm_atomic_state *state);void (*audio_codec_enable)(struct drm_connector *connector,struct intel_encoder *encoder,const struct drm_display_mode *adjusted_mode);drivers/gpu/drm/i915/intel_display.c +6
-75@@ -12114,73 +12114,10 @@ u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)return dev->driver->get_vblank_counter (dev, crtc->pipe); } -static void intel_atomic_wait_for_vblanks (struct drm_device *dev, -struct drm_i915_private *dev_priv, -unsigned crtc_mask) -{ -unsigned last_vblank_count[I915_MAX_PIPES ]; -enum pipe pipe; -int ret; - -if (!crtc_mask) -return ; - -for_each_pipe (dev_priv, pipe) { -struct intel_crtc *crtc =intel_get_crtc_for_pipe (dev_priv, - pipe); - -if (!((1 << pipe) & crtc_mask)) -continue ; - - ret =drm_crtc_vblank_get (&crtc->base); -if (WARN_ON (ret !=0 )) { - crtc_mask &= ~(1 << pipe); -continue ; - } - - last_vblank_count[pipe] =drm_crtc_vblank_count (&crtc->base); - } - -for_each_pipe (dev_priv, pipe) { -struct intel_crtc *crtc =intel_get_crtc_for_pipe (dev_priv, - pipe); -long lret; - -if (!((1 << pipe) & crtc_mask)) -continue ; - - lret =wait_event_timeout (dev->vblank[pipe].queue, - last_vblank_count[pipe] != -drm_crtc_vblank_count (&crtc->base), -msecs_to_jiffies (50 )); - -WARN (!lret,"pipe %c vblank wait timed out\n" ,pipe_name (pipe)); - -drm_crtc_vblank_put (&crtc->base); - } -} - -static bool needs_vblank_wait (struct intel_crtc_state *crtc_state) -{ -/* fb updated, need to unpin old fb */ -if (crtc_state->fb_changed) -return true; - -/* wm changes, need vblank before final wm's */ -if (crtc_state->update_wm_post) -return true; - -if (crtc_state->wm.need_postvbl_update) -return true; - -return false; -} -static void intel_update_crtc (struct drm_crtc *crtc,struct drm_atomic_state *state,struct drm_crtc_state *old_crtc_state, -struct drm_crtc_state *new_crtc_state, -unsigned int *crtc_vblank_mask) +struct drm_crtc_state *new_crtc_state) {struct drm_device *dev = crtc->dev;struct drm_i915_private *dev_priv =to_i915 (dev);@@ -12203,13 +12140,9 @@ static void intel_update_crtc(struct drm_crtc *crtc, }drm_atomic_helper_commit_planes_on_crtc (old_crtc_state); - -if (needs_vblank_wait (pipe_config)) - *crtc_vblank_mask |=drm_crtc_mask (crtc); } -static void intel_update_crtcs (struct drm_atomic_state *state, -unsigned int *crtc_vblank_mask) +static void intel_update_crtcs (struct drm_atomic_state *state) {struct drm_crtc *crtc;struct drm_crtc_state *old_crtc_state, *new_crtc_state;@@ -12220,12 +12153,11 @@ static void intel_update_crtcs(struct drm_atomic_state *state,continue ;intel_update_crtc (crtc, state, old_crtc_state, - new_crtc_state, crtc_vblank_mask); + new_crtc_state); } } -static void skl_update_crtcs (struct drm_atomic_state *state, -unsigned int *crtc_vblank_mask) +static void skl_update_crtcs (struct drm_atomic_state *state) {struct drm_i915_private *dev_priv =to_i915 (state->dev);struct intel_atomic_state *intel_state =to_intel_atomic_state (state);@@ -12284,7 +12216,7 @@ static void skl_update_crtcs(struct drm_atomic_state *state, vbl_wait = true;intel_update_crtc (crtc, state, old_crtc_state, - new_crtc_state, crtc_vblank_mask); + new_crtc_state);if (vbl_wait)intel_wait_for_vblank (dev_priv, pipe);@@ -12346,7 +12278,6 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)struct intel_crtc_state *intel_cstate;bool hw_check = intel_state->modeset;u64 put_domains[I915_MAX_PIPES ] = {}; -unsigned crtc_vblank_mask =0 ;int i;intel_atomic_commit_fence_wait (intel_state);@@ -12438,7 +12369,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)pm_qos_update_request (&dev_priv->pm_qos_atomic,0 );/* Now enable the clocks, plane, pipe, and connectors that we set up. */ - dev_priv->display.update_crtcs (state, &crtc_vblank_mask); + dev_priv->display.update_crtcs (state);/* FIXME: We should call drm_atomic_helper_commit_hw_done() here * already, but still need the state for the delayed optimization. To drivers/gpu/drm/i915/intel_display.c static void intel_atomic_commit_tail(struct drm_atomic_state *state) · line 12383
Quoted 3 lines
drivers/gpu/drm/i915/intel_display.c +0
-0@@ -12450,7 +12381,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)* we don't need out special handling any more. */ if (!state->legacy_cursor_update)I think this if is dead code, since either we use the fastpath in
intel_legacy_cursor_update, which means no atomic commit. Or we don't, and then we clear this hack (on most platforms at least) since it just wreaks complete havoc.
Quoted 6 lines
We should probably do this logic in the async helpers, i.e. if async helpers reject a cursor update, clear
state->legacy_cursor_update.Since I think we don't necessarily need this patch in this series, I think it'd be better in a separate series to straighten out the
async_updatestory. Which would then include moving i915 over to the core support.
Erm, not sure what you mean here, isn't state->legacy_cursor_update mostly false, which means in most cases we'll wait?
~Maarten
_______________________________________________
Intel-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Re: [RFC PATCH 1/5] drm/i915: Always wait for flip_done
Quoted 175 lines · Maarten Lankhorst
Op 30-08-17 om 14:43 schreef Daniel Vetter:
Quoted 174 lines · Maarten Lankhorst
Quoted 165 lines
The next commit removes the wait for
flip_donein indrm_atomic_helper_commit_cleanup_done, but we need it for the tests to pass. Instead of using complicated vblank tracking which ends up being ignored anyway, call the correct atomic helper. :)RFC because I'm not completely sure what we want to do with the vblank waiting, I think for now this patch is the right way to go until we decide because it preserves the status quo when
drm_crtc_commitwas introduced.Signed-off-by Maarten Lankhorst <[email protected]>--- drivers/gpu/drm/i915/i915_drv.h | 3 +- drivers/gpu/drm/i915/intel_display.c | 83 +++--------------------------------- 2 files changed, 8 insertions(+), 78 deletions(-)drivers/gpu/drm/i915/i915_drv.h +1
-2@@ -707,8 +707,7 @@ struct drm_i915_display_funcs { struct drm_atomic_state *old_state);void (*crtc_disable)(struct intel_crtc_state *old_crtc_state,struct drm_atomic_state *old_state); -void (*update_crtcs)(struct drm_atomic_state *state, -unsigned int *crtc_vblank_mask); +void (*update_crtcs)(struct drm_atomic_state *state);void (*audio_codec_enable)(struct drm_connector *connector,struct intel_encoder *encoder,const struct drm_display_mode *adjusted_mode);drivers/gpu/drm/i915/intel_display.c +6
-75@@ -12114,73 +12114,10 @@ u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)return dev->driver->get_vblank_counter (dev, crtc->pipe); } -static void intel_atomic_wait_for_vblanks (struct drm_device *dev, -struct drm_i915_private *dev_priv, -unsigned crtc_mask) -{ -unsigned last_vblank_count[I915_MAX_PIPES ]; -enum pipe pipe; -int ret; - -if (!crtc_mask) -return ; - -for_each_pipe (dev_priv, pipe) { -struct intel_crtc *crtc =intel_get_crtc_for_pipe (dev_priv, - pipe); - -if (!((1 << pipe) & crtc_mask)) -continue ; - - ret =drm_crtc_vblank_get (&crtc->base); -if (WARN_ON (ret !=0 )) { - crtc_mask &= ~(1 << pipe); -continue ; - } - - last_vblank_count[pipe] =drm_crtc_vblank_count (&crtc->base); - } - -for_each_pipe (dev_priv, pipe) { -struct intel_crtc *crtc =intel_get_crtc_for_pipe (dev_priv, - pipe); -long lret; - -if (!((1 << pipe) & crtc_mask)) -continue ; - - lret =wait_event_timeout (dev->vblank[pipe].queue, - last_vblank_count[pipe] != -drm_crtc_vblank_count (&crtc->base), -msecs_to_jiffies (50 )); - -WARN (!lret,"pipe %c vblank wait timed out\n" ,pipe_name (pipe)); - -drm_crtc_vblank_put (&crtc->base); - } -} - -static bool needs_vblank_wait (struct intel_crtc_state *crtc_state) -{ -/* fb updated, need to unpin old fb */ -if (crtc_state->fb_changed) -return true; - -/* wm changes, need vblank before final wm's */ -if (crtc_state->update_wm_post) -return true; - -if (crtc_state->wm.need_postvbl_update) -return true; - -return false; -} -static void intel_update_crtc (struct drm_crtc *crtc,struct drm_atomic_state *state,struct drm_crtc_state *old_crtc_state, -struct drm_crtc_state *new_crtc_state, -unsigned int *crtc_vblank_mask) +struct drm_crtc_state *new_crtc_state) {struct drm_device *dev = crtc->dev;struct drm_i915_private *dev_priv =to_i915 (dev);@@ -12203,13 +12140,9 @@ static void intel_update_crtc(struct drm_crtc *crtc, }drm_atomic_helper_commit_planes_on_crtc (old_crtc_state); - -if (needs_vblank_wait (pipe_config)) - *crtc_vblank_mask |=drm_crtc_mask (crtc); } -static void intel_update_crtcs (struct drm_atomic_state *state, -unsigned int *crtc_vblank_mask) +static void intel_update_crtcs (struct drm_atomic_state *state) {struct drm_crtc *crtc;struct drm_crtc_state *old_crtc_state, *new_crtc_state;@@ -12220,12 +12153,11 @@ static void intel_update_crtcs(struct drm_atomic_state *state,continue ;intel_update_crtc (crtc, state, old_crtc_state, - new_crtc_state, crtc_vblank_mask); + new_crtc_state); } } -static void skl_update_crtcs (struct drm_atomic_state *state, -unsigned int *crtc_vblank_mask) +static void skl_update_crtcs (struct drm_atomic_state *state) {struct drm_i915_private *dev_priv =to_i915 (state->dev);struct intel_atomic_state *intel_state =to_intel_atomic_state (state);@@ -12284,7 +12216,7 @@ static void skl_update_crtcs(struct drm_atomic_state *state, vbl_wait = true;intel_update_crtc (crtc, state, old_crtc_state, - new_crtc_state, crtc_vblank_mask); + new_crtc_state);if (vbl_wait)intel_wait_for_vblank (dev_priv, pipe);@@ -12346,7 +12278,6 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)struct intel_crtc_state *intel_cstate;bool hw_check = intel_state->modeset;u64 put_domains[I915_MAX_PIPES ] = {}; -unsigned crtc_vblank_mask =0 ;int i;intel_atomic_commit_fence_wait (intel_state);@@ -12438,7 +12369,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)pm_qos_update_request (&dev_priv->pm_qos_atomic,0 );/* Now enable the clocks, plane, pipe, and connectors that we set up. */ - dev_priv->display.update_crtcs (state, &crtc_vblank_mask); + dev_priv->display.update_crtcs (state);/* FIXME: We should call drm_atomic_helper_commit_hw_done() here * already, but still need the state for the delayed optimization. To drivers/gpu/drm/i915/intel_display.c static void intel_atomic_commit_tail(struct drm_atomic_state *state) · line 12383
Quoted 3 lines
drivers/gpu/drm/i915/intel_display.c +0
-0@@ -12450,7 +12381,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)* we don't need out special handling any more. */ if (!state->legacy_cursor_update)I think this if is dead code, since either we use the fastpath in
intel_legacy_cursor_update, which means no atomic commit. Or we don't, and then we clear this hack (on most platforms at least) since it just wreaks complete havoc.
Quoted 7 lines
Quoted 6 lines
We should probably do this logic in the async helpers, i.e. if async helpers reject a cursor update, clear
state->legacy_cursor_update.Since I think we don't necessarily need this patch in this series, I think it'd be better in a separate series to straighten out the
async_updatestory. Which would then include moving i915 over to the core support.Erm, not sure what you mean here, isn't
state->legacy_cursor_updatemostly false, which means in most cases we'll wait?
Yup. And the few cases where it's true should be handled by the fastpath/async plane update logic. Would allow us to ditch a few conditions all over the code.
-Daniel
Signature · 7 lines
Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch _______________________________________________ Intel-gfx mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Maarten Lankhorst
maintainerRe: [RFC PATCH 1/5] drm/i915: Always wait for flip_done
Op 30-08-17 om 15:40 schreef Daniel Vetter:
Quoted 179 lines · Maarten Lankhorst
Quoted 178 lines
Op 30-08-17 om 14:43 schreef Daniel Vetter:
Quoted 177 lines · Maarten Lankhorst
Quoted 165 lines
The next commit removes the wait for
flip_donein indrm_atomic_helper_commit_cleanup_done, but we need it for the tests to pass. Instead of using complicated vblank tracking which ends up being ignored anyway, call the correct atomic helper. :)RFC because I'm not completely sure what we want to do with the vblank waiting, I think for now this patch is the right way to go until we decide because it preserves the status quo when
drm_crtc_commitwas introduced.Signed-off-by Maarten Lankhorst <[email protected]>--- drivers/gpu/drm/i915/i915_drv.h | 3 +- drivers/gpu/drm/i915/intel_display.c | 83 +++--------------------------------- 2 files changed, 8 insertions(+), 78 deletions(-)drivers/gpu/drm/i915/i915_drv.h +1
-2@@ -707,8 +707,7 @@ struct drm_i915_display_funcs { struct drm_atomic_state *old_state);void (*crtc_disable)(struct intel_crtc_state *old_crtc_state,struct drm_atomic_state *old_state); -void (*update_crtcs)(struct drm_atomic_state *state, -unsigned int *crtc_vblank_mask); +void (*update_crtcs)(struct drm_atomic_state *state);void (*audio_codec_enable)(struct drm_connector *connector,struct intel_encoder *encoder,const struct drm_display_mode *adjusted_mode);drivers/gpu/drm/i915/intel_display.c +6
-75@@ -12114,73 +12114,10 @@ u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)return dev->driver->get_vblank_counter (dev, crtc->pipe); } -static void intel_atomic_wait_for_vblanks (struct drm_device *dev, -struct drm_i915_private *dev_priv, -unsigned crtc_mask) -{ -unsigned last_vblank_count[I915_MAX_PIPES ]; -enum pipe pipe; -int ret; - -if (!crtc_mask) -return ; - -for_each_pipe (dev_priv, pipe) { -struct intel_crtc *crtc =intel_get_crtc_for_pipe (dev_priv, - pipe); - -if (!((1 << pipe) & crtc_mask)) -continue ; - - ret =drm_crtc_vblank_get (&crtc->base); -if (WARN_ON (ret !=0 )) { - crtc_mask &= ~(1 << pipe); -continue ; - } - - last_vblank_count[pipe] =drm_crtc_vblank_count (&crtc->base); - } - -for_each_pipe (dev_priv, pipe) { -struct intel_crtc *crtc =intel_get_crtc_for_pipe (dev_priv, - pipe); -long lret; - -if (!((1 << pipe) & crtc_mask)) -continue ; - - lret =wait_event_timeout (dev->vblank[pipe].queue, - last_vblank_count[pipe] != -drm_crtc_vblank_count (&crtc->base), -msecs_to_jiffies (50 )); - -WARN (!lret,"pipe %c vblank wait timed out\n" ,pipe_name (pipe)); - -drm_crtc_vblank_put (&crtc->base); - } -} - -static bool needs_vblank_wait (struct intel_crtc_state *crtc_state) -{ -/* fb updated, need to unpin old fb */ -if (crtc_state->fb_changed) -return true; - -/* wm changes, need vblank before final wm's */ -if (crtc_state->update_wm_post) -return true; - -if (crtc_state->wm.need_postvbl_update) -return true; - -return false; -} -static void intel_update_crtc (struct drm_crtc *crtc,struct drm_atomic_state *state,struct drm_crtc_state *old_crtc_state, -struct drm_crtc_state *new_crtc_state, -unsigned int *crtc_vblank_mask) +struct drm_crtc_state *new_crtc_state) {struct drm_device *dev = crtc->dev;struct drm_i915_private *dev_priv =to_i915 (dev);@@ -12203,13 +12140,9 @@ static void intel_update_crtc(struct drm_crtc *crtc, }drm_atomic_helper_commit_planes_on_crtc (old_crtc_state); - -if (needs_vblank_wait (pipe_config)) - *crtc_vblank_mask |=drm_crtc_mask (crtc); } -static void intel_update_crtcs (struct drm_atomic_state *state, -unsigned int *crtc_vblank_mask) +static void intel_update_crtcs (struct drm_atomic_state *state) {struct drm_crtc *crtc;struct drm_crtc_state *old_crtc_state, *new_crtc_state;@@ -12220,12 +12153,11 @@ static void intel_update_crtcs(struct drm_atomic_state *state,continue ;intel_update_crtc (crtc, state, old_crtc_state, - new_crtc_state, crtc_vblank_mask); + new_crtc_state); } } -static void skl_update_crtcs (struct drm_atomic_state *state, -unsigned int *crtc_vblank_mask) +static void skl_update_crtcs (struct drm_atomic_state *state) {struct drm_i915_private *dev_priv =to_i915 (state->dev);struct intel_atomic_state *intel_state =to_intel_atomic_state (state);@@ -12284,7 +12216,7 @@ static void skl_update_crtcs(struct drm_atomic_state *state, vbl_wait = true;intel_update_crtc (crtc, state, old_crtc_state, - new_crtc_state, crtc_vblank_mask); + new_crtc_state);if (vbl_wait)intel_wait_for_vblank (dev_priv, pipe);@@ -12346,7 +12278,6 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)struct intel_crtc_state *intel_cstate;bool hw_check = intel_state->modeset;u64 put_domains[I915_MAX_PIPES ] = {}; -unsigned crtc_vblank_mask =0 ;int i;intel_atomic_commit_fence_wait (intel_state);@@ -12438,7 +12369,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)pm_qos_update_request (&dev_priv->pm_qos_atomic,0 );/* Now enable the clocks, plane, pipe, and connectors that we set up. */ - dev_priv->display.update_crtcs (state, &crtc_vblank_mask); + dev_priv->display.update_crtcs (state);/* FIXME: We should call drm_atomic_helper_commit_hw_done() here * already, but still need the state for the delayed optimization. To drivers/gpu/drm/i915/intel_display.c static void intel_atomic_commit_tail(struct drm_atomic_state *state) · line 12383
Quoted 3 lines
drivers/gpu/drm/i915/intel_display.c +0
-0@@ -12450,7 +12381,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)* we don't need out special handling any more. */ if (!state->legacy_cursor_update)I think this if is dead code, since either we use the fastpath in
intel_legacy_cursor_update, which means no atomic commit. Or we don't, and then we clear this hack (on most platforms at least) since it just wreaks complete havoc.We should probably do this logic in the async helpers, i.e. if async helpers reject a cursor update, clear
state->legacy_cursor_update.
Quoted 8 lines
Quoted 4 lines
Quoted 3 lines
Since I think we don't necessarily need this patch in this series, I think it'd be better in a separate series to straighten out the
async_updatestory. Which would then include moving i915 over to the core support.Erm, not sure what you mean here, isn't
state->legacy_cursor_updatemostly false, which means in most cases we'll wait?Yup. And the few cases where it's true should be handled by the fastpath/async plane update logic. Would allow us to ditch a few conditions all over the code.
-Daniel
I've done some more tests, and it seems this patch is required.
Without this we may not always wait, and that could result in spurious failures of page flip with -EBUSY. I'd love to hide this from userspace, but I don't think that's possible yet. It's best to always call drm_atomic_helper_wait_for_flip_done() for now. It's a noop for legacy_cursor_update anyway. commit->flip_done is always set early.
~Maarten
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [RFC PATCH 1/5] drm/i915: Always wait for flip_done
Quoted 189 lines · Maarten Lankhorst
Op 30-08-17 om 15:40 schreef Daniel Vetter:
Quoted 179 lines · Maarten Lankhorst
Quoted 178 lines
Op 30-08-17 om 14:43 schreef Daniel Vetter:
Quoted 177 lines · Maarten Lankhorst
Quoted 165 lines
The next commit removes the wait for
flip_donein indrm_atomic_helper_commit_cleanup_done, but we need it for the tests to pass. Instead of using complicated vblank tracking which ends up being ignored anyway, call the correct atomic helper. :)RFC because I'm not completely sure what we want to do with the vblank waiting, I think for now this patch is the right way to go until we decide because it preserves the status quo when
drm_crtc_commitwas introduced.Signed-off-by Maarten Lankhorst <[email protected]>--- drivers/gpu/drm/i915/i915_drv.h | 3 +- drivers/gpu/drm/i915/intel_display.c | 83 +++--------------------------------- 2 files changed, 8 insertions(+), 78 deletions(-)drivers/gpu/drm/i915/i915_drv.h +1
-2@@ -707,8 +707,7 @@ struct drm_i915_display_funcs { struct drm_atomic_state *old_state);void (*crtc_disable)(struct intel_crtc_state *old_crtc_state,struct drm_atomic_state *old_state); -void (*update_crtcs)(struct drm_atomic_state *state, -unsigned int *crtc_vblank_mask); +void (*update_crtcs)(struct drm_atomic_state *state);void (*audio_codec_enable)(struct drm_connector *connector,struct intel_encoder *encoder,const struct drm_display_mode *adjusted_mode);drivers/gpu/drm/i915/intel_display.c +6
-75@@ -12114,73 +12114,10 @@ u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)return dev->driver->get_vblank_counter (dev, crtc->pipe); } -static void intel_atomic_wait_for_vblanks (struct drm_device *dev, -struct drm_i915_private *dev_priv, -unsigned crtc_mask) -{ -unsigned last_vblank_count[I915_MAX_PIPES ]; -enum pipe pipe; -int ret; - -if (!crtc_mask) -return ; - -for_each_pipe (dev_priv, pipe) { -struct intel_crtc *crtc =intel_get_crtc_for_pipe (dev_priv, - pipe); - -if (!((1 << pipe) & crtc_mask)) -continue ; - - ret =drm_crtc_vblank_get (&crtc->base); -if (WARN_ON (ret !=0 )) { - crtc_mask &= ~(1 << pipe); -continue ; - } - - last_vblank_count[pipe] =drm_crtc_vblank_count (&crtc->base); - } - -for_each_pipe (dev_priv, pipe) { -struct intel_crtc *crtc =intel_get_crtc_for_pipe (dev_priv, - pipe); -long lret; - -if (!((1 << pipe) & crtc_mask)) -continue ; - - lret =wait_event_timeout (dev->vblank[pipe].queue, - last_vblank_count[pipe] != -drm_crtc_vblank_count (&crtc->base), -msecs_to_jiffies (50 )); - -WARN (!lret,"pipe %c vblank wait timed out\n" ,pipe_name (pipe)); - -drm_crtc_vblank_put (&crtc->base); - } -} - -static bool needs_vblank_wait (struct intel_crtc_state *crtc_state) -{ -/* fb updated, need to unpin old fb */ -if (crtc_state->fb_changed) -return true; - -/* wm changes, need vblank before final wm's */ -if (crtc_state->update_wm_post) -return true; - -if (crtc_state->wm.need_postvbl_update) -return true; - -return false; -} -static void intel_update_crtc (struct drm_crtc *crtc,struct drm_atomic_state *state,struct drm_crtc_state *old_crtc_state, -struct drm_crtc_state *new_crtc_state, -unsigned int *crtc_vblank_mask) +struct drm_crtc_state *new_crtc_state) {struct drm_device *dev = crtc->dev;struct drm_i915_private *dev_priv =to_i915 (dev);@@ -12203,13 +12140,9 @@ static void intel_update_crtc(struct drm_crtc *crtc, }drm_atomic_helper_commit_planes_on_crtc (old_crtc_state); - -if (needs_vblank_wait (pipe_config)) - *crtc_vblank_mask |=drm_crtc_mask (crtc); } -static void intel_update_crtcs (struct drm_atomic_state *state, -unsigned int *crtc_vblank_mask) +static void intel_update_crtcs (struct drm_atomic_state *state) {struct drm_crtc *crtc;struct drm_crtc_state *old_crtc_state, *new_crtc_state;@@ -12220,12 +12153,11 @@ static void intel_update_crtcs(struct drm_atomic_state *state,continue ;intel_update_crtc (crtc, state, old_crtc_state, - new_crtc_state, crtc_vblank_mask); + new_crtc_state); } } -static void skl_update_crtcs (struct drm_atomic_state *state, -unsigned int *crtc_vblank_mask) +static void skl_update_crtcs (struct drm_atomic_state *state) {struct drm_i915_private *dev_priv =to_i915 (state->dev);struct intel_atomic_state *intel_state =to_intel_atomic_state (state);@@ -12284,7 +12216,7 @@ static void skl_update_crtcs(struct drm_atomic_state *state, vbl_wait = true;intel_update_crtc (crtc, state, old_crtc_state, - new_crtc_state, crtc_vblank_mask); + new_crtc_state);if (vbl_wait)intel_wait_for_vblank (dev_priv, pipe);@@ -12346,7 +12278,6 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)struct intel_crtc_state *intel_cstate;bool hw_check = intel_state->modeset;u64 put_domains[I915_MAX_PIPES ] = {}; -unsigned crtc_vblank_mask =0 ;int i;intel_atomic_commit_fence_wait (intel_state);@@ -12438,7 +12369,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)pm_qos_update_request (&dev_priv->pm_qos_atomic,0 );/* Now enable the clocks, plane, pipe, and connectors that we set up. */ - dev_priv->display.update_crtcs (state, &crtc_vblank_mask); + dev_priv->display.update_crtcs (state);/* FIXME: We should call drm_atomic_helper_commit_hw_done() here * already, but still need the state for the delayed optimization. To drivers/gpu/drm/i915/intel_display.c static void intel_atomic_commit_tail(struct drm_atomic_state *state) · line 12383
Quoted 3 lines
drivers/gpu/drm/i915/intel_display.c +0
-0@@ -12450,7 +12381,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)* we don't need out special handling any more. */ if (!state->legacy_cursor_update)I think this if is dead code, since either we use the fastpath in
intel_legacy_cursor_update, which means no atomic commit. Or we don't, and then we clear this hack (on most platforms at least) since it just wreaks complete havoc.We should probably do this logic in the async helpers, i.e. if async helpers reject a cursor update, clear
state->legacy_cursor_update.Quoted 8 lines
Quoted 4 lines
Quoted 3 lines
Since I think we don't necessarily need this patch in this series, I think it'd be better in a separate series to straighten out the
async_updatestory. Which would then include moving i915 over to the core support.Erm, not sure what you mean here, isn't
state->legacy_cursor_updatemostly false, which means in most cases we'll wait?Yup. And the few cases where it's true should be handled by the fastpath/async plane update logic. Would allow us to ditch a few conditions all over the code.
-Daniel
Quoted 6 lines
I've done some more tests, and it seems this patch is required.
Without this we may not always wait, and that could result in spurious failures of page flip with
-EBUSY. I'd love to hide this from userspace, but I don't think that's possible yet. It's best to always calldrm_atomic_helper_wait_for_flip_done()for now. It's a noop forlegacy_cursor_updateanyway.commit->flip_doneis always set early.
I think we have a mistunderstanding here, I meant to say that you should imo remove the if (state->legacy_cursor_update) check and call the wait_for_flips_done helper unconditionally, not remove the call to the function itself. That should work, and since we have a separate cursor fastpath, also not cause troubles.
-Daniel
Signature · 7 lines
Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
Maarten Lankhorst
maintainerRe: [RFC PATCH 1/5] drm/i915: Always wait for flip_done
Op 04-09-17 om 09:30 schreef Daniel Vetter:
Quoted 195 lines · Maarten Lankhorst
Quoted 188 lines
Op 30-08-17 om 15:40 schreef Daniel Vetter:
Quoted 179 lines · Maarten Lankhorst
Quoted 178 lines
Op 30-08-17 om 14:43 schreef Daniel Vetter:
Quoted 177 lines · Maarten Lankhorst
Quoted 165 lines
The next commit removes the wait for
flip_donein indrm_atomic_helper_commit_cleanup_done, but we need it for the tests to pass. Instead of using complicated vblank tracking which ends up being ignored anyway, call the correct atomic helper. :)RFC because I'm not completely sure what we want to do with the vblank waiting, I think for now this patch is the right way to go until we decide because it preserves the status quo when
drm_crtc_commitwas introduced.Signed-off-by Maarten Lankhorst <[email protected]>--- drivers/gpu/drm/i915/i915_drv.h | 3 +- drivers/gpu/drm/i915/intel_display.c | 83 +++--------------------------------- 2 files changed, 8 insertions(+), 78 deletions(-)drivers/gpu/drm/i915/i915_drv.h +1
-2@@ -707,8 +707,7 @@ struct drm_i915_display_funcs { struct drm_atomic_state *old_state);void (*crtc_disable)(struct intel_crtc_state *old_crtc_state,struct drm_atomic_state *old_state); -void (*update_crtcs)(struct drm_atomic_state *state, -unsigned int *crtc_vblank_mask); +void (*update_crtcs)(struct drm_atomic_state *state);void (*audio_codec_enable)(struct drm_connector *connector,struct intel_encoder *encoder,const struct drm_display_mode *adjusted_mode);drivers/gpu/drm/i915/intel_display.c +6
-75@@ -12114,73 +12114,10 @@ u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)return dev->driver->get_vblank_counter (dev, crtc->pipe); } -static void intel_atomic_wait_for_vblanks (struct drm_device *dev, -struct drm_i915_private *dev_priv, -unsigned crtc_mask) -{ -unsigned last_vblank_count[I915_MAX_PIPES ]; -enum pipe pipe; -int ret; - -if (!crtc_mask) -return ; - -for_each_pipe (dev_priv, pipe) { -struct intel_crtc *crtc =intel_get_crtc_for_pipe (dev_priv, - pipe); - -if (!((1 << pipe) & crtc_mask)) -continue ; - - ret =drm_crtc_vblank_get (&crtc->base); -if (WARN_ON (ret !=0 )) { - crtc_mask &= ~(1 << pipe); -continue ; - } - - last_vblank_count[pipe] =drm_crtc_vblank_count (&crtc->base); - } - -for_each_pipe (dev_priv, pipe) { -struct intel_crtc *crtc =intel_get_crtc_for_pipe (dev_priv, - pipe); -long lret; - -if (!((1 << pipe) & crtc_mask)) -continue ; - - lret =wait_event_timeout (dev->vblank[pipe].queue, - last_vblank_count[pipe] != -drm_crtc_vblank_count (&crtc->base), -msecs_to_jiffies (50 )); - -WARN (!lret,"pipe %c vblank wait timed out\n" ,pipe_name (pipe)); - -drm_crtc_vblank_put (&crtc->base); - } -} - -static bool needs_vblank_wait (struct intel_crtc_state *crtc_state) -{ -/* fb updated, need to unpin old fb */ -if (crtc_state->fb_changed) -return true; - -/* wm changes, need vblank before final wm's */ -if (crtc_state->update_wm_post) -return true; - -if (crtc_state->wm.need_postvbl_update) -return true; - -return false; -} -static void intel_update_crtc (struct drm_crtc *crtc,struct drm_atomic_state *state,struct drm_crtc_state *old_crtc_state, -struct drm_crtc_state *new_crtc_state, -unsigned int *crtc_vblank_mask) +struct drm_crtc_state *new_crtc_state) {struct drm_device *dev = crtc->dev;struct drm_i915_private *dev_priv =to_i915 (dev);@@ -12203,13 +12140,9 @@ static void intel_update_crtc(struct drm_crtc *crtc, }drm_atomic_helper_commit_planes_on_crtc (old_crtc_state); - -if (needs_vblank_wait (pipe_config)) - *crtc_vblank_mask |=drm_crtc_mask (crtc); } -static void intel_update_crtcs (struct drm_atomic_state *state, -unsigned int *crtc_vblank_mask) +static void intel_update_crtcs (struct drm_atomic_state *state) {struct drm_crtc *crtc;struct drm_crtc_state *old_crtc_state, *new_crtc_state;@@ -12220,12 +12153,11 @@ static void intel_update_crtcs(struct drm_atomic_state *state,continue ;intel_update_crtc (crtc, state, old_crtc_state, - new_crtc_state, crtc_vblank_mask); + new_crtc_state); } } -static void skl_update_crtcs (struct drm_atomic_state *state, -unsigned int *crtc_vblank_mask) +static void skl_update_crtcs (struct drm_atomic_state *state) {struct drm_i915_private *dev_priv =to_i915 (state->dev);struct intel_atomic_state *intel_state =to_intel_atomic_state (state);@@ -12284,7 +12216,7 @@ static void skl_update_crtcs(struct drm_atomic_state *state, vbl_wait = true;intel_update_crtc (crtc, state, old_crtc_state, - new_crtc_state, crtc_vblank_mask); + new_crtc_state);if (vbl_wait)intel_wait_for_vblank (dev_priv, pipe);@@ -12346,7 +12278,6 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)struct intel_crtc_state *intel_cstate;bool hw_check = intel_state->modeset;u64 put_domains[I915_MAX_PIPES ] = {}; -unsigned crtc_vblank_mask =0 ;int i;intel_atomic_commit_fence_wait (intel_state);@@ -12438,7 +12369,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)pm_qos_update_request (&dev_priv->pm_qos_atomic,0 );/* Now enable the clocks, plane, pipe, and connectors that we set up. */ - dev_priv->display.update_crtcs (state, &crtc_vblank_mask); + dev_priv->display.update_crtcs (state);/* FIXME: We should call drm_atomic_helper_commit_hw_done() here * already, but still need the state for the delayed optimization. To drivers/gpu/drm/i915/intel_display.c static void intel_atomic_commit_tail(struct drm_atomic_state *state) · line 12383
Quoted 3 lines
drivers/gpu/drm/i915/intel_display.c +0
-0@@ -12450,7 +12381,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)* we don't need out special handling any more. */ if (!state->legacy_cursor_update)I think this if is dead code, since either we use the fastpath in
intel_legacy_cursor_update, which means no atomic commit. Or we don't, and then we clear this hack (on most platforms at least) since it just wreaks complete havoc.We should probably do this logic in the async helpers, i.e. if async helpers reject a cursor update, clear
state->legacy_cursor_update.Quoted 8 lines
Quoted 4 lines
Quoted 3 lines
Since I think we don't necessarily need this patch in this series, I think it'd be better in a separate series to straighten out the
async_updatestory. Which would then include moving i915 over to the core support.Erm, not sure what you mean here, isn't
state->legacy_cursor_updatemostly false, which means in most cases we'll wait?Yup. And the few cases where it's true should be handled by the fastpath/async plane update logic. Would allow us to ditch a few conditions all over the code.
-DanielQuoted 6 lines
I've done some more tests, and it seems this patch is required.
Without this we may not always wait, and that could result in spurious failures of page flip with
-EBUSY. I'd love to hide this from userspace, but I don't think that's possible yet. It's best to always calldrm_atomic_helper_wait_for_flip_done()for now. It's a noop forlegacy_cursor_updateanyway.commit->flip_doneis always set early.
Quoted 5 lines
I think we have a mistunderstanding here, I meant to say that you should imo remove the if (
state->legacy_cursor_update) check and call thewait_for_flips_donehelper unconditionally, not remove the call to the function itself. That should work, and since we have a separate cursor fastpath, also not cause troubles.
True. The if is even a noop because setup_commit completes flip_done immediately.. Should be harmless to remove..
~Maarten
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [Intel-gfx] [RFC PATCH 1/5] drm/i915: Always wait for flip_done
In reply to Maarten LankhorstQuoting Maarten Lankhorst (2017-08-30 13:17:48)
Quoted 8 lines
The next commit removes the wait for
flip_donein indrm_atomic_helper_commit_cleanup_done, but we need it for the tests to pass. Instead of using complicated vblank tracking which ends up being ignored anyway, call the correct atomic helper. :)RFC because I'm not completely sure what we want to do with the vblank waiting, I think for now this patch is the right way to go until we decide because it preserves the status quo when
drm_crtc_commitwas introduced.
Fwiw, this is fixing a bug in rotation:
drivers/gpu/drm/i915/intel_display.c u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc) · line 12167
Quoted 5 lines
drivers/gpu/drm/i915/intel_display.c +0
-5-static bool needs_vblank_wait (struct intel_crtc_state *crtc_state) -{ -/* fb updated, need to unpin old fb */ -if (crtc_state->fb_changed) -return true;
is insufficient as the fb may be unchanged but a new vma allocated for the rotated pages.
-Chris
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Maarten Lankhorst
maintainerPATCH 2/5 drm/atomic: Remove waits in drm_atomic_helper_commit_cleanup_done
In reply to Maarten LankhorstWhen commit synchronization through drm_crtc_commit was first introduced, we tried to solve the problem of the flip_done needing a reference count by blocking in cleanup_done.
This has been changed by commit 24835e442f28 ("drm: reference count event->completion") which made the waits here no longer needed.
--- drivers/gpu/drm/drm_atomic_helper.c | 17 ----------------- 1 file changed, 17 deletions(-)
drivers/gpu/drm/drm_atomic_helper.c +0 -17
@@ -1885,7 +1885,6 @@ void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *old_state)struct drm_crtc_state *new_crtc_state;struct drm_crtc_commit *commit;int i; -long ret;for_each_new_crtc_in_state (old_state, crtc, new_crtc_state, i) { commit = old_state->crtcs[i].commit;
@@ -1895,22 +1894,6 @@ void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *old_state)complete_all (&commit->cleanup_done);WARN_ON (!try_wait_for_completion (&commit->hw_done)); -/* commit_list borrows our reference, need to remove before we -* clean up our drm_atomic_state. But only after it actually -* completed, otherwise subsequent commits won't stall properly. */ -if (try_wait_for_completion (&commit->flip_done)) - goto del_commit; - -/* We must wait for the vblank event to signal our completion -* before releasing our reference, since the vblank work does -* not hold a reference of its own. */ - ret =wait_for_completion_timeout (&commit->flip_done, -10 *HZ ); -if (ret ==0 ) -DRM_ERROR ("[CRTC:%d:%s] flip_done timed out\n" , - crtc->base.id, crtc->name); - -del_commit:spin_lock (&crtc->commit_lock);list_del (&commit->commit_entry);spin_unlock (&crtc->commit_lock);
Signature · 6 lines
2.11.0 _______________________________________________ Intel-gfx mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Re: [PATCH 2/5] drm/atomic: Remove waits in drm_atomic_helper_commit_cleanup_done
Quoted 6 lines · Maarten Lankhorst
When commit synchronization through
drm_crtc_commitwas first introduced, we tried to solve the problem of theflip_doneneeding a reference count by blocking incleanup_done.This has been changed by commit
24835e442f28("drm: reference countevent->completion") which made the waits here no longer needed.
This is wrong. Your next patch makes this no longer necessary.
Quoted 20 lines
Signed-off-by Maarten Lankhorst <[email protected]>Suggested-by Daniel Vetter <[email protected]>--- drivers/gpu/drm/drm_atomic_helper.c | 17 ----------------- 1 file changed, 17 deletions(-)drivers/gpu/drm/drm_atomic_helper.c +0
-1@@ -1885,7 +1885,6 @@ void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *old_state)struct drm_crtc_state *new_crtc_state;struct drm_crtc_commit *commit;int i; -long ret;for_each_new_crtc_in_state (old_state, crtc, new_crtc_state, i) { commit = old_state->crtcs[i].commit;
drivers/gpu/drm/drm_atomic_helper.c void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *old_state) · line 1900
Quoted 6 lines
drivers/gpu/drm/drm_atomic_helper.c +0
-3@@ -1895,22 +1894,6 @@ void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *old_state)complete_all (&commit->cleanup_done);WARN_ON (!try_wait_for_completion (&commit->hw_done)); -/* commit_list borrows our reference, need to remove before we -* clean up our drm_atomic_state. But only after it actually -* completed, otherwise subsequent commits won't stall properly. */
This comment here is the clue: "... otherwise subsequent commits wont stall properly". When we remove the drm_crtc_commit from commit_list, the next commit won't be able to properly stall for flip_done. Hence we must wait for flip_done before removing it.
But with your new patch we wait for flip_done using old_crtc_state->commit, and this is indeed no longer necessary.
With the commit message and patch ordering fixed up:
Quoted 23 lines
drivers/gpu/drm/drm_atomic_helper.c +0
-13-if (try_wait_for_completion (&commit->flip_done)) - goto del_commit; - -/* We must wait for the vblank event to signal our completion -* before releasing our reference, since the vblank work does -* not hold a reference of its own. */ - ret =wait_for_completion_timeout (&commit->flip_done, -10 *HZ ); -if (ret ==0 ) -DRM_ERROR ("[CRTC:%d:%s] flip_done timed out\n" , - crtc->base.id, crtc->name); - -del_commit:spin_lock (&crtc->commit_lock);list_del (&commit->commit_entry);spin_unlock (&crtc->commit_lock);Signature · 6 lines
2.11.0 _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
Signature · 7 lines
Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
Maarten Lankhorst
maintainerPATCH 3/5 drm/atomic: Move drm_crtc_commit to drm_crtc_state, v2.
In reply to Maarten LankhorstMost code only cares about the current commit or previous commit. Fortuantely we already have a place to track those. Move it to drm_crtc_state where it belongs. :)
The per-crtc commit_list is kept for places where we have to look deeper than the current or previous commit for checking whether to stall on unpin. This is used in drm_atomic_helper_setup_commit and intel_has_pending_fb_unpin.
Changes since v1:
- Update kerneldoc for drm_crtc.commit_list. (danvet)
--- drivers/gpu/drm/drm_atomic.c | 7 --- drivers/gpu/drm/drm_atomic_helper.c | 92 ++++++++++--------------------------- include/drm/drm_atomic.h | 1 - include/drm/drm_crtc.h | 23 ++++++++-- 4 files changed, 42 insertions(+), 81 deletions(-)
drivers/gpu/drm/drm_atomic.c +0 -7
@@ -163,13 +163,6 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state) crtc->funcs->atomic_destroy_state (crtc, state->crtcs[i].state); -if (state->crtcs[i].commit) { -kfree (state->crtcs[i].commit->event); - state->crtcs[i].commit->event =NULL ; -drm_crtc_commit_put (state->crtcs[i].commit); - } - - state->crtcs[i].commit =NULL ; state->crtcs[i].ptr =NULL ; state->crtcs[i].state =NULL ; }
drivers/gpu/drm/drm_atomic_helper.c +23 -69
192 lines not on this page · raw message
include/drm/drm_atomic.h +0 -1
@@ -144,7 +144,6 @@ struct __drm_planes_state {struct __drm_crtcs_state {struct drm_crtc *ptr;struct drm_crtc_state *state, *old_state, *new_state; -struct drm_crtc_commit *commit;s32 __user *out_fence_ptr;unsigned last_vblank_count; };
include/drm/drm_crtc.h +19 -4
@@ -253,6 +253,15 @@ struct drm_crtc_state {*/ struct drm_pending_vblank_event *event; +/** +* @commit: +* +* This tracks how the commit for this update proceeds through the +* various phases. This is never cleared, except when we destroy the +* state, so that subsequent commits can synchronize with previous ones. +*/ +struct drm_crtc_commit *commit; +struct drm_atomic_state *state; };
@@ -808,10 +817,16 @@ struct drm_crtc {* @commit_list: * * List of &drm_crtc_commit structures tracking pending commits. -* Protected by @commit_lock. This list doesn't hold its own full -* reference, but burrows it from the ongoing commit. Commit entries -* must be removed from this list once the commit is fully completed, -* but before it's correspoding &drm_atomic_state gets destroyed. +* Protected by @commit_lock. This list holds its own full reference, +* as does the ongoing commit. +* +* "Note that the commit for a state change is also tracked in +* &drm_crtc_state.commit. For accessing the immediately preceeding +* commit in an atomic update it is recommended to just use that +* pointer in the old CRTC state, since accessing that doesn't need +* any locking or list-walking. @commit_list should only be used to +* stall for framebuffer cleanup that's signalled through +* &drm_crtc_commit.cleanup_done." */ struct list_head commit_list;
Signature · 6 lines
2.11.0 _______________________________________________ Intel-gfx mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Re: [PATCH 3/5] drm/atomic: Move drm_crtc_commit to drm_crtc_state, v2.
Hi Maarten,
Thank you for the patch.
Quoted 79 lines · On Wednesday, 30 August 2017 15:17:50 EEST Maarten Lankhorst wrote:
Most code only cares about the current commit or previous commit. Fortuantely we already have a place to track those. Move it to
drm_crtc_statewhere it belongs. :)The per-crtc
commit_listis kept for places where we have to look deeper than the current or previous commit for checking whether to stall on unpin. This is used indrm_atomic_helper_setup_commitandintel_has_pending_fb_unpin.Changes since v1:
- Update kerneldoc for drm_crtc.commit_list. (danvet)Signed-off-by Maarten Lankhorst <[email protected]>Reviewed-by Daniel Vetter <[email protected]>--- drivers/gpu/drm/drm_atomic.c | 7 --- drivers/gpu/drm/drm_atomic_helper.c | 92 +++++++++------------------------- include/drm/drm_atomic.h | 1 - include/drm/drm_crtc.h | 23 ++++++++-- 4 files changed, 42 insertions(+), 81 deletions(-)drivers/gpu/drm/drm_atomic.c +0
-7@@ -163,13 +163,6 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state) crtc->funcs->atomic_destroy_state(crtc, state->crtcs[i].state); -if (state->crtcs[i].commit) { -kfree (state->crtcs[i].commit->event); - state->crtcs[i].commit->event =NULL ; -drm_crtc_commit_put (state->crtcs[i].commit); - } - - state->crtcs[i].commit =NULL ; state->crtcs[i].ptr =NULL ; state->crtcs[i].state =NULL ; }(quoted diff) +0
-0
b/drivers/gpu/drm/drm_atomic_helper.cindex11d0e94a2181..8ccb8b6536c0100644drivers/gpu/drm/drm_atomic_helper.c +5
-6@@ -1262,12 +1262,12 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks);void drm_atomic_helper_wait_for_flip_done (struct drm_device *dev,struct drm_atomic_state *old_state) { -struct drm_crtc_state *unused; +struct drm_crtc_state *new_crtc_state;struct drm_crtc *crtc;int i; -for_each_new_crtc_in_state (old_state, crtc, unused, i) { -struct drm_crtc_commit *commit = old_state->crtcs[i].commit; +for_each_new_crtc_in_state (old_state, crtc, new_crtc_state, i) { +struct drm_crtc_commit *commit = new_crtc_state->commit;int ret;if (!commit)@@ -1388,11 +1388,10 @@ int drm_atomic_helper_async_check(struct drm_device *dev, {struct drm_crtc *crtc;struct drm_crtc_state *crtc_state; -struct drm_crtc_commit *commit;struct drm_plane *__plane, *plane =NULL ;struct drm_plane_state *__plane_state, *plane_state =NULL ;const struct drm_plane_helper_funcs *funcs; -int i, j, n_planes =0 ; +int i, n_planes =0 ;for_each_new_crtc_in_state (state, crtc, crtc_state, i) {if (drm_atomic_crtc_needs_modeset (crtc_state))@@ -1420,33 +1419,10 @@ int drm_atomic_helper_async_check(struct drm_device *dev, return -EINVAL ;/* -* Don't do an async update if there is an outstanding commit modifying +* TODO: Don't do an async update if there is an outstanding commit
Quoted 4 lines
modifying
* the plane. This prevents our async update's changes from getting
* overridden by a previous synchronous update's state. */
As mentioned in a comment to your previous patch, this is unrelated to $SUBJECT. You should mention and explain this change in the commit message (possibly splitting it out in a separate commit if you think that would make more sense, up to you).
Quoted 221 lines
drivers/gpu/drm/drm_atomic_helper.c +1
-40-for_each_new_crtc_in_state (state, crtc, crtc_state, i) { -if (plane->crtc != crtc) -continue ; - -spin_lock (&crtc->commit_lock); - commit =list_first_entry_or_null (&crtc->commit_list, - struct drm_crtc_commit, - commit_entry); -if (!commit) { -spin_unlock (&crtc->commit_lock); -continue ; - } -spin_unlock (&crtc->commit_lock); - -if (!crtc->state->state) -continue ; - -for_each_plane_in_state (crtc->state->state, __plane, - __plane_state, j) { -if (__plane == plane) -return -EINVAL ; - } - }return funcs->atomic_async_check (plane, plane_state); }@@ -1731,7 +1707,7 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,kref_init (&commit->ref); commit->crtc = crtc; - state->crtcs[i].commit = commit; + new_crtc_state->commit = commit; ret =stall_checks (crtc, nonblock);if (ret)@@ -1769,22 +1745,6 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, }EXPORT_SYMBOL (drm_atomic_helper_setup_commit ); - -static struct drm_crtc_commit *preceeding_commit (struct drm_crtc *crtc) -{ -struct drm_crtc_commit *commit; -int i =0 ; - -list_for_each_entry (commit, &crtc->commit_list, commit_entry) { -/* skip the first entry, that's the current commit */ -if (i ==1 ) -return commit; - i++; - } - -return NULL ; -} -/** * drm_atomic_helper_wait_for_dependencies - wait for required preceeding commits * @old_state: atomic state object with old state structures
drivers/gpu/drm/drm_atomic_helper.c +3
-7@@ -1800,17 +1760,13 @@ static struct drm_crtc_commit *preceeding_commit(struct drm_crtc *crtc) voiddrm_atomic_helper_wait_for_dependencies (struct drm_atomic_state *old_state) {struct drm_crtc *crtc; -struct drm_crtc_state *new_crtc_state; +struct drm_crtc_state *old_crtc_state;struct drm_crtc_commit *commit;int i;long ret; -for_each_new_crtc_in_state (old_state, crtc, new_crtc_state, i) { -spin_lock (&crtc->commit_lock); - commit =preceeding_commit (crtc); -if (commit) -drm_crtc_commit_get (commit); -spin_unlock (&crtc->commit_lock); +for_each_old_crtc_in_state (old_state, crtc, old_crtc_state, i) { + commit = old_crtc_state->commit;if (!commit)drivers/gpu/drm/drm_atomic_helper.c +4
-13continue ;@@ -1828,8 +1784,6 @@ void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state) if (ret == 0)DRM_ERROR ("[CRTC:%d:%s] flip_done timed out\n" , crtc->base.id, crtc->name); - -drm_crtc_commit_put (commit); } }EXPORT_SYMBOL (drm_atomic_helper_wait_for_dependencies);@@ -1857,7 +1811,7 @@ void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state) int i;for_each_new_crtc_in_state (old_state, crtc, new_crtc_state, i) { - commit = old_state->crtcs[i].commit; + commit = new_crtc_state->commit;if (!commit)continue ;@@ -1887,7 +1841,7 @@ void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *old_state) int i;for_each_new_crtc_in_state (old_state, crtc, new_crtc_state, i) { - commit = old_state->crtcs[i].commit; + commit = new_crtc_state->commit;if (WARN_ON (!commit))continue ;@@ -2277,20 +2231,13 @@ int drm_atomic_helper_swap_state(struct drm_atomic_state *state, struct drm_private_state *old_obj_state, *new_obj_state;if (stall) { -for_each_new_crtc_in_state (state, crtc, new_crtc_state, i) { -spin_lock (&crtc->commit_lock); - commit =list_first_entry_or_null (&crtc->commit_list, - struct drm_crtc_commit, commit_entry); -if (commit) -drm_crtc_commit_get (commit); -spin_unlock (&crtc->commit_lock); +for_each_old_crtc_in_state (state, crtc, old_crtc_state, i) { + commit = old_crtc_state->commit;if (!commit)continue ; ret =wait_for_completion_interruptible (&commit->hw_done); -drm_crtc_commit_put (commit); -if (ret)return ret;drivers/gpu/drm/drm_atomic_helper.c +4
-3}@@ -2315,13 +2262,13 @@ int drm_atomic_helper_swap_state(struct drm_atomic_state *state, state->crtcs[i].state = old_crtc_state; crtc->state = new_crtc_state; -if (state->crtcs[i].commit) { +if (new_crtc_state->commit) {spin_lock (&crtc->commit_lock); -list_add (&state->crtcs[i].commit->commit_entry, +list_add (&new_crtc_state->commit->commit_entry, &crtc->commit_list);spin_unlock (&crtc->commit_lock); - state->crtcs[i].commit->event =NULL ; + new_crtc_state->commit->event =NULL ; } }@@ -3169,6 +3116,7 @@ void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc, state->connectors_changed = false; state->color_mgmt_changed = false; state->zpos_changed = false; + state->commit =NULL ; state->event =NULL ; state->pageflip_flags =0 ; }@@ -3207,6 +3155,12 @@
EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state); */
void__drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state){drivers/gpu/drm/drm_atomic_helper.c +6
-0+if (state->commit) { +kfree (state->commit->event); + state->commit->event =NULL ; +drm_crtc_commit_put (state->commit); + } +drm_property_blob_put (state->mode_blob);drm_property_blob_put (state->degamma_lut);drm_property_blob_put (state->ctm);include/drm/drm_atomic.h +0
-1@@ -144,7 +144,6 @@ struct __drm_planes_state {struct __drm_crtcs_state {struct drm_crtc *ptr;struct drm_crtc_state *state, *old_state, *new_state; -struct drm_crtc_commit *commit;s32 __user *out_fence_ptr;unsigned last_vblank_count; };include/drm/drm_crtc.h +19
-4@@ -253,6 +253,15 @@ struct drm_crtc_state {*/ struct drm_pending_vblank_event *event; +/** +* @commit: +* +* This tracks how the commit for this update proceeds through the +* various phases. This is never cleared, except when we destroy the +* state, so that subsequent commits can synchronize with previous ones. +*/ +struct drm_crtc_commit *commit; +struct drm_atomic_state *state; };@@ -808,10 +817,16 @@ struct drm_crtc {* @commit_list: * * List of &drm_crtc_commit structures tracking pending commits. -* Protected by @commit_lock. This list doesn't hold its own full -* reference, but burrows it from the ongoing commit. Commit entries -* must be removed from this list once the commit is fully completed, -* but before it's correspoding &drm_atomic_state gets destroyed. +* Protected by @commit_lock. This list holds its own full reference, +* as does the ongoing commit. +* +* "Note that the commit for a state change is also tracked in +* &drm_crtc_state.commit. For accessing the immediately preceeding +* commit in an atomic update it is recommended to just use that +* pointer in the old CRTC state, since accessing that doesn't need +* any locking or list-walking. @commit_list should only be used to +* stall for framebuffer cleanup that's signalled through +* &drm_crtc_commit.cleanup_done." */ struct list_head commit_list;
Signature · 8 lines
Regards, Laurent Pinchart _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
Maarten Lankhorst
maintainerRe: [PATCH 3/5] drm/atomic: Move drm_crtc_commit to drm_crtc_state, v2.
Op 30-08-17 om 15:09 schreef Laurent Pinchart:
Quoted 81 lines
Hi Maarten,
Thank you for the patch.
Quoted 76 lines · On Wednesday, 30 August 2017 15:17:50 EEST Maarten Lankhorst wrote:
Most code only cares about the current commit or previous commit. Fortuantely we already have a place to track those. Move it to
drm_crtc_statewhere it belongs. :)The per-crtc
commit_listis kept for places where we have to look deeper than the current or previous commit for checking whether to stall on unpin. This is used indrm_atomic_helper_setup_commitandintel_has_pending_fb_unpin.Changes since v1:
- Update kerneldoc for drm_crtc.commit_list. (danvet)Signed-off-by Maarten Lankhorst <[email protected]>Reviewed-by Daniel Vetter <[email protected]>--- drivers/gpu/drm/drm_atomic.c | 7 --- drivers/gpu/drm/drm_atomic_helper.c | 92 +++++++++------------------------- include/drm/drm_atomic.h | 1 - include/drm/drm_crtc.h | 23 ++++++++-- 4 files changed, 42 insertions(+), 81 deletions(-)drivers/gpu/drm/drm_atomic.c +0
-7@@ -163,13 +163,6 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state) crtc->funcs->atomic_destroy_state(crtc, state->crtcs[i].state); -if (state->crtcs[i].commit) { -kfree (state->crtcs[i].commit->event); - state->crtcs[i].commit->event =NULL ; -drm_crtc_commit_put (state->crtcs[i].commit); - } - - state->crtcs[i].commit =NULL ; state->crtcs[i].ptr =NULL ; state->crtcs[i].state =NULL ; }(quoted diff) +0
-0
b/drivers/gpu/drm/drm_atomic_helper.cindex11d0e94a2181..8ccb8b6536c0100644drivers/gpu/drm/drm_atomic_helper.c +4
-5@@ -1262,12 +1262,12 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks);void drm_atomic_helper_wait_for_flip_done (struct drm_device *dev,struct drm_atomic_state *old_state) { -struct drm_crtc_state *unused; +struct drm_crtc_state *new_crtc_state;struct drm_crtc *crtc;int i; -for_each_new_crtc_in_state (old_state, crtc, unused, i) { -struct drm_crtc_commit *commit = old_state->crtcs[i].commit; +for_each_new_crtc_in_state (old_state, crtc, new_crtc_state, i) { +struct drm_crtc_commit *commit = new_crtc_state->commit;int ret;if (!commit)@@ -1388,11 +1388,10 @@ int drm_atomic_helper_async_check(struct drm_device *dev, {struct drm_crtc *crtc;struct drm_crtc_state *crtc_state; -struct drm_crtc_commit *commit;struct drm_plane *__plane, *plane =NULL ;struct drm_plane_state *__plane_state, *plane_state =NULL ;const struct drm_plane_helper_funcs *funcs; -int i, j, n_planes =0 ; +int i, n_planes =0 ;for_each_new_crtc_in_state (state, crtc, crtc_state, i) {if (drm_atomic_crtc_needs_modeset (crtc_state))@@ -1420,33 +1419,10 @@ int drm_atomic_helper_async_check(struct drm_device *dev, return -EINVAL ;
Quoted 11 lines
Quoted 7 lines
drivers/gpu/drm/drm_atomic_helper.c +1
-1/* -* Don't do an async update if there is an outstanding commit modifying +* TODO: Don't do an async update if there is an outstanding commit modifying
* the plane. This prevents our async update's changes from getting
* overridden by a previous synchronous update's state. */As mentioned in a comment to your previous patch, this is unrelated to $SUBJECT. You should mention and explain this change in the commit message (possibly splitting it out in a separate commit if you think that would make more sense, up to you).
I'm all for removing this, it doesn't work.. But I g uess it can be kept in for now and I'll drop this hunk.
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Maarten Lankhorst
maintainerPATCH 4/5 drm/atomic: Fix freeing connector/plane state too early by tracking commits, v2.
In reply to Maarten LankhorstCurrently we neatly track the crtc state, but forget to look at plane/connector state.
When doing a nonblocking modeset, immediately followed by a setprop before the modeset completes, the setprop will see the modesets new state as the old state and free it.
This has to be solved by waiting for hw_done on the connector, even if it's not assigned to a crtc. When a connector is unbound we take the last crtc commit, and when it stays unbound we create a new fake crtc commit for that gets signaled on hw_done for all the planes/connectors.
We wait for it the same way as we do for crtc's, which will make sure we never run into a use-after-free situation.
Changes since v1:
- Only create a single disable commit. (danvet)
- Fix leak in intel_legacy_cursor_update.
Testcase: kms_atomic_transition.plane-use-after-nonblocking-unbind*
Cc: Laurent Pinchart <[email protected]>
--- drivers/gpu/drm/drm_atomic.c | 4 + drivers/gpu/drm/drm_atomic_helper.c | 156 +++++++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_display.c | 2 + include/drm/drm_atomic.h | 12 +++ include/drm/drm_connector.h | 7 ++ include/drm/drm_plane.h | 7 ++ 6 files changed, 182 insertions(+), 6 deletions(-)
drivers/gpu/drm/drm_atomic.c +4 -0
@@ -192,6 +192,10 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state) } state->num_private_objs =0 ; +if (state->fake_commit) { +drm_crtc_commit_put (state->fake_commit); + state->fake_commit =NULL ; + } }EXPORT_SYMBOL (drm_atomic_state_default_clear);
drivers/gpu/drm/drm_atomic_helper.c +150 -6
228 lines not on this page · raw message
drivers/gpu/drm/i915/intel_display.c +2 -0
@@ -13109,8 +13109,10 @@ intel_legacy_cursor_update(struct drm_plane *plane,/* Swap plane state */ new_plane_state->fence = old_plane_state->fence; + new_plane_state->commit = old_plane_state->commit; *to_intel_plane_state (old_plane_state) = *to_intel_plane_state (new_plane_state); new_plane_state->fence =NULL ; + new_plane_state->commit =NULL ; new_plane_state->fb = old_fb;to_intel_plane_state (new_plane_state)->vma =NULL ;
include/drm/drm_atomic.h +12 -0
@@ -236,6 +236,18 @@ struct drm_atomic_state {struct drm_modeset_acquire_ctx *acquire_ctx;/** +* @fake_commit: +* +* Used for signaling unbound planes/connectors. +* When a connector or plane is not bound to any CRTC, it's still important +* to preserve linearity to prevent the atomic states from being freed to early. +* +* This commit (if set) is not bound to any crtc, but will be completed when +* drm_atomic_helper_commit_hw_done() is called. +*/ +struct drm_crtc_commit *fake_commit; + +/** * @commit_work: * * Work item which can be used by the driver or helpers to execute the
include/drm/drm_connector.h +7 -0
@@ -347,6 +347,13 @@ struct drm_connector_state {struct drm_atomic_state *state; +/** +* @commit: Tracks the pending commit to prevent use-after-free conditions. +* +* Is only set when @crtc is NULL. +*/ +struct drm_crtc_commit *commit; +struct drm_tv_connector_state tv;/**
include/drm/drm_plane.h +7 -0
@@ -123,6 +123,13 @@ struct drm_plane_state {*/ bool visible; +/** +* @commit: Tracks the pending commit to prevent use-after-free conditions. +* +* Is only set when @crtc is NULL. +*/ +struct drm_crtc_commit *commit; +struct drm_atomic_state *state; };
Signature · 6 lines
2.11.0 _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH 4/5] drm/atomic: Fix freeing connector/plane state too early by tracking commits, v2.
Quoted 76 lines · Maarten Lankhorst
Currently we neatly track the crtc state, but forget to look at plane/connector state.
When doing a nonblocking modeset, immediately followed by a setprop before the modeset completes, the setprop will see the modesets new state as the old state and free it.
This has to be solved by waiting for
hw_doneon the connector, even if it's not assigned to a crtc. When a connector is unbound we take the last crtc commit, and when it stays unbound we create a new fake crtc commit for that gets signaled onhw_donefor all the planes/connectors.We wait for it the same way as we do for crtc's, which will make sure we never run into a use-after-free situation.
Changes since v1:
- Only create a single disable commit. (danvet)
- Fix leak inintel_legacy_cursor_update.Signed-off-by Maarten Lankhorst <[email protected]>Testcase: kms_atomic_transition.plane-use-after-nonblocking-unbind*
Cc: Laurent Pinchart <[email protected]>--- drivers/gpu/drm/drm_atomic.c | 4 + drivers/gpu/drm/drm_atomic_helper.c | 156 +++++++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_display.c | 2 + include/drm/drm_atomic.h | 12 +++ include/drm/drm_connector.h | 7 ++ include/drm/drm_plane.h | 7 ++ 6 files changed, 182 insertions(+), 6 deletions(-)drivers/gpu/drm/drm_atomic.c +4
-0@@ -192,6 +192,10 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state) } state->num_private_objs =0 ; +if (state->fake_commit) { +drm_crtc_commit_put (state->fake_commit); + state->fake_commit =NULL ; + } }EXPORT_SYMBOL (drm_atomic_state_default_clear);drivers/gpu/drm/drm_atomic_helper.c +21
-0@@ -1644,6 +1644,40 @@ static void release_crtc_commit(struct completion *completion)drm_crtc_commit_put (commit); } +static void init_commit (struct drm_crtc_commit *commit,struct drm_crtc *crtc) +{ +init_completion (&commit->flip_done); +init_completion (&commit->hw_done); +init_completion (&commit->cleanup_done); +INIT_LIST_HEAD (&commit->commit_entry); +kref_init (&commit->ref); + commit->crtc = crtc; +} + +static struct drm_crtc_commit * +fake_or_crtc_commit (struct drm_atomic_state *state,struct drm_crtc *crtc) +{ +struct drm_crtc_commit *commit; + +if (crtc) { +struct drm_crtc_state *new_crtc_state; + + new_crtc_state =drm_atomic_get_new_crtc_state (state, crtc); + + commit = new_crtc_state->commit;
drivers/gpu/drm/drm_atomic_helper.c static void release_crtc_commit(struct completion *completion) · line 1677
Quoted 10 lines
drivers/gpu/drm/drm_atomic_helper.c +10
-0+ }else if (!state->fake_commit) { + state->fake_commit = commit =kzalloc (sizeof (*commit),GFP_KERNEL ); +if (!commit) +return NULL ; + +init_commit (commit,NULL ); + }else + commit = state->fake_commit; + +drm_crtc_commit_get (commit);
Double refcount for the case where you call init_commit? Aka I think this leaks.
Quoted 32 lines
drivers/gpu/drm/drm_atomic_helper.c +8
-6+return commit; +} +/** * drm_atomic_helper_setup_commit - setup possibly nonblocking commit * @state: new modeset state to be committed @@ -1692,6 +1726,10 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, {struct drm_crtc *crtc;struct drm_crtc_state *old_crtc_state, *new_crtc_state; +struct drm_connector *conn; +struct drm_connector_state *old_conn_state, *new_conn_state; +struct drm_plane *plane; +struct drm_plane_state *old_plane_state, *new_plane_state;struct drm_crtc_commit *commit;int i, ret;@@ -1700,12 +1738,7 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,if (!commit)return -ENOMEM ; -init_completion (&commit->flip_done); -init_completion (&commit->hw_done); -init_completion (&commit->cleanup_done); -INIT_LIST_HEAD (&commit->commit_entry); -kref_init (&commit->ref); - commit->crtc = crtc; +init_commit (commit, crtc); new_crtc_state->commit = commit;
drivers/gpu/drm/drm_atomic_helper.c int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, · line 1777
Quoted 4 lines
drivers/gpu/drm/drm_atomic_helper.c +1
-0@@ -1741,6 +1774,36 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,drm_crtc_commit_get (commit); } +for_each_oldnew_connector_in_state (state, conn, old_conn_state, new_conn_state, i) {
Maybe a commen there like
/* commit tracked through the crtc_state->commit */
Feels at least a bit non-obvious how this works.
drivers/gpu/drm/drm_atomic_helper.c int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, · line 1780
Quoted 3 lines
drivers/gpu/drm/drm_atomic_helper.c +3
-0+if (new_conn_state->crtc) +continue ; +
Please add the
/* Userspace is not allowed to get ahead of the previous * commit with nonblocking ones. */
comment from stall_checks here and below. Even better if we could extract this, but macro is ugly and functions wont work.
Quoted 90 lines
drivers/gpu/drm/drm_atomic_helper.c +72
-0+if (nonblock && old_conn_state->commit && + !try_wait_for_completion (&old_conn_state->commit->flip_done)) +return -EBUSY ; + + commit =fake_or_crtc_commit (state, old_conn_state->crtc); +if (!commit) +return -ENOMEM ; + + new_conn_state->commit = commit; + } + +for_each_oldnew_plane_in_state (state, plane, old_plane_state, new_plane_state, i) { +if (new_plane_state->crtc) +continue ; + +if (nonblock && old_plane_state->commit && + !try_wait_for_completion (&old_plane_state->commit->flip_done)) +return -EBUSY ; + + commit =fake_or_crtc_commit (state, old_plane_state->crtc); +if (!commit) +return -ENOMEM ; + + new_plane_state->commit = commit; + } +return 0 ; }EXPORT_SYMBOL (drm_atomic_helper_setup_commit);@@ -1761,6 +1824,10 @@ void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state) {struct drm_crtc *crtc;struct drm_crtc_state *old_crtc_state; +struct drm_plane *plane; +struct drm_plane_state *old_plane_state; +struct drm_connector *conn; +struct drm_connector_state *old_conn_state;struct drm_crtc_commit *commit;int i;long ret;@@ -1785,6 +1852,48 @@ void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state)DRM_ERROR ("[CRTC:%d:%s] flip_done timed out\n" , crtc->base.id, crtc->name); } + +for_each_old_connector_in_state (old_state, conn, old_conn_state, i) { + commit = old_conn_state->commit; + +if (!commit) +continue ; + + ret =wait_for_completion_timeout (&commit->hw_done, +10 *HZ ); +if (ret ==0 ) +DRM_ERROR ("[CONNECTOR:%d:%s] hw_done timed out\n" , + conn->base.id, conn->name); + +/* Currently no support for overwriting flips, hence +* stall for previous one to execute completely. */ + ret =wait_for_completion_timeout (&commit->flip_done, +10 *HZ ); +if (ret ==0 ) +DRM_ERROR ("[CONNECTOR:%d:%s] flip_done timed out\n" , + conn->base.id, conn->name); + } + +for_each_old_plane_in_state (old_state, plane, old_plane_state, i) { + commit = old_plane_state->commit; + +if (!commit) +continue ; + + ret =wait_for_completion_timeout (&commit->hw_done, +10 *HZ ); +if (ret ==0 ) +DRM_ERROR ("[PLANE:%d:%s] hw_done timed out\n" , + plane->base.id, plane->name); + +/* Currently no support for overwriting flips, hence +* stall for previous one to execute completely. */ + ret =wait_for_completion_timeout (&commit->flip_done, +10 *HZ ); +if (ret ==0 ) +DRM_ERROR ("[PLANE:%d:%s] flip_done timed out\n" , + plane->base.id, plane->name); + } }EXPORT_SYMBOL (drm_atomic_helper_wait_for_dependencies);
drivers/gpu/drm/drm_atomic_helper.c void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state) · line 1935
Quoted 8 lines
drivers/gpu/drm/drm_atomic_helper.c +5
-0@@ -1819,6 +1928,11 @@ void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state)WARN_ON (new_crtc_state->event);complete_all (&commit->hw_done); } + +if (old_state->fake_commit) { +complete_all (&old_state->fake_commit->hw_done); +complete_all (&old_state->fake_commit->flip_done); + }
Just to avoid surprises, I think we should also complete_all(cleanup_done) on the fake commit in cleanup_done().
Quoted 73 lines
drivers/gpu/drm/drm_atomic_helper.c +30
-0}EXPORT_SYMBOL (drm_atomic_helper_commit_hw_done);@@ -2241,6 +2355,28 @@ int drm_atomic_helper_swap_state(struct drm_atomic_state *state,if (ret)return ret; } + +for_each_old_connector_in_state (state, connector, old_conn_state, i) { + commit = old_conn_state->commit; + +if (!commit) +continue ; + + ret =wait_for_completion_interruptible (&commit->hw_done); +if (ret) +return ret; + } + +for_each_old_plane_in_state (state, plane, old_plane_state, i) { + commit = old_plane_state->commit; + +if (!commit) +continue ; + + ret =wait_for_completion_interruptible (&commit->hw_done); +if (ret) +return ret; + } }for_each_oldnew_connector_in_state (state, connector, old_conn_state, new_conn_state, i) {@@ -3223,6 +3359,7 @@ void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,drm_framebuffer_get (state->fb); state->fence =NULL ; + state->commit =NULL ; }EXPORT_SYMBOL (__drm_atomic_helper_plane_duplicate_state);@@ -3264,6 +3401,9 @@ void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state)if (state->fence)dma_fence_put (state->fence); + +if (state->commit) +drm_crtc_commit_put (state->commit); }EXPORT_SYMBOL (__drm_atomic_helper_plane_destroy_state);@@ -3342,6 +3482,7 @@ __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,memcpy (state, connector->state,sizeof (*state));if (state->crtc)drm_connector_get (connector); + state->commit =NULL ; }EXPORT_SYMBOL (__drm_atomic_helper_connector_duplicate_state);@@ -3468,6 +3609,9 @@ __drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state) {if (state->crtc)drm_connector_put (state->connector); + +if (state->commit) +drm_crtc_commit_put (state->commit); }EXPORT_SYMBOL (__drm_atomic_helper_connector_destroy_state);drivers/gpu/drm/i915/intel_display.c +0
-0
drivers/gpu/drm/i915/intel_display.c intel_legacy_cursor_update(struct drm_plane *plane, · line 13115
Quoted 7 lines
drivers/gpu/drm/i915/intel_display.c +2
-0@@ -13109,8 +13109,10 @@ intel_legacy_cursor_update(struct drm_plane *plane,/* Swap plane state */ new_plane_state->fence = old_plane_state->fence; + new_plane_state->commit = old_plane_state->commit; *to_intel_plane_state (old_plane_state) = *to_intel_plane_state (new_plane_state); new_plane_state->fence =NULL ; + new_plane_state->commit =NULL ;
Would be good if we could switch to Gustavo's async work and push these tricks into shared code ...
Quoted 8 lines
drivers/gpu/drm/i915/intel_display.c +0
-0new_plane_state->fb = old_fb;to_intel_plane_state (new_plane_state)->vma =NULL ;include/drm/drm_atomic.h +0
-0
include/drm/drm_atomic.h struct drm_atomic_state { · line 243
Quoted 8 lines
include/drm/drm_atomic.h +5
-0@@ -236,6 +236,18 @@ struct drm_atomic_state {struct drm_modeset_acquire_ctx *acquire_ctx;/** +* @fake_commit: +* +* Used for signaling unbound planes/connectors. +* When a connector or plane is not bound to any CRTC, it's still important +* to preserve linearity to prevent the atomic states from being freed to early.
s/to early/too early/.
include/drm/drm_atomic.h struct drm_atomic_state { · line 246
Quoted 3 lines
include/drm/drm_atomic.h +3
-0+* +* This commit (if set) is not bound to any crtc, but will be completed when +* drm_atomic_helper_commit_hw_done() is called.
... and drm_atomic_helper_cleanup_done() ...
Quoted 32 lines
include/drm/drm_atomic.h +4
-0+*/ +struct drm_crtc_commit *fake_commit; + +/** * @commit_work: * * Work item which can be used by the driver or helpers to execute the include/drm/drm_connector.h +7
-0@@ -347,6 +347,13 @@ struct drm_connector_state {struct drm_atomic_state *state; +/** +* @commit: Tracks the pending commit to prevent use-after-free conditions. +* +* Is only set when @crtc is NULL. +*/ +struct drm_crtc_commit *commit; +struct drm_tv_connector_state tv;/** include/drm/drm_plane.h +0
-0@@ -123,6 +123,13 @@ struct drm_plane_state {*/ bool visible;
include/drm/drm_plane.h struct drm_plane_state { · line 134
Quoted 10 lines
include/drm/drm_plane.h +7
-0+/** +* @commit: Tracks the pending commit to prevent use-after-free conditions. +* +* Is only set when @crtc is NULL. +*/ +struct drm_crtc_commit *commit; +struct drm_atomic_state *state; };
With the above nits addressed:
Quoted 8 lines
Signature · 7 lines
-- 2.11.0 _______________________________________________ Intel-gfx mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 7 lines
Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch _______________________________________________ Intel-gfx mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Maarten Lankhorst
maintainerRe: [Intel-gfx] [PATCH 4/5] drm/atomic: Fix freeing connector/plane state too early by tracking commits, v2.
Op 30-08-17 om 14:40 schreef Daniel Vetter:
Quoted 135 lines · Maarten Lankhorst
Quoted 76 lines
Currently we neatly track the crtc state, but forget to look at plane/connector state.
When doing a nonblocking modeset, immediately followed by a setprop before the modeset completes, the setprop will see the modesets new state as the old state and free it.
This has to be solved by waiting for
hw_doneon the connector, even if it's not assigned to a crtc. When a connector is unbound we take the last crtc commit, and when it stays unbound we create a new fake crtc commit for that gets signaled onhw_donefor all the planes/connectors.We wait for it the same way as we do for crtc's, which will make sure we never run into a use-after-free situation.
Changes since v1:
- Only create a single disable commit. (danvet)
- Fix leak inintel_legacy_cursor_update.Signed-off-by Maarten Lankhorst <[email protected]>Testcase: kms_atomic_transition.plane-use-after-nonblocking-unbind*
Cc: Laurent Pinchart <[email protected]>--- drivers/gpu/drm/drm_atomic.c | 4 + drivers/gpu/drm/drm_atomic_helper.c | 156 +++++++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_display.c | 2 + include/drm/drm_atomic.h | 12 +++ include/drm/drm_connector.h | 7 ++ include/drm/drm_plane.h | 7 ++ 6 files changed, 182 insertions(+), 6 deletions(-)drivers/gpu/drm/drm_atomic.c +4
-0@@ -192,6 +192,10 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state) } state->num_private_objs =0 ; +if (state->fake_commit) { +drm_crtc_commit_put (state->fake_commit); + state->fake_commit =NULL ; + } }EXPORT_SYMBOL (drm_atomic_state_default_clear);drivers/gpu/drm/drm_atomic_helper.c +21
-0@@ -1644,6 +1644,40 @@ static void release_crtc_commit(struct completion *completion)drm_crtc_commit_put (commit); } +static void init_commit (struct drm_crtc_commit *commit,struct drm_crtc *crtc) +{ +init_completion (&commit->flip_done); +init_completion (&commit->hw_done); +init_completion (&commit->cleanup_done); +INIT_LIST_HEAD (&commit->commit_entry); +kref_init (&commit->ref); + commit->crtc = crtc; +} + +static struct drm_crtc_commit * +fake_or_crtc_commit (struct drm_atomic_state *state,struct drm_crtc *crtc) +{ +struct drm_crtc_commit *commit; + +if (crtc) { +struct drm_crtc_state *new_crtc_state; + + new_crtc_state =drm_atomic_get_new_crtc_state (state, crtc); + + commit = new_crtc_state->commit;drivers/gpu/drm/drm_atomic_helper.c static void release_crtc_commit(struct completion *completion) · line 1677
Quoted 10 lines
drivers/gpu/drm/drm_atomic_helper.c +10
-0+ }else if (!state->fake_commit) { + state->fake_commit = commit =kzalloc (sizeof (*commit),GFP_KERNEL ); +if (!commit) +return NULL ; + +init_commit (commit,NULL ); + }else + commit = state->fake_commit; + +drm_crtc_commit_get (commit);Double refcount for the case where you call
init_commit? Aka I think this leaks.Quoted 32 lines
drivers/gpu/drm/drm_atomic_helper.c +8
-6+return commit; +} +/** * drm_atomic_helper_setup_commit - setup possibly nonblocking commit * @state: new modeset state to be committed @@ -1692,6 +1726,10 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, {struct drm_crtc *crtc;struct drm_crtc_state *old_crtc_state, *new_crtc_state; +struct drm_connector *conn; +struct drm_connector_state *old_conn_state, *new_conn_state; +struct drm_plane *plane; +struct drm_plane_state *old_plane_state, *new_plane_state;struct drm_crtc_commit *commit;int i, ret;@@ -1700,12 +1738,7 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,if (!commit)return -ENOMEM ; -init_completion (&commit->flip_done); -init_completion (&commit->hw_done); -init_completion (&commit->cleanup_done); -INIT_LIST_HEAD (&commit->commit_entry); -kref_init (&commit->ref); - commit->crtc = crtc; +init_commit (commit, crtc); new_crtc_state->commit = commit;drivers/gpu/drm/drm_atomic_helper.c int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, · line 1777
Quoted 4 lines
drivers/gpu/drm/drm_atomic_helper.c +1
-0@@ -1741,6 +1774,36 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,drm_crtc_commit_get (commit); } +for_each_oldnew_connector_in_state (state, conn, old_conn_state, new_conn_state, i) {Maybe a commen there like
/* commit tracked through the crtc_state->commit */Feels at least a bit non-obvious how this works.
drivers/gpu/drm/drm_atomic_helper.c int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, · line 1780
Quoted 3 lines
drivers/gpu/drm/drm_atomic_helper.c +3
-0+if (new_conn_state->crtc) +continue ; +Please add the
Quoted 5 lines
/* Userspace is not allowed to get ahead of the previous * commit with nonblocking ones. */comment from
stall_checkshere and below. Even better if we could extract this, but macro is ugly and functions wont work.
Ok.
Quoted 89 lines
Quoted 89 lines
drivers/gpu/drm/drm_atomic_helper.c +72
-0+if (nonblock && old_conn_state->commit && + !try_wait_for_completion (&old_conn_state->commit->flip_done)) +return -EBUSY ; + + commit =fake_or_crtc_commit (state, old_conn_state->crtc); +if (!commit) +return -ENOMEM ; + + new_conn_state->commit = commit; + } + +for_each_oldnew_plane_in_state (state, plane, old_plane_state, new_plane_state, i) { +if (new_plane_state->crtc) +continue ; + +if (nonblock && old_plane_state->commit && + !try_wait_for_completion (&old_plane_state->commit->flip_done)) +return -EBUSY ; + + commit =fake_or_crtc_commit (state, old_plane_state->crtc); +if (!commit) +return -ENOMEM ; + + new_plane_state->commit = commit; + } +return 0 ; }EXPORT_SYMBOL (drm_atomic_helper_setup_commit);@@ -1761,6 +1824,10 @@ void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state) {struct drm_crtc *crtc;struct drm_crtc_state *old_crtc_state; +struct drm_plane *plane; +struct drm_plane_state *old_plane_state; +struct drm_connector *conn; +struct drm_connector_state *old_conn_state;struct drm_crtc_commit *commit;int i;long ret;@@ -1785,6 +1852,48 @@ void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state)DRM_ERROR ("[CRTC:%d:%s] flip_done timed out\n" , crtc->base.id, crtc->name); } + +for_each_old_connector_in_state (old_state, conn, old_conn_state, i) { + commit = old_conn_state->commit; + +if (!commit) +continue ; + + ret =wait_for_completion_timeout (&commit->hw_done, +10 *HZ ); +if (ret ==0 ) +DRM_ERROR ("[CONNECTOR:%d:%s] hw_done timed out\n" , + conn->base.id, conn->name); + +/* Currently no support for overwriting flips, hence +* stall for previous one to execute completely. */ + ret =wait_for_completion_timeout (&commit->flip_done, +10 *HZ ); +if (ret ==0 ) +DRM_ERROR ("[CONNECTOR:%d:%s] flip_done timed out\n" , + conn->base.id, conn->name); + } + +for_each_old_plane_in_state (old_state, plane, old_plane_state, i) { + commit = old_plane_state->commit; + +if (!commit) +continue ; + + ret =wait_for_completion_timeout (&commit->hw_done, +10 *HZ ); +if (ret ==0 ) +DRM_ERROR ("[PLANE:%d:%s] hw_done timed out\n" , + plane->base.id, plane->name); + +/* Currently no support for overwriting flips, hence +* stall for previous one to execute completely. */ + ret =wait_for_completion_timeout (&commit->flip_done, +10 *HZ ); +if (ret ==0 ) +DRM_ERROR ("[PLANE:%d:%s] flip_done timed out\n" , + plane->base.id, plane->name); + } }EXPORT_SYMBOL (drm_atomic_helper_wait_for_dependencies);
Quoted 11 lines
drivers/gpu/drm/drm_atomic_helper.c void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state) · line 1935
Quoted 9 lines
drivers/gpu/drm/drm_atomic_helper.c +5
-0@@ -1819,6 +1928,11 @@ void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state)WARN_ON (new_crtc_state->event);complete_all (&commit->hw_done); } + +if (old_state->fake_commit) { +complete_all (&old_state->fake_commit->hw_done); +complete_all (&old_state->fake_commit->flip_done); + }Just to avoid surprises, I think we should also
complete_all(cleanup_done)on the fake commit incleanup_done().
Sure, now there's only 1 it makes sense. :)
Quoted 74 lines
Quoted 74 lines
drivers/gpu/drm/drm_atomic_helper.c +30
-0}EXPORT_SYMBOL (drm_atomic_helper_commit_hw_done);@@ -2241,6 +2355,28 @@ int drm_atomic_helper_swap_state(struct drm_atomic_state *state,if (ret)return ret; } + +for_each_old_connector_in_state (state, connector, old_conn_state, i) { + commit = old_conn_state->commit; + +if (!commit) +continue ; + + ret =wait_for_completion_interruptible (&commit->hw_done); +if (ret) +return ret; + } + +for_each_old_plane_in_state (state, plane, old_plane_state, i) { + commit = old_plane_state->commit; + +if (!commit) +continue ; + + ret =wait_for_completion_interruptible (&commit->hw_done); +if (ret) +return ret; + } }for_each_oldnew_connector_in_state (state, connector, old_conn_state, new_conn_state, i) {@@ -3223,6 +3359,7 @@ void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,drm_framebuffer_get (state->fb); state->fence =NULL ; + state->commit =NULL ; }EXPORT_SYMBOL (__drm_atomic_helper_plane_duplicate_state);@@ -3264,6 +3401,9 @@ void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state)if (state->fence)dma_fence_put (state->fence); + +if (state->commit) +drm_crtc_commit_put (state->commit); }EXPORT_SYMBOL (__drm_atomic_helper_plane_destroy_state);@@ -3342,6 +3482,7 @@ __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,memcpy (state, connector->state,sizeof (*state));if (state->crtc)drm_connector_get (connector); + state->commit =NULL ; }EXPORT_SYMBOL (__drm_atomic_helper_connector_duplicate_state);@@ -3468,6 +3609,9 @@ __drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state) {if (state->crtc)drm_connector_put (state->connector); + +if (state->commit) +drm_crtc_commit_put (state->commit); }EXPORT_SYMBOL (__drm_atomic_helper_connector_destroy_state);drivers/gpu/drm/i915/intel_display.c +0
-0@@ -13109,8 +13109,10 @@ intel_legacy_cursor_update(struct drm_plane *plane,
Quoted 8 lines
drivers/gpu/drm/i915/intel_display.c intel_legacy_cursor_update(struct drm_plane *plane, · line 13115
Quoted 6 lines
drivers/gpu/drm/i915/intel_display.c +2
-0/* Swap plane state */ new_plane_state->fence = old_plane_state->fence; + new_plane_state->commit = old_plane_state->commit; *to_intel_plane_state (old_plane_state) = *to_intel_plane_state (new_plane_state); new_plane_state->fence =NULL ; + new_plane_state->commit =NULL ;Would be good if we could switch to Gustavo's async work and push these tricks into shared code ...
We do this as an evil hack because we can't track whether something is using the current plane or not.
If we apply patch 5, we could directly swap plane->state because we know whether the cursor plane is in use or not, and get rid of this evil hack here.
Quoted 69 lines
Quoted 9 lines
drivers/gpu/drm/i915/intel_display.c +0
-0new_plane_state->fb = old_fb;to_intel_plane_state (new_plane_state)->vma =NULL ;include/drm/drm_atomic.h +0
-0include/drm/drm_atomic.h struct drm_atomic_state { · line 243
Quoted 8 lines
include/drm/drm_atomic.h +5
-0@@ -236,6 +236,18 @@ struct drm_atomic_state {struct drm_modeset_acquire_ctx *acquire_ctx;/** +* @fake_commit: +* +* Used for signaling unbound planes/connectors. +* When a connector or plane is not bound to any CRTC, it's still important +* to preserve linearity to prevent the atomic states from being freed to early. s/to early/too early/.
include/drm/drm_atomic.h struct drm_atomic_state { · line 246
Quoted 3 lines
include/drm/drm_atomic.h +3
-0+* +* This commit (if set) is not bound to any crtc, but will be completed when +* drm_atomic_helper_commit_hw_done() is called. ... and
drm_atomic_helper_cleanup_done()...Quoted 32 lines
include/drm/drm_atomic.h +4
-0+*/ +struct drm_crtc_commit *fake_commit; + +/** * @commit_work: * * Work item which can be used by the driver or helpers to execute the include/drm/drm_connector.h +7
-0@@ -347,6 +347,13 @@ struct drm_connector_state {struct drm_atomic_state *state; +/** +* @commit: Tracks the pending commit to prevent use-after-free conditions. +* +* Is only set when @crtc is NULL. +*/ +struct drm_crtc_commit *commit; +struct drm_tv_connector_state tv;/** include/drm/drm_plane.h +0
-0@@ -123,6 +123,13 @@ struct drm_plane_state {*/ bool visible;include/drm/drm_plane.h struct drm_plane_state { · line 134
Quoted 10 lines
include/drm/drm_plane.h +7
-0+/** +* @commit: Tracks the pending commit to prevent use-after-free conditions. +* +* Is only set when @crtc is NULL. +*/ +struct drm_crtc_commit *commit; +struct drm_atomic_state *state; };With the above nits addressed:
Quoted 1 line
Reviewed-by Daniel Vetter <[email protected]>
+1
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH 4/5] drm/atomic: Fix freeing connector/plane state too early by tracking commits, v2.
In reply to Maarten LankhorstHi Maarten,
Thank you for the patch.
Quoted 53 lines · On Wednesday, 30 August 2017 15:17:51 EEST Maarten Lankhorst wrote:
Currently we neatly track the crtc state, but forget to look at plane/connector state.
When doing a nonblocking modeset, immediately followed by a setprop before the modeset completes, the setprop will see the modesets new state as the old state and free it.
This has to be solved by waiting for
hw_doneon the connector, even if it's not assigned to a crtc. When a connector is unbound we take the last crtc commit, and when it stays unbound we create a new fake crtc commit for that gets signaled onhw_donefor all the planes/connectors.We wait for it the same way as we do for crtc's, which will make sure we never run into a use-after-free situation.
Changes since v1:
- Only create a single disable commit. (danvet)
- Fix leak inintel_legacy_cursor_update.Signed-off-by Maarten Lankhorst <[email protected]>Testcase: kms_atomic_transition.plane-use-after-nonblocking-unbind*
Cc: Laurent Pinchart <[email protected]>--- drivers/gpu/drm/drm_atomic.c | 4 + drivers/gpu/drm/drm_atomic_helper.c | 156 ++++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_display.c | 2 + include/drm/drm_atomic.h | 12 +++ include/drm/drm_connector.h | 7 ++ include/drm/drm_plane.h | 7 ++ 6 files changed, 182 insertions(+), 6 deletions(-)drivers/gpu/drm/drm_atomic.c +4
-0@@ -192,6 +192,10 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state) } state->num_private_objs =0 ; +if (state->fake_commit) { +drm_crtc_commit_put (state->fake_commit); + state->fake_commit =NULL ; + } }EXPORT_SYMBOL (drm_atomic_state_default_clear);(quoted diff) +0
-0
b/drivers/gpu/drm/drm_atomic_helper.cindex8ccb8b6536c0..034f563fb130100644
drivers/gpu/drm/drm_atomic_helper.c static void release_crtc_commit(struct completion · line 1649
Quoted 6 lines
drivers/gpu/drm/drm_atomic_helper.c +2
-0@@ -1644,6 +1644,40 @@ static void release_crtc_commit(struct completion *completion) drm_crtc_commit_put(commit); } +static void init_commit (struct drm_crtc_commit *commit,struct drm_crtc *crtc) +{
You could allocate the commit in this function too, the kzalloc() is currently duplicated. The function should probably be called alloc_commit() then.
Quoted 19 lines
drivers/gpu/drm/drm_atomic_helper.c +19
-0+init_completion (&commit->flip_done); +init_completion (&commit->hw_done); +init_completion (&commit->cleanup_done); +INIT_LIST_HEAD (&commit->commit_entry); +kref_init (&commit->ref); + commit->crtc = crtc; +} + +static struct drm_crtc_commit * +fake_or_crtc_commit (struct drm_atomic_state *state,struct drm_crtc *crtc) +{ +struct drm_crtc_commit *commit; + +if (crtc) { +struct drm_crtc_state *new_crtc_state; + + new_crtc_state =drm_atomic_get_new_crtc_state (state, crtc); + + commit = new_crtc_state->commit;
drivers/gpu/drm/drm_atomic_helper.c static void release_crtc_commit(struct completion *completion) · line 1677
Quoted 10 lines
drivers/gpu/drm/drm_atomic_helper.c +10
-0+ }else if (!state->fake_commit) { + state->fake_commit = commit =kzalloc (sizeof (*commit),GFP_KERNEL ); +if (!commit) +return NULL ; + +init_commit (commit,NULL ); + }else + commit = state->fake_commit; + +drm_crtc_commit_get (commit);
I believe the reference counting is right. The double reference in the second case (kref_init() when initializing the commit and drm_crtc_commit_get()) should not cause a leak. The kref_init() takes a reference to store the commit in state->fake_commit, released in drm_atomic_state_default_clear(), and the drm_crtc_commit_get() takes a reference returned by the function, stored in new_*_state->commit by the caller.
This being said, I think the reference counting is confusing, as proved by Daniel thinking there was a leak here (or by me thinking there's no leak while there's one :-)). To make the implementation clearer, I propose turning the definition of drm_crtc_commit_get() to
static inline struct drm_crtc_commit * drm_crtc_commit_get(struct drm_crtc_commit *commit)
{
kref_get(&commit->ref);
return commit;
}and writing this function as
/* Return a new reference to the commit object */
static struct drm_crtc_commit *fake_or_crtc_commit(struct drm_atomic_state *state, struct drm_crtc *crtc)
{
struct drm_crtc_commit *commit;
if (crtc) {
struct drm_crtc_state *new_crtc_state;
new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
commit = new_crtc_state->commit;
} else {
if (!state->fake_commit)
state->fake_commit = alloc_commit(NULL);
commit = state->fake_commit;
}
return drm_crtc_commit_get(commit);
}Quoted 33 lines
drivers/gpu/drm/drm_atomic_helper.c +3
-0+return commit; +} +/** * drm_atomic_helper_setup_commit - setup possibly nonblocking commit * @state: new modeset state to be committed
drivers/gpu/drm/drm_atomic_helper.c +5
-6@@ -1692,6 +1726,10 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, {struct drm_crtc *crtc;struct drm_crtc_state *old_crtc_state, *new_crtc_state; +struct drm_connector *conn; +struct drm_connector_state *old_conn_state, *new_conn_state; +struct drm_plane *plane; +struct drm_plane_state *old_plane_state, *new_plane_state;struct drm_crtc_commit *commit;int i, ret;@@ -1700,12 +1738,7 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, if (!commit) return -ENOMEM; -init_completion (&commit->flip_done); -init_completion (&commit->hw_done); -init_completion (&commit->cleanup_done); -INIT_LIST_HEAD (&commit->commit_entry); -kref_init (&commit->ref); - commit->crtc = crtc; +init_commit (commit, crtc); new_crtc_state->commit = commit;@@ -1741,6 +1774,36 @@ int drm_atomic_helper_setup_commit(structdrm_atomic_state *state,drm_crtc_commit_get (commit );
drivers/gpu/drm/drm_atomic_helper.c int drm_atomic_helper_setup_commit(struct · line 1784
Quoted 10 lines
drivers/gpu/drm/drm_atomic_helper.c +7
-0} +for_each_oldnew_connector_in_state (state, conn, old_conn_state, new_conn_state, i) { +if (new_conn_state->crtc) +continue ; + +if (nonblock && old_conn_state->commit && + !try_wait_for_completion (&old_conn_state->commit->flip_done)) +return -EBUSY ;
flip_done only, not hw_done ? A comment that explains why would be helpful.
Quoted 6 lines
drivers/gpu/drm/drm_atomic_helper.c +6
-0+ + commit =fake_or_crtc_commit (state, old_conn_state->crtc); +if (!commit) +return -ENOMEM ; + + new_conn_state->commit = commit;
drivers/gpu/drm/drm_atomic_helper.c int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, · line 1798
Quoted 10 lines
drivers/gpu/drm/drm_atomic_helper.c +9
-0+ } + +for_each_oldnew_plane_in_state (state, plane, old_plane_state, new_plane_state, i) { +if (new_plane_state->crtc) +continue ; + +if (nonblock && old_plane_state->commit && + !try_wait_for_completion (&old_plane_state->commit->flip_done)) +return -EBUSY ;
Same here.
Quoted 36 lines
drivers/gpu/drm/drm_atomic_helper.c +11
-0+ commit =fake_or_crtc_commit (state, old_plane_state->crtc); +if (!commit) +return -ENOMEM ; + + new_plane_state->commit = commit; + } +return 0 ; }EXPORT_SYMBOL (drm_atomic_helper_setup_commit);@@ -1761,6 +1824,10 @@ void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state) {struct drm_crtc *crtc;struct drm_crtc_state *old_crtc_state; +struct drm_plane *plane; +struct drm_plane_state *old_plane_state; +struct drm_connector *conn; +struct drm_connector_state *old_conn_state;struct drm_crtc_commit *commit;int i;long ret;@@ -1785,6 +1852,48 @@ void drm_atomic_helper_wait_for_dependencies(struct
drm_atomic_state*old_state) DRM_ERROR("[CRTC:%d:%s]flip_donetimed out\n",drivers/gpu/drm/drm_atomic_helper.c +10
-0crtc->base.id, crtc->name); } + +for_each_old_connector_in_state (old_state, conn, old_conn_state, i) { + commit = old_conn_state->commit; + +if (!commit) +continue ; + + ret =wait_for_completion_timeout (&commit->hw_done, +10 *HZ ); +if (ret ==0 )
drivers/gpu/drm/drm_atomic_helper.c void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state) · line 1874
Quoted 10 lines
drivers/gpu/drm/drm_atomic_helper.c +10
-0+DRM_ERROR ("[CONNECTOR:%d:%s] hw_done timed out\n" , + conn->base.id, conn->name); + +/* Currently no support for overwriting flips, hence +* stall for previous one to execute completely. */ + ret =wait_for_completion_timeout (&commit->flip_done, +10 *HZ ); +if (ret ==0 ) +DRM_ERROR ("[CONNECTOR:%d:%s] flip_done timed out\n" , + conn->base.id, conn->name);
There's probably something I don't get, but given that the connector state -
Quoted 1 line
commit pointer is only set for commits that have no CRTC, do we have a
guarantee that there will be a page flip to be signalled ? Can't we for instance disable a connector without a page flip ? Or set a property on an already disabled connector ?
Quoted 38 lines
drivers/gpu/drm/drm_atomic_helper.c +27
-0+ } + +for_each_old_plane_in_state (old_state, plane, old_plane_state, i) { + commit = old_plane_state->commit; + +if (!commit) +continue ; + + ret =wait_for_completion_timeout (&commit->hw_done, +10 *HZ ); +if (ret ==0 ) +DRM_ERROR ("[PLANE:%d:%s] hw_done timed out\n" , + plane->base.id, plane->name); + +/* Currently no support for overwriting flips, hence +* stall for previous one to execute completely. */ + ret =wait_for_completion_timeout (&commit->flip_done, +10 *HZ ); +if (ret ==0 ) +DRM_ERROR ("[PLANE:%d:%s] flip_done timed out\n" , + plane->base.id, plane->name); + } }EXPORT_SYMBOL (drm_atomic_helper_wait_for_dependencies);@@ -1819,6 +1928,11 @@ void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state) WARN_ON(new_crtc_state->event);complete_all (&commit->hw_done); } + +if (old_state->fake_commit) { +complete_all (&old_state->fake_commit->hw_done); +complete_all (&old_state->fake_commit->flip_done); + } }EXPORT_SYMBOL (drm_atomic_helper_commit_hw_done);
drivers/gpu/drm/drm_atomic_helper.c int drm_atomic_helper_swap_state(struct · line 2358
Quoted 4 lines
drivers/gpu/drm/drm_atomic_helper.c +1
-0@@ -2241,6 +2355,28 @@ int drm_atomic_helper_swap_state(struct drm_atomic_state *state, if (ret) return ret; } +
A comment would be helpful here too. In particular explaining why you wait on hw_done only isn't straightforward.
Quoted 141 lines
drivers/gpu/drm/drm_atomic_helper.c +21
-0+for_each_old_connector_in_state (state, connector, old_conn_state, i) { + commit = old_conn_state->commit; + +if (!commit) +continue ; + + ret =wait_for_completion_interruptible (&commit->hw_done); +if (ret) +return ret; + } + +for_each_old_plane_in_state (state, plane, old_plane_state, i) { + commit = old_plane_state->commit; + +if (!commit) +continue ; + + ret =wait_for_completion_interruptible (&commit->hw_done); +if (ret) +return ret; + } } for_each_oldnew_connector_in_state(state, connector, old_conn_state,
new_conn_state, i) { @@ -3223,6 +3359,7 @@ void __drm_atomic_helper_plane_duplicate_state(structdrm_plane*plane,drm_framebuffer_get(state->fb);drivers/gpu/drm/drm_atomic_helper.c +8
-0state->fence =NULL ; + state->commit =NULL ; }EXPORT_SYMBOL (__drm_atomic_helper_plane_duplicate_state);@@ -3264,6 +3401,9 @@ void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state)if (state->fence)dma_fence_put (state->fence); + +if (state->commit) +drm_crtc_commit_put (state->commit); }EXPORT_SYMBOL (__drm_atomic_helper_plane_destroy_state);@@ -3342,6 +3482,7 @@ __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,memcpy (state, connector->state,sizeof (*state));if (state->crtc)drm_connector_get (connector); + state->commit =NULL ; }EXPORT_SYMBOL (__drm_atomic_helper_connector_duplicate_state);@@ -3468,6 +3609,9 @@ __drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state) {if (state->crtc)drm_connector_put (state->connector); + +if (state->commit) +drm_crtc_commit_put (state->commit); }EXPORT_SYMBOL (__drm_atomic_helper_connector_destroy_state);(quoted diff) +0
-0
b/drivers/gpu/drm/i915/intel_display.cindex3f3cb96aa11e..70ce02753177100644drivers/gpu/drm/i915/intel_display.c +2
-0@@ -13109,8 +13109,10 @@ intel_legacy_cursor_update(struct drm_plane *plane,/* Swap plane state */ new_plane_state->fence = old_plane_state->fence; + new_plane_state->commit = old_plane_state->commit; *to_intel_plane_state (old_plane_state) = *to_intel_plane_state (new_plane_state); new_plane_state->fence =NULL ; + new_plane_state->commit =NULL ; new_plane_state->fb = old_fb;to_intel_plane_state (new_plane_state)->vma =NULL ;include/drm/drm_atomic.h +4
-0@@ -236,6 +236,18 @@ struct drm_atomic_state {struct drm_modeset_acquire_ctx *acquire_ctx;/** +* @fake_commit: +* +* Used for signaling unbound planes/connectors. +* When a connector or plane is not bound to any CRTC, it's still important
include/drm/drm_atomic.h +1
-0+* to preserve linearity to prevent the atomic states from being freed to early.
include/drm/drm_atomic.h +2
-0+* +* This commit (if set) is not bound to any crtc, but will be completed when
include/drm/drm_atomic.h +5
-0+* drm_atomic_helper_commit_hw_done() is called. +*/ +struct drm_crtc_commit *fake_commit; + +/** * @commit_work: * * Work item which can be used by the driver or helpers to execute the include/drm/drm_connector.h +2
-0@@ -347,6 +347,13 @@ struct drm_connector_state {struct drm_atomic_state *state; +/** +* @commit: Tracks the pending commit to prevent use-after-free conditions.
include/drm/drm_connector.h +5
-0+* +* Is only set when @crtc is NULL. +*/ +struct drm_crtc_commit *commit; +struct drm_tv_connector_state tv;/** include/drm/drm_plane.h +2
-0@@ -123,6 +123,13 @@ struct drm_plane_state {*/ bool visible; +/** +* @commit: Tracks the pending commit to prevent use-after-free conditions.
include/drm/drm_plane.h +5
-0+* +* Is only set when @crtc is NULL. +*/ +struct drm_crtc_commit *commit; +struct drm_atomic_state *state; };
Signature · 8 lines
Regards, Laurent Pinchart _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH 4/5] drm/atomic: Fix freeing connector/plane state too early by tracking commits, v2.
Quoted 132 lines · Laurent Pinchart
Hi Maarten,
Thank you for the patch.
Quoted 53 lines · On Wednesday, 30 August 2017 15:17:51 EEST Maarten Lankhorst wrote:
Currently we neatly track the crtc state, but forget to look at plane/connector state.
When doing a nonblocking modeset, immediately followed by a setprop before the modeset completes, the setprop will see the modesets new state as the old state and free it.
This has to be solved by waiting for
hw_doneon the connector, even if it's not assigned to a crtc. When a connector is unbound we take the last crtc commit, and when it stays unbound we create a new fake crtc commit for that gets signaled onhw_donefor all the planes/connectors.We wait for it the same way as we do for crtc's, which will make sure we never run into a use-after-free situation.
Changes since v1:
- Only create a single disable commit. (danvet)
- Fix leak inintel_legacy_cursor_update.Signed-off-by Maarten Lankhorst <[email protected]>Testcase: kms_atomic_transition.plane-use-after-nonblocking-unbind*
Cc: Laurent Pinchart <[email protected]>--- drivers/gpu/drm/drm_atomic.c | 4 + drivers/gpu/drm/drm_atomic_helper.c | 156 ++++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_display.c | 2 + include/drm/drm_atomic.h | 12 +++ include/drm/drm_connector.h | 7 ++ include/drm/drm_plane.h | 7 ++ 6 files changed, 182 insertions(+), 6 deletions(-)drivers/gpu/drm/drm_atomic.c +4
-0@@ -192,6 +192,10 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state) } state->num_private_objs =0 ; +if (state->fake_commit) { +drm_crtc_commit_put (state->fake_commit); + state->fake_commit =NULL ; + } }EXPORT_SYMBOL (drm_atomic_state_default_clear);(quoted diff) +0
-0
b/drivers/gpu/drm/drm_atomic_helper.cindex8ccb8b6536c0..034f563fb130100644drivers/gpu/drm/drm_atomic_helper.c static void release_crtc_commit(struct completion · line 1649
Quoted 6 lines
drivers/gpu/drm/drm_atomic_helper.c +2
-0@@ -1644,6 +1644,40 @@ static void release_crtc_commit(struct completion *completion) drm_crtc_commit_put(commit); } +static void init_commit (struct drm_crtc_commit *commit,struct drm_crtc *crtc) +{You could allocate the commit in this function too, the
kzalloc()is currently duplicated. The function should probably be calledalloc_commit()then.Quoted 19 lines
drivers/gpu/drm/drm_atomic_helper.c +19
-0+init_completion (&commit->flip_done); +init_completion (&commit->hw_done); +init_completion (&commit->cleanup_done); +INIT_LIST_HEAD (&commit->commit_entry); +kref_init (&commit->ref); + commit->crtc = crtc; +} + +static struct drm_crtc_commit * +fake_or_crtc_commit (struct drm_atomic_state *state,struct drm_crtc *crtc) +{ +struct drm_crtc_commit *commit; + +if (crtc) { +struct drm_crtc_state *new_crtc_state; + + new_crtc_state =drm_atomic_get_new_crtc_state (state, crtc); + + commit = new_crtc_state->commit;drivers/gpu/drm/drm_atomic_helper.c static void release_crtc_commit(struct completion *completion) · line 1677
Quoted 10 lines
drivers/gpu/drm/drm_atomic_helper.c +10
-0+ }else if (!state->fake_commit) { + state->fake_commit = commit =kzalloc (sizeof (*commit),GFP_KERNEL ); +if (!commit) +return NULL ; + +init_commit (commit,NULL ); + }else + commit = state->fake_commit; + +drm_crtc_commit_get (commit);I believe the reference counting is right. The double reference in the second case (
kref_init()when initializing the commit anddrm_crtc_commit_get()) should not cause a leak. Thekref_init()takes a reference to store the commit instate->fake_commit, released indrm_atomic_state_default_clear(), and thedrm_crtc_commit_get()takes a reference returned by the function, stored in new_*_state->commit by the caller.This being said, I think the reference counting is confusing, as proved by Daniel thinking there was a leak here (or by me thinking there's no leak while there's one :-)). To make the implementation clearer, I propose turning the definition of
drm_crtc_commit_get()tostatic inline struct
drm_crtc_commit*drm_crtc_commit_get(struct drm_crtc_commit *commit){ kref_get(&commit->ref); return commit; }and writing this function as
/* Return a new reference to the commit object */
static structdrm_crtc_commit*fake_or_crtc_commit(struct drm_atomic_state *state, struct drm_crtc *crtc){ struct drm_crtc_commit *commit; if (crtc) { struct drm_crtc_state *new_crtc_state; new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); commit = new_crtc_state->commit; } else {
Quoted 8 lines
if (!state->fake_commit) state->fake_commit = alloc_commit(NULL); commit = state->fake_commit; } return drm_crtc_commit_get(commit); }
+1 on something like this, the compressed layout with assigning both commit and ->fake_commit is what tricked me into seeing a leak. -Daniel
Signature · 7 lines
Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch _______________________________________________ Intel-gfx mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Re: [Intel-gfx] [PATCH 4/5] drm/atomic: Fix freeing connector/plane state too early by tracking commits, v2.
Quoted 88 lines · On Wednesday, 30 August 2017 17:17:36 EEST Daniel Vetter wrote:
Quoted 87 lines · Laurent Pinchart
Hi Maarten,
Thank you for the patch.
Quoted 57 lines · On Wednesday, 30 August 2017 15:17:51 EEST Maarten Lankhorst wrote:
Currently we neatly track the crtc state, but forget to look at plane/connector state.
When doing a nonblocking modeset, immediately followed by a setprop before the modeset completes, the setprop will see the modesets new state as the old state and free it.
This has to be solved by waiting for
hw_doneon the connector, even if it's not assigned to a crtc. When a connector is unbound we take the last crtc commit, and when it stays unbound we create a new fake crtc commit for that gets signaled onhw_donefor all the planes/connectors.We wait for it the same way as we do for crtc's, which will make sure we never run into a use-after-free situation.
Changes since v1:
- Only create a single disable commit. (danvet)
- Fix leak inintel_legacy_cursor_update.Signed-off-by Maarten Lankhorst <[email protected]>Testcase: kms_atomic_transition.plane-use-after-nonblocking-unbind*
Cc: Laurent Pinchart <[email protected]>
---drivers/gpu/drm/drm_atomic.c | 4 + drivers/gpu/drm/drm_atomic_helper.c | 156 ++++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_display.c | 2 + include/drm/drm_atomic.h | 12 +++ include/drm/drm_connector.h | 7 ++ include/drm/drm_plane.h | 7 ++ 6 files changed, 182 insertions(+), 6 deletions(-)drivers/gpu/drm/drm_atomic.c +4
-0@@ -192,6 +192,10 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state) } state->num_private_objs =0 ; +if (state->fake_commit) { +drm_crtc_commit_put (state->fake_commit); + state->fake_commit =NULL ; + } }
EXPORT_SYMBOL(drm_atomic_state_default_clear);(quoted diff) +0
-0
b/drivers/gpu/drm/drm_atomic_helper.cindex8ccb8b6536c0..034f563fb130100644drivers/gpu/drm/drm_atomic_helper.c static void release_crtc_commit(struct completion · line 1650
Quoted 7 lines
drivers/gpu/drm/drm_atomic_helper.c +2
-0@@ -1644,6 +1644,40 @@ static void release_crtc_commit(struct completion *completion) drm_crtc_commit_put(commit); } +static void init_commit (struct drm_crtc_commit *commit,struct drm_crtc *crtc) +{You could allocate the commit in this function too, the
kzalloc()is currently duplicated. The function should probably be calledalloc_commit()then.>Quoted 14 lines
drivers/gpu/drm/drm_atomic_helper.c +13
-0+init_completion (&commit->flip_done); +init_completion (&commit->hw_done); +init_completion (&commit->cleanup_done); +INIT_LIST_HEAD (&commit->commit_entry); +kref_init (&commit->ref); + commit->crtc = crtc; +} + +static struct drm_crtc_commit * +fake_or_crtc_commit (struct drm_atomic_state *state,struct drm_crtc *crtc) +{ +struct drm_crtc_commit *commit; +
Quoted 8 lines
Quoted 8 lines
drivers/gpu/drm/drm_atomic_helper.c static void release_crtc_commit(struct completion *completion)
Quoted 8 lines
drivers/gpu/drm/drm_atomic_helper.c +8
-0+if (crtc) { +struct drm_crtc_state *new_crtc_state; + + new_crtc_state =drm_atomic_get_new_crtc_state (state, crtc); + + commit = new_crtc_state->commit; + }else if (!state->fake_commit) { + state->fake_commit = commit = kzalloc(sizeof(*commit),
GFP_KERNEL);
Quoted 56 lines
Quoted 56 lines
drivers/gpu/drm/drm_atomic_helper.c static void release_crtc_commit(struct completion *completion) · line 1677
Quoted 8 lines
drivers/gpu/drm/drm_atomic_helper.c +8
-0+if (!commit) +return NULL ; + +init_commit (commit,NULL ); + }else + commit = state->fake_commit; + +drm_crtc_commit_get (commit);I believe the reference counting is right. The double reference in the second case (
kref_init()when initializing the commit anddrm_crtc_commit_get()) should not cause a leak. Thekref_init()takes a reference to store the commit instate->fake_commit, released indrm_atomic_state_default_clear(), and thedrm_crtc_commit_get()takes a reference returned by the function, stored in new_*_state->commit by the caller.This being said, I think the reference counting is confusing, as proved by Daniel thinking there was a leak here (or by me thinking there's no leak while there's one :-)). To make the implementation clearer, I propose turning the definition of
drm_crtc_commit_get()tostatic inline struct
drm_crtc_commit*drm_crtc_commit_get(struct drm_crtc_commit *commit){kref_get(&commit->ref); return commit;}
and writing this function as
/* Return a new reference to the commit object */
static structdrm_crtc_commit*fake_or_crtc_commit(struct drm_atomic_state *state, struct drm_crtc *crtc){struct drm_crtc_commit *commit; if (crtc) { struct drm_crtc_state *new_crtc_state; new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); commit = new_crtc_state->commit; } else { if (!state->fake_commit) state->fake_commit = alloc_commit(NULL); commit = state->fake_commit;
Quoted 8 lines
Quoted 5 lines
} return drm_crtc_commit_get(commit);}
+1 on something like this, the compressed layout with assigning both commit and ->fake_commit is what tricked me into seeing a leak.
What I think makes it clearer is to store the return value of functions returning a reference directly in the pointer that stores the reference. That's why I prefer
1. if (!state->fake_commit)
2. state->fake_commit = alloc_commit(NULL);
3.
4. commit = state->fake_commit;
Line 2 stores the pointer in an object that thus requires a reference, which is returned by alloc_commit(). Line 4 stores the pointer in a local variable, and thus doesn't require a reference.
Signature · 8 lines
Regards, Laurent Pinchart _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
Maarten Lankhorst
maintainerRFC PATCH 5/5 drm/atomic: Make async plane update checks work as intended.
In reply to Maarten LankhorstBy always keeping track of the last commit in plane_state, we know whether there is an active update on the plane or not. With that information we can reject the fast update, and force the slowpath to be used as was originally intended.
--- drivers/gpu/drm/drm_atomic_helper.c | 25 +++++++++++-------------- drivers/gpu/drm/i915/intel_display.c | 8 ++++++++ include/drm/drm_plane.h | 5 +++-- 3 files changed, 22 insertions(+), 16 deletions(-)
drivers/gpu/drm/drm_atomic_helper.c +11 -14
@@ -1388,8 +1388,8 @@ int drm_atomic_helper_async_check(struct drm_device *dev, {struct drm_crtc *crtc;struct drm_crtc_state *crtc_state; -struct drm_plane *__plane, *plane =NULL ; -struct drm_plane_state *__plane_state, *plane_state =NULL ; +struct drm_plane *plane; +struct drm_plane_state *old_plane_state, *new_plane_state;const struct drm_plane_helper_funcs *funcs;int i, n_planes =0 ;
@@ -1398,33 +1398,33 @@ int drm_atomic_helper_async_check(struct drm_device *dev,return -EINVAL ; } -for_each_new_plane_in_state (state, __plane, __plane_state, i) { +for_each_oldnew_plane_in_state (state, plane, old_plane_state, new_plane_state, i) n_planes++; - plane = __plane; - plane_state = __plane_state; - }/* FIXME: we support only single plane updates for now */ -if (!plane || n_planes !=1 ) +if (n_planes !=1 )return -EINVAL ; -if (!plane_state->crtc) +if (!new_plane_state->crtc)return -EINVAL ; funcs = plane->helper_private;if (!funcs->atomic_async_update)return -EINVAL ; -if (plane_state->fence) +if (new_plane_state->fence)return -EINVAL ;/* -* TODO: Don't do an async update if there is an outstanding commit modifying +* Don't do an async update if there is an outstanding commit modifying * the plane. This prevents our async update's changes from getting * overridden by a previous synchronous update's state. */ +if (old_plane_state->commit && + !try_wait_for_completion (&old_plane_state->commit->hw_done)) +return -EBUSY ; -return funcs->atomic_async_check (plane, plane_state); +return funcs->atomic_async_check (plane, new_plane_state); }EXPORT_SYMBOL (drm_atomic_helper_async_check);
@@ -1790,9 +1790,6 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, }for_each_oldnew_plane_in_state (state, plane, old_plane_state, new_plane_state, i) { -if (new_plane_state->crtc) -continue ; -if (nonblock && old_plane_state->commit && !try_wait_for_completion (&old_plane_state->commit->flip_done))return -EBUSY ;
drivers/gpu/drm/i915/intel_display.c +8 -0
@@ -13043,6 +13043,14 @@ intel_legacy_cursor_update(struct drm_plane *plane, goto slow; old_plane_state = plane->state; +/* +* Don't do an async update if there is an outstanding commit modifying +* the plane. This prevents our async update's changes from getting +* overridden by a previous synchronous update's state. +*/ +if (old_plane_state->commit && + !try_wait_for_completion (&old_plane_state->commit->hw_done)) + goto slow;/* * If any parameters change that may affect watermarks,
include/drm/drm_plane.h +3 -2
@@ -124,9 +124,10 @@ struct drm_plane_state {bool visible;/** -* @commit: Tracks the pending commit to prevent use-after-free conditions. +* @commit: Tracks the pending commit to prevent use-after-free conditions, +* and for async plane updates. * -* Is only set when @crtc is NULL. +* May be NULL. */ struct drm_crtc_commit *commit;
Signature · 6 lines
2.11.0 _______________________________________________ Intel-gfx mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Re: [RFC PATCH 5/5] drm/atomic: Make async plane update checks work as intended.
Quoted 7 lines · Maarten Lankhorst
By always keeping track of the last commit in
plane_state, we know whether there is an active update on the plane or not. With that information we can reject the fast update, and force the slowpath to be used as was originally intended.Cc Gustavo Padovan <[email protected]>Signed-off-by Maarten Lankhorst <[email protected]>
Makes sense, but I think like patch 1 it would be better to do this in a separate series. Which would then include a patch to move i915 over to the async plane support.
One more comment below.
Quoted 48 lines
--- drivers/gpu/drm/drm_atomic_helper.c | 25 +++++++++++-------------- drivers/gpu/drm/i915/intel_display.c | 8 ++++++++ include/drm/drm_plane.h | 5 +++-- 3 files changed, 22 insertions(+), 16 deletions(-)drivers/gpu/drm/drm_atomic_helper.c +6
-9@@ -1388,8 +1388,8 @@ int drm_atomic_helper_async_check(struct drm_device *dev, {struct drm_crtc *crtc;struct drm_crtc_state *crtc_state; -struct drm_plane *__plane, *plane =NULL ; -struct drm_plane_state *__plane_state, *plane_state =NULL ; +struct drm_plane *plane; +struct drm_plane_state *old_plane_state, *new_plane_state;const struct drm_plane_helper_funcs *funcs;int i, n_planes =0 ;@@ -1398,33 +1398,33 @@ int drm_atomic_helper_async_check(struct drm_device *dev,return -EINVAL ; } -for_each_new_plane_in_state (state, __plane, __plane_state, i) { +for_each_oldnew_plane_in_state (state, plane, old_plane_state, new_plane_state, i) n_planes++; - plane = __plane; - plane_state = __plane_state; - }/* FIXME: we support only single plane updates for now */ -if (!plane || n_planes !=1 ) +if (n_planes !=1 )return -EINVAL ; -if (!plane_state->crtc) +if (!new_plane_state->crtc)return -EINVAL ; funcs = plane->helper_private;if (!funcs->atomic_async_update)return -EINVAL ; -if (plane_state->fence) +if (new_plane_state->fence)return -EINVAL ;
drivers/gpu/drm/drm_atomic_helper.c int drm_atomic_helper_async_check(struct drm_device *dev, · line 1425
Quoted 10 lines
drivers/gpu/drm/drm_atomic_helper.c +4
-1/* -* TODO: Don't do an async update if there is an outstanding commit modifying +* Don't do an async update if there is an outstanding commit modifying * the plane. This prevents our async update's changes from getting * overridden by a previous synchronous update's state. */ +if (old_plane_state->commit && + !try_wait_for_completion (&old_plane_state->commit->hw_done)) +return -EBUSY ;
Instead of forcing us to always set the plane_state->commit pointer (bunch of pointles refcounting), perhaps just check plane_state->crtc->state->commit? We do hold the necessary locks to at least look at that.
-Daniel
Quoted 59 lines
drivers/gpu/drm/drm_atomic_helper.c +1
-4-return funcs->atomic_async_check (plane, plane_state); +return funcs->atomic_async_check (plane, new_plane_state); }EXPORT_SYMBOL (drm_atomic_helper_async_check);@@ -1790,9 +1790,6 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, }for_each_oldnew_plane_in_state (state, plane, old_plane_state, new_plane_state, i) { -if (new_plane_state->crtc) -continue ; -if (nonblock && old_plane_state->commit && !try_wait_for_completion (&old_plane_state->commit->flip_done))return -EBUSY ;drivers/gpu/drm/i915/intel_display.c +8
-0@@ -13043,6 +13043,14 @@ intel_legacy_cursor_update(struct drm_plane *plane, goto slow; old_plane_state = plane->state; +/* +* Don't do an async update if there is an outstanding commit modifying +* the plane. This prevents our async update's changes from getting +* overridden by a previous synchronous update's state. +*/ +if (old_plane_state->commit && + !try_wait_for_completion (&old_plane_state->commit->hw_done)) + goto slow;/* * If any parameters change that may affect watermarks, include/drm/drm_plane.h +3
-2@@ -124,9 +124,10 @@ struct drm_plane_state {bool visible;/** -* @commit: Tracks the pending commit to prevent use-after-free conditions. +* @commit: Tracks the pending commit to prevent use-after-free conditions, +* and for async plane updates. * -* Is only set when @crtc is NULL. +* May be NULL. */ struct drm_crtc_commit *commit;Signature · 6 lines
2.11.0 _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
Signature · 7 lines
Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
Maarten Lankhorst
maintainerRe: [RFC PATCH 5/5] drm/atomic: Make async plane update checks work as intended.
Op 30-08-17 om 14:46 schreef Daniel Vetter:
Quoted 63 lines · Maarten Lankhorst
Quoted 7 lines
By always keeping track of the last commit in
plane_state, we know whether there is an active update on the plane or not. With that information we can reject the fast update, and force the slowpath to be used as was originally intended.Cc Gustavo Padovan <[email protected]>Signed-off-by Maarten Lankhorst <[email protected]>Makes sense, but I think like patch 1 it would be better to do this in a separate series. Which would then include a patch to move i915 over to the async plane support.
One more comment below.
Quoted 49 lines
--- drivers/gpu/drm/drm_atomic_helper.c | 25 +++++++++++-------------- drivers/gpu/drm/i915/intel_display.c | 8 ++++++++ include/drm/drm_plane.h | 5 +++-- 3 files changed, 22 insertions(+), 16 deletions(-)drivers/gpu/drm/drm_atomic_helper.c +6
-9@@ -1388,8 +1388,8 @@ int drm_atomic_helper_async_check(struct drm_device *dev, {struct drm_crtc *crtc;struct drm_crtc_state *crtc_state; -struct drm_plane *__plane, *plane =NULL ; -struct drm_plane_state *__plane_state, *plane_state =NULL ; +struct drm_plane *plane; +struct drm_plane_state *old_plane_state, *new_plane_state;const struct drm_plane_helper_funcs *funcs;int i, n_planes =0 ;@@ -1398,33 +1398,33 @@ int drm_atomic_helper_async_check(struct drm_device *dev,return -EINVAL ; } -for_each_new_plane_in_state (state, __plane, __plane_state, i) { +for_each_oldnew_plane_in_state (state, plane, old_plane_state, new_plane_state, i) n_planes++; - plane = __plane; - plane_state = __plane_state; - }/* FIXME: we support only single plane updates for now */ -if (!plane || n_planes !=1 ) +if (n_planes !=1 )return -EINVAL ; -if (!plane_state->crtc) +if (!new_plane_state->crtc)return -EINVAL ; funcs = plane->helper_private;if (!funcs->atomic_async_update)return -EINVAL ; -if (plane_state->fence) +if (new_plane_state->fence)return -EINVAL ;
Quoted 13 lines
drivers/gpu/drm/drm_atomic_helper.c int drm_atomic_helper_async_check(struct drm_device *dev, · line 1425
Quoted 9 lines
drivers/gpu/drm/drm_atomic_helper.c +4
-1/* -* TODO: Don't do an async update if there is an outstanding commit modifying +* Don't do an async update if there is an outstanding commit modifying * the plane. This prevents our async update's changes from getting * overridden by a previous synchronous update's state. */ +if (old_plane_state->commit && + !try_wait_for_completion (&old_plane_state->commit->hw_done)) +return -EBUSY ;Instead of forcing us to always set the
plane_state->commitpointer (bunch of pointles refcounting), perhaps just checkplane_state->crtc->state->commit? We do hold the necessary locks to at least look at that.
Then we'd always take the slowpath?
The point here was to check whether the current plane was part of the most recent commit, to know this we must either add a flip_planes mask member to drm_crtc_commit, or add a pointer in plane_state to the most recent commit it was part of.
_______________________________________________
Intel-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Re: [RFC PATCH 5/5] drm/atomic: Make async plane update checks work as intended.
Quoted 77 lines · Maarten Lankhorst
Op 30-08-17 om 14:46 schreef Daniel Vetter:
Quoted 63 lines · Maarten Lankhorst
Quoted 7 lines
By always keeping track of the last commit in
plane_state, we know whether there is an active update on the plane or not. With that information we can reject the fast update, and force the slowpath to be used as was originally intended.Cc Gustavo Padovan <[email protected]>Signed-off-by Maarten Lankhorst <[email protected]>Makes sense, but I think like patch 1 it would be better to do this in a separate series. Which would then include a patch to move i915 over to the async plane support.
One more comment below.
Quoted 49 lines
--- drivers/gpu/drm/drm_atomic_helper.c | 25 +++++++++++-------------- drivers/gpu/drm/i915/intel_display.c | 8 ++++++++ include/drm/drm_plane.h | 5 +++-- 3 files changed, 22 insertions(+), 16 deletions(-)drivers/gpu/drm/drm_atomic_helper.c +6
-9@@ -1388,8 +1388,8 @@ int drm_atomic_helper_async_check(struct drm_device *dev, {struct drm_crtc *crtc;struct drm_crtc_state *crtc_state; -struct drm_plane *__plane, *plane =NULL ; -struct drm_plane_state *__plane_state, *plane_state =NULL ; +struct drm_plane *plane; +struct drm_plane_state *old_plane_state, *new_plane_state;const struct drm_plane_helper_funcs *funcs;int i, n_planes =0 ;@@ -1398,33 +1398,33 @@ int drm_atomic_helper_async_check(struct drm_device *dev,return -EINVAL ; } -for_each_new_plane_in_state (state, __plane, __plane_state, i) { +for_each_oldnew_plane_in_state (state, plane, old_plane_state, new_plane_state, i) n_planes++; - plane = __plane; - plane_state = __plane_state; - }/* FIXME: we support only single plane updates for now */ -if (!plane || n_planes !=1 ) +if (n_planes !=1 )return -EINVAL ; -if (!plane_state->crtc) +if (!new_plane_state->crtc)return -EINVAL ; funcs = plane->helper_private;if (!funcs->atomic_async_update)return -EINVAL ; -if (plane_state->fence) +if (new_plane_state->fence)return -EINVAL ;Quoted 13 lines
drivers/gpu/drm/drm_atomic_helper.c int drm_atomic_helper_async_check(struct drm_device *dev, · line 1425
Quoted 9 lines
drivers/gpu/drm/drm_atomic_helper.c +4
-1/* -* TODO: Don't do an async update if there is an outstanding commit modifying +* Don't do an async update if there is an outstanding commit modifying * the plane. This prevents our async update's changes from getting * overridden by a previous synchronous update's state. */ +if (old_plane_state->commit && + !try_wait_for_completion (&old_plane_state->commit->hw_done)) +return -EBUSY ;Instead of forcing us to always set the
plane_state->commitpointer (bunch of pointles refcounting), perhaps just checkplane_state->crtc->state->commit? We do hold the necessary locks to at least look at that.
Quoted 6 lines
Then we'd always take the slowpath?
The point here was to check whether the current plane was part of the most recent commit, to know this we must either add a
flip_planesmask member todrm_crtc_commit, or add a pointer inplane_stateto the most recent commit it was part of.
Hm right, that would block us against ongoing page_flips ... I guess tracking commits at the plane level makes sense. If you can add that to the commit message please, since otherwise I'll forget again? -Daniel
Signature · 7 lines
Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch _______________________________________________ Intel-gfx mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Gustavo Padovan
Reviewed-byRe: [Intel-gfx] [RFC PATCH 5/5] drm/atomic: Make async plane update checks work as intended.
In reply to Daniel Vetter2017-08-30 Daniel Vetter <[email protected]>:
Quoted 6 lines · Maarten Lankhorst
Quoted 5 lines
By always keeping track of the last commit in
plane_state, we know whether there is an active update on the plane or not. With that information we can reject the fast update, and force the slowpath to be used as was originally intended.
Quoted 6 lines
Quoted 2 lines
Cc Gustavo Padovan <[email protected]>Signed-off-by Maarten Lankhorst <[email protected]>Makes sense, but I think like patch 1 it would be better to do this in a separate series. Which would then include a patch to move i915 over to the async plane support.
This patch makes sense to me and it is better than the fix I wrote but never got around to send it out. I can pick in here locally, put the patches I have here for the drivers on top of it and send to intel-gfx for CI.
Anyway, without the i915 change, this is
Gustavo
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Daniel Vetter
Reviewed-byRe: [Intel-gfx] [RFC PATCH 5/5] drm/atomic: Make async plane update checks work as intended.
Quoted 15 lines · Gustavo Padovan
2017-08-30 Daniel Vetter <[email protected]>:
Quoted 6 lines · Maarten Lankhorst
Quoted 5 lines
By always keeping track of the last commit in
plane_state, we know whether there is an active update on the plane or not. With that information we can reject the fast update, and force the slowpath to be used as was originally intended.Quoted 6 lines
Quoted 2 lines
Cc Gustavo Padovan <[email protected]>Signed-off-by Maarten Lankhorst <[email protected]>Makes sense, but I think like patch 1 it would be better to do this in a separate series. Which would then include a patch to move i915 over to the async plane support.
Quoted 7 lines
This patch makes sense to me and it is better than the fix I wrote but never got around to send it out. I can pick in here locally, put the patches I have here for the drivers on top of it and send to intel-gfx for CI.
Anyway, without the i915 change, this is
Reviewed-by Gustavo Padovan <[email protected]>
I can supply the r-b for the i915 hunk :-)
Signature · 7 lines
Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel