In order to break a chicken-and-egg problem in wanting to use i2c_transfer on the drm_dp_aux before it is registered with userspace (which is a requirement for i2c_add_adapter() sadly), we need to prepare enough state internally so that drm_dp_aux->algo->master_xfer() is operation. A trio of patches to expose this operation from i2c has been sent, which we can plug in here to replace the open-coding. I want to get the ball rolling on this as I have a regression fix pending getting i915 init reordered. -Chris
Rather than have both drm_dp_aux lock within its transfer, and i2c to lock around the transfer, use the same lock by filling in the locking callbacks that i2c wants to use. We require our own hw_mutex as we bypass i2c_transfer for drm_dp_dpcd_access().
Signed-off-by: Chris Wilson chris@chris-wilson.co.uk Cc: Dave Airlie airlied@redhat.com Cc: Rafael Antognolli rafael.antognolli@intel.com Cc: Ville Syrjälä ville.syrjala@linux.intel.com Cc: dri-devel@lists.freedesktop.org --- drivers/gpu/drm/drm_dp_helper.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index eeaf5a7c3aa7..4b088afa21b2 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -708,8 +708,6 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
memset(&msg, 0, sizeof(msg));
- mutex_lock(&aux->hw_mutex); - for (i = 0; i < num; i++) { msg.address = msgs[i].addr; drm_dp_i2c_msg_set_request(&msg, &msgs[i]); @@ -764,8 +762,6 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, msg.size = 0; (void)drm_dp_i2c_do_msg(aux, &msg);
- mutex_unlock(&aux->hw_mutex); - return err; }
@@ -774,6 +770,26 @@ static const struct i2c_algorithm drm_dp_i2c_algo = { .master_xfer = drm_dp_i2c_xfer, };
+static struct drm_dp_aux *i2c_to_aux(struct i2c_adapter *i2c) +{ + return container_of(i2c, struct drm_dp_aux, ddc); +} + +static void lock_bus(struct i2c_adapter *i2c, unsigned int flags) +{ + mutex_lock(&i2c_to_aux(i2c)->hw_mutex); +} + +static int trylock_bus(struct i2c_adapter *i2c, unsigned int flags) +{ + return mutex_trylock(&i2c_to_aux(i2c)->hw_mutex); +} + +static void unlock_bus(struct i2c_adapter *i2c, unsigned int flags) +{ + mutex_unlock(&i2c_to_aux(i2c)->hw_mutex); +} + /** * drm_dp_aux_register() - initialise and register aux channel * @aux: DisplayPort AUX channel @@ -790,6 +806,10 @@ int drm_dp_aux_register(struct drm_dp_aux *aux) aux->ddc.algo_data = aux; aux->ddc.retries = 3;
+ aux->ddc.lock_bus = lock_bus; + aux->ddc.trylock_bus = trylock_bus; + aux->ddc.unlock_bus = unlock_bus; + aux->ddc.class = I2C_CLASS_DDC; aux->ddc.owner = THIS_MODULE; aux->ddc.dev.parent = aux->dev;
When trying to split up the initialisation phase and the registration phase, one immediate problem encountered is trying to use our own i2c devices before registration with userspace (to read EDID during device discovery). drm_dp_aux in particular only offers an interface for setting up the device *after* we have exposed the connector via sysfs. In order to break the chicken-and-egg problem, export drm_dp_aux_init() to minimally prepare the i2c device for internal use before drm_connector_register().
Signed-off-by: Chris Wilson chris@chris-wilson.co.uk Cc: Dave Airlie airlied@redhat.com Cc: Rafael Antognolli rafael.antognolli@intel.com Cc: Ville Syrjälä ville.syrjala@linux.intel.com Cc: dri-devel@lists.freedesktop.org --- drivers/gpu/drm/drm_dp_helper.c | 26 +++++++++++++++++++++----- include/drm/drm_dp_helper.h | 1 + 2 files changed, 22 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 4b088afa21b2..9b4ec65e1de6 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -791,15 +791,16 @@ static void unlock_bus(struct i2c_adapter *i2c, unsigned int flags) }
/** - * drm_dp_aux_register() - initialise and register aux channel + * drm_dp_aux_init() - minimally initialise an aux channel * @aux: DisplayPort AUX channel * - * Returns 0 on success or a negative error code on failure. + * If you need to use the drm_dp_aux's i2c adapter prior to registering it + * with the outside world, call drm_dp_aux_init() first. You must still + * call drm_dp_aux_register() once the connector has been registered to + * allow userspace access to the auxiliary DP channel. */ -int drm_dp_aux_register(struct drm_dp_aux *aux) +void drm_dp_aux_init(struct drm_dp_aux *aux) { - int ret; - mutex_init(&aux->hw_mutex);
aux->ddc.algo = &drm_dp_i2c_algo; @@ -809,6 +810,21 @@ int drm_dp_aux_register(struct drm_dp_aux *aux) aux->ddc.lock_bus = lock_bus; aux->ddc.trylock_bus = trylock_bus; aux->ddc.unlock_bus = unlock_bus; +} +EXPORT_SYMBOL(drm_dp_aux_init); + +/** + * 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(struct drm_dp_aux *aux) +{ + int ret; + + if (!aux->ddc.algo) + drm_dp_aux_init(aux);
aux->ddc.class = I2C_CLASS_DDC; aux->ddc.owner = THIS_MODULE; diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 5a848e734422..4d85cf2874af 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -805,6 +805,7 @@ int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link); int drm_dp_link_power_down(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);
+void drm_dp_aux_init(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);
On Fri, Jun 17, 2016 at 09:33:18AM +0100, Chris Wilson wrote:
When trying to split up the initialisation phase and the registration phase, one immediate problem encountered is trying to use our own i2c devices before registration with userspace (to read EDID during device discovery). drm_dp_aux in particular only offers an interface for setting up the device *after* we have exposed the connector via sysfs. In order to break the chicken-and-egg problem, export drm_dp_aux_init() to minimally prepare the i2c device for internal use before drm_connector_register().
Signed-off-by: Chris Wilson chris@chris-wilson.co.uk Cc: Dave Airlie airlied@redhat.com Cc: Rafael Antognolli rafael.antognolli@intel.com Cc: Ville Syrjälä ville.syrjala@linux.intel.com Cc: dri-devel@lists.freedesktop.org
drivers/gpu/drm/drm_dp_helper.c | 26 +++++++++++++++++++++----- include/drm/drm_dp_helper.h | 1 + 2 files changed, 22 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 4b088afa21b2..9b4ec65e1de6 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -791,15 +791,16 @@ static void unlock_bus(struct i2c_adapter *i2c, unsigned int flags) }
/**
- drm_dp_aux_register() - initialise and register aux channel
- drm_dp_aux_init() - minimally initialise an aux channel
- @aux: DisplayPort AUX channel
- Returns 0 on success or a negative error code on failure.
- If you need to use the drm_dp_aux's i2c adapter prior to registering it
- with the outside world, call drm_dp_aux_init() first. You must still
- call drm_dp_aux_register() once the connector has been registered to
*/
- allow userspace access to the auxiliary DP channel.
-int drm_dp_aux_register(struct drm_dp_aux *aux) +void drm_dp_aux_init(struct drm_dp_aux *aux) {
int ret;
mutex_init(&aux->hw_mutex);
aux->ddc.algo = &drm_dp_i2c_algo;
@@ -809,6 +810,21 @@ int drm_dp_aux_register(struct drm_dp_aux *aux) aux->ddc.lock_bus = lock_bus; aux->ddc.trylock_bus = trylock_bus; aux->ddc.unlock_bus = unlock_bus; +} +EXPORT_SYMBOL(drm_dp_aux_init);
+/**
- drm_dp_aux_register() - initialise and register aux channel
- @aux: DisplayPort AUX channel
- Returns 0 on success or a negative error code on failure.
I amended kerneldoc slightly here and merged both, thanks. -Daniel
- */
+int drm_dp_aux_register(struct drm_dp_aux *aux) +{
int ret;
if (!aux->ddc.algo)
drm_dp_aux_init(aux);
aux->ddc.class = I2C_CLASS_DDC; aux->ddc.owner = THIS_MODULE;
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 5a848e734422..4d85cf2874af 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -805,6 +805,7 @@ int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link); int drm_dp_link_power_down(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);
+void drm_dp_aux_init(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);
-- 2.8.1
Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx
dri-devel@lists.freedesktop.org