Commit 7779c5e2 authored by Rob Clark's avatar Rob Clark Committed by Dave Airlie

drm/dp: move hw_mutex up the call stack

1) don't let other threads trying to bang on aux channel interrupt the
defer timeout/logic
2) don't let other threads interrupt the i2c over aux logic

Technically, according to people who actually have the DP spec, this
should not be required.  In practice, it makes some troublesome Dell
monitor (and perhaps others) work, so probably a case of "It's compliant
if it works with windows" on the hw vendor's part..

v2: rebased to come before DPCD/AUX logging patch for easier backport
to stable branches.
Reported-by: default avatarDave Wysochanski <dwysocha@redhat.com>
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1274157
Cc: stable@vger.kernel.org
Signed-off-by: default avatarRob Clark <robdclark@gmail.com>
Reviewed-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 5456248d
...@@ -179,7 +179,7 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, ...@@ -179,7 +179,7 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
{ {
struct drm_dp_aux_msg msg; struct drm_dp_aux_msg msg;
unsigned int retry; unsigned int retry;
int err; int err = 0;
memset(&msg, 0, sizeof(msg)); memset(&msg, 0, sizeof(msg));
msg.address = offset; msg.address = offset;
...@@ -187,6 +187,8 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, ...@@ -187,6 +187,8 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
msg.buffer = buffer; msg.buffer = buffer;
msg.size = size; msg.size = size;
mutex_lock(&aux->hw_mutex);
/* /*
* The specification doesn't give any recommendation on how often to * The specification doesn't give any recommendation on how often to
* retry native transactions. We used to retry 7 times like for * retry native transactions. We used to retry 7 times like for
...@@ -195,25 +197,24 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, ...@@ -195,25 +197,24 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
*/ */
for (retry = 0; retry < 32; retry++) { for (retry = 0; retry < 32; retry++) {
mutex_lock(&aux->hw_mutex);
err = aux->transfer(aux, &msg); err = aux->transfer(aux, &msg);
mutex_unlock(&aux->hw_mutex);
if (err < 0) { if (err < 0) {
if (err == -EBUSY) if (err == -EBUSY)
continue; continue;
return err; goto unlock;
} }
switch (msg.reply & DP_AUX_NATIVE_REPLY_MASK) { switch (msg.reply & DP_AUX_NATIVE_REPLY_MASK) {
case DP_AUX_NATIVE_REPLY_ACK: case DP_AUX_NATIVE_REPLY_ACK:
if (err < size) if (err < size)
return -EPROTO; err = -EPROTO;
return err; goto unlock;
case DP_AUX_NATIVE_REPLY_NACK: case DP_AUX_NATIVE_REPLY_NACK:
return -EIO; err = -EIO;
goto unlock;
case DP_AUX_NATIVE_REPLY_DEFER: case DP_AUX_NATIVE_REPLY_DEFER:
usleep_range(AUX_RETRY_INTERVAL, AUX_RETRY_INTERVAL + 100); usleep_range(AUX_RETRY_INTERVAL, AUX_RETRY_INTERVAL + 100);
...@@ -222,7 +223,11 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, ...@@ -222,7 +223,11 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
} }
DRM_DEBUG_KMS("too many retries, giving up\n"); DRM_DEBUG_KMS("too many retries, giving up\n");
return -EIO; err = -EIO;
unlock:
mutex_unlock(&aux->hw_mutex);
return err;
} }
/** /**
...@@ -544,9 +549,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) ...@@ -544,9 +549,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
int max_retries = max(7, drm_dp_i2c_retry_count(msg, dp_aux_i2c_speed_khz)); int max_retries = max(7, drm_dp_i2c_retry_count(msg, dp_aux_i2c_speed_khz));
for (retry = 0, defer_i2c = 0; retry < (max_retries + defer_i2c); retry++) { for (retry = 0, defer_i2c = 0; retry < (max_retries + defer_i2c); retry++) {
mutex_lock(&aux->hw_mutex);
ret = aux->transfer(aux, msg); ret = aux->transfer(aux, msg);
mutex_unlock(&aux->hw_mutex);
if (ret < 0) { if (ret < 0) {
if (ret == -EBUSY) if (ret == -EBUSY)
continue; continue;
...@@ -685,6 +688,8 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, ...@@ -685,6 +688,8 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
memset(&msg, 0, sizeof(msg)); memset(&msg, 0, sizeof(msg));
mutex_lock(&aux->hw_mutex);
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
msg.address = msgs[i].addr; msg.address = msgs[i].addr;
drm_dp_i2c_msg_set_request(&msg, &msgs[i]); drm_dp_i2c_msg_set_request(&msg, &msgs[i]);
...@@ -739,6 +744,8 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, ...@@ -739,6 +744,8 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
msg.size = 0; msg.size = 0;
(void)drm_dp_i2c_do_msg(aux, &msg); (void)drm_dp_i2c_do_msg(aux, &msg);
mutex_unlock(&aux->hw_mutex);
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment