Skip to content

Commit

Permalink
drm/dp: add a hw mutex around the transfer functions. (v2)
Browse files Browse the repository at this point in the history
This should avoid races between connector probing and HPD
irqs in the future, currently mode_config.mutex blocks this
possibility.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Dave Airlie <airlied@redhat.com>
  • Loading branch information
Dave Airlie committed Jun 4, 2014
1 parent 885ae1c commit 4f71d0c
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 20 deletions.
21 changes: 14 additions & 7 deletions drivers/gpu/drm/drm_dp_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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);
10 changes: 5 additions & 5 deletions drivers/gpu/drm/i915/intel_dp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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);
}
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
5 changes: 3 additions & 2 deletions drivers/gpu/drm/radeon/atombios_dp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 *****/
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/radeon/radeon_i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
4 changes: 2 additions & 2 deletions drivers/gpu/drm/tegra/dpaux.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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);
Expand Down
7 changes: 4 additions & 3 deletions include/drm/drm_dp_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
};
Expand Down Expand Up @@ -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_ */

0 comments on commit 4f71d0c

Please sign in to comment.