diff options
| author | Luca Ceresoli <luca.ceresoli@bootlin.com> | 2025-03-26 18:47:36 +0100 |
|---|---|---|
| committer | Louis Chauvet <louis.chauvet@bootlin.com> | 2025-04-07 11:38:04 +0200 |
| commit | 30d1b37d4c022b5e6c164c090a60a3be1a66876e (patch) | |
| tree | a2ae4c064d59d7a6d996a639319237588172ace0 /drivers/gpu/drm/drm_bridge.c | |
| parent | 0cc6aadd7fc1e629b715ea3d1ba537ef2da95eec (diff) | |
| download | linux-next-30d1b37d4c022b5e6c164c090a60a3be1a66876e.tar.gz linux-next-30d1b37d4c022b5e6c164c090a60a3be1a66876e.zip | |
drm/bridge: add support for refcounting
DRM bridges are currently considered as a fixed element of a DRM card, and
thus their lifetime is assumed to extend for as long as the card
exists. New use cases, such as hot-pluggable hardware with video bridges,
require DRM bridges to be added to and removed from a DRM card without
tearing the card down. This is possible for connectors already (used by DP
MST), it is now needed for DRM bridges as well.
As a first preliminary step, make bridges reference-counted to allow a
struct drm_bridge (along with the private driver structure embedding it) to
stay allocated even after the driver has been removed, until the last
reference is put.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20250326-drm-bridge-refcount-v9-2-5e0661fe1f84@bootlin.com
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
Diffstat (limited to 'drivers/gpu/drm/drm_bridge.c')
| -rw-r--r-- | drivers/gpu/drm/drm_bridge.c | 63 |
1 files changed, 62 insertions, 1 deletions
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 84fa1a1330cb..22b459af112f 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -199,23 +199,84 @@ static DEFINE_MUTEX(bridge_lock); static LIST_HEAD(bridge_list); +static void __drm_bridge_free(struct kref *kref) +{ + struct drm_bridge *bridge = container_of(kref, struct drm_bridge, refcount); + + kfree(bridge->container); +} + +/** + * drm_bridge_get - Acquire a bridge reference + * @bridge: DRM bridge + * + * This function increments the bridge's refcount. + * + * Returns: + * Pointer to @bridge. + */ +struct drm_bridge *drm_bridge_get(struct drm_bridge *bridge) +{ + if (bridge) + kref_get(&bridge->refcount); + + return bridge; +} +EXPORT_SYMBOL(drm_bridge_get); + +/** + * drm_bridge_put - Release a bridge reference + * @bridge: DRM bridge + * + * This function decrements the bridge's reference count and frees the + * object if the reference count drops to zero. + */ +void drm_bridge_put(struct drm_bridge *bridge) +{ + if (bridge) + kref_put(&bridge->refcount, __drm_bridge_free); +} +EXPORT_SYMBOL(drm_bridge_put); + +/** + * drm_bridge_put_void - wrapper to drm_bridge_put() taking a void pointer + * + * @data: pointer to @struct drm_bridge, cast to a void pointer + * + * Wrapper of drm_bridge_put() to be used when a function taking a void + * pointer is needed, for example as a devm action. + */ +static void drm_bridge_put_void(void *data) +{ + struct drm_bridge *bridge = (struct drm_bridge *)data; + + drm_bridge_put(bridge); +} + void *__devm_drm_bridge_alloc(struct device *dev, size_t size, size_t offset, const struct drm_bridge_funcs *funcs) { void *container; struct drm_bridge *bridge; + int err; if (!funcs) { dev_warn(dev, "Missing funcs pointer\n"); return ERR_PTR(-EINVAL); } - container = devm_kzalloc(dev, size, GFP_KERNEL); + container = kzalloc(size, GFP_KERNEL); if (!container) return ERR_PTR(-ENOMEM); bridge = container + offset; + bridge->container = container; bridge->funcs = funcs; + kref_init(&bridge->refcount); + + err = devm_add_action_or_reset(dev, drm_bridge_put_void, bridge); + if (err) + return ERR_PTR(err); return container; } |
