drm/dp: add a hw mutex around the transfer functions. (v2)
authorDave Airlie <airlied@redhat.com>
Wed, 4 Jun 2014 06:02:28 +0000 (16:02 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 4 Jun 2014 23:54:29 +0000 (09:54 +1000)
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>
drivers/gpu/drm/drm_dp_helper.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/radeon_i2c.c
drivers/gpu/drm/tegra/dpaux.c
include/drm/drm_dp_helper.h

index 494219ccdf9621a4f7b35a605088531a68859ecf..08e33b8b13a433be43b0a39f462791388a856b95 100644 (file)
@@ -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);
index c4d8839212829f9c48bd1f10bc070063c44c6668..d01bb430b5bcacf61a21a5e5748ac02f410e2a12 100644 (file)
@@ -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);
index 225f6c66effa98a85a16fefd5034a5c1171fa9f2..a54c44181a0fe9740d7ab5a76032aa14a4aefd18 100644 (file)
@@ -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 *****/
index 427ee4d6d0b558fb5cde878119bc31054d60abe9..add622008407e77b18955802ad1eee39ae994cfa 100644 (file)
@@ -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);
 }
 
index 005c19bd92dfa0e5350303d84290b27b9aae144d..2b725ba7facc6eb2d1a6905b4eb5129c6221b2ef 100644 (file)
@@ -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);
index 488b41635dec5ad86ef35b325fe4844f57271429..a21568bf15145940cecdc86623d9c4b79dd1111c 100644 (file)
@@ -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_ */