forked from luck/tmp_suning_uos_patched
e1000e: Serdes - attempt autoneg when link restored.
This patch addresses an issue where we did not restart auto-negotiation on serdes links when the link partner was disabled and re-enabled. It includes reworking the serdes link detect mechanism to be a state machine for 82571 and 82572 parts only. Signed-off-by: dave graham <david.graham@intel.com> Acked-by: Bruce Allan <bruce.w.allan@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
573cca8c6f
commit
c9523379d6
@ -61,6 +61,7 @@
|
||||
static s32 e1000_get_phy_id_82571(struct e1000_hw *hw);
|
||||
static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw);
|
||||
static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw);
|
||||
static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw);
|
||||
static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset,
|
||||
u16 words, u16 *data);
|
||||
static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw);
|
||||
@ -250,7 +251,7 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter)
|
||||
case e1000_media_type_internal_serdes:
|
||||
func->setup_physical_interface =
|
||||
e1000_setup_fiber_serdes_link_82571;
|
||||
func->check_for_link = e1000e_check_for_serdes_link;
|
||||
func->check_for_link = e1000_check_for_serdes_link_82571;
|
||||
func->get_link_up_info =
|
||||
e1000e_get_speed_and_duplex_fiber_serdes;
|
||||
break;
|
||||
@ -830,6 +831,10 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
|
||||
hw->dev_spec.e82571.alt_mac_addr_is_present)
|
||||
e1000e_set_laa_state_82571(hw, true);
|
||||
|
||||
/* Reinitialize the 82571 serdes link state machine */
|
||||
if (hw->phy.media_type == e1000_media_type_internal_serdes)
|
||||
hw->mac.serdes_link_state = e1000_serdes_link_down;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1214,6 +1219,131 @@ static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw)
|
||||
return e1000e_setup_fiber_serdes_link(hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_check_for_serdes_link_82571 - Check for link (Serdes)
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Checks for link up on the hardware. If link is not up and we have
|
||||
* a signal, then we need to force link up.
|
||||
**/
|
||||
s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
|
||||
{
|
||||
struct e1000_mac_info *mac = &hw->mac;
|
||||
u32 rxcw;
|
||||
u32 ctrl;
|
||||
u32 status;
|
||||
s32 ret_val = 0;
|
||||
|
||||
ctrl = er32(CTRL);
|
||||
status = er32(STATUS);
|
||||
rxcw = er32(RXCW);
|
||||
|
||||
if ((rxcw & E1000_RXCW_SYNCH) && !(rxcw & E1000_RXCW_IV)) {
|
||||
|
||||
/* Receiver is synchronized with no invalid bits. */
|
||||
switch (mac->serdes_link_state) {
|
||||
case e1000_serdes_link_autoneg_complete:
|
||||
if (!(status & E1000_STATUS_LU)) {
|
||||
/*
|
||||
* We have lost link, retry autoneg before
|
||||
* reporting link failure
|
||||
*/
|
||||
mac->serdes_link_state =
|
||||
e1000_serdes_link_autoneg_progress;
|
||||
hw_dbg(hw, "AN_UP -> AN_PROG\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case e1000_serdes_link_forced_up:
|
||||
/*
|
||||
* If we are receiving /C/ ordered sets, re-enable
|
||||
* auto-negotiation in the TXCW register and disable
|
||||
* forced link in the Device Control register in an
|
||||
* attempt to auto-negotiate with our link partner.
|
||||
*/
|
||||
if (rxcw & E1000_RXCW_C) {
|
||||
/* Enable autoneg, and unforce link up */
|
||||
ew32(TXCW, mac->txcw);
|
||||
ew32(CTRL,
|
||||
(ctrl & ~E1000_CTRL_SLU));
|
||||
mac->serdes_link_state =
|
||||
e1000_serdes_link_autoneg_progress;
|
||||
hw_dbg(hw, "FORCED_UP -> AN_PROG\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case e1000_serdes_link_autoneg_progress:
|
||||
/*
|
||||
* If the LU bit is set in the STATUS register,
|
||||
* autoneg has completed sucessfully. If not,
|
||||
* try foring the link because the far end may be
|
||||
* available but not capable of autonegotiation.
|
||||
*/
|
||||
if (status & E1000_STATUS_LU) {
|
||||
mac->serdes_link_state =
|
||||
e1000_serdes_link_autoneg_complete;
|
||||
hw_dbg(hw, "AN_PROG -> AN_UP\n");
|
||||
} else {
|
||||
/*
|
||||
* Disable autoneg, force link up and
|
||||
* full duplex, and change state to forced
|
||||
*/
|
||||
ew32(TXCW,
|
||||
(mac->txcw & ~E1000_TXCW_ANE));
|
||||
ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
|
||||
ew32(CTRL, ctrl);
|
||||
|
||||
/* Configure Flow Control after link up. */
|
||||
ret_val =
|
||||
e1000e_config_fc_after_link_up(hw);
|
||||
if (ret_val) {
|
||||
hw_dbg(hw, "Error config flow control\n");
|
||||
break;
|
||||
}
|
||||
mac->serdes_link_state =
|
||||
e1000_serdes_link_forced_up;
|
||||
hw_dbg(hw, "AN_PROG -> FORCED_UP\n");
|
||||
}
|
||||
mac->serdes_has_link = true;
|
||||
break;
|
||||
|
||||
case e1000_serdes_link_down:
|
||||
default:
|
||||
/* The link was down but the receiver has now gained
|
||||
* valid sync, so lets see if we can bring the link
|
||||
* up. */
|
||||
ew32(TXCW, mac->txcw);
|
||||
ew32(CTRL,
|
||||
(ctrl & ~E1000_CTRL_SLU));
|
||||
mac->serdes_link_state =
|
||||
e1000_serdes_link_autoneg_progress;
|
||||
hw_dbg(hw, "DOWN -> AN_PROG\n");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (!(rxcw & E1000_RXCW_SYNCH)) {
|
||||
mac->serdes_has_link = false;
|
||||
mac->serdes_link_state = e1000_serdes_link_down;
|
||||
hw_dbg(hw, "ANYSTATE -> DOWN\n");
|
||||
} else {
|
||||
/*
|
||||
* We have sync, and can tolerate one
|
||||
* invalid (IV) codeword before declaring
|
||||
* link down, so reread to look again
|
||||
*/
|
||||
udelay(10);
|
||||
rxcw = er32(RXCW);
|
||||
if (rxcw & E1000_RXCW_IV) {
|
||||
mac->serdes_link_state = e1000_serdes_link_down;
|
||||
mac->serdes_has_link = false;
|
||||
hw_dbg(hw, "ANYSTATE -> DOWN\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_valid_led_default_82571 - Verify a valid default LED config
|
||||
* @hw: pointer to the HW structure
|
||||
|
@ -459,6 +459,13 @@ enum e1000_smart_speed {
|
||||
e1000_smart_speed_off
|
||||
};
|
||||
|
||||
enum e1000_serdes_link_state {
|
||||
e1000_serdes_link_down = 0,
|
||||
e1000_serdes_link_autoneg_progress,
|
||||
e1000_serdes_link_autoneg_complete,
|
||||
e1000_serdes_link_forced_up
|
||||
};
|
||||
|
||||
/* Receive Descriptor */
|
||||
struct e1000_rx_desc {
|
||||
__le64 buffer_addr; /* Address of the descriptor's data buffer */
|
||||
@ -787,6 +794,7 @@ struct e1000_mac_info {
|
||||
bool in_ifs_mode;
|
||||
bool serdes_has_link;
|
||||
bool tx_pkt_filtering;
|
||||
enum e1000_serdes_link_state serdes_link_state;
|
||||
};
|
||||
|
||||
struct e1000_phy_info {
|
||||
|
Loading…
Reference in New Issue
Block a user