On Tue, Mar 15, 2011 at 7:04 AM, Chris Wilson <chris at chris-wilson.co.uk> wrote: > 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 at bu3sch.de> > Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
Looks good. Reviewed-by: Alex Deucher <alexdeucher at gmail.com> > --- > > I was going to suggest tuning the i2c_adapter.retries of the affected > components, but that only covers EGAIN and not EREMOTEIO/ETIMEDOUT that > afflicts us. With the alteration to only retry the transfer of the > affected block, this looks to be a reasonable idea and complements the > logic to retry corrupted transfers. > -Chris > > --- > ?drivers/gpu/drm/drm_edid.c | ? 44 > ++++++++++++++++++++++++++------------------ > ?1 files changed, 26 insertions(+), 18 deletions(-) > > diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c > index a245d17..ddc3da9 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, > ? ? ? ? ? ? ? ? ? ? ?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 * > -- > 1.7.2.3 > > _______________________________________________ > dri-devel mailing list > dri-devel at lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/dri-devel >