aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2011-03-15 07:04:41 -0400
committerDave Airlie <airlied@redhat.com>2011-03-15 21:25:13 -0400
commit4819d2e4310796c4e9eef674499af9b9caf36b5a (patch)
treef2896e922639aa5813646b75ef6d0d4832591b4d /drivers/gpu/drm
parent942b0e95c34f1ba432d08e1c0288ed032d32c3b2 (diff)
drm: Retry i2c transfer of EDID block after failure
Usually EDID retrieval is fine. However, sometimes, especially when the machine is loaded, it fails, but succeeds after a few retries. Based on a patch by Michael Buesch. Reported-by: Michael Buesch <mb@bu3sch.de> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/drm_edid.c40
1 files changed, 24 insertions, 16 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index af60d9be9632..9c595e3b9c20 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -230,24 +230,32 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
230 int block, int len) 230 int block, int len)
231{ 231{
232 unsigned char start = block * EDID_LENGTH; 232 unsigned char start = block * EDID_LENGTH;
233 struct i2c_msg msgs[] = { 233 int ret, retries = 5;
234 {
235 .addr = DDC_ADDR,
236 .flags = 0,
237 .len = 1,
238 .buf = &start,
239 }, {
240 .addr = DDC_ADDR,
241 .flags = I2C_M_RD,
242 .len = len,
243 .buf = buf,
244 }
245 };
246 234
247 if (i2c_transfer(adapter, msgs, 2) == 2) 235 /* The core i2c driver will automatically retry the transfer if the
248 return 0; 236 * adapter reports EAGAIN. However, we find that bit-banging transfers
237 * are susceptible to errors under a heavily loaded machine and
238 * generate spurious NAKs and timeouts. Retrying the transfer
239 * of the individual block a few times seems to overcome this.
240 */
241 do {
242 struct i2c_msg msgs[] = {
243 {
244 .addr = DDC_ADDR,
245 .flags = 0,
246 .len = 1,
247 .buf = &start,
248 }, {
249 .addr = DDC_ADDR,
250 .flags = I2C_M_RD,
251 .len = len,
252 .buf = buf,
253 }
254 };
255 ret = i2c_transfer(adapter, msgs, 2);
256 } while (ret != 2 && --retries);
249 257
250 return -1; 258 return ret == 2 ? 0 : -1;
251} 259}
252 260
253static u8 * 261static u8 *