Message ID | 20200915033220.165985-2-acelan.kao@canonical.com |
---|---|
State | New |
Headers | show |
Series | Thunderbolt3 daisy chain sometimes doesn't work | expand |
On 15.09.20 05:32, AceLan Kao wrote: > From: Mika Westerberg <mika.westerberg@linux.intel.com> > > BugLink: https://bugs.launchpad.net/bugs/1895606 > > Kai-Heng reported that sometimes DROM parsing of ASUS PA27AC Thunderbolt 3 > monitor fails. This makes the driver to fail to add the device so only > DisplayPort tunneling is functional. > > It is not clear what exactly happens but waiting for 100 ms and retrying > the read seems to work this around so we do that here. > > Link: https://bugzilla.kernel.org/show_bug.cgi?id=206493 > Reported-by: Kai-Heng Feng <kai.heng.feng@canonical.com> > Tested-by: Kai-Heng Feng <kai.heng.feng@canonical.com> > Cc: stable@vger.kernel.org > Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> > (cherry picked from commit f022ff7bf377ca94367be05de61277934d42ea74 > linux-next) > Signed-off-by: AceLan Kao <acelan.kao@canonical.com> Acked-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com> > --- > drivers/thunderbolt/eeprom.c | 20 ++++++++++++++++---- > 1 file changed, 16 insertions(+), 4 deletions(-) > > diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c > index ee5196479854..fa491944de1a 100644 > --- a/drivers/thunderbolt/eeprom.c > +++ b/drivers/thunderbolt/eeprom.c > @@ -7,6 +7,7 @@ > */ > > #include <linux/crc32.h> > +#include <linux/delay.h> > #include <linux/property.h> > #include <linux/slab.h> > #include "tb.h" > @@ -386,8 +387,8 @@ static int tb_drom_parse_entries(struct tb_switch *sw) > struct tb_drom_entry_header *entry = (void *) (sw->drom + pos); > if (pos + 1 == drom_size || pos + entry->len > drom_size > || !entry->len) { > - tb_sw_warn(sw, "drom buffer overrun, aborting\n"); > - return -EIO; > + tb_sw_warn(sw, "DROM buffer overrun\n"); > + return -EILSEQ; > } > > switch (entry->type) { > @@ -493,7 +494,8 @@ int tb_drom_read(struct tb_switch *sw) > u16 size; > u32 crc; > struct tb_drom_header *header; > - int res; > + int res, retries = 1; > + > if (sw->drom) > return 0; > > @@ -581,7 +583,17 @@ int tb_drom_read(struct tb_switch *sw) > tb_sw_warn(sw, "drom device_rom_revision %#x unknown\n", > header->device_rom_revision); > > - return tb_drom_parse_entries(sw); > + res = tb_drom_parse_entries(sw); > + /* If the DROM parsing fails, wait a moment and retry once */ > + if (res == -EILSEQ && retries--) { > + tb_sw_warn(sw, "parsing DROM failed, retrying\n"); > + msleep(100); > + res = tb_drom_read_n(sw, 0, sw->drom, size); > + if (!res) > + goto parse; > + } > + > + return res; > err: > kfree(sw->drom); > sw->drom = NULL; >
diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c index ee5196479854..fa491944de1a 100644 --- a/drivers/thunderbolt/eeprom.c +++ b/drivers/thunderbolt/eeprom.c @@ -7,6 +7,7 @@ */ #include <linux/crc32.h> +#include <linux/delay.h> #include <linux/property.h> #include <linux/slab.h> #include "tb.h" @@ -386,8 +387,8 @@ static int tb_drom_parse_entries(struct tb_switch *sw) struct tb_drom_entry_header *entry = (void *) (sw->drom + pos); if (pos + 1 == drom_size || pos + entry->len > drom_size || !entry->len) { - tb_sw_warn(sw, "drom buffer overrun, aborting\n"); - return -EIO; + tb_sw_warn(sw, "DROM buffer overrun\n"); + return -EILSEQ; } switch (entry->type) { @@ -493,7 +494,8 @@ int tb_drom_read(struct tb_switch *sw) u16 size; u32 crc; struct tb_drom_header *header; - int res; + int res, retries = 1; + if (sw->drom) return 0; @@ -581,7 +583,17 @@ int tb_drom_read(struct tb_switch *sw) tb_sw_warn(sw, "drom device_rom_revision %#x unknown\n", header->device_rom_revision); - return tb_drom_parse_entries(sw); + res = tb_drom_parse_entries(sw); + /* If the DROM parsing fails, wait a moment and retry once */ + if (res == -EILSEQ && retries--) { + tb_sw_warn(sw, "parsing DROM failed, retrying\n"); + msleep(100); + res = tb_drom_read_n(sw, 0, sw->drom, size); + if (!res) + goto parse; + } + + return res; err: kfree(sw->drom); sw->drom = NULL;