lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:   Thu, 21 Oct 2021 12:29:01 -0700
From:   Douglas Anderson <dianders@...omium.org>
To:     dri-devel@...ts.freedesktop.org
Cc:     Philip Chen <philipchen@...omium.org>,
        Douglas Anderson <dianders@...omium.org>,
        Boris Brezillon <boris.brezillon@...labora.com>,
        Daniel Vetter <daniel@...ll.ch>,
        David Airlie <airlied@...ux.ie>,
        Jagan Teki <jagan@...rulasolutions.com>,
        Laurent Pinchart <laurent.pinchart+renesas@...asonboard.com>,
        Maarten Lankhorst <maarten.lankhorst@...ux.intel.com>,
        Maxime Ripard <mripard@...nel.org>,
        Neil Armstrong <narmstrong@...libre.com>,
        Robert Foss <robert.foss@...aro.org>,
        Thomas Zimmermann <tzimmermann@...e.de>,
        linux-kernel@...r.kernel.org
Subject: [PATCH] drm/bridge: Fix the bridge chain order for pre_enable / post_disable

Right now, the chaining order of
pre_enable/enable/disable/post_disable looks like this:

pre_enable:   start from connector and move to encoder
enable:       start from encoder and move to connector
disable:      start from connector and move to encoder
post_disable: start from encoder and move to connector

In the above, it can be seen that at least pre_enable() and
post_disable() are opposites of each other and enable() and disable()
are opposites. However, it seems broken that pre_enable() and enable()
would not move in the same direction. In other parts of Linux you can
see that various stages move in the same order. For instance, during
system suspend the "early" calls run in the same order as the normal
calls run in the same order as the "late" calls run in the same order
as the "noirq" calls.

Let fix the above so that it makes more sense. Now we'll have:

pre_enable:   start from encoder and move to connector
enable:       start from encoder and move to connector
disable:      start from connector and move to encoder
post_disable: start from connector and move to encoder

This order is chosen because if there are parent-child relationships
anywhere I would expect that the encoder would be a parent and the
connector a child--not the other way around.

This can be important when using the DP AUX bus to instantiate a
panel. The DP AUX bus is likely part of a bridge driver and is a
parent of the panel. We'd like the bridge to be pre_enabled before the
panel and the panel to be post_disabled before the
bridge. Specifically, this allows pm_runtime_put_sync_suspend() in a
bridge driver's post_suspend to work properly even a panel is under
it.

NOTE: it's entirely possible that this change could break someone who
was relying on the old order. Hopefully this isn't the case, but if
this does break someone it seems like it's better to do it sonner
rather than later so we can fix everyone to handle the order that
makes the most sense.

A FURTHER NOTE: Looking closer at commit 4e5763f03e10 ("drm/bridge:
ti-sn65dsi86: Wrap panel with panel-bridge") you can see that patch
inadvertently changed the order of things. The order used to be
correct (panel prepare was at the tail of the bridge enable) but it
became backwards. We'll restore the original order with this patch.

Fixes: 4e5763f03e10 ("drm/bridge: ti-sn65dsi86: Wrap panel with panel-bridge")
Fixes: 05193dc38197 ("drm/bridge: Make the bridge chain a double-linked list")
Signed-off-by: Douglas Anderson <dianders@...omium.org>
---

 drivers/gpu/drm/drm_bridge.c | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index c96847fc0ebc..98808af59afd 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -583,18 +583,14 @@ EXPORT_SYMBOL(drm_bridge_chain_mode_set);
 void drm_bridge_chain_pre_enable(struct drm_bridge *bridge)
 {
 	struct drm_encoder *encoder;
-	struct drm_bridge *iter;
 
 	if (!bridge)
 		return;
 
 	encoder = bridge->encoder;
-	list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
-		if (iter->funcs->pre_enable)
-			iter->funcs->pre_enable(iter);
-
-		if (iter == bridge)
-			break;
+	list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
+		if (bridge->funcs->pre_enable)
+			bridge->funcs->pre_enable(bridge);
 	}
 }
 EXPORT_SYMBOL(drm_bridge_chain_pre_enable);
@@ -684,26 +680,30 @@ void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge,
 					  struct drm_atomic_state *old_state)
 {
 	struct drm_encoder *encoder;
+	struct drm_bridge *iter;
 
 	if (!bridge)
 		return;
 
 	encoder = bridge->encoder;
-	list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
-		if (bridge->funcs->atomic_post_disable) {
+	list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
+		if (iter->funcs->atomic_post_disable) {
 			struct drm_bridge_state *old_bridge_state;
 
 			old_bridge_state =
 				drm_atomic_get_old_bridge_state(old_state,
-								bridge);
+								iter);
 			if (WARN_ON(!old_bridge_state))
 				return;
 
-			bridge->funcs->atomic_post_disable(bridge,
-							   old_bridge_state);
-		} else if (bridge->funcs->post_disable) {
-			bridge->funcs->post_disable(bridge);
+			iter->funcs->atomic_post_disable(iter,
+							 old_bridge_state);
+		} else if (iter->funcs->post_disable) {
+			iter->funcs->post_disable(iter);
 		}
+
+		if (iter == bridge)
+			break;
 	}
 }
 EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
-- 
2.33.0.1079.g6e70778dc9-goog

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ