[PATCH RFC v2 06/24] drm/display: bridge-connector: add APIs to add/remove the connector dynamically
From: Luca Ceresoli
Date: Thu Oct 01 2026 - 08:59:50 EST
drm_bridge_connector_init() adds a drmm-allocated connector. For bridge
hotplug drmm allocations are not suitable because a connector may have to
be added and removed multiple times in the lifetime of a card.
In preparation for bridge hotplug, add APIs to add and remove a connector
using regular non-managed allocations.
For the dynamic connector, this requires the kfree() the allocated struct
drm_bridge_connector in the destroy func. However that func will be called
even when using the pre-existing drmm API, leading to a double free
(kfree() in the destroy callback + drmm).
One option to avoid this issue is introducing two mostly identical
drm_connector_funcs instances, one with .destroy and one without. But that
would be an annoying code duplication. Instead take a different approach:
always allocate using non-drmm kzalloc_obj(), so that deallocation always
happen in destroy->kfree().
Signed-off-by: Luca Ceresoli <luca.ceresoli@xxxxxxxxxxx>
---
Uhm, maybe the change from drmm_kzalloc to kzalloc_obj and addition of
kfree to the destroy callback should eb a separate commit?
---
drivers/gpu/drm/display/drm_bridge_connector.c | 24 +++++++++++++++++++++++-
include/drm/drm_bridge_connector.h | 4 ++++
2 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 1c222e27767d..2a0065208fb8 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -285,6 +285,7 @@ static void drm_bridge_connector_dynconn_destroy(struct drm_connector *connector
drm_connector_cleanup(connector);
drm_bridge_connector_put_bridges(bridge_connector);
+ kfree(bridge_connector);
}
static const struct drm_connector_funcs drm_bridge_connector_funcs = {
@@ -1184,7 +1185,7 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
struct drm_connector *connector;
int ret;
- bridge_connector = drmm_kzalloc(drm, sizeof(*bridge_connector), GFP_KERNEL);
+ bridge_connector = kzalloc_obj(*bridge_connector);
if (!bridge_connector)
return ERR_PTR(-ENOMEM);
@@ -1199,3 +1200,24 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
return connector;
}
EXPORT_SYMBOL_GPL(drm_bridge_connector_init);
+
+struct drm_connector *drm_bridge_connector_dynamic_add(struct drm_device *drm,
+ struct drm_encoder *encoder)
+{
+ struct drm_bridge_connector *bridge_connector;
+
+ bridge_connector = kzalloc_obj(*bridge_connector);
+ if (!bridge_connector)
+ return ERR_PTR(-ENOMEM);
+
+ return drm_bridge_connector_initialize(bridge_connector, drm, encoder);
+}
+EXPORT_SYMBOL_GPL(drm_bridge_connector_dynamic_add);
+
+void drm_bridge_connector_dynamic_remove(struct drm_connector *connector)
+{
+ struct drm_bridge_connector *bridge_connector = to_drm_bridge_connector(connector);
+
+ drm_bridge_connector_fini(bridge_connector);
+}
+EXPORT_SYMBOL_GPL(drm_bridge_connector_dynamic_remove);
diff --git a/include/drm/drm_bridge_connector.h b/include/drm/drm_bridge_connector.h
index 69630815fb09..de6ec91dbfab 100644
--- a/include/drm/drm_bridge_connector.h
+++ b/include/drm/drm_bridge_connector.h
@@ -9,8 +9,12 @@
struct drm_connector;
struct drm_device;
struct drm_encoder;
+struct drm_bridge_connector;
struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
struct drm_encoder *encoder);
+struct drm_connector *drm_bridge_connector_dynamic_add(struct drm_device *drm,
+ struct drm_encoder *encoder);
+void drm_bridge_connector_dynamic_remove(struct drm_connector *connector);
#endif /* __DRM_BRIDGE_CONNECTOR_H__ */
--
2.55.0