These loops in drm_bridge.c iterate over the encoder chain using list_for_each_entry_reverse), which does not prevent changes to the bridge chain while iterating over it.
Take the encoder chain mutex while iterating to avoid chain changes while iterating. All the "simple" loops are converted. drm_atomic_bridge_chain_pre_enable() and drm_atomic_bridge_chain_post_disable() are handled by a separate commit. Signed-off-by: Luca Ceresoli <[email protected]> --- drivers/gpu/drm/drm_bridge.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 554959147a00efa9807c245290cba8977ce88fc5..66c0a80db8426ffb360248895cfe2a11d6007ed7 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -706,6 +706,7 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, return; encoder = bridge->encoder; + drm_encoder_chain_lock(encoder); list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { if (iter->funcs->atomic_disable) { iter->funcs->atomic_disable(iter, state); @@ -716,6 +717,7 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, if (iter == bridge) break; } + drm_encoder_chain_unlock(encoder); } EXPORT_SYMBOL(drm_atomic_bridge_chain_disable); @@ -1220,6 +1222,7 @@ int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, return ret; encoder = bridge->encoder; + drm_encoder_chain_lock(encoder); list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { int ret; @@ -1234,12 +1237,15 @@ int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, crtc_state->state); ret = drm_atomic_bridge_check(iter, crtc_state, conn_state); - if (ret) + if (ret) { + drm_encoder_chain_unlock(encoder); return ret; + } if (iter == bridge) break; } + drm_encoder_chain_unlock(encoder); return 0; } -- 2.51.0
