mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-02-20 09:06:44 +07:00
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_get_phy_id_82571(struct e1000_hw *hw);
|
||||||
static s32 e1000_setup_copper_link_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_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,
|
static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset,
|
||||||
u16 words, u16 *data);
|
u16 words, u16 *data);
|
||||||
static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw);
|
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:
|
case e1000_media_type_internal_serdes:
|
||||||
func->setup_physical_interface =
|
func->setup_physical_interface =
|
||||||
e1000_setup_fiber_serdes_link_82571;
|
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 =
|
func->get_link_up_info =
|
||||||
e1000e_get_speed_and_duplex_fiber_serdes;
|
e1000e_get_speed_and_duplex_fiber_serdes;
|
||||||
break;
|
break;
|
||||||
@ -830,6 +831,10 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
|
|||||||
hw->dev_spec.e82571.alt_mac_addr_is_present)
|
hw->dev_spec.e82571.alt_mac_addr_is_present)
|
||||||
e1000e_set_laa_state_82571(hw, true);
|
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;
|
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);
|
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
|
* e1000_valid_led_default_82571 - Verify a valid default LED config
|
||||||
* @hw: pointer to the HW structure
|
* @hw: pointer to the HW structure
|
||||||
|
@ -459,6 +459,13 @@ enum e1000_smart_speed {
|
|||||||
e1000_smart_speed_off
|
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 */
|
/* Receive Descriptor */
|
||||||
struct e1000_rx_desc {
|
struct e1000_rx_desc {
|
||||||
__le64 buffer_addr; /* Address of the descriptor's data buffer */
|
__le64 buffer_addr; /* Address of the descriptor's data buffer */
|
||||||
@ -787,6 +794,7 @@ struct e1000_mac_info {
|
|||||||
bool in_ifs_mode;
|
bool in_ifs_mode;
|
||||||
bool serdes_has_link;
|
bool serdes_has_link;
|
||||||
bool tx_pkt_filtering;
|
bool tx_pkt_filtering;
|
||||||
|
enum e1000_serdes_link_state serdes_link_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct e1000_phy_info {
|
struct e1000_phy_info {
|
||||||
|
Loading…
Reference in New Issue
Block a user