From e5e1a0000746ded4d9fa16fceda0748aec2b6e6a Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Fri, 9 Jan 2026 08:31:41 +0100 Subject: [PATCH] drm/bridge: samsung-dsim: samsung_dsim_host_attach: use a temporary variable for the next bridge In preparation to handle refcounting of the out_bridge, we need to ensure the out_bridge pointer contains either a valid bridge pointer or NULL, not an ERR_PTR. Otherwise calls such as drm_bridge_get/put() would try to redeference an ERR_PTR. As a preliminary cleanup, add a temporary local 'next_bridge' pointer and only copy it in dsi->out_bridge as late as possible, i.e. just before calling pdata->host_ops->attach() which uses it (only in the exynos driver). Not strictly needed, but for symmetry move the clearing of dsi->out_bridge in samsung_dsim_host_detach() to after pdata->host_ops->detach(). Acked-by: Maxime Ripard Tested-by: Marek Szyprowski Link: https://patch.msgid.link/20260109-drm-bridge-alloc-getput-drm_of_find_bridge-2-v2-10-8bad3ef90b9f@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/bridge/samsung-dsim.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index eabc4c32f6ab4..8dd058124e933 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -1886,6 +1886,7 @@ static int samsung_dsim_host_attach(struct mipi_dsi_host *host, { struct samsung_dsim *dsi = host_to_dsi(host); const struct samsung_dsim_plat_data *pdata = dsi->plat_data; + struct drm_bridge *next_bridge; struct device *dev = dsi->dev; struct device_node *np = dev->of_node; struct device_node *remote; @@ -1924,17 +1925,17 @@ of_find_panel_or_bridge: panel = of_drm_find_panel(remote); if (!IS_ERR(panel)) { - dsi->out_bridge = devm_drm_panel_bridge_add(dev, panel); + next_bridge = devm_drm_panel_bridge_add(dev, panel); } else { - dsi->out_bridge = of_drm_find_bridge(remote); - if (!dsi->out_bridge) - dsi->out_bridge = ERR_PTR(-EINVAL); + next_bridge = of_drm_find_bridge(remote); + if (!next_bridge) + next_bridge = ERR_PTR(-EINVAL); } of_node_put(remote); - if (IS_ERR(dsi->out_bridge)) { - ret = PTR_ERR(dsi->out_bridge); + if (IS_ERR(next_bridge)) { + ret = PTR_ERR(next_bridge); DRM_DEV_ERROR(dev, "failed to find the bridge: %d\n", ret); return ret; } @@ -1958,10 +1959,13 @@ of_find_panel_or_bridge: return ret; } + // The next bridge can be used by host_ops->attach + dsi->out_bridge = next_bridge; + if (pdata->host_ops && pdata->host_ops->attach) { ret = pdata->host_ops->attach(dsi, device); if (ret) - return ret; + goto err_release_next_bridge; } dsi->lanes = device->lanes; @@ -1969,6 +1973,10 @@ of_find_panel_or_bridge: dsi->mode_flags = device->mode_flags; return 0; + +err_release_next_bridge: + dsi->out_bridge = NULL; + return ret; } static void samsung_dsim_unregister_te_irq(struct samsung_dsim *dsi) @@ -1985,11 +1993,11 @@ static int samsung_dsim_host_detach(struct mipi_dsi_host *host, struct samsung_dsim *dsi = host_to_dsi(host); const struct samsung_dsim_plat_data *pdata = dsi->plat_data; - dsi->out_bridge = NULL; - if (pdata->host_ops && pdata->host_ops->detach) pdata->host_ops->detach(dsi, device); + dsi->out_bridge = NULL; + samsung_dsim_unregister_te_irq(dsi); drm_bridge_remove(&dsi->bridge); -- 2.47.3