aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/dsa
diff options
context:
space:
mode:
authorAlfred Lee2023-08-14 17:13:23 -0700
committerGreg Kroah-Hartman2023-08-23 17:52:35 +0200
commitdf83af3b996d79d7eb51eaefdffb7f4352e55052 (patch)
tree0e5080854cd761c8de330c92218181c2f0e589a5 /drivers/net/dsa
parent740924313a1b4eb223a6494e199ad83d58f906c7 (diff)
net: dsa: mv88e6xxx: Wait for EEPROM done before HW reset
[ Upstream commit 23d775f12dcd23d052a4927195f15e970e27ab26 ] If the switch is reset during active EEPROM transactions, as in just after an SoC reset after power up, the I2C bus transaction may be cut short leaving the EEPROM internal I2C state machine in the wrong state. When the switch is reset again, the bad state machine state may result in data being read from the wrong memory location causing the switch to enter unexpected mode rendering it inoperational. Fixes: a3dcb3e7e70c ("net: dsa: mv88e6xxx: Wait for EEPROM done after HW reset") Signed-off-by: Alfred Lee <l00g33k@gmail.com> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Link: https://lore.kernel.org/r/20230815001323.24739-1-l00g33k@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'drivers/net/dsa')
-rw-r--r--drivers/net/dsa/mv88e6xxx/chip.c8
1 files changed, 8 insertions, 0 deletions
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index b69bd44ada1f..a73008b9e0b3 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -3006,6 +3006,14 @@ static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip)
/* If there is a GPIO connected to the reset pin, toggle it */
if (gpiod) {
+ /* If the switch has just been reset and not yet completed
+ * loading EEPROM, the reset may interrupt the I2C transaction
+ * mid-byte, causing the first EEPROM read after the reset
+ * from the wrong location resulting in the switch booting
+ * to wrong mode and inoperable.
+ */
+ mv88e6xxx_g1_wait_eeprom_done(chip);
+
gpiod_set_value_cansleep(gpiod, 1);
usleep_range(10000, 20000);
gpiod_set_value_cansleep(gpiod, 0);