[PATCH net-next v2 3/4] net-e1000e: reworked carrier detection logic
From: David Decotigny
Date: Tue Nov 22 2011 - 14:24:40 EST
From: Maciej Åenczykowski <zenczykowski@xxxxxxxxx>
This change removes an un-needed final pause in case of timeout and
reworks the "link is up" detection logic.
Signed-off-by: David Decotigny <david.decotigny@xxxxxxxxxx>
---
drivers/net/ethernet/intel/e1000e/phy.c | 64 +++++++++++++++++++------------
1 files changed, 39 insertions(+), 25 deletions(-)
diff --git a/drivers/net/ethernet/intel/e1000e/phy.c b/drivers/net/ethernet/intel/e1000e/phy.c
index 8666476..f487a7f 100644
--- a/drivers/net/ethernet/intel/e1000e/phy.c
+++ b/drivers/net/ethernet/intel/e1000e/phy.c
@@ -1775,39 +1775,53 @@ static s32 e1000_wait_autoneg(struct e1000_hw *hw)
* Polls the PHY status register for link, 'iterations' number of times.
**/
s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
- u32 usec_interval, bool *success)
+ u32 usec_interval, bool *success)
{
- s32 ret_val = 0;
- u16 i, phy_status;
+ u32 i;
+ u16 phy_reg;
+ int good_reads_phy_status = 0;
+
+ }
+
+ /*
+ * Remember that e1e_rphy may fail because of another entity
+ * (like the firmware) holding the lock, we need to handle
+ * this gracefully - by waiting and trying again.
+ *
+ * Some PHYs require the PHY_STATUS register to be read twice
+ * due to the link bit being sticky. No harm doing it across
+ * the board.
+ */
+ for (i = 0; i < iterations; /* i incremented manually */) {
+ if (0 == e1e_rphy(hw, PHY_STATUS, &phy_reg)) {
+ if (++good_reads_phy_status < 2)
+ continue; /* Re-read once, to make sure */
- for (i = 0; i < iterations; i++) {
- /*
- * Some PHYs require the PHY_STATUS register to be read
- * twice due to the link bit being sticky. No harm doing
- * it across the board.
- */
- ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
- if (ret_val)
/*
- * If the first read fails, another entity may have
- * ownership of the resources, wait and try again to
- * see if they have relinquished the resources yet.
+ * Great, we got at least 2 successfull reads
*/
- udelay(usec_interval);
- ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
- if (ret_val)
- break;
- if (phy_status & MII_SR_LINK_STATUS)
- break;
- if (usec_interval >= 1000)
- mdelay(usec_interval/1000);
+
+ if (phy_reg & MII_SR_LINK_STATUS) {
+ /* success: link up */
+ *success = true;
+ return 0;
+ }
+ }
+
+ /* Pause now and re-iterate */
+ if (++i >= iterations)
+ break; /* Pause not needed after last iteration */
+ else if (usec_interval >= 1000)
+ mdelay(usec_interval / 1000);
else
udelay(usec_interval);
}
- *success = (i < iterations);
-
- return ret_val;
+ /* no success in for(;;) loop */
+ *success = false;
+ if (good_reads_phy_status < 2)
+ return -E1000_ERR_PHY;
+ return 0;
}
/**
--
1.7.3.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/