[PATCH 6/8] sfc: QT2025C: Work around PHY firmware initialisation bug
From: Ben Hutchings <hidden>
Date: 2009-12-23 23:48:35
Subsystem:
networking drivers, the rest · Maintainers:
Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
From: Matthew Slattery <redacted> The PHY's firmware very occasionally appears to lock up very early, but with the heartbeat update still running. Rebooting the microcontroller core seems to be sufficient to recover. Signed-off-by: Ben Hutchings <redacted> --- drivers/net/sfc/qt202x_phy.c | 59 ++++++++++++++++++++++++++++++++++++----- 1 files changed, 51 insertions(+), 8 deletions(-)
diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c
index 0cd6eed..326ffa4 100644
--- a/drivers/net/sfc/qt202x_phy.c
+++ b/drivers/net/sfc/qt202x_phy.c@@ -63,11 +63,16 @@ struct qt202x_phy_data { #define QT2022C2_MAX_RESET_TIME 500 #define QT2022C2_RESET_WAIT 10 +#define QT2025C_MAX_HEARTB_TIME (5 * HZ) +#define QT2025C_HEARTB_WAIT 100 +#define QT2025C_MAX_FWSTART_TIME (25 * HZ / 10) +#define QT2025C_FWSTART_WAIT 100 + #define BUG17190_INTERVAL (2 * HZ) -static int qt2025c_wait_reset(struct efx_nic *efx) +static int qt2025c_wait_heartbeat(struct efx_nic *efx) { - unsigned long timeout = jiffies + 10 * HZ; + unsigned long timeout = jiffies + QT2025C_MAX_HEARTB_TIME; int reg, old_counter = 0; /* Wait for firmware heartbeat to start */
@@ -84,9 +89,17 @@ static int qt2025c_wait_reset(struct efx_nic *efx) break; if (time_after(jiffies, timeout)) return -ETIMEDOUT; - msleep(10); + msleep(QT2025C_HEARTB_WAIT); } + return 0; +} + +static int qt2025c_wait_fw_status_good(struct efx_nic *efx) +{ + unsigned long timeout = jiffies + QT2025C_MAX_FWSTART_TIME; + int reg; + /* Wait for firmware status to look good */ for (;;) { reg = efx_mdio_read(efx, MDIO_MMD_PCS, PCS_UC8051_STATUS_REG);
@@ -98,12 +111,44 @@ static int qt2025c_wait_reset(struct efx_nic *efx) break; if (time_after(jiffies, timeout)) return -ETIMEDOUT; - msleep(100); + msleep(QT2025C_FWSTART_WAIT); } return 0; } +static void qt2025c_restart_firmware(struct efx_nic *efx) +{ + /* Restart microcontroller execution of firmware from RAM */ + efx_mdio_write(efx, 3, 0xe854, 0x00c0); + efx_mdio_write(efx, 3, 0xe854, 0x0040); + msleep(50); +} + +static int qt2025c_wait_reset(struct efx_nic *efx) +{ + int rc; + + rc = qt2025c_wait_heartbeat(efx); + if (rc != 0) + return rc; + + rc = qt2025c_wait_fw_status_good(efx); + if (rc == -ETIMEDOUT) { + /* Bug 17689: occasionally heartbeat starts but firmware status + * code never progresses beyond 0x00. Try again, once, after + * restarting execution of the firmware image. */ + EFX_LOG(efx, "bashing QT2025C microcontroller\n"); + qt2025c_restart_firmware(efx); + rc = qt2025c_wait_heartbeat(efx); + if (rc != 0) + return rc; + rc = qt2025c_wait_fw_status_good(efx); + } + + return rc; +} + static void qt2025c_firmware_id(struct efx_nic *efx) { struct qt202x_phy_data *phy_data = efx->phy_data;
@@ -229,10 +274,8 @@ static int qt2025c_select_phy_mode(struct efx_nic *efx) efx_mdio_write(efx, 1, 0xc300, 0x0002); msleep(20); - /* Restart microcontroller execution from RAM */ - efx_mdio_write(efx, 3, 0xe854, 0x00c0); - efx_mdio_write(efx, 3, 0xe854, 0x0040); - msleep(50); + /* Restart microcontroller execution of firmware from RAM */ + qt2025c_restart_firmware(efx); /* Wait for the microcontroller to be ready again */ rc = qt2025c_wait_reset(efx);
--
1.5.5
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.