diff options
Diffstat (limited to 'drivers/gpu/drm/drm_bridge.c')
| -rw-r--r-- | drivers/gpu/drm/drm_bridge.c | 49 | 
1 files changed, 43 insertions, 6 deletions
| diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index b4c89ec01998..dd45d9b504d8 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -23,6 +23,7 @@  #include <linux/debugfs.h>  #include <linux/err.h> +#include <linux/export.h>  #include <linux/media-bus-format.h>  #include <linux/module.h>  #include <linux/mutex.h> @@ -203,6 +204,8 @@ static void __drm_bridge_free(struct kref *kref)  {  	struct drm_bridge *bridge = container_of(kref, struct drm_bridge, refcount); +	if (bridge->funcs->destroy) +		bridge->funcs->destroy(bridge);  	kfree(bridge->container);  } @@ -292,6 +295,11 @@ EXPORT_SYMBOL(__devm_drm_bridge_alloc);   */  void drm_bridge_add(struct drm_bridge *bridge)  { +	if (!bridge->container) +		DRM_WARN("DRM bridge corrupted or not allocated by devm_drm_bridge_alloc()\n"); + +	drm_bridge_get(bridge); +  	mutex_init(&bridge->hpd_mutex);  	if (bridge->ops & DRM_BRIDGE_OP_HDMI) @@ -339,6 +347,8 @@ void drm_bridge_remove(struct drm_bridge *bridge)  	mutex_unlock(&bridge_lock);  	mutex_destroy(&bridge->hpd_mutex); + +	drm_bridge_put(bridge);  }  EXPORT_SYMBOL(drm_bridge_remove); @@ -404,11 +414,17 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,  	if (!encoder || !bridge)  		return -EINVAL; -	if (previous && (!previous->dev || previous->encoder != encoder)) -		return -EINVAL; +	drm_bridge_get(bridge); -	if (bridge->dev) -		return -EBUSY; +	if (previous && (!previous->dev || previous->encoder != encoder)) { +		ret = -EINVAL; +		goto err_put_bridge; +	} + +	if (bridge->dev) { +		ret = -EBUSY; +		goto err_put_bridge; +	}  	bridge->dev = encoder->dev;  	bridge->encoder = encoder; @@ -457,6 +473,8 @@ err_reset_bridge:  			      "failed to attach bridge %pOF to encoder %s\n",  			      bridge->of_node, encoder->name); +err_put_bridge: +	drm_bridge_put(bridge);  	return ret;  }  EXPORT_SYMBOL(drm_bridge_attach); @@ -477,6 +495,7 @@ void drm_bridge_detach(struct drm_bridge *bridge)  	list_del(&bridge->chain_node);  	bridge->dev = NULL; +	drm_bridge_put(bridge);  }  /** @@ -1218,12 +1237,13 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_check);   * The detection status on success, or connector_status_unknown if the bridge   * doesn't support output detection.   */ -enum drm_connector_status drm_bridge_detect(struct drm_bridge *bridge) +enum drm_connector_status +drm_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connector)  {  	if (!(bridge->ops & DRM_BRIDGE_OP_DETECT))  		return connector_status_unknown; -	return bridge->funcs->detect(bridge); +	return bridge->funcs->detect(bridge, connector);  }  EXPORT_SYMBOL_GPL(drm_bridge_detect); @@ -1392,6 +1412,23 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np)  EXPORT_SYMBOL(of_drm_find_bridge);  #endif +/** + * devm_drm_put_bridge - Release a bridge reference obtained via devm + * @dev: device that got the bridge via devm + * @bridge: pointer to a struct drm_bridge obtained via devm + * + * Same as drm_bridge_put() for bridge pointers obtained via devm functions + * such as devm_drm_bridge_alloc(). + * + * This function is a temporary workaround and MUST NOT be used. Manual + * handling of bridge lifetime is inherently unsafe. + */ +void devm_drm_put_bridge(struct device *dev, struct drm_bridge *bridge) +{ +	devm_release_action(dev, drm_bridge_put_void, bridge); +} +EXPORT_SYMBOL(devm_drm_put_bridge); +  static void drm_bridge_debugfs_show_bridge(struct drm_printer *p,  					   struct drm_bridge *bridge,  					   unsigned int idx) | 
