* drm_get_edid i2c failure
@ 2011-03-05 14:56 Michael Buesch
2011-03-15 11:04 ` [PATCH] drm: Retry i2c transfer of EDID block after failure Chris Wilson
0 siblings, 1 reply; 4+ messages in thread
From: Michael Buesch @ 2011-03-05 14:56 UTC (permalink / raw)
To: David Airlie; +Cc: dri-devel
Getting the EDID succeeds most of the time on my system. However,
every now and then, especially when the machine is highly loaded,
i2c communication and thus drm_get_edid() fails.
My guess is that some kind of electrical noise and/or misdesign in
the used components is the root cause of this.
The display with the issues is an Apple Cinema connected via DVI.
Another LG display is connected through VGA to the other connector
of the ATI Radeon HD 5450. (xrandr is used)
This is what kernel log shows on errors:
[ 9509.250829] i2c i2c-3: sendbytes: NAK bailout.
[ 9519.655190] i2c i2c-3: readbytes: ack/nak timeout
[ 9519.655258] [drm:radeon_dvi_detect] *ERROR* DVI-I-1: probed a monitor but no|invalid EDID
[ 9550.716078] [drm:radeon_dvi_detect] *ERROR* DVI-I-1: probed a monitor but no|invalid EDID
[ 9560.738835] i2c i2c-3: sendbytes: NAK bailout.
[ 9612.778073] [drm:radeon_dvi_detect] *ERROR* DVI-I-1: probed a monitor but no|invalid EDID
The display flickers for a few seconds and then continues to
work correctly.
So I applied the following patch to the kernel to workaround the issue:
Index: linux-2.6.37/drivers/gpu/drm/drm_edid.c
===================================================================
--- linux-2.6.37.orig/drivers/gpu/drm/drm_edid.c 2011-03-05 13:09:17.001960834 +0100
+++ linux-2.6.37/drivers/gpu/drm/drm_edid.c 2011-03-05 13:11:34.974194354 +0100
@@ -343,9 +343,16 @@ struct edid *drm_get_edid(struct drm_con
struct i2c_adapter *adapter)
{
struct edid *edid = NULL;
+ unsigned int tries;
- if (drm_probe_ddc(adapter))
- edid = (struct edid *)drm_do_get_edid(connector, adapter);
+ for (tries = 0; tries < 20; tries++) {
+ if (drm_probe_ddc(adapter))
+ edid = (struct edid *)drm_do_get_edid(connector, adapter);
+ if (edid)
+ break;
+ }
+ if (tries > 0 && tries < 20)
+ printk(KERN_INFO "drm_get_edid(): Succeed after %u tries\n", tries);
connector->display_info.raw_edid = (char *)edid;
This seems to help. I get messages like:
[ 6506.029922] i2c i2c-3: sendbytes: NAK bailout.
[ 6506.030828] i2c i2c-3: sendbytes: NAK bailout.
[ 6506.137459] drm_get_edid(): Succeed after 3 tries
[ 8647.073894] i2c i2c-3: sendbytes: NAK bailout.
[ 8647.196343] drm_get_edid(): Succeed after 2 tries
[ 8749.381956] drm_get_edid(): Succeed after 1 tries
[ 8759.523868] i2c i2c-3: readbytes: ack/nak timeout
[ 8759.668134] drm_get_edid(): Succeed after 1 tries
I was wondering if a real fix or workaround could be found for mainline inclusion.
Would it be acceptable to have a retry loop similar to the above patch?
Some suggestions?
--
Greetings, Michael.
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH] drm: Retry i2c transfer of EDID block after failure
2011-03-05 14:56 drm_get_edid i2c failure Michael Buesch
@ 2011-03-15 11:04 ` Chris Wilson
2011-03-15 17:02 ` Alex Deucher
2011-03-15 22:20 ` Michael Buesch
0 siblings, 2 replies; 4+ messages in thread
From: Chris Wilson @ 2011-03-15 11:04 UTC (permalink / raw)
To: David Airlie; +Cc: dri-devel, Michael Buesch
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>
---
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
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] drm: Retry i2c transfer of EDID block after failure
2011-03-15 11:04 ` [PATCH] drm: Retry i2c transfer of EDID block after failure Chris Wilson
@ 2011-03-15 17:02 ` Alex Deucher
2011-03-15 22:20 ` Michael Buesch
1 sibling, 0 replies; 4+ messages in thread
From: Alex Deucher @ 2011-03-15 17:02 UTC (permalink / raw)
To: Chris Wilson; +Cc: Michael Buesch, dri-devel
On Tue, Mar 15, 2011 at 7:04 AM, Chris Wilson <chris@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@bu3sch.de>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Looks good.
Reviewed-by: Alex Deucher <alexdeucher@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@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] drm: Retry i2c transfer of EDID block after failure
2011-03-15 11:04 ` [PATCH] drm: Retry i2c transfer of EDID block after failure Chris Wilson
2011-03-15 17:02 ` Alex Deucher
@ 2011-03-15 22:20 ` Michael Buesch
1 sibling, 0 replies; 4+ messages in thread
From: Michael Buesch @ 2011-03-15 22:20 UTC (permalink / raw)
To: Chris Wilson; +Cc: dri-devel
On Tue, 2011-03-15 at 11:04 +0000, Chris Wilson 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@bu3sch.de>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> ---
I'm currently testing this. It boots, but to see if
it fixes the issue, I'll have to run some more tests.
Note that this patch is subject to .37-table
and probably earlier releases, too.
--
Greetings, Michael.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2011-03-15 22:20 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-03-05 14:56 drm_get_edid i2c failure Michael Buesch
2011-03-15 11:04 ` [PATCH] drm: Retry i2c transfer of EDID block after failure Chris Wilson
2011-03-15 17:02 ` Alex Deucher
2011-03-15 22:20 ` Michael Buesch
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox