summaryrefslogtreecommitdiff
path: root/drivers/net/sfc
diff options
context:
space:
mode:
authorMatthew Slattery <mslattery@solarflare.com>2009-12-23 16:48:32 +0300
committerDavid S. Miller <davem@davemloft.net>2009-12-24 06:09:07 +0300
commit1a1284ef97ca79ba747d211b697e996a248a8555 (patch)
treed338e531d49433d84f1baeba1934a55e1942fcd9 /drivers/net/sfc
parent0d83b2f64c330ee3892cb3117ac5d56e97185ecf (diff)
downloadlinux-1a1284ef97ca79ba747d211b697e996a248a8555.tar.xz
sfc: QT2025C: Work around PHY firmware initialisation bug
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 <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/sfc')
-rw-r--r--drivers/net/sfc/qt202x_phy.c59
1 files changed, 51 insertions, 8 deletions
diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c
index 0cd6eed02069..326ffa49fbd2 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);