mirror of
https://github.com/torvalds/linux.git
synced 2026-03-13 22:36:17 +01:00
drm/display: bridge_connector: get/put the stored bridges
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. Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> Tested-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> # db410c Tested-by: Geert Uytterhoeven <geert+renesas@glider.be> Tested-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com> Tested-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com> Link: https://patch.msgid.link/20251017-drm-bridge-alloc-getput-bridge-connector-fix-hdmi_cec-v2-2-667abf6d47c0@bootlin.com Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
This commit is contained in:
parent
b402753693
commit
13adb8c978
1 changed files with 39 additions and 13 deletions
|
|
@ -618,6 +618,20 @@ static const struct drm_connector_hdmi_cec_funcs drm_bridge_connector_hdmi_cec_f
|
|||
* Bridge Connector Initialisation
|
||||
*/
|
||||
|
||||
static void drm_bridge_connector_put_bridges(struct drm_device *dev, void *data)
|
||||
{
|
||||
struct drm_bridge_connector *bridge_connector = (struct drm_bridge_connector *)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 bridges
|
||||
* @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);
|
||||
|
||||
ret = drmm_add_action(drm, drm_bridge_connector_put_bridges, bridge_connector);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
bridge_connector->encoder = encoder;
|
||||
|
||||
/*
|
||||
|
|
@ -672,14 +690,22 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
|
|||
if (!bridge->ycbcr_420_allowed)
|
||||
connector->ycbcr_420_allowed = false;
|
||||
|
||||
if (bridge->ops & DRM_BRIDGE_OP_EDID)
|
||||
bridge_connector->bridge_edid = bridge;
|
||||
if (bridge->ops & DRM_BRIDGE_OP_HPD)
|
||||
bridge_connector->bridge_hpd = bridge;
|
||||
if (bridge->ops & DRM_BRIDGE_OP_DETECT)
|
||||
bridge_connector->bridge_detect = bridge;
|
||||
if (bridge->ops & DRM_BRIDGE_OP_MODES)
|
||||
bridge_connector->bridge_modes = bridge;
|
||||
if (bridge->ops & DRM_BRIDGE_OP_EDID) {
|
||||
drm_bridge_put(bridge_connector->bridge_edid);
|
||||
bridge_connector->bridge_edid = drm_bridge_get(bridge);
|
||||
}
|
||||
if (bridge->ops & DRM_BRIDGE_OP_HPD) {
|
||||
drm_bridge_put(bridge_connector->bridge_hpd);
|
||||
bridge_connector->bridge_hpd = drm_bridge_get(bridge);
|
||||
}
|
||||
if (bridge->ops & DRM_BRIDGE_OP_DETECT) {
|
||||
drm_bridge_put(bridge_connector->bridge_detect);
|
||||
bridge_connector->bridge_detect = drm_bridge_get(bridge);
|
||||
}
|
||||
if (bridge->ops & DRM_BRIDGE_OP_MODES) {
|
||||
drm_bridge_put(bridge_connector->bridge_modes);
|
||||
bridge_connector->bridge_modes = 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);
|
||||
|
||||
bridge_connector->bridge_hdmi = bridge;
|
||||
bridge_connector->bridge_hdmi = drm_bridge_get(bridge);
|
||||
|
||||
if (bridge->supported_formats)
|
||||
supported_formats = 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);
|
||||
|
||||
bridge_connector->bridge_hdmi_audio = bridge;
|
||||
bridge_connector->bridge_hdmi_audio = drm_bridge_get(bridge);
|
||||
}
|
||||
|
||||
if (bridge->ops & DRM_BRIDGE_OP_DP_AUDIO) {
|
||||
|
|
@ -728,21 +754,21 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
|
|||
!bridge->funcs->dp_audio_shutdown)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
bridge_connector->bridge_dp_audio = bridge;
|
||||
bridge_connector->bridge_dp_audio = drm_bridge_get(bridge);
|
||||
}
|
||||
|
||||
if (bridge->ops & DRM_BRIDGE_OP_HDMI_CEC_NOTIFIER) {
|
||||
if (bridge_connector->bridge_hdmi_cec)
|
||||
return ERR_PTR(-EBUSY);
|
||||
|
||||
bridge_connector->bridge_hdmi_cec = bridge;
|
||||
bridge_connector->bridge_hdmi_cec = drm_bridge_get(bridge);
|
||||
}
|
||||
|
||||
if (bridge->ops & DRM_BRIDGE_OP_HDMI_CEC_ADAPTER) {
|
||||
if (bridge_connector->bridge_hdmi_cec)
|
||||
return ERR_PTR(-EBUSY);
|
||||
|
||||
bridge_connector->bridge_hdmi_cec = bridge;
|
||||
bridge_connector->bridge_hdmi_cec = drm_bridge_get(bridge);
|
||||
|
||||
if (!bridge->funcs->hdmi_cec_enable ||
|
||||
!bridge->funcs->hdmi_cec_log_addr ||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue