]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/bridge: prevent encoder chain changes while iterating with list_for_each_entry_re...
authorLuca Ceresoli <luca.ceresoli@bootlin.com>
Tue, 24 Mar 2026 08:58:13 +0000 (09:58 +0100)
committerLuca Ceresoli <luca.ceresoli@bootlin.com>
Thu, 16 Apr 2026 07:08:42 +0000 (09:08 +0200)
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.

Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>
Link: https://patch.msgid.link/20260324-drm-bridge-alloc-encoder-chain-mutex-v5-6-8bf786c5c7e6@bootlin.com
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
drivers/gpu/drm/drm_bridge.c

index 344b7f317bf4df78763290499f3b478ca4a09b04..86e9c49232f71c8c124e496031d00385150d6caa 100644 (file)
@@ -808,6 +808,7 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge,
                return;
 
        encoder = bridge->encoder;
+       mutex_lock(&encoder->bridge_chain_mutex);
        list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
                if (iter->funcs->atomic_disable) {
                        iter->funcs->atomic_disable(iter, state);
@@ -818,6 +819,7 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge,
                if (iter == bridge)
                        break;
        }
+       mutex_unlock(&encoder->bridge_chain_mutex);
 }
 EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
 
@@ -1322,25 +1324,27 @@ int drm_atomic_bridge_chain_check(struct drm_bridge *bridge,
                return ret;
 
        encoder = bridge->encoder;
-       list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
-               int ret;
-
-               /*
-                * Bus flags are propagated by default. If a bridge needs to
-                * tweak the input bus flags for any reason, it should happen
-                * in its &drm_bridge_funcs.atomic_check() implementation such
-                * that preceding bridges in the chain can propagate the new
-                * bus flags.
-                */
-               drm_atomic_bridge_propagate_bus_flags(iter, conn,
-                                                     crtc_state->state);
-
-               ret = drm_atomic_bridge_check(iter, crtc_state, conn_state);
-               if (ret)
-                       return ret;
+       scoped_guard(mutex, &encoder->bridge_chain_mutex) {
+               list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
+                       int ret;
+
+                       /*
+                        * Bus flags are propagated by default. If a bridge needs to
+                        * tweak the input bus flags for any reason, it should happen
+                        * in its &drm_bridge_funcs.atomic_check() implementation such
+                        * that preceding bridges in the chain can propagate the new
+                        * bus flags.
+                        */
+                       drm_atomic_bridge_propagate_bus_flags(iter, conn,
+                                                             crtc_state->state);
+
+                       ret = drm_atomic_bridge_check(iter, crtc_state, conn_state);
+                       if (ret)
+                               return ret;
 
-               if (iter == bridge)
-                       break;
+                       if (iter == bridge)
+                               break;
+               }
        }
 
        return 0;