public inbox for linux-arm-kernel@lists.infradead.org
 help / color / mirror / Atom feed
* [PATCH v5] drm/bridge: add of_drm_find_and_get_bridge() and a managed *next_bridge, deprecate of_drm_find_bridge()
@ 2026-02-03 10:35 Luca Ceresoli
  2026-02-03 10:35 ` [PATCH v5] drm/bridge: imx8qxp-pixel-link: get/put the next bridge Luca Ceresoli
  0 siblings, 1 reply; 6+ messages in thread
From: Luca Ceresoli @ 2026-02-03 10:35 UTC (permalink / raw)
  To: Liu Ying, Andrzej Hajda, Neil Armstrong, Robert Foss,
	Laurent Pinchart, Jonas Karlman, Jernej Skrabec,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam
  Cc: Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel, imx,
	linux-arm-kernel, linux-kernel, Luca Ceresoli

This v4 contains the leftovers of the v3 series that deprecated
of_drm_find_bridge(), added a replacement which handles bridge refcounting,
and converted some of the direct users. All patches have been applied
except the imx8qxp-pixel-link ones, which still need a review for the first
patch.

@Liu, patch 1 is waiting for a review and it's non-trivial, it would be
nice if you could have a look at that one at least.

This is part of the work to support hotplug of DRM bridges. The grand plan
was discussed in [0].

Here's the work breakdown (➜ marks the current series):

 1. ➜ add refcounting to DRM bridges struct drm_bridge,
      based on devm_drm_bridge_alloc()
    A. ✔ add new alloc API and refcounting (v6.16)
    B. ✔ convert all bridge drivers to new API (v6.17)
    C. ✔ kunit tests (v6.17)
    D. ✔ add get/put to drm_bridge_add/remove() + attach/detach()
         and warn on old allocation pattern (v6.17)
    E. ➜ add get/put on drm_bridge accessors
       1. ✔ drm_bridge_chain_get_first_bridge(), add cleanup action (v6.18)
       2. ✔ drm_bridge_get_prev_bridge() (v6.18)
       3. ✔ drm_bridge_get_next_bridge() (v6.19)
       4. ✔ drm_for_each_bridge_in_chain() (v6.19)
       5. ✔ drm_bridge_connector_init (v6.19)
       6. … protect encoder bridge chain with a mutex
       7. ➜ of_drm_find_bridge()
          a. ➜✔… add of_drm_get_bridge(), convert basic direct users
	         (v6.20?, one driver still pending)
	  b. convert other direct users
	  c. convert bridge-only drm_of_find_panel_or_bridge() users
       8. drm_of_find_panel_or_bridge, *_of_get_bridge
       9. ✔ enforce drm_bridge_add before drm_bridge_attach (v6.19)
    F. ✔ debugfs improvements
       1. ✔ add top-level 'bridges' file (v6.16)
       2. ✔ show refcount and list lingering bridges (v6.19)
 2. … handle gracefully atomic updates during bridge removal
    A. ✔ Add drm_dev_enter/exit() to protect device resources (v6.20?)
    B. … protect private_obj removal from list
 3. … DSI host-device driver interaction
 4. ✔ removing the need for the "always-disconnected" connector
 5. finish the hotplug bridge work, moving code to the core and potentially
    removing the hotplug-bridge itself (this needs to be clarified as
    points 1-3 are developed)

[0] https://lore.kernel.org/lkml/20250206-hotplug-drm-bridge-v6-0-9d6f2c9c3058@bootlin.com/#t

Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
Changes in v5:
- Changed the only remaining patch after Liu Ying's requests for code
  readability
- Link to v4: https://lore.kernel.org/r/20260107-drm-bridge-alloc-getput-drm_of_find_bridge-v4-0-a62b4399a6bf@bootlin.com

Changes in v4:
- Added review trailers
- Link to v3: https://lore.kernel.org/r/20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com

Changes in v3:
- Completely rewrote using the __drm_bridge_free() idea to prevent
  use-after-free of the next_bridge for the common cases
- Added needed cleanups to the imx8qxp-pixel-link and imx8qxp-pxl2dpi
  drivers
- Removed various patches converting simple cases, to reduce the number of
  e-mails sent; will be moved to the follow-up series
- Link to v2: https://lore.kernel.org/r/20251128-drm-bridge-alloc-getput-drm_of_find_bridge-v2-0-88f8a107eca2@bootlin.com

Changes in v2:
- All patches: renamed drm_of_find_bridge() -> of_drm_get_bridge()
- Various fixes and improvements to patches 1-6, see individual patches
  changelog
- Removed bouncing recipient: Edmund Dea <edmund.j.dea@intel.com>
- Link to v1: https://lore.kernel.org/r/20251119-drm-bridge-alloc-getput-drm_of_find_bridge-v1-0-0db98a7fe474@bootlin.com

---
Luca Ceresoli (1):
      drm/bridge: imx8qxp-pixel-link: get/put the next bridge

 drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)
---
base-commit: 4a0f7d0f51c0965a8a394a8c5d65be2d24e362df
change-id: 20251117-drm-bridge-alloc-getput-drm_of_find_bridge-74903367448d

Best regards,
--  
Luca Ceresoli <luca.ceresoli@bootlin.com>



^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v5] drm/bridge: imx8qxp-pixel-link: get/put the next bridge
  2026-02-03 10:35 [PATCH v5] drm/bridge: add of_drm_find_and_get_bridge() and a managed *next_bridge, deprecate of_drm_find_bridge() Luca Ceresoli
@ 2026-02-03 10:35 ` Luca Ceresoli
  2026-02-04  6:27   ` Liu Ying
  0 siblings, 1 reply; 6+ messages in thread
From: Luca Ceresoli @ 2026-02-03 10:35 UTC (permalink / raw)
  To: Liu Ying, Andrzej Hajda, Neil Armstrong, Robert Foss,
	Laurent Pinchart, Jonas Karlman, Jernej Skrabec,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam
  Cc: Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel, imx,
	linux-arm-kernel, linux-kernel, Luca Ceresoli

This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
function and stores it until driver removal. of_drm_find_bridge() is
deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
refcounted and use bridge->next_bridge to put the reference on
deallocation.

To keep the code as simple and reliable as possible, get a reference for
each pointer that stores a drm_bridge address when it is stored and release
it when the pointer is overwritten or goes out of scope. Also remove the
intermediate selected_bridge variable to reduce the refcounted variables in
the function. The involved pointers are:

 * next_bridge loop-local variable:
   - get reference by of_drm_find_and_get_bridge()
   - put reference at the end of the loop iteration (__free)

 * pl->bridge.next_bridge, tied to struct imx8qxp_pixel_link lifetime:
   - get reference when assigned (by copy from next_bridge)
   - put reference before reassignment if reassignment happens
   - put reference when the struct imx8qxp_pixel_link embedding the
     struct drm_bridge is destroyed (struct drm_bridge::next_bridge)

Additionally, split the somewhat complex if() for readability.

Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>

---

Changes in v5:
- rewrite commit message after Liu's review to clarify the per-pointer
  get/put idea
- split the if()s involved in selcting the bridge
- remove intermediate selected_bridge pointer
- removed Maxime's R-by, patch changed
---
 drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
index 91e4f4d55469..e29e099b893a 100644
--- a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
+++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
@@ -23,7 +23,6 @@
 
 struct imx8qxp_pixel_link {
 	struct drm_bridge bridge;
-	struct drm_bridge *next_bridge;
 	struct device *dev;
 	struct imx_sc_ipc *ipc_handle;
 	u8 stream_id;
@@ -140,7 +139,7 @@ static int imx8qxp_pixel_link_bridge_attach(struct drm_bridge *bridge,
 	}
 
 	return drm_bridge_attach(encoder,
-				 pl->next_bridge, bridge,
+				 pl->bridge.next_bridge, bridge,
 				 DRM_BRIDGE_ATTACH_NO_CONNECTOR);
 }
 
@@ -260,7 +259,6 @@ static int imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
 {
 	struct device_node *np = pl->dev->of_node;
 	struct device_node *port;
-	struct drm_bridge *selected_bridge = NULL;
 	u32 port_id;
 	bool found_port = false;
 	int reg;
@@ -297,7 +295,8 @@ static int imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
 			continue;
 		}
 
-		struct drm_bridge *next_bridge = of_drm_find_bridge(remote);
+		struct drm_bridge *next_bridge __free(drm_bridge_put) =
+			of_drm_find_and_get_bridge(remote);
 		if (!next_bridge)
 			return -EPROBE_DEFER;
 
@@ -305,12 +304,16 @@ static int imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
 		 * Select the next bridge with companion PXL2DPI if
 		 * present, otherwise default to the first bridge
 		 */
-		if (!selected_bridge || of_property_present(remote, "fsl,companion-pxl2dpi"))
-			selected_bridge = next_bridge;
+		if (!pl->bridge.next_bridge)
+			pl->bridge.next_bridge = drm_bridge_get(next_bridge);
+
+		if (of_property_present(remote, "fsl,companion-pxl2dpi")) {
+			drm_bridge_put(pl->bridge.next_bridge);
+			pl->bridge.next_bridge = drm_bridge_get(next_bridge);
+		}
 	}
 
 	pl->mst_addr = port_id - 1;
-	pl->next_bridge = selected_bridge;
 
 	return 0;
 }

-- 
2.52.0



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v5] drm/bridge: imx8qxp-pixel-link: get/put the next bridge
  2026-02-03 10:35 ` [PATCH v5] drm/bridge: imx8qxp-pixel-link: get/put the next bridge Luca Ceresoli
@ 2026-02-04  6:27   ` Liu Ying
  2026-02-05  8:52     ` Luca Ceresoli
  0 siblings, 1 reply; 6+ messages in thread
From: Liu Ying @ 2026-02-04  6:27 UTC (permalink / raw)
  To: Luca Ceresoli, Andrzej Hajda, Neil Armstrong, Robert Foss,
	Laurent Pinchart, Jonas Karlman, Jernej Skrabec,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam
  Cc: Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel, imx,
	linux-arm-kernel, linux-kernel

Hi Luca,

On Tue, Feb 03, 2026 at 11:35:25AM +0100, Luca Ceresoli wrote:
> This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
> function and stores it until driver removal. of_drm_find_bridge() is
> deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
> refcounted and use bridge->next_bridge to put the reference on
> deallocation.
> 
> To keep the code as simple and reliable as possible, get a reference for
> each pointer that stores a drm_bridge address when it is stored and release
> it when the pointer is overwritten or goes out of scope. Also remove the
> intermediate selected_bridge variable to reduce the refcounted variables in
> the function. The involved pointers are:
> 
>  * next_bridge loop-local variable:
>    - get reference by of_drm_find_and_get_bridge()
>    - put reference at the end of the loop iteration (__free)
> 
>  * pl->bridge.next_bridge, tied to struct imx8qxp_pixel_link lifetime:
>    - get reference when assigned (by copy from next_bridge)
>    - put reference before reassignment if reassignment happens
>    - put reference when the struct imx8qxp_pixel_link embedding the
>      struct drm_bridge is destroyed (struct drm_bridge::next_bridge)
> 
> Additionally, split the somewhat complex if() for readability.
> 
> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
> 
> ---
> 
> Changes in v5:
> - rewrite commit message after Liu's review to clarify the per-pointer
>   get/put idea
> - split the if()s involved in selcting the bridge
> - remove intermediate selected_bridge pointer
> - removed Maxime's R-by, patch changed
> ---
>  drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c | 17 ++++++++++-------
>  1 file changed, 10 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
> index 91e4f4d55469..e29e099b893a 100644
> --- a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
> +++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
> @@ -23,7 +23,6 @@
>  
>  struct imx8qxp_pixel_link {
>  	struct drm_bridge bridge;
> -	struct drm_bridge *next_bridge;
>  	struct device *dev;
>  	struct imx_sc_ipc *ipc_handle;
>  	u8 stream_id;
> @@ -140,7 +139,7 @@ static int imx8qxp_pixel_link_bridge_attach(struct drm_bridge *bridge,
>  	}
>  
>  	return drm_bridge_attach(encoder,
> -				 pl->next_bridge, bridge,
> +				 pl->bridge.next_bridge, bridge,
>  				 DRM_BRIDGE_ATTACH_NO_CONNECTOR);
>  }
>  
> @@ -260,7 +259,6 @@ static int imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
>  {
>  	struct device_node *np = pl->dev->of_node;
>  	struct device_node *port;
> -	struct drm_bridge *selected_bridge = NULL;
>  	u32 port_id;
>  	bool found_port = false;
>  	int reg;
> @@ -297,7 +295,8 @@ static int imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
>  			continue;
>  		}
>  
> -		struct drm_bridge *next_bridge = of_drm_find_bridge(remote);
> +		struct drm_bridge *next_bridge __free(drm_bridge_put) =
> +			of_drm_find_and_get_bridge(remote);
>  		if (!next_bridge)
>  			return -EPROBE_DEFER;
>  
> @@ -305,12 +304,16 @@ static int imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
>  		 * Select the next bridge with companion PXL2DPI if
>  		 * present, otherwise default to the first bridge
>  		 */
> -		if (!selected_bridge || of_property_present(remote, "fsl,companion-pxl2dpi"))
> -			selected_bridge = next_bridge;
> +		if (!pl->bridge.next_bridge)
> +			pl->bridge.next_bridge = drm_bridge_get(next_bridge);
> +
> +		if (of_property_present(remote, "fsl,companion-pxl2dpi")) {
> +			drm_bridge_put(pl->bridge.next_bridge);
> +			pl->bridge.next_bridge = drm_bridge_get(next_bridge);
> +		}

Can you drop the intermediate next_bridge variable to simplify the code?

-8<-
if (!pl->bridge.next_bridge) {
        pl->bridge.next_bridge = of_drm_find_and_get_bridge(remote);
        if (!pl->bridge.next_bridge)
                return -EPROBE_DEFER;
}

if (of_property_present(remote, "fsl,companion-pxl2dpi")) {
        drm_bridge_put(pl->bridge.next_bridge);
        pl->bridge.next_bridge = of_drm_find_and_get_bridge(remote);
        if (!pl->bridge.next_bridge)
                return -EPROBE_DEFER;
}
-8<-

>  	}
>  
>  	pl->mst_addr = port_id - 1;
> -	pl->next_bridge = selected_bridge;
>  
>  	return 0;
>  }
> 

-- 
Regards,
Liu Ying


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v5] drm/bridge: imx8qxp-pixel-link: get/put the next bridge
  2026-02-04  6:27   ` Liu Ying
@ 2026-02-05  8:52     ` Luca Ceresoli
  2026-02-05  9:26       ` Liu Ying
  0 siblings, 1 reply; 6+ messages in thread
From: Luca Ceresoli @ 2026-02-05  8:52 UTC (permalink / raw)
  To: Liu Ying, Andrzej Hajda, Neil Armstrong, Robert Foss,
	Laurent Pinchart, Jonas Karlman, Jernej Skrabec,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam
  Cc: Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel, imx,
	linux-arm-kernel, linux-kernel

Hello Liu,

On Wed Feb 4, 2026 at 7:27 AM CET, Liu Ying wrote:
> Hi Luca,
>
> On Tue, Feb 03, 2026 at 11:35:25AM +0100, Luca Ceresoli wrote:
>> This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
>> function and stores it until driver removal. of_drm_find_bridge() is
>> deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
>> refcounted and use bridge->next_bridge to put the reference on
>> deallocation.
>>
>> To keep the code as simple and reliable as possible, get a reference for
>> each pointer that stores a drm_bridge address when it is stored and release
>> it when the pointer is overwritten or goes out of scope. Also remove the
>> intermediate selected_bridge variable to reduce the refcounted variables in
>> the function. The involved pointers are:
>>
>>  * next_bridge loop-local variable:
>>    - get reference by of_drm_find_and_get_bridge()
>>    - put reference at the end of the loop iteration (__free)
>>
>>  * pl->bridge.next_bridge, tied to struct imx8qxp_pixel_link lifetime:
>>    - get reference when assigned (by copy from next_bridge)
>>    - put reference before reassignment if reassignment happens
>>    - put reference when the struct imx8qxp_pixel_link embedding the
>>      struct drm_bridge is destroyed (struct drm_bridge::next_bridge)
>>
>> Additionally, split the somewhat complex if() for readability.
>>
>> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
>>
>> ---
>>
>> Changes in v5:
>> - rewrite commit message after Liu's review to clarify the per-pointer
>>   get/put idea
>> - split the if()s involved in selcting the bridge
>> - remove intermediate selected_bridge pointer
>> - removed Maxime's R-by, patch changed
>> ---
>>  drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c | 17 ++++++++++-------
>>  1 file changed, 10 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
>> index 91e4f4d55469..e29e099b893a 100644
>> --- a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
>> +++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
>> @@ -23,7 +23,6 @@
>>
>>  struct imx8qxp_pixel_link {
>>  	struct drm_bridge bridge;
>> -	struct drm_bridge *next_bridge;
>>  	struct device *dev;
>>  	struct imx_sc_ipc *ipc_handle;
>>  	u8 stream_id;
>> @@ -140,7 +139,7 @@ static int imx8qxp_pixel_link_bridge_attach(struct drm_bridge *bridge,
>>  	}
>>
>>  	return drm_bridge_attach(encoder,
>> -				 pl->next_bridge, bridge,
>> +				 pl->bridge.next_bridge, bridge,
>>  				 DRM_BRIDGE_ATTACH_NO_CONNECTOR);
>>  }
>>
>> @@ -260,7 +259,6 @@ static int imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
>>  {
>>  	struct device_node *np = pl->dev->of_node;
>>  	struct device_node *port;
>> -	struct drm_bridge *selected_bridge = NULL;
>>  	u32 port_id;
>>  	bool found_port = false;
>>  	int reg;
>> @@ -297,7 +295,8 @@ static int imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
>>  			continue;
>>  		}
>>
>> -		struct drm_bridge *next_bridge = of_drm_find_bridge(remote);
>> +		struct drm_bridge *next_bridge __free(drm_bridge_put) =
>> +			of_drm_find_and_get_bridge(remote);
>>  		if (!next_bridge)
>>  			return -EPROBE_DEFER;
>>
>> @@ -305,12 +304,16 @@ static int imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
>>  		 * Select the next bridge with companion PXL2DPI if
>>  		 * present, otherwise default to the first bridge
>>  		 */
>> -		if (!selected_bridge || of_property_present(remote, "fsl,companion-pxl2dpi"))
>> -			selected_bridge = next_bridge;
>> +		if (!pl->bridge.next_bridge)
>> +			pl->bridge.next_bridge = drm_bridge_get(next_bridge);
>> +
>> +		if (of_property_present(remote, "fsl,companion-pxl2dpi")) {
>> +			drm_bridge_put(pl->bridge.next_bridge);
>> +			pl->bridge.next_bridge = drm_bridge_get(next_bridge);
>> +		}
>
> Can you drop the intermediate next_bridge variable to simplify the code?
>
> -8<-
> if (!pl->bridge.next_bridge) {
>         pl->bridge.next_bridge = of_drm_find_and_get_bridge(remote);
>         if (!pl->bridge.next_bridge)
>                 return -EPROBE_DEFER;
> }
>
> if (of_property_present(remote, "fsl,companion-pxl2dpi")) {
>         drm_bridge_put(pl->bridge.next_bridge);
>         pl->bridge.next_bridge = of_drm_find_and_get_bridge(remote);
>         if (!pl->bridge.next_bridge)
>                 return -EPROBE_DEFER;
> }
> -8<-

Potentially calling of_drm_find_and_get_bridge() twice on the same node,
with a put in the middle, looks poorly readable to me, even though it still
looks correct code.

However I think we can do even better with an 'else if':

  if (!pl->bridge.next_bridge) {
         pl->bridge.next_bridge = of_drm_find_and_get_bridge(remote);
         if (!pl->bridge.next_bridge)
                 return -EPROBE_DEFER;
  } else if (of_property_present(remote, "fsl,companion-pxl2dpi")) {   <===
         drm_bridge_put(pl->bridge.next_bridge);
         pl->bridge.next_bridge = of_drm_find_and_get_bridge(remote);
         if (!pl->bridge.next_bridge)
                 return -EPROBE_DEFER;
  }

Looks OK?

Luca

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v5] drm/bridge: imx8qxp-pixel-link: get/put the next bridge
  2026-02-05  8:52     ` Luca Ceresoli
@ 2026-02-05  9:26       ` Liu Ying
  2026-02-11 21:27         ` Luca Ceresoli
  0 siblings, 1 reply; 6+ messages in thread
From: Liu Ying @ 2026-02-05  9:26 UTC (permalink / raw)
  To: Luca Ceresoli, Andrzej Hajda, Neil Armstrong, Robert Foss,
	Laurent Pinchart, Jonas Karlman, Jernej Skrabec,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam
  Cc: Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel, imx,
	linux-arm-kernel, linux-kernel

On Thu, Feb 05, 2026 at 09:52:04AM +0100, Luca Ceresoli wrote:
> Hello Liu,

Hello Luca,

> 
> On Wed Feb 4, 2026 at 7:27 AM CET, Liu Ying wrote:
>> Hi Luca,
>>
>> On Tue, Feb 03, 2026 at 11:35:25AM +0100, Luca Ceresoli wrote:
>>> This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
>>> function and stores it until driver removal. of_drm_find_bridge() is
>>> deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
>>> refcounted and use bridge->next_bridge to put the reference on
>>> deallocation.
>>>
>>> To keep the code as simple and reliable as possible, get a reference for
>>> each pointer that stores a drm_bridge address when it is stored and release
>>> it when the pointer is overwritten or goes out of scope. Also remove the
>>> intermediate selected_bridge variable to reduce the refcounted variables in
>>> the function. The involved pointers are:
>>>
>>>  * next_bridge loop-local variable:
>>>    - get reference by of_drm_find_and_get_bridge()
>>>    - put reference at the end of the loop iteration (__free)
>>>
>>>  * pl->bridge.next_bridge, tied to struct imx8qxp_pixel_link lifetime:
>>>    - get reference when assigned (by copy from next_bridge)
>>>    - put reference before reassignment if reassignment happens
>>>    - put reference when the struct imx8qxp_pixel_link embedding the
>>>      struct drm_bridge is destroyed (struct drm_bridge::next_bridge)
>>>
>>> Additionally, split the somewhat complex if() for readability.
>>>
>>> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
>>>
>>> ---
>>>
>>> Changes in v5:
>>> - rewrite commit message after Liu's review to clarify the per-pointer
>>>   get/put idea
>>> - split the if()s involved in selcting the bridge
>>> - remove intermediate selected_bridge pointer
>>> - removed Maxime's R-by, patch changed
>>> ---
>>>  drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c | 17 ++++++++++-------
>>>  1 file changed, 10 insertions(+), 7 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
>>> index 91e4f4d55469..e29e099b893a 100644
>>> --- a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
>>> +++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
>>> @@ -23,7 +23,6 @@
>>>
>>>  struct imx8qxp_pixel_link {
>>>  	struct drm_bridge bridge;
>>> -	struct drm_bridge *next_bridge;
>>>  	struct device *dev;
>>>  	struct imx_sc_ipc *ipc_handle;
>>>  	u8 stream_id;
>>> @@ -140,7 +139,7 @@ static int imx8qxp_pixel_link_bridge_attach(struct drm_bridge *bridge,
>>>  	}
>>>
>>>  	return drm_bridge_attach(encoder,
>>> -				 pl->next_bridge, bridge,
>>> +				 pl->bridge.next_bridge, bridge,
>>>  				 DRM_BRIDGE_ATTACH_NO_CONNECTOR);
>>>  }
>>>
>>> @@ -260,7 +259,6 @@ static int imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
>>>  {
>>>  	struct device_node *np = pl->dev->of_node;
>>>  	struct device_node *port;
>>> -	struct drm_bridge *selected_bridge = NULL;
>>>  	u32 port_id;
>>>  	bool found_port = false;
>>>  	int reg;
>>> @@ -297,7 +295,8 @@ static int imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
>>>  			continue;
>>>  		}
>>>
>>> -		struct drm_bridge *next_bridge = of_drm_find_bridge(remote);
>>> +		struct drm_bridge *next_bridge __free(drm_bridge_put) =
>>> +			of_drm_find_and_get_bridge(remote);
>>>  		if (!next_bridge)
>>>  			return -EPROBE_DEFER;
>>>
>>> @@ -305,12 +304,16 @@ static int imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
>>>  		 * Select the next bridge with companion PXL2DPI if
>>>  		 * present, otherwise default to the first bridge
>>>  		 */
>>> -		if (!selected_bridge || of_property_present(remote, "fsl,companion-pxl2dpi"))
>>> -			selected_bridge = next_bridge;
>>> +		if (!pl->bridge.next_bridge)
>>> +			pl->bridge.next_bridge = drm_bridge_get(next_bridge);
>>> +
>>> +		if (of_property_present(remote, "fsl,companion-pxl2dpi")) {
>>> +			drm_bridge_put(pl->bridge.next_bridge);
>>> +			pl->bridge.next_bridge = drm_bridge_get(next_bridge);
>>> +		}
>>
>> Can you drop the intermediate next_bridge variable to simplify the code?
>>
>> -8<-
>> if (!pl->bridge.next_bridge) {
>>         pl->bridge.next_bridge = of_drm_find_and_get_bridge(remote);
>>         if (!pl->bridge.next_bridge)
>>                 return -EPROBE_DEFER;
>> }
>>
>> if (of_property_present(remote, "fsl,companion-pxl2dpi")) {
>>         drm_bridge_put(pl->bridge.next_bridge);
>>         pl->bridge.next_bridge = of_drm_find_and_get_bridge(remote);
>>         if (!pl->bridge.next_bridge)
>>                 return -EPROBE_DEFER;
>> }
>> -8<-
> 
> Potentially calling of_drm_find_and_get_bridge() twice on the same node,
> with a put in the middle, looks poorly readable to me, even though it still
> looks correct code.
> 
> However I think we can do even better with an 'else if':
> 
>   if (!pl->bridge.next_bridge) {
>          pl->bridge.next_bridge = of_drm_find_and_get_bridge(remote);
>          if (!pl->bridge.next_bridge)
>                  return -EPROBE_DEFER;
>   } else if (of_property_present(remote, "fsl,companion-pxl2dpi")) {   <===
>          drm_bridge_put(pl->bridge.next_bridge);
>          pl->bridge.next_bridge = of_drm_find_and_get_bridge(remote);
>          if (!pl->bridge.next_bridge)
>                  return -EPROBE_DEFER;
>   }
> 
> Looks OK?

Both are fine to me.  TBH, I feel my version with two 'if's is a bit easier
to read.  But, I'd say up to you.

> 
> Luca
> 
> --
> Luca Ceresoli, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com/

-- 
Regards,
Liu Ying


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v5] drm/bridge: imx8qxp-pixel-link: get/put the next bridge
  2026-02-05  9:26       ` Liu Ying
@ 2026-02-11 21:27         ` Luca Ceresoli
  0 siblings, 0 replies; 6+ messages in thread
From: Luca Ceresoli @ 2026-02-11 21:27 UTC (permalink / raw)
  To: Liu Ying, Andrzej Hajda, Neil Armstrong, Robert Foss,
	Laurent Pinchart, Jonas Karlman, Jernej Skrabec,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam
  Cc: Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel, imx,
	linux-arm-kernel, linux-kernel

Hello Liu,

On Thu Feb 5, 2026 at 10:26 AM CET, Liu Ying wrote:
> On Thu, Feb 05, 2026 at 09:52:04AM +0100, Luca Ceresoli wrote:
>> Hello Liu,
>
> Hello Luca,
>
>>
>> On Wed Feb 4, 2026 at 7:27 AM CET, Liu Ying wrote:
>>> Hi Luca,
>>>
>>> On Tue, Feb 03, 2026 at 11:35:25AM +0100, Luca Ceresoli wrote:
>>>> This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
>>>> function and stores it until driver removal. of_drm_find_bridge() is
>>>> deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
>>>> refcounted and use bridge->next_bridge to put the reference on
>>>> deallocation.
>>>>
>>>> To keep the code as simple and reliable as possible, get a reference for
>>>> each pointer that stores a drm_bridge address when it is stored and release
>>>> it when the pointer is overwritten or goes out of scope. Also remove the
>>>> intermediate selected_bridge variable to reduce the refcounted variables in
>>>> the function. The involved pointers are:
>>>>
>>>>  * next_bridge loop-local variable:
>>>>    - get reference by of_drm_find_and_get_bridge()
>>>>    - put reference at the end of the loop iteration (__free)
>>>>
>>>>  * pl->bridge.next_bridge, tied to struct imx8qxp_pixel_link lifetime:
>>>>    - get reference when assigned (by copy from next_bridge)
>>>>    - put reference before reassignment if reassignment happens
>>>>    - put reference when the struct imx8qxp_pixel_link embedding the
>>>>      struct drm_bridge is destroyed (struct drm_bridge::next_bridge)
>>>>
>>>> Additionally, split the somewhat complex if() for readability.
>>>>
>>>> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
>>>>
>>>> ---
>>>>
>>>> Changes in v5:
>>>> - rewrite commit message after Liu's review to clarify the per-pointer
>>>>   get/put idea
>>>> - split the if()s involved in selcting the bridge
>>>> - remove intermediate selected_bridge pointer
>>>> - removed Maxime's R-by, patch changed
>>>> ---
>>>>  drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c | 17 ++++++++++-------
>>>>  1 file changed, 10 insertions(+), 7 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
>>>> index 91e4f4d55469..e29e099b893a 100644
>>>> --- a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
>>>> +++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
>>>> @@ -23,7 +23,6 @@
>>>>
>>>>  struct imx8qxp_pixel_link {
>>>>  	struct drm_bridge bridge;
>>>> -	struct drm_bridge *next_bridge;
>>>>  	struct device *dev;
>>>>  	struct imx_sc_ipc *ipc_handle;
>>>>  	u8 stream_id;
>>>> @@ -140,7 +139,7 @@ static int imx8qxp_pixel_link_bridge_attach(struct drm_bridge *bridge,
>>>>  	}
>>>>
>>>>  	return drm_bridge_attach(encoder,
>>>> -				 pl->next_bridge, bridge,
>>>> +				 pl->bridge.next_bridge, bridge,
>>>>  				 DRM_BRIDGE_ATTACH_NO_CONNECTOR);
>>>>  }
>>>>
>>>> @@ -260,7 +259,6 @@ static int imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
>>>>  {
>>>>  	struct device_node *np = pl->dev->of_node;
>>>>  	struct device_node *port;
>>>> -	struct drm_bridge *selected_bridge = NULL;
>>>>  	u32 port_id;
>>>>  	bool found_port = false;
>>>>  	int reg;
>>>> @@ -297,7 +295,8 @@ static int imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
>>>>  			continue;
>>>>  		}
>>>>
>>>> -		struct drm_bridge *next_bridge = of_drm_find_bridge(remote);
>>>> +		struct drm_bridge *next_bridge __free(drm_bridge_put) =
>>>> +			of_drm_find_and_get_bridge(remote);
>>>>  		if (!next_bridge)
>>>>  			return -EPROBE_DEFER;
>>>>
>>>> @@ -305,12 +304,16 @@ static int imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
>>>>  		 * Select the next bridge with companion PXL2DPI if
>>>>  		 * present, otherwise default to the first bridge
>>>>  		 */
>>>> -		if (!selected_bridge || of_property_present(remote, "fsl,companion-pxl2dpi"))
>>>> -			selected_bridge = next_bridge;
>>>> +		if (!pl->bridge.next_bridge)
>>>> +			pl->bridge.next_bridge = drm_bridge_get(next_bridge);
>>>> +
>>>> +		if (of_property_present(remote, "fsl,companion-pxl2dpi")) {
>>>> +			drm_bridge_put(pl->bridge.next_bridge);
>>>> +			pl->bridge.next_bridge = drm_bridge_get(next_bridge);
>>>> +		}
>>>
>>> Can you drop the intermediate next_bridge variable to simplify the code?
>>>
>>> -8<-
>>> if (!pl->bridge.next_bridge) {
>>>         pl->bridge.next_bridge = of_drm_find_and_get_bridge(remote);
>>>         if (!pl->bridge.next_bridge)
>>>                 return -EPROBE_DEFER;
>>> }
>>>
>>> if (of_property_present(remote, "fsl,companion-pxl2dpi")) {
>>>         drm_bridge_put(pl->bridge.next_bridge);
>>>         pl->bridge.next_bridge = of_drm_find_and_get_bridge(remote);
>>>         if (!pl->bridge.next_bridge)
>>>                 return -EPROBE_DEFER;
>>> }
>>> -8<-
>>
>> Potentially calling of_drm_find_and_get_bridge() twice on the same node,
>> with a put in the middle, looks poorly readable to me, even though it still
>> looks correct code.
>>
>> However I think we can do even better with an 'else if':
>>
>>   if (!pl->bridge.next_bridge) {
>>          pl->bridge.next_bridge = of_drm_find_and_get_bridge(remote);
>>          if (!pl->bridge.next_bridge)
>>                  return -EPROBE_DEFER;
>>   } else if (of_property_present(remote, "fsl,companion-pxl2dpi")) {   <===
>>          drm_bridge_put(pl->bridge.next_bridge);
>>          pl->bridge.next_bridge = of_drm_find_and_get_bridge(remote);
>>          if (!pl->bridge.next_bridge)
>>                  return -EPROBE_DEFER;
>>   }
>>
>> Looks OK?
>
> Both are fine to me.  TBH, I feel my version with two 'if's is a bit easier
> to read.  But, I'd say up to you.

I think this is really a minor detail and there is no obvious "best"
version, so I'll send v6 as I had it ready and build-tested already,
i.e. with the 'else if' version.

Thanks for the discussion!

Luca

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-02-11 21:28 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-03 10:35 [PATCH v5] drm/bridge: add of_drm_find_and_get_bridge() and a managed *next_bridge, deprecate of_drm_find_bridge() Luca Ceresoli
2026-02-03 10:35 ` [PATCH v5] drm/bridge: imx8qxp-pixel-link: get/put the next bridge Luca Ceresoli
2026-02-04  6:27   ` Liu Ying
2026-02-05  8:52     ` Luca Ceresoli
2026-02-05  9:26       ` Liu Ying
2026-02-11 21:27         ` Luca Ceresoli

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox