From 4f71d0cb76339a10fd445b0b281acc45c71b6271 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 4 Jun 2014 16:02:28 +1000 Subject: [PATCH] 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: Daniel Vetter Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_dp_helper.c | 21 ++++++++++++++------- drivers/gpu/drm/i915/intel_dp.c | 10 +++++----- drivers/gpu/drm/radeon/atombios_dp.c | 5 +++-- drivers/gpu/drm/radeon/radeon_i2c.c | 2 +- drivers/gpu/drm/tegra/dpaux.c | 4 ++-- include/drm/drm_dp_helper.h | 7 ++++--- 6 files changed, 29 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 494219ccdf96..08e33b8b13a4 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -216,7 +216,7 @@ i2c_dp_aux_prepare_bus(struct i2c_adapter *adapter) * * IMPORTANT: * This interface is deprecated, please switch to the new dp aux helpers and - * drm_dp_aux_register_i2c_bus(). + * drm_dp_aux_register(). */ int 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, * transactions. */ for (retry = 0; retry < 7; retry++) { + + mutex_lock(&aux->hw_mutex); err = aux->transfer(aux, &msg); + mutex_unlock(&aux->hw_mutex); if (err < 0) { if (err == -EBUSY) continue; @@ -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. */ for (retry = 0; retry < 7; retry++) { + mutex_lock(&aux->hw_mutex); err = aux->transfer(aux, msg); + mutex_unlock(&aux->hw_mutex); if (err < 0) { if (err == -EBUSY) continue; @@ -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 * * 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_data = aux; aux->ddc.retries = 3; @@ -750,14 +757,14 @@ int drm_dp_aux_register_i2c_bus(struct drm_dp_aux *aux) 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 */ -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); } -EXPORT_SYMBOL(drm_dp_aux_unregister_i2c_bus); +EXPORT_SYMBOL(drm_dp_aux_unregister); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index c4d883921282..d01bb430b5bc 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -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, 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) { - 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); return; } @@ -714,7 +714,7 @@ intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector) intel_dp->aux.ddc.dev.kobj.name); if (ret < 0) { 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) struct intel_dp *intel_dp = &intel_dig_port->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); if (is_edp(intel_dp)) { cancel_delayed_work_sync(&intel_dp->panel_vdd_work); @@ -4244,7 +4244,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, intel_dp->psr_setup_done = false; 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)) { cancel_delayed_work_sync(&intel_dp->panel_vdd_work); mutex_lock(&dev->mode_config.connection_mutex); diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 225f6c66effa..a54c44181a0f 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -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->aux.dev = radeon_connector->base.kdev; 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) 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 *****/ diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index 427ee4d6d0b5..add622008407 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -988,7 +988,7 @@ void radeon_i2c_destroy(struct radeon_i2c_chan *i2c) return; i2c_del_adapter(&i2c->adapter); if (i2c->has_aux) - drm_dp_aux_unregister_i2c_bus(&i2c->aux); + drm_dp_aux_unregister(&i2c->aux); kfree(i2c); } diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index 005c19bd92df..2b725ba7facc 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c @@ -332,7 +332,7 @@ static int tegra_dpaux_probe(struct platform_device *pdev) dpaux->aux.transfer = tegra_dpaux_transfer; dpaux->aux.dev = &pdev->dev; - err = drm_dp_aux_register_i2c_bus(&dpaux->aux); + err = drm_dp_aux_register(&dpaux->aux); if (err < 0) return err; @@ -355,7 +355,7 @@ static int tegra_dpaux_remove(struct platform_device *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); list_del(&dpaux->list); diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 488b41635dec..a21568bf1514 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -514,6 +514,7 @@ struct drm_dp_aux_msg { * @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 * @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 * * The .dev field should be set to a pointer to the device that implements @@ -546,7 +547,7 @@ struct drm_dp_aux { const char *name; struct i2c_adapter ddc; struct device *dev; - + struct mutex hw_mutex; ssize_t (*transfer)(struct drm_dp_aux *aux, 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); 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_aux_register_i2c_bus(struct drm_dp_aux *aux); -void drm_dp_aux_unregister_i2c_bus(struct drm_dp_aux *aux); +int drm_dp_aux_register(struct drm_dp_aux *aux); +void drm_dp_aux_unregister(struct drm_dp_aux *aux); #endif /* _DRM_DP_HELPER_H_ */ -- 2.39.5