Commit 1a40d5c1 authored by Bruce Allan's avatar Bruce Allan Committed by David S. Miller

e1000e: ensure the link state is correct for serdes links

This patch ensures that the link state (as reported in
mac->serdes_has_link) will transition to false when autoneg fails to
complete but valid codewords were detected.
Signed-off-by: default avatarBruce Allan <bruce.w.allan@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 17f208de
...@@ -1356,8 +1356,20 @@ static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw) ...@@ -1356,8 +1356,20 @@ static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw)
* e1000_check_for_serdes_link_82571 - Check for link (Serdes) * e1000_check_for_serdes_link_82571 - Check for link (Serdes)
* @hw: pointer to the HW structure * @hw: pointer to the HW structure
* *
* Checks for link up on the hardware. If link is not up and we have * Reports the link state as up or down.
* a signal, then we need to force link up. *
* If autonegotiation is supported by the link partner, the link state is
* determined by the result of autonegotiation. This is the most likely case.
* If autonegotiation is not supported by the link partner, and the link
* has a valid signal, force the link up.
*
* The link state is represented internally here by 4 states:
*
* 1) down
* 2) autoneg_progress
* 3) autoneg_complete (the link sucessfully autonegotiated)
* 4) forced_up (the link has been forced up, it did not autonegotiate)
*
**/ **/
static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
{ {
...@@ -1383,6 +1395,7 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) ...@@ -1383,6 +1395,7 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
*/ */
mac->serdes_link_state = mac->serdes_link_state =
e1000_serdes_link_autoneg_progress; e1000_serdes_link_autoneg_progress;
mac->serdes_has_link = false;
e_dbg("AN_UP -> AN_PROG\n"); e_dbg("AN_UP -> AN_PROG\n");
} }
break; break;
...@@ -1397,57 +1410,64 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) ...@@ -1397,57 +1410,64 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
if (rxcw & E1000_RXCW_C) { if (rxcw & E1000_RXCW_C) {
/* Enable autoneg, and unforce link up */ /* Enable autoneg, and unforce link up */
ew32(TXCW, mac->txcw); ew32(TXCW, mac->txcw);
ew32(CTRL, ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
(ctrl & ~E1000_CTRL_SLU));
mac->serdes_link_state = mac->serdes_link_state =
e1000_serdes_link_autoneg_progress; e1000_serdes_link_autoneg_progress;
mac->serdes_has_link = false;
e_dbg("FORCED_UP -> AN_PROG\n"); e_dbg("FORCED_UP -> AN_PROG\n");
} }
break; break;
case e1000_serdes_link_autoneg_progress: case e1000_serdes_link_autoneg_progress:
/* if (rxcw & E1000_RXCW_C) {
* If the LU bit is set in the STATUS register, /*
* autoneg has completed sucessfully. If not, * We received /C/ ordered sets, meaning the
* try foring the link because the far end may be * link partner has autonegotiated, and we can
* available but not capable of autonegotiation. * trust the Link Up (LU) status bit.
*/ */
if (status & E1000_STATUS_LU) { if (status & E1000_STATUS_LU) {
mac->serdes_link_state = mac->serdes_link_state =
e1000_serdes_link_autoneg_complete; e1000_serdes_link_autoneg_complete;
e_dbg("AN_PROG -> AN_UP\n"); e_dbg("AN_PROG -> AN_UP\n");
mac->serdes_has_link = true;
} else {
/* Autoneg completed, but failed. */
mac->serdes_link_state =
e1000_serdes_link_down;
e_dbg("AN_PROG -> DOWN\n");
}
} else { } else {
/* /*
* Disable autoneg, force link up and * The link partner did not autoneg.
* full duplex, and change state to forced * Force link up and full duplex, and change
* state to forced.
*/ */
ew32(TXCW, ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE));
(mac->txcw & ~E1000_TXCW_ANE));
ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD); ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
ew32(CTRL, ctrl); ew32(CTRL, ctrl);
/* Configure Flow Control after link up. */ /* Configure Flow Control after link up. */
ret_val = ret_val = e1000e_config_fc_after_link_up(hw);
e1000e_config_fc_after_link_up(hw);
if (ret_val) { if (ret_val) {
e_dbg("Error config flow control\n"); e_dbg("Error config flow control\n");
break; break;
} }
mac->serdes_link_state = mac->serdes_link_state =
e1000_serdes_link_forced_up; e1000_serdes_link_forced_up;
mac->serdes_has_link = true;
e_dbg("AN_PROG -> FORCED_UP\n"); e_dbg("AN_PROG -> FORCED_UP\n");
} }
mac->serdes_has_link = true;
break; break;
case e1000_serdes_link_down: case e1000_serdes_link_down:
default: default:
/* The link was down but the receiver has now gained /*
* The link was down but the receiver has now gained
* valid sync, so lets see if we can bring the link * valid sync, so lets see if we can bring the link
* up. */ * up.
*/
ew32(TXCW, mac->txcw); ew32(TXCW, mac->txcw);
ew32(CTRL, ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
(ctrl & ~E1000_CTRL_SLU));
mac->serdes_link_state = mac->serdes_link_state =
e1000_serdes_link_autoneg_progress; e1000_serdes_link_autoneg_progress;
e_dbg("DOWN -> AN_PROG\n"); e_dbg("DOWN -> AN_PROG\n");
...@@ -1460,9 +1480,9 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) ...@@ -1460,9 +1480,9 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
e_dbg("ANYSTATE -> DOWN\n"); e_dbg("ANYSTATE -> DOWN\n");
} else { } else {
/* /*
* We have sync, and can tolerate one * We have sync, and can tolerate one invalid (IV)
* invalid (IV) codeword before declaring * codeword before declaring link down, so reread
* link down, so reread to look again * to look again.
*/ */
udelay(10); udelay(10);
rxcw = er32(RXCW); rxcw = er32(RXCW);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment