Commit 4f71d0cb authored by Dave Airlie's avatar Dave Airlie

drm/dp: add a hw mutex around the transfer functions. (v2)

This should avoid races between connector probing and HPD
irqs in the future, currently mode_config.mutex blocks this
possibility.
Reviewed-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 885ae1c5
...@@ -216,7 +216,7 @@ i2c_dp_aux_prepare_bus(struct i2c_adapter *adapter) ...@@ -216,7 +216,7 @@ i2c_dp_aux_prepare_bus(struct i2c_adapter *adapter)
* *
* IMPORTANT: * IMPORTANT:
* This interface is deprecated, please switch to the new dp aux helpers and * This interface is deprecated, please switch to the new dp aux helpers and
* drm_dp_aux_register_i2c_bus(). * drm_dp_aux_register().
*/ */
int int
i2c_dp_aux_add_bus(struct i2c_adapter *adapter) i2c_dp_aux_add_bus(struct i2c_adapter *adapter)
...@@ -382,7 +382,10 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, ...@@ -382,7 +382,10 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
* transactions. * transactions.
*/ */
for (retry = 0; retry < 7; retry++) { for (retry = 0; retry < 7; retry++) {
mutex_lock(&aux->hw_mutex);
err = aux->transfer(aux, &msg); err = aux->transfer(aux, &msg);
mutex_unlock(&aux->hw_mutex);
if (err < 0) { if (err < 0) {
if (err == -EBUSY) if (err == -EBUSY)
continue; continue;
...@@ -596,7 +599,9 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) ...@@ -596,7 +599,9 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
* before giving up the AUX transaction. * before giving up the AUX transaction.
*/ */
for (retry = 0; retry < 7; retry++) { for (retry = 0; retry < 7; retry++) {
mutex_lock(&aux->hw_mutex);
err = aux->transfer(aux, msg); err = aux->transfer(aux, msg);
mutex_unlock(&aux->hw_mutex);
if (err < 0) { if (err < 0) {
if (err == -EBUSY) if (err == -EBUSY)
continue; continue;
...@@ -729,13 +734,15 @@ static const struct i2c_algorithm drm_dp_i2c_algo = { ...@@ -729,13 +734,15 @@ static const struct i2c_algorithm drm_dp_i2c_algo = {
}; };
/** /**
* drm_dp_aux_register_i2c_bus() - register an I2C adapter for I2C-over-AUX * drm_dp_aux_register() - initialise and register aux channel
* @aux: DisplayPort AUX channel * @aux: DisplayPort AUX channel
* *
* Returns 0 on success or a negative error code on failure. * Returns 0 on success or a negative error code on failure.
*/ */
int drm_dp_aux_register_i2c_bus(struct drm_dp_aux *aux) int drm_dp_aux_register(struct drm_dp_aux *aux)
{ {
mutex_init(&aux->hw_mutex);
aux->ddc.algo = &drm_dp_i2c_algo; aux->ddc.algo = &drm_dp_i2c_algo;
aux->ddc.algo_data = aux; aux->ddc.algo_data = aux;
aux->ddc.retries = 3; aux->ddc.retries = 3;
...@@ -750,14 +757,14 @@ int drm_dp_aux_register_i2c_bus(struct drm_dp_aux *aux) ...@@ -750,14 +757,14 @@ int drm_dp_aux_register_i2c_bus(struct drm_dp_aux *aux)
return i2c_add_adapter(&aux->ddc); return i2c_add_adapter(&aux->ddc);
} }
EXPORT_SYMBOL(drm_dp_aux_register_i2c_bus); EXPORT_SYMBOL(drm_dp_aux_register);
/** /**
* drm_dp_aux_unregister_i2c_bus() - unregister an I2C-over-AUX adapter * drm_dp_aux_unregister() - unregister an AUX adapter
* @aux: DisplayPort AUX channel * @aux: DisplayPort AUX channel
*/ */
void drm_dp_aux_unregister_i2c_bus(struct drm_dp_aux *aux) void drm_dp_aux_unregister(struct drm_dp_aux *aux)
{ {
i2c_del_adapter(&aux->ddc); i2c_del_adapter(&aux->ddc);
} }
EXPORT_SYMBOL(drm_dp_aux_unregister_i2c_bus); EXPORT_SYMBOL(drm_dp_aux_unregister);
...@@ -702,9 +702,9 @@ intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector) ...@@ -702,9 +702,9 @@ intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
DRM_DEBUG_KMS("registering %s bus for %s\n", name, DRM_DEBUG_KMS("registering %s bus for %s\n", name,
connector->base.kdev->kobj.name); connector->base.kdev->kobj.name);
ret = drm_dp_aux_register_i2c_bus(&intel_dp->aux); ret = drm_dp_aux_register(&intel_dp->aux);
if (ret < 0) { if (ret < 0) {
DRM_ERROR("drm_dp_aux_register_i2c_bus() for %s failed (%d)\n", DRM_ERROR("drm_dp_aux_register() for %s failed (%d)\n",
name, ret); name, ret);
return; return;
} }
...@@ -714,7 +714,7 @@ intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector) ...@@ -714,7 +714,7 @@ intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
intel_dp->aux.ddc.dev.kobj.name); intel_dp->aux.ddc.dev.kobj.name);
if (ret < 0) { if (ret < 0) {
DRM_ERROR("sysfs_create_link() for %s failed (%d)\n", name, ret); DRM_ERROR("sysfs_create_link() for %s failed (%d)\n", name, ret);
drm_dp_aux_unregister_i2c_bus(&intel_dp->aux); drm_dp_aux_unregister(&intel_dp->aux);
} }
} }
...@@ -3662,7 +3662,7 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder) ...@@ -3662,7 +3662,7 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
struct intel_dp *intel_dp = &intel_dig_port->dp; struct intel_dp *intel_dp = &intel_dig_port->dp;
struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_device *dev = intel_dp_to_dev(intel_dp);
drm_dp_aux_unregister_i2c_bus(&intel_dp->aux); drm_dp_aux_unregister(&intel_dp->aux);
drm_encoder_cleanup(encoder); drm_encoder_cleanup(encoder);
if (is_edp(intel_dp)) { if (is_edp(intel_dp)) {
cancel_delayed_work_sync(&intel_dp->panel_vdd_work); cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
...@@ -4244,7 +4244,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, ...@@ -4244,7 +4244,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
intel_dp->psr_setup_done = false; intel_dp->psr_setup_done = false;
if (!intel_edp_init_connector(intel_dp, intel_connector, &power_seq)) { if (!intel_edp_init_connector(intel_dp, intel_connector, &power_seq)) {
drm_dp_aux_unregister_i2c_bus(&intel_dp->aux); drm_dp_aux_unregister(&intel_dp->aux);
if (is_edp(intel_dp)) { if (is_edp(intel_dp)) {
cancel_delayed_work_sync(&intel_dp->panel_vdd_work); cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
mutex_lock(&dev->mode_config.connection_mutex); mutex_lock(&dev->mode_config.connection_mutex);
......
...@@ -222,11 +222,12 @@ void radeon_dp_aux_init(struct radeon_connector *radeon_connector) ...@@ -222,11 +222,12 @@ void radeon_dp_aux_init(struct radeon_connector *radeon_connector)
radeon_connector->ddc_bus->rec.hpd = radeon_connector->hpd.hpd; radeon_connector->ddc_bus->rec.hpd = radeon_connector->hpd.hpd;
radeon_connector->ddc_bus->aux.dev = radeon_connector->base.kdev; radeon_connector->ddc_bus->aux.dev = radeon_connector->base.kdev;
radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer; radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer;
ret = drm_dp_aux_register_i2c_bus(&radeon_connector->ddc_bus->aux);
ret = drm_dp_aux_register(&radeon_connector->ddc_bus->aux);
if (!ret) if (!ret)
radeon_connector->ddc_bus->has_aux = true; radeon_connector->ddc_bus->has_aux = true;
WARN(ret, "drm_dp_aux_register_i2c_bus() failed with error %d\n", ret); WARN(ret, "drm_dp_aux_register() failed with error %d\n", ret);
} }
/***** general DP utility functions *****/ /***** general DP utility functions *****/
......
...@@ -988,7 +988,7 @@ void radeon_i2c_destroy(struct radeon_i2c_chan *i2c) ...@@ -988,7 +988,7 @@ void radeon_i2c_destroy(struct radeon_i2c_chan *i2c)
return; return;
i2c_del_adapter(&i2c->adapter); i2c_del_adapter(&i2c->adapter);
if (i2c->has_aux) if (i2c->has_aux)
drm_dp_aux_unregister_i2c_bus(&i2c->aux); drm_dp_aux_unregister(&i2c->aux);
kfree(i2c); kfree(i2c);
} }
......
...@@ -332,7 +332,7 @@ static int tegra_dpaux_probe(struct platform_device *pdev) ...@@ -332,7 +332,7 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
dpaux->aux.transfer = tegra_dpaux_transfer; dpaux->aux.transfer = tegra_dpaux_transfer;
dpaux->aux.dev = &pdev->dev; dpaux->aux.dev = &pdev->dev;
err = drm_dp_aux_register_i2c_bus(&dpaux->aux); err = drm_dp_aux_register(&dpaux->aux);
if (err < 0) if (err < 0)
return err; return err;
...@@ -355,7 +355,7 @@ static int tegra_dpaux_remove(struct platform_device *pdev) ...@@ -355,7 +355,7 @@ static int tegra_dpaux_remove(struct platform_device *pdev)
{ {
struct tegra_dpaux *dpaux = platform_get_drvdata(pdev); struct tegra_dpaux *dpaux = platform_get_drvdata(pdev);
drm_dp_aux_unregister_i2c_bus(&dpaux->aux); drm_dp_aux_unregister(&dpaux->aux);
mutex_lock(&dpaux_lock); mutex_lock(&dpaux_lock);
list_del(&dpaux->list); list_del(&dpaux->list);
......
...@@ -514,6 +514,7 @@ struct drm_dp_aux_msg { ...@@ -514,6 +514,7 @@ struct drm_dp_aux_msg {
* @name: user-visible name of this AUX channel and the I2C-over-AUX adapter * @name: user-visible name of this AUX channel and the I2C-over-AUX adapter
* @ddc: I2C adapter that can be used for I2C-over-AUX communication * @ddc: I2C adapter that can be used for I2C-over-AUX communication
* @dev: pointer to struct device that is the parent for this AUX channel * @dev: pointer to struct device that is the parent for this AUX channel
* @hw_mutex: internal mutex used for locking transfers
* @transfer: transfers a message representing a single AUX transaction * @transfer: transfers a message representing a single AUX transaction
* *
* The .dev field should be set to a pointer to the device that implements * The .dev field should be set to a pointer to the device that implements
...@@ -546,7 +547,7 @@ struct drm_dp_aux { ...@@ -546,7 +547,7 @@ struct drm_dp_aux {
const char *name; const char *name;
struct i2c_adapter ddc; struct i2c_adapter ddc;
struct device *dev; struct device *dev;
struct mutex hw_mutex;
ssize_t (*transfer)(struct drm_dp_aux *aux, ssize_t (*transfer)(struct drm_dp_aux *aux,
struct drm_dp_aux_msg *msg); struct drm_dp_aux_msg *msg);
}; };
...@@ -605,7 +606,7 @@ int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link); ...@@ -605,7 +606,7 @@ int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link);
int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link); int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link);
int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link); int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link);
int drm_dp_aux_register_i2c_bus(struct drm_dp_aux *aux); int drm_dp_aux_register(struct drm_dp_aux *aux);
void drm_dp_aux_unregister_i2c_bus(struct drm_dp_aux *aux); void drm_dp_aux_unregister(struct drm_dp_aux *aux);
#endif /* _DRM_DP_HELPER_H_ */ #endif /* _DRM_DP_HELPER_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment