From nobody Mon Feb 9 03:20:04 2026 Received: from smtpout-02.galae.net (smtpout-02.galae.net [185.246.84.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 76FAC2BE7CD for ; Fri, 17 Oct 2025 16:15:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.84.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760717750; cv=none; b=fJRsLnhmnuPnGf/RWcHMvdbA4i2P1V+ylh5lVKndjPvFYfLcyUVo7WIkeQd2MczYkyuMsm+h2EAXAUH29KKnyA/49Z5tF83C1RfFRhuNjopffKl3Ay+xBsegHHvLAVTEI9wlLD0hgGR2BifcJ2bTM/bx9LPKB/7YYe7xHZTFU1Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760717750; c=relaxed/simple; bh=czoOsq71YeBmeZTSfCv8GRKj2niLLuNt4X6xQprXSY0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=So2h9kzGnoNuxDLFr65T+R9zuXk9Ji4cU2386jBbEqpG5KGP9/DJDipeRpJyVuvciuWggxOLF+Tm7edUyI1BXs3ApTvZA2Az3gBxss80coZKXXi1IYASdXeyNw+oa4Htm0aDMWZ0/L1ZIEAG+AG/sN4sETa3AqhEqU+WNxxslyE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=yLQWAAaF; arc=none smtp.client-ip=185.246.84.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="yLQWAAaF" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-02.galae.net (Postfix) with ESMTPS id BD7561A1476; Fri, 17 Oct 2025 16:15:45 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 93AC6606DB; Fri, 17 Oct 2025 16:15:45 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 99207102F235B; Fri, 17 Oct 2025 18:15:42 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1760717744; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=+Lxo9LHWsvDkpogxDakPiZH8k4KgCyFe/SU/GRt++l4=; b=yLQWAAaFWvMLhdbGJ1R1W447C8ntabI1PCc4kQg1APlfK9G4E5fqUdjXN13r3Cjwe+9Rxv I46bEY3CdUyTwKzOCtIExfGCpwbcqSgLQgnTIJJyKrFJCl86SdIcohx1cvxZmF/Zu/XSR3 0ts6aBa2dJgHe9OQHDTVXIvObM93//Mq9gr6GrXqJDTYgoSgX2lbc0x2ILzoBPY5Wt2o8B cgNglUc7RkflxxPKNy8rNhjyougA7AGQP31S7Gm+zjlNigKmrqbjgcbHIu7UDbhMiCJx4E 0kLIwuqKe7dNh24Xmoqkl44CMnb+YAPBJICeh1lJF23Yxz82/ShK+AV8QMkD0A== From: Luca Ceresoli Date: Fri, 17 Oct 2025 18:15:04 +0200 Subject: [PATCH v2 1/3] Revert "drm/display: bridge_connector: get/put the stored bridges" Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251017-drm-bridge-alloc-getput-bridge-connector-fix-hdmi_cec-v2-1-667abf6d47c0@bootlin.com> References: <20251017-drm-bridge-alloc-getput-bridge-connector-fix-hdmi_cec-v2-0-667abf6d47c0@bootlin.com> In-Reply-To: <20251017-drm-bridge-alloc-getput-bridge-connector-fix-hdmi_cec-v2-0-667abf6d47c0@bootlin.com> To: Marek Szyprowski , Naresh Kamboju , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Dmitry Baryshkov Cc: Hui Pu , Thomas Petazzoni , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Luca Ceresoli X-Mailer: b4 0.14.2 X-Last-TLS-Session-Version: TLSv1.3 This reverts commit 2be300f9a0b6f6b0ae2a90be97e558ec0535be54. The commit being reverted moved all the bridge_connector->bridge_* assignments to just before the final successful return in order to handle the bridge refcounting in a clean way. This introduced a bug, because a bit before the successful return drmm_connector_hdmi_cec_register() is called, which calls funcs->init() which is drm_bridge_connector_hdmi_cec_init() which needs bridge_connector->bridge_hdmi_cec to be set. The reported bug may be fixed in a relatively simple way, but other similar patterns are potentially present, so just revert the offending commit. A different approach will be implemented. Fixes: 2be300f9a0b6 ("drm/display: bridge_connector: get/put the stored bri= dges") Reported-by: Marek Szyprowski Closes: https://lore.kernel.org/all/336fbfdd-c424-490e-b5d1-8ee84043dc80@sa= msung.com/ Reported-by: Naresh Kamboju Closes: https://lore.kernel.org/r/CA+G9fYuKHp3QgPKjgFY3TfkDdh5Vf=3DAe5pCW+e= U41Bu=3DD7th2g@mail.gmail.com Signed-off-by: Luca Ceresoli Reviewed-by: Dmitry Baryshkov Reviewed-by: Louis Chauvet Tested-by entirely. Tested-by: Dmitry Baryshkov # db410c Tested-by: Geert Uytterhoeven Tested-by: Marek Szyprowski Tested-by: Tommaso Merciai --- Changes in v2: none --- drivers/gpu/drm/display/drm_bridge_connector.c | 114 ++++++++-------------= ---- 1 file changed, 36 insertions(+), 78 deletions(-) diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/d= rm/display/drm_bridge_connector.c index 7b18be3ff9a32b362468351835bdab43c3f524f1..a5bdd6c1064399ece6b19560f14= 5b877c9e0680e 100644 --- a/drivers/gpu/drm/display/drm_bridge_connector.c +++ b/drivers/gpu/drm/display/drm_bridge_connector.c @@ -618,20 +618,6 @@ static const struct drm_connector_hdmi_cec_funcs drm_b= ridge_connector_hdmi_cec_f * Bridge Connector Initialisation */ =20 -static void drm_bridge_connector_put_bridges(struct drm_device *dev, void = *data) -{ - struct drm_bridge_connector *bridge_connector =3D (struct drm_bridge_conn= ector *)data; - - drm_bridge_put(bridge_connector->bridge_edid); - drm_bridge_put(bridge_connector->bridge_hpd); - drm_bridge_put(bridge_connector->bridge_detect); - drm_bridge_put(bridge_connector->bridge_modes); - drm_bridge_put(bridge_connector->bridge_hdmi); - drm_bridge_put(bridge_connector->bridge_hdmi_audio); - drm_bridge_put(bridge_connector->bridge_dp_audio); - drm_bridge_put(bridge_connector->bridge_hdmi_cec); -} - /** * drm_bridge_connector_init - Initialise a connector for a chain of bridg= es * @drm: the DRM device @@ -652,15 +638,7 @@ struct drm_connector *drm_bridge_connector_init(struct= drm_device *drm, struct drm_bridge_connector *bridge_connector; struct drm_connector *connector; struct i2c_adapter *ddc =3D NULL; - struct drm_bridge *panel_bridge __free(drm_bridge_put) =3D NULL; - struct drm_bridge *bridge_edid __free(drm_bridge_put) =3D NULL; - struct drm_bridge *bridge_hpd __free(drm_bridge_put) =3D NULL; - struct drm_bridge *bridge_detect __free(drm_bridge_put) =3D NULL; - struct drm_bridge *bridge_modes __free(drm_bridge_put) =3D NULL; - struct drm_bridge *bridge_hdmi __free(drm_bridge_put) =3D NULL; - struct drm_bridge *bridge_hdmi_audio __free(drm_bridge_put) =3D NULL; - struct drm_bridge *bridge_dp_audio __free(drm_bridge_put) =3D NULL; - struct drm_bridge *bridge_hdmi_cec __free(drm_bridge_put) =3D NULL; + struct drm_bridge *panel_bridge =3D NULL; unsigned int supported_formats =3D BIT(HDMI_COLORSPACE_RGB); unsigned int max_bpc =3D 8; bool support_hdcp =3D false; @@ -671,10 +649,6 @@ struct drm_connector *drm_bridge_connector_init(struct= drm_device *drm, if (!bridge_connector) return ERR_PTR(-ENOMEM); =20 - ret =3D drmm_add_action(drm, drm_bridge_connector_put_bridges, bridge_con= nector); - if (ret) - return ERR_PTR(ret); - bridge_connector->encoder =3D encoder; =20 /* @@ -698,30 +672,22 @@ struct drm_connector *drm_bridge_connector_init(struc= t drm_device *drm, if (!bridge->ycbcr_420_allowed) connector->ycbcr_420_allowed =3D false; =20 - if (bridge->ops & DRM_BRIDGE_OP_EDID) { - drm_bridge_put(bridge_edid); - bridge_edid =3D drm_bridge_get(bridge); - } - if (bridge->ops & DRM_BRIDGE_OP_HPD) { - drm_bridge_put(bridge_hpd); - bridge_hpd =3D drm_bridge_get(bridge); - } - if (bridge->ops & DRM_BRIDGE_OP_DETECT) { - drm_bridge_put(bridge_detect); - bridge_detect =3D drm_bridge_get(bridge); - } - if (bridge->ops & DRM_BRIDGE_OP_MODES) { - drm_bridge_put(bridge_modes); - bridge_modes =3D drm_bridge_get(bridge); - } + if (bridge->ops & DRM_BRIDGE_OP_EDID) + bridge_connector->bridge_edid =3D bridge; + if (bridge->ops & DRM_BRIDGE_OP_HPD) + bridge_connector->bridge_hpd =3D bridge; + if (bridge->ops & DRM_BRIDGE_OP_DETECT) + bridge_connector->bridge_detect =3D bridge; + if (bridge->ops & DRM_BRIDGE_OP_MODES) + bridge_connector->bridge_modes =3D bridge; if (bridge->ops & DRM_BRIDGE_OP_HDMI) { - if (bridge_hdmi) + if (bridge_connector->bridge_hdmi) return ERR_PTR(-EBUSY); if (!bridge->funcs->hdmi_write_infoframe || !bridge->funcs->hdmi_clear_infoframe) return ERR_PTR(-EINVAL); =20 - bridge_hdmi =3D drm_bridge_get(bridge); + bridge_connector->bridge_hdmi =3D bridge; =20 if (bridge->supported_formats) supported_formats =3D bridge->supported_formats; @@ -730,10 +696,10 @@ struct drm_connector *drm_bridge_connector_init(struc= t drm_device *drm, } =20 if (bridge->ops & DRM_BRIDGE_OP_HDMI_AUDIO) { - if (bridge_hdmi_audio) + if (bridge_connector->bridge_hdmi_audio) return ERR_PTR(-EBUSY); =20 - if (bridge_dp_audio) + if (bridge_connector->bridge_dp_audio) return ERR_PTR(-EBUSY); =20 if (!bridge->hdmi_audio_max_i2s_playback_channels && @@ -744,14 +710,14 @@ struct drm_connector *drm_bridge_connector_init(struc= t drm_device *drm, !bridge->funcs->hdmi_audio_shutdown) return ERR_PTR(-EINVAL); =20 - bridge_hdmi_audio =3D drm_bridge_get(bridge); + bridge_connector->bridge_hdmi_audio =3D bridge; } =20 if (bridge->ops & DRM_BRIDGE_OP_DP_AUDIO) { - if (bridge_dp_audio) + if (bridge_connector->bridge_dp_audio) return ERR_PTR(-EBUSY); =20 - if (bridge_hdmi_audio) + if (bridge_connector->bridge_hdmi_audio) return ERR_PTR(-EBUSY); =20 if (!bridge->hdmi_audio_max_i2s_playback_channels && @@ -762,7 +728,7 @@ struct drm_connector *drm_bridge_connector_init(struct = drm_device *drm, !bridge->funcs->dp_audio_shutdown) return ERR_PTR(-EINVAL); =20 - bridge_dp_audio =3D drm_bridge_get(bridge); + bridge_connector->bridge_dp_audio =3D bridge; } =20 if (bridge->ops & DRM_BRIDGE_OP_HDMI_CEC_NOTIFIER) { @@ -773,10 +739,10 @@ struct drm_connector *drm_bridge_connector_init(struc= t drm_device *drm, } =20 if (bridge->ops & DRM_BRIDGE_OP_HDMI_CEC_ADAPTER) { - if (bridge_hdmi_cec) + if (bridge_connector->bridge_hdmi_cec) return ERR_PTR(-EBUSY); =20 - bridge_hdmi_cec =3D drm_bridge_get(bridge); + bridge_connector->bridge_hdmi_cec =3D bridge; =20 if (!bridge->funcs->hdmi_cec_enable || !bridge->funcs->hdmi_cec_log_addr || @@ -796,7 +762,7 @@ struct drm_connector *drm_bridge_connector_init(struct = drm_device *drm, ddc =3D bridge->ddc; =20 if (drm_bridge_is_panel(bridge)) - panel_bridge =3D drm_bridge_get(bridge); + panel_bridge =3D bridge; =20 if (bridge->support_hdcp) support_hdcp =3D true; @@ -805,13 +771,13 @@ struct drm_connector *drm_bridge_connector_init(struc= t drm_device *drm, if (connector_type =3D=3D DRM_MODE_CONNECTOR_Unknown) return ERR_PTR(-EINVAL); =20 - if (bridge_hdmi) { + if (bridge_connector->bridge_hdmi) { if (!connector->ycbcr_420_allowed) supported_formats &=3D ~BIT(HDMI_COLORSPACE_YUV420); =20 ret =3D drmm_connector_hdmi_init(drm, connector, - bridge_hdmi->vendor, - bridge_hdmi->product, + bridge_connector->bridge_hdmi->vendor, + bridge_connector->bridge_hdmi->product, &drm_bridge_connector_funcs, &drm_bridge_connector_hdmi_funcs, connector_type, ddc, @@ -827,14 +793,15 @@ struct drm_connector *drm_bridge_connector_init(struc= t drm_device *drm, return ERR_PTR(ret); } =20 - if (bridge_hdmi_audio || bridge_dp_audio) { + if (bridge_connector->bridge_hdmi_audio || + bridge_connector->bridge_dp_audio) { struct device *dev; struct drm_bridge *bridge; =20 - if (bridge_hdmi_audio) - bridge =3D bridge_hdmi_audio; + if (bridge_connector->bridge_hdmi_audio) + bridge =3D bridge_connector->bridge_hdmi_audio; else - bridge =3D bridge_dp_audio; + bridge =3D bridge_connector->bridge_dp_audio; =20 dev =3D bridge->hdmi_audio_dev; =20 @@ -848,9 +815,9 @@ struct drm_connector *drm_bridge_connector_init(struct = drm_device *drm, return ERR_PTR(ret); } =20 - if (bridge_hdmi_cec && - bridge_hdmi_cec->ops & DRM_BRIDGE_OP_HDMI_CEC_NOTIFIER) { - struct drm_bridge *bridge =3D bridge_hdmi_cec; + if (bridge_connector->bridge_hdmi_cec && + bridge_connector->bridge_hdmi_cec->ops & DRM_BRIDGE_OP_HDMI_CEC_NOTIF= IER) { + struct drm_bridge *bridge =3D bridge_connector->bridge_hdmi_cec; =20 ret =3D drmm_connector_hdmi_cec_notifier_register(connector, NULL, @@ -859,9 +826,9 @@ struct drm_connector *drm_bridge_connector_init(struct = drm_device *drm, return ERR_PTR(ret); } =20 - if (bridge_hdmi_cec && - bridge_hdmi_cec->ops & DRM_BRIDGE_OP_HDMI_CEC_ADAPTER) { - struct drm_bridge *bridge =3D bridge_hdmi_cec; + if (bridge_connector->bridge_hdmi_cec && + bridge_connector->bridge_hdmi_cec->ops & DRM_BRIDGE_OP_HDMI_CEC_ADAPT= ER) { + struct drm_bridge *bridge =3D bridge_connector->bridge_hdmi_cec; =20 ret =3D drmm_connector_hdmi_cec_register(connector, &drm_bridge_connector_hdmi_cec_funcs, @@ -874,9 +841,9 @@ struct drm_connector *drm_bridge_connector_init(struct = drm_device *drm, =20 drm_connector_helper_add(connector, &drm_bridge_connector_helper_funcs); =20 - if (bridge_hpd) + if (bridge_connector->bridge_hpd) connector->polled =3D DRM_CONNECTOR_POLL_HPD; - else if (bridge_detect) + else if (bridge_connector->bridge_detect) connector->polled =3D DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; =20 @@ -887,15 +854,6 @@ struct drm_connector *drm_bridge_connector_init(struct= drm_device *drm, IS_ENABLED(CONFIG_DRM_DISPLAY_HDCP_HELPER)) drm_connector_attach_content_protection_property(connector, true); =20 - bridge_connector->bridge_edid =3D drm_bridge_get(bridge_edid); - bridge_connector->bridge_hpd =3D drm_bridge_get(bridge_hpd); - bridge_connector->bridge_detect =3D drm_bridge_get(bridge_detect); - bridge_connector->bridge_modes =3D drm_bridge_get(bridge_modes); - bridge_connector->bridge_hdmi =3D drm_bridge_get(bridge_hdmi); - bridge_connector->bridge_hdmi_audio =3D drm_bridge_get(bridge_hdmi_audio); - bridge_connector->bridge_dp_audio =3D drm_bridge_get(bridge_dp_audio); - bridge_connector->bridge_hdmi_cec =3D drm_bridge_get(bridge_hdmi_cec); - return connector; } EXPORT_SYMBOL_GPL(drm_bridge_connector_init); --=20 2.51.0 From nobody Mon Feb 9 03:20:04 2026 Received: from smtpout-02.galae.net (smtpout-02.galae.net [185.246.84.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 87D8E2BE64C for ; Fri, 17 Oct 2025 16:15:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.84.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760717752; cv=none; b=E5okPf+tlIkHlxjpEEubdmVddDAYjbR/JDfuYyL4z8DKF5Ab6DcCvWbEAln75DqTfhF8XeET8B3BnDaBldpXkmiSwvcpgdyR1vRgL3Qj6aobPPEauiqOYYAoCA88DJdYGSFq8y2V0OI+8c04JKTLkHq933lKkaINWFMKmc1+zPw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760717752; c=relaxed/simple; bh=XBMOcB5q4xrcoFGgvtQ/jzvKHjTGs1MimnWOMlogoDI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=qwFQXO1VuudL/LppRnXMW9z3HqXUP3YHSVEgueMtpJsRQxjU2DIs2Ox7WGM/3AX4zOUt9mSGPyf1qlhOAAOFH65B0dv0qQh/p/Zn3cH37dBYeqc3+Cw3yx4c9ZYbyWMdArFchn3t+7BBFWBrNcHNFKpzjDCXT0bUU3+iGxFYENQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=1fHduYnJ; arc=none smtp.client-ip=185.246.84.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="1fHduYnJ" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-02.galae.net (Postfix) with ESMTPS id C3D331A1483; Fri, 17 Oct 2025 16:15:48 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 9881E606DB; Fri, 17 Oct 2025 16:15:48 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 252E6102F2361; Fri, 17 Oct 2025 18:15:44 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1760717747; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=TcoDsORlor4mmaUdW6zET3q7u/9c8G/+kpyV7LHDxM8=; b=1fHduYnJ4bACBS4Bsxt2cTDAt0BI41fTKq800HE5xPlbrJmMa1ei/RlsVgpBu9iXT9HFN/ VtPa64oHRtWkDqZ936Ee6Ai+v5U4KE44VLBPtPfgt2iHQu1V0a5TGdxuJZxrWpGmioNxi9 Yo1o2Hd4rzhx+RoxczPYHkrXMoZz5f4m0RxR02T1W1adrdjrh+tjBeJPX+iq4/5yxL1qmP wMJDHsXak1OIyc/kmXXSYZGQr7mWiEt3UxsY4CGhXGlzJFHi0HX4BboPFz0CGSvgRFpaFq XsxczabVC9u9m0uCPAcDVOB5mFXNJ/mEkAUuizUrX7/fVd+S/h8Ul0YVYz6z/Q== From: Luca Ceresoli Date: Fri, 17 Oct 2025 18:15:05 +0200 Subject: [PATCH v2 2/3] drm/display: bridge_connector: get/put the stored bridges Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251017-drm-bridge-alloc-getput-bridge-connector-fix-hdmi_cec-v2-2-667abf6d47c0@bootlin.com> References: <20251017-drm-bridge-alloc-getput-bridge-connector-fix-hdmi_cec-v2-0-667abf6d47c0@bootlin.com> In-Reply-To: <20251017-drm-bridge-alloc-getput-bridge-connector-fix-hdmi_cec-v2-0-667abf6d47c0@bootlin.com> To: Marek Szyprowski , Naresh Kamboju , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Dmitry Baryshkov Cc: Hui Pu , Thomas Petazzoni , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Luca Ceresoli X-Mailer: b4 0.14.2 X-Last-TLS-Session-Version: TLSv1.3 drm_bridge_connector_init() takes eight pointers to various bridges, some of which can be identical, and stores them in pointers inside struct drm_bridge_connector. Get a reference to each of the taken bridges and put it on cleanup. Achieve this by adding a drmm cleanup callback whic puts all the non-NULL bridges. Using drmm ensures the cleanup happens on drm_device teardown, whichever is the return value of this function. Four of these pointers (edid, hpd, detect and modes) can be written multiple times (up to once per loop iterations), in order to eventually store the last matching bridge. So when one of those pointers is overwritten, we need to put the reference that we got during the previous assignment. Add a drm_bridge_put() before writing them to handle this. Signed-off-by: Luca Ceresoli Reviewed-by: Dmitry Baryshkov Reviewed-by: Louis Chauvet Tested-by: Dmitry Baryshkov # db410c Tested-by: Geert Uytterhoeven Tested-by: Marek Szyprowski Tested-by: Tommaso Merciai --- This patch was added in v2: - it is a rewrite of the original (buggy) patch, but simpler after realizing thanks to drmm we don't need the temporary pointers as the stored pointers will be put just before deallocating - compared to the original patch, moved the panel_bridge changes to a separate patch for clarity --- drivers/gpu/drm/display/drm_bridge_connector.c | 52 +++++++++++++++++++---= ---- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/d= rm/display/drm_bridge_connector.c index a5bdd6c1064399ece6b19560f145b877c9e0680e..95ccf86527129edaa6fcc75c620= 2985e73c46da8 100644 --- a/drivers/gpu/drm/display/drm_bridge_connector.c +++ b/drivers/gpu/drm/display/drm_bridge_connector.c @@ -618,6 +618,20 @@ static const struct drm_connector_hdmi_cec_funcs drm_b= ridge_connector_hdmi_cec_f * Bridge Connector Initialisation */ =20 +static void drm_bridge_connector_put_bridges(struct drm_device *dev, void = *data) +{ + struct drm_bridge_connector *bridge_connector =3D (struct drm_bridge_conn= ector *)data; + + drm_bridge_put(bridge_connector->bridge_edid); + drm_bridge_put(bridge_connector->bridge_hpd); + drm_bridge_put(bridge_connector->bridge_detect); + drm_bridge_put(bridge_connector->bridge_modes); + drm_bridge_put(bridge_connector->bridge_hdmi); + drm_bridge_put(bridge_connector->bridge_hdmi_audio); + drm_bridge_put(bridge_connector->bridge_dp_audio); + drm_bridge_put(bridge_connector->bridge_hdmi_cec); +} + /** * drm_bridge_connector_init - Initialise a connector for a chain of bridg= es * @drm: the DRM device @@ -649,6 +663,10 @@ struct drm_connector *drm_bridge_connector_init(struct= drm_device *drm, if (!bridge_connector) return ERR_PTR(-ENOMEM); =20 + ret =3D drmm_add_action(drm, drm_bridge_connector_put_bridges, bridge_con= nector); + if (ret) + return ERR_PTR(ret); + bridge_connector->encoder =3D encoder; =20 /* @@ -672,14 +690,22 @@ struct drm_connector *drm_bridge_connector_init(struc= t drm_device *drm, if (!bridge->ycbcr_420_allowed) connector->ycbcr_420_allowed =3D false; =20 - if (bridge->ops & DRM_BRIDGE_OP_EDID) - bridge_connector->bridge_edid =3D bridge; - if (bridge->ops & DRM_BRIDGE_OP_HPD) - bridge_connector->bridge_hpd =3D bridge; - if (bridge->ops & DRM_BRIDGE_OP_DETECT) - bridge_connector->bridge_detect =3D bridge; - if (bridge->ops & DRM_BRIDGE_OP_MODES) - bridge_connector->bridge_modes =3D bridge; + if (bridge->ops & DRM_BRIDGE_OP_EDID) { + drm_bridge_put(bridge_connector->bridge_edid); + bridge_connector->bridge_edid =3D drm_bridge_get(bridge); + } + if (bridge->ops & DRM_BRIDGE_OP_HPD) { + drm_bridge_put(bridge_connector->bridge_hpd); + bridge_connector->bridge_hpd =3D drm_bridge_get(bridge); + } + if (bridge->ops & DRM_BRIDGE_OP_DETECT) { + drm_bridge_put(bridge_connector->bridge_detect); + bridge_connector->bridge_detect =3D drm_bridge_get(bridge); + } + if (bridge->ops & DRM_BRIDGE_OP_MODES) { + drm_bridge_put(bridge_connector->bridge_modes); + bridge_connector->bridge_modes =3D drm_bridge_get(bridge); + } if (bridge->ops & DRM_BRIDGE_OP_HDMI) { if (bridge_connector->bridge_hdmi) return ERR_PTR(-EBUSY); @@ -687,7 +713,7 @@ struct drm_connector *drm_bridge_connector_init(struct = drm_device *drm, !bridge->funcs->hdmi_clear_infoframe) return ERR_PTR(-EINVAL); =20 - bridge_connector->bridge_hdmi =3D bridge; + bridge_connector->bridge_hdmi =3D drm_bridge_get(bridge); =20 if (bridge->supported_formats) supported_formats =3D bridge->supported_formats; @@ -710,7 +736,7 @@ struct drm_connector *drm_bridge_connector_init(struct = drm_device *drm, !bridge->funcs->hdmi_audio_shutdown) return ERR_PTR(-EINVAL); =20 - bridge_connector->bridge_hdmi_audio =3D bridge; + bridge_connector->bridge_hdmi_audio =3D drm_bridge_get(bridge); } =20 if (bridge->ops & DRM_BRIDGE_OP_DP_AUDIO) { @@ -728,21 +754,21 @@ struct drm_connector *drm_bridge_connector_init(struc= t drm_device *drm, !bridge->funcs->dp_audio_shutdown) return ERR_PTR(-EINVAL); =20 - bridge_connector->bridge_dp_audio =3D bridge; + bridge_connector->bridge_dp_audio =3D drm_bridge_get(bridge); } =20 if (bridge->ops & DRM_BRIDGE_OP_HDMI_CEC_NOTIFIER) { if (bridge_connector->bridge_hdmi_cec) return ERR_PTR(-EBUSY); =20 - bridge_connector->bridge_hdmi_cec =3D bridge; + bridge_connector->bridge_hdmi_cec =3D drm_bridge_get(bridge); } =20 if (bridge->ops & DRM_BRIDGE_OP_HDMI_CEC_ADAPTER) { if (bridge_connector->bridge_hdmi_cec) return ERR_PTR(-EBUSY); =20 - bridge_connector->bridge_hdmi_cec =3D bridge; + bridge_connector->bridge_hdmi_cec =3D drm_bridge_get(bridge); =20 if (!bridge->funcs->hdmi_cec_enable || !bridge->funcs->hdmi_cec_log_addr || --=20 2.51.0 From nobody Mon Feb 9 03:20:04 2026 Received: from smtpout-04.galae.net (smtpout-04.galae.net [185.171.202.116]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 62E462BEC4A for ; Fri, 17 Oct 2025 16:15:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.171.202.116 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760717754; cv=none; b=Le5R+14PYH8xV5eRCoCEACCc0HcDJVT6ltFxl8KRbyRCVhGI6cD9hsJuckieagqtenFiEpMzVhxYS0m/xDAAserBxklhm9CcWAy3kz89x57mxpE3BDXkP0GNE3zP26iQ6Ctn1h3sbMhHx2KQ2ad92xyd6zrL1VXyN14pTGAYNCs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760717754; c=relaxed/simple; bh=Rhbv2GJPo2sczGthMx5gRHSAtvlHAWGofonAGIPwQ7s=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=fdU5BBPgBMLPq9PDxS44h+gKWatfxLCpsw1EkDGPQGURjO40beMz/24V1iJ1EPSAFrIZyGU94rKSWFoLwLEqcnPLZdxQKe/zJSzCKb0Lkg7NLKt6gcwostjlV1Ip4ygartG/L/IyBGLbPMkZF4KI8NG0fR7hxLRz4NlhGoa1RLY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=M46xBQ0C; arc=none smtp.client-ip=185.171.202.116 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="M46xBQ0C" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id 627E4C041FB; Fri, 17 Oct 2025 16:15:31 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id ACFD5606DB; Fri, 17 Oct 2025 16:15:50 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id D28D6102F2326; Fri, 17 Oct 2025 18:15:47 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1760717749; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=sF/nhZKtfysMmP54ubTvP/iQM/X0HdA/QjQ50RURtXU=; b=M46xBQ0Cqed1BxM8oRLaViX5BJmNwme4wCTVE3XLHaIthNEs1xOI9NUK2vbzoOH7BuM8R5 nsBbnKQeNI+nzcMvpn1Edr9J1xO/GRH3Do1/i4GcT/26LlZ8586uanLUm5bEF2MfUUTlfU 9ImBuVky8gIH10sRHhfa8x4VOSFvPIK1utx3o7qDQHe3lqrGFW2ZRRmEKjlCyCGmeV43ue XiWM8rmhPZPo4kJXicKAJn6jJu6TSSKIEa7ilj873CaKNd3hAH2GE5bViC2nA5MlZZENXV OYpzxusqHgaUwcR53AtrcRCe7I/KSl7qB7cOKGb+Ond2lz5q49PtMrm6EZvMCA== From: Luca Ceresoli Date: Fri, 17 Oct 2025 18:15:06 +0200 Subject: [PATCH v2 3/3] drm/display: bridge_connector: get/put the panel_bridge Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251017-drm-bridge-alloc-getput-bridge-connector-fix-hdmi_cec-v2-3-667abf6d47c0@bootlin.com> References: <20251017-drm-bridge-alloc-getput-bridge-connector-fix-hdmi_cec-v2-0-667abf6d47c0@bootlin.com> In-Reply-To: <20251017-drm-bridge-alloc-getput-bridge-connector-fix-hdmi_cec-v2-0-667abf6d47c0@bootlin.com> To: Marek Szyprowski , Naresh Kamboju , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Dmitry Baryshkov Cc: Hui Pu , Thomas Petazzoni , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Luca Ceresoli X-Mailer: b4 0.14.2 X-Last-TLS-Session-Version: TLSv1.3 The panel_bridge pointer is taken inside the loop and used after the loop. Being a local variable, use a cleanup action to ensure it is put on return. Based on the code structure the panel_bridge pointer might be assigned during multiple loop iterations. Even though this is probably not possible in the practice, ensure there is no reference leak by putting the reference to the old value before overwriting with the new value. Signed-off-by: Luca Ceresoli Reviewed-by: Dmitry Baryshkov Reviewed-by: Louis Chauvet Tested-by: Dmitry Baryshkov # db410c Tested-by: Geert Uytterhoeven Tested-by: Marek Szyprowski Tested-by: Tommaso Merciai --- This patch was added in v2: - taking the panel_bridge specific code from the original (buggy) patch, and split it for clarity from the larger patch covering stored bridge pointers - comapred to the original code, added drm_bridge_put() for extra safety even though likely not necessary --- drivers/gpu/drm/display/drm_bridge_connector.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/d= rm/display/drm_bridge_connector.c index 95ccf86527129edaa6fcc75c6202985e73c46da8..a2d30cf9e06df44b89456b5aba8= 198ee1e5d5601 100644 --- a/drivers/gpu/drm/display/drm_bridge_connector.c +++ b/drivers/gpu/drm/display/drm_bridge_connector.c @@ -652,7 +652,7 @@ struct drm_connector *drm_bridge_connector_init(struct = drm_device *drm, struct drm_bridge_connector *bridge_connector; struct drm_connector *connector; struct i2c_adapter *ddc =3D NULL; - struct drm_bridge *panel_bridge =3D NULL; + struct drm_bridge *panel_bridge __free(drm_bridge_put) =3D NULL; unsigned int supported_formats =3D BIT(HDMI_COLORSPACE_RGB); unsigned int max_bpc =3D 8; bool support_hdcp =3D false; @@ -787,8 +787,10 @@ struct drm_connector *drm_bridge_connector_init(struct= drm_device *drm, if (bridge->ddc) ddc =3D bridge->ddc; =20 - if (drm_bridge_is_panel(bridge)) - panel_bridge =3D bridge; + if (drm_bridge_is_panel(bridge)) { + drm_bridge_put(panel_bridge); + panel_bridge =3D drm_bridge_get(bridge); + } =20 if (bridge->support_hdcp) support_hdcp =3D true; --=20 2.51.0