[PATCH 1/1] drm/bridge: Fix handling of bridges with pre_enable_prev_first flag

Vladimir Lypak vladimir.lypak at gmail.com
Fri Jul 7 19:00:19 UTC 2023


In function drm_atomic_bridge_chain_post_disable handling of
pre_enable_prev_first flag is broken because "next" variable will always
end up set to value of "bridge". This breaks loop which should disable
bridges in reverse:

 next = list_next_entry(bridge, chain_node);

 if (next->pre_enable_prev_first) {
        /* next bridge had requested that prev
         * was enabled first, so disabled last
         */
        limit = next;

        /* Find the next bridge that has NOT requested
         * prev to be enabled first / disabled last
         */
        list_for_each_entry_from(next, &encoder->bridge_chain,
                                 chain_node) {
// Next condition is always true. It is likely meant to be inversed
// according to comment above. But doing this uncovers another problem:
// it won't work if there are few bridges with this flag set at the end.
                if (next->pre_enable_prev_first) {
                        next = list_prev_entry(next, chain_node);
                        limit = next;
// Here we always set next = limit = branch at first iteration.
                        break;
                }
        }

        /* Call these bridges in reverse order */
        list_for_each_entry_from_reverse(next, &encoder->bridge_chain,
                                         chain_node) {
// This loop never executes past this branch.
                if (next == bridge)
                        break;

                drm_atomic_bridge_call_post_disable(next, old_state);

In this patch logic for handling the flag is simplified. Temporary
"iter" variable is introduced instead of "next" which is used only
inside inner loops.

Fixes: 4fb912e5e190 ("drm/bridge: Introduce pre_enable_prev_first to alter bridge init order")
Signed-off-by: Vladimir Lypak <vladimir.lypak at gmail.com>
---
 drivers/gpu/drm/drm_bridge.c | 46 ++++++++++++++----------------------
 1 file changed, 18 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index c3d69af02e79..7a5b39a46325 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -660,7 +660,7 @@ void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge,
 					  struct drm_atomic_state *old_state)
 {
 	struct drm_encoder *encoder;
-	struct drm_bridge *next, *limit;
+	struct drm_bridge *iter, *limit;
 
 	if (!bridge)
 		return;
@@ -670,36 +670,26 @@ void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge,
 	list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
 		limit = NULL;
 
-		if (!list_is_last(&bridge->chain_node, &encoder->bridge_chain)) {
-			next = list_next_entry(bridge, chain_node);
-
-			if (next->pre_enable_prev_first) {
-				/* next bridge had requested that prev
-				 * was enabled first, so disabled last
-				 */
-				limit = next;
-
-				/* Find the next bridge that has NOT requested
-				 * prev to be enabled first / disabled last
-				 */
-				list_for_each_entry_from(next, &encoder->bridge_chain,
-							 chain_node) {
-					if (next->pre_enable_prev_first) {
-						next = list_prev_entry(next, chain_node);
-						limit = next;
-						break;
-					}
-				}
+		/* Find sequence of bridges (bridge, limit] which requested prev to
+		 * be enabled first and disabled last
+		 */
+		iter = list_next_entry(bridge, chain_node);
+		list_for_each_entry_from(iter, &encoder->bridge_chain, chain_node) {
+			if (!iter->pre_enable_prev_first)
+				break;
+
+			limit = iter;
+		}
 
-				/* Call these bridges in reverse order */
-				list_for_each_entry_from_reverse(next, &encoder->bridge_chain,
-								 chain_node) {
-					if (next == bridge)
-						break;
-
-					drm_atomic_bridge_call_post_disable(next,
-									    old_state);
-				}
+		if (limit) {
+			/* Call these bridges in reverse order */
+			iter = limit;
+			list_for_each_entry_from_reverse(iter,
+					&encoder->bridge_chain, chain_node) {
+				if (iter == bridge)
+					break;
+
+				drm_atomic_bridge_call_post_disable(iter, old_state);
 			}
 		}
 
-- 
2.41.0



More information about the dri-devel mailing list