The modeset lock protects the DDC code from concurrent modeset operations, which use the same registers. Move that code from the connector helpers into the DDC helpers .pre_xfer() and .post_xfer(). Both, .pre_xfer() and .post_xfer(), enclose the transfer of data blocks over the I2C channel in the internal I2C function bit_xfer(). Both calls are executed unconditionally if present. Invoking DDC transfers from any where within the driver now takes the lock. Signed-off-by: Thomas Zimmermann <tzimmermann@xxxxxxx> --- drivers/gpu/drm/mgag200/mgag200_ddc.c | 24 ++++++++++++++++++++++++ drivers/gpu/drm/mgag200/mgag200_mode.c | 9 --------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_ddc.c b/drivers/gpu/drm/mgag200/mgag200_ddc.c index 3fa11b190943e..6d81ea8931e88 100644 --- a/drivers/gpu/drm/mgag200/mgag200_ddc.c +++ b/drivers/gpu/drm/mgag200/mgag200_ddc.c @@ -99,6 +99,28 @@ static int mgag200_ddc_algo_bit_data_getscl(void *data) return (mga_i2c_read_gpio(ddc->mdev) & ddc->clock) ? 1 : 0; } +static int mgag200_ddc_algo_bit_data_pre_xfer(struct i2c_adapter *adapter) +{ + struct mgag200_ddc *ddc = i2c_get_adapdata(adapter); + struct mga_device *mdev = ddc->mdev; + + /* + * Protect access to I/O registers from concurrent modesetting + * by acquiring the I/O-register lock. + */ + mutex_lock(&mdev->rmmio_lock); + + return 0; +} + +static void mgag200_ddc_algo_bit_data_post_xfer(struct i2c_adapter *adapter) +{ + struct mgag200_ddc *ddc = i2c_get_adapdata(adapter); + struct mga_device *mdev = ddc->mdev; + + mutex_unlock(&mdev->rmmio_lock); +} + static void mgag200_ddc_release(struct drm_device *dev, void *res) { struct mgag200_ddc *ddc = res; @@ -133,6 +155,8 @@ struct i2c_adapter *mgag200_ddc_create(struct mga_device *mdev) bit->setscl = mgag200_ddc_algo_bit_data_setscl; bit->getsda = mgag200_ddc_algo_bit_data_getsda; bit->getscl = mgag200_ddc_algo_bit_data_getscl; + bit->pre_xfer = mgag200_ddc_algo_bit_data_pre_xfer; + bit->post_xfer = mgag200_ddc_algo_bit_data_post_xfer; bit->udelay = 10; bit->timeout = usecs_to_jiffies(2200); diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 4ca2f4cba1077..f6bec6d9a3b3f 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -725,23 +725,14 @@ void mgag200_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_st int mgag200_vga_connector_helper_get_modes(struct drm_connector *connector) { - struct mga_device *mdev = to_mga_device(connector->dev); const struct drm_edid *drm_edid; int count; - /* - * Protect access to I/O registers from concurrent modesetting - * by acquiring the I/O-register lock. - */ - mutex_lock(&mdev->rmmio_lock); - drm_edid = drm_edid_read(connector); drm_edid_connector_update(connector, drm_edid); count = drm_edid_connector_add_modes(connector); drm_edid_free(drm_edid); - mutex_unlock(&mdev->rmmio_lock); - return count; } -- 2.44.0