Skip to content

Commit

Permalink
drm: Retry i2c transfer of EDID block after failure
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Chris Wilson authored and Dave Airlie committed Mar 16, 2011
1 parent 942b0e9 commit 4819d2e
Showing 1 changed file with 24 additions and 16 deletions.
40 changes: 24 additions & 16 deletions drivers/gpu/drm/drm_edid.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,24 +230,32 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
int block, int len)
{
unsigned char start = block * EDID_LENGTH;
struct i2c_msg msgs[] = {
{
.addr = DDC_ADDR,
.flags = 0,
.len = 1,
.buf = &start,
}, {
.addr = DDC_ADDR,
.flags = I2C_M_RD,
.len = len,
.buf = buf,
}
};
int ret, retries = 5;

if (i2c_transfer(adapter, msgs, 2) == 2)
return 0;
/* The core i2c driver will automatically retry the transfer if the
* adapter reports EAGAIN. However, we find that bit-banging transfers
* are susceptible to errors under a heavily loaded machine and
* generate spurious NAKs and timeouts. Retrying the transfer
* of the individual block a few times seems to overcome this.
*/
do {
struct i2c_msg msgs[] = {
{
.addr = DDC_ADDR,
.flags = 0,
.len = 1,
.buf = &start,
}, {
.addr = DDC_ADDR,
.flags = I2C_M_RD,
.len = len,
.buf = buf,
}
};
ret = i2c_transfer(adapter, msgs, 2);
} while (ret != 2 && --retries);

return -1;
return ret == 2 ? 0 : -1;
}

static u8 *
Expand Down

0 comments on commit 4819d2e

Please sign in to comment.