Commit 1ae289b0 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch '1GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue

Tony Nguyen says:

====================
Intel Wired LAN Driver Updates 2024-03-27 (e1000e)

This series contains updates to e1000e driver only.

Vitaly adds retry mechanism for some PHY operations to workaround MDI
error and moves SMBus configuration to avoid possible PHY loss.

* '1GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue:
  e1000e: move force SMBUS from enable ulp function to avoid PHY loss issue
  e1000e: Workaround for sporadic MDI error on Meteor Lake systems
====================

Link: https://lore.kernel.org/r/20240327185517.2587564-1-anthony.l.nguyen@intel.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 03796540 861e8086
...@@ -628,6 +628,7 @@ struct e1000_phy_info { ...@@ -628,6 +628,7 @@ struct e1000_phy_info {
u32 id; u32 id;
u32 reset_delay_us; /* in usec */ u32 reset_delay_us; /* in usec */
u32 revision; u32 revision;
u32 retry_count;
enum e1000_media_type media_type; enum e1000_media_type media_type;
...@@ -644,6 +645,7 @@ struct e1000_phy_info { ...@@ -644,6 +645,7 @@ struct e1000_phy_info {
bool polarity_correction; bool polarity_correction;
bool speed_downgraded; bool speed_downgraded;
bool autoneg_wait_to_complete; bool autoneg_wait_to_complete;
bool retry_enabled;
}; };
struct e1000_nvm_info { struct e1000_nvm_info {
......
...@@ -222,11 +222,18 @@ static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw) ...@@ -222,11 +222,18 @@ static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw)
if (hw->mac.type >= e1000_pch_lpt) { if (hw->mac.type >= e1000_pch_lpt) {
/* Only unforce SMBus if ME is not active */ /* Only unforce SMBus if ME is not active */
if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) { if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) {
/* Switching PHY interface always returns MDI error
* so disable retry mechanism to avoid wasting time
*/
e1000e_disable_phy_retry(hw);
/* Unforce SMBus mode in PHY */ /* Unforce SMBus mode in PHY */
e1e_rphy_locked(hw, CV_SMB_CTRL, &phy_reg); e1e_rphy_locked(hw, CV_SMB_CTRL, &phy_reg);
phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS; phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
e1e_wphy_locked(hw, CV_SMB_CTRL, phy_reg); e1e_wphy_locked(hw, CV_SMB_CTRL, phy_reg);
e1000e_enable_phy_retry(hw);
/* Unforce SMBus mode in MAC */ /* Unforce SMBus mode in MAC */
mac_reg = er32(CTRL_EXT); mac_reg = er32(CTRL_EXT);
mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS; mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
...@@ -310,6 +317,11 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw) ...@@ -310,6 +317,11 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
goto out; goto out;
} }
/* There is no guarantee that the PHY is accessible at this time
* so disable retry mechanism to avoid wasting time
*/
e1000e_disable_phy_retry(hw);
/* The MAC-PHY interconnect may be in SMBus mode. If the PHY is /* The MAC-PHY interconnect may be in SMBus mode. If the PHY is
* inaccessible and resetting the PHY is not blocked, toggle the * inaccessible and resetting the PHY is not blocked, toggle the
* LANPHYPC Value bit to force the interconnect to PCIe mode. * LANPHYPC Value bit to force the interconnect to PCIe mode.
...@@ -380,6 +392,8 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw) ...@@ -380,6 +392,8 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
break; break;
} }
e1000e_enable_phy_retry(hw);
hw->phy.ops.release(hw); hw->phy.ops.release(hw);
if (!ret_val) { if (!ret_val) {
...@@ -449,6 +463,11 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) ...@@ -449,6 +463,11 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
phy->id = e1000_phy_unknown; phy->id = e1000_phy_unknown;
if (hw->mac.type == e1000_pch_mtp) {
phy->retry_count = 2;
e1000e_enable_phy_retry(hw);
}
ret_val = e1000_init_phy_workarounds_pchlan(hw); ret_val = e1000_init_phy_workarounds_pchlan(hw);
if (ret_val) if (ret_val)
return ret_val; return ret_val;
...@@ -1146,18 +1165,6 @@ s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx) ...@@ -1146,18 +1165,6 @@ s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx)
if (ret_val) if (ret_val)
goto out; goto out;
/* Force SMBus mode in PHY */
ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg);
if (ret_val)
goto release;
phy_reg |= CV_SMB_CTRL_FORCE_SMBUS;
e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg);
/* Force SMBus mode in MAC */
mac_reg = er32(CTRL_EXT);
mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
ew32(CTRL_EXT, mac_reg);
/* Si workaround for ULP entry flow on i127/rev6 h/w. Enable /* Si workaround for ULP entry flow on i127/rev6 h/w. Enable
* LPLU and disable Gig speed when entering ULP * LPLU and disable Gig speed when entering ULP
*/ */
...@@ -1313,6 +1320,11 @@ static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force) ...@@ -1313,6 +1320,11 @@ static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force)
/* Toggle LANPHYPC Value bit */ /* Toggle LANPHYPC Value bit */
e1000_toggle_lanphypc_pch_lpt(hw); e1000_toggle_lanphypc_pch_lpt(hw);
/* Switching PHY interface always returns MDI error
* so disable retry mechanism to avoid wasting time
*/
e1000e_disable_phy_retry(hw);
/* Unforce SMBus mode in PHY */ /* Unforce SMBus mode in PHY */
ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg); ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg);
if (ret_val) { if (ret_val) {
...@@ -1333,6 +1345,8 @@ static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force) ...@@ -1333,6 +1345,8 @@ static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force)
phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS; phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg); e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg);
e1000e_enable_phy_retry(hw);
/* Unforce SMBus mode in MAC */ /* Unforce SMBus mode in MAC */
mac_reg = er32(CTRL_EXT); mac_reg = er32(CTRL_EXT);
mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS; mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
......
...@@ -6623,6 +6623,7 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime) ...@@ -6623,6 +6623,7 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
struct e1000_hw *hw = &adapter->hw; struct e1000_hw *hw = &adapter->hw;
u32 ctrl, ctrl_ext, rctl, status, wufc; u32 ctrl, ctrl_ext, rctl, status, wufc;
int retval = 0; int retval = 0;
u16 smb_ctrl;
/* Runtime suspend should only enable wakeup for link changes */ /* Runtime suspend should only enable wakeup for link changes */
if (runtime) if (runtime)
...@@ -6696,6 +6697,23 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime) ...@@ -6696,6 +6697,23 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
if (retval) if (retval)
return retval; return retval;
} }
/* Force SMBUS to allow WOL */
/* Switching PHY interface always returns MDI error
* so disable retry mechanism to avoid wasting time
*/
e1000e_disable_phy_retry(hw);
e1e_rphy(hw, CV_SMB_CTRL, &smb_ctrl);
smb_ctrl |= CV_SMB_CTRL_FORCE_SMBUS;
e1e_wphy(hw, CV_SMB_CTRL, smb_ctrl);
e1000e_enable_phy_retry(hw);
/* Force SMBus mode in MAC */
ctrl_ext = er32(CTRL_EXT);
ctrl_ext |= E1000_CTRL_EXT_FORCE_SMBUS;
ew32(CTRL_EXT, ctrl_ext);
} }
/* Ensure that the appropriate bits are set in LPI_CTRL /* Ensure that the appropriate bits are set in LPI_CTRL
......
...@@ -107,6 +107,16 @@ s32 e1000e_phy_reset_dsp(struct e1000_hw *hw) ...@@ -107,6 +107,16 @@ s32 e1000e_phy_reset_dsp(struct e1000_hw *hw)
return e1e_wphy(hw, M88E1000_PHY_GEN_CONTROL, 0); return e1e_wphy(hw, M88E1000_PHY_GEN_CONTROL, 0);
} }
void e1000e_disable_phy_retry(struct e1000_hw *hw)
{
hw->phy.retry_enabled = false;
}
void e1000e_enable_phy_retry(struct e1000_hw *hw)
{
hw->phy.retry_enabled = true;
}
/** /**
* e1000e_read_phy_reg_mdic - Read MDI control register * e1000e_read_phy_reg_mdic - Read MDI control register
* @hw: pointer to the HW structure * @hw: pointer to the HW structure
...@@ -118,18 +128,24 @@ s32 e1000e_phy_reset_dsp(struct e1000_hw *hw) ...@@ -118,18 +128,24 @@ s32 e1000e_phy_reset_dsp(struct e1000_hw *hw)
**/ **/
s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data) s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
{ {
u32 i, mdic = 0, retry_counter, retry_max;
struct e1000_phy_info *phy = &hw->phy; struct e1000_phy_info *phy = &hw->phy;
u32 i, mdic = 0; bool success;
if (offset > MAX_PHY_REG_ADDRESS) { if (offset > MAX_PHY_REG_ADDRESS) {
e_dbg("PHY Address %d is out of range\n", offset); e_dbg("PHY Address %d is out of range\n", offset);
return -E1000_ERR_PARAM; return -E1000_ERR_PARAM;
} }
retry_max = phy->retry_enabled ? phy->retry_count : 0;
/* Set up Op-code, Phy Address, and register offset in the MDI /* Set up Op-code, Phy Address, and register offset in the MDI
* Control register. The MAC will take care of interfacing with the * Control register. The MAC will take care of interfacing with the
* PHY to retrieve the desired data. * PHY to retrieve the desired data.
*/ */
for (retry_counter = 0; retry_counter <= retry_max; retry_counter++) {
success = true;
mdic = ((offset << E1000_MDIC_REG_SHIFT) | mdic = ((offset << E1000_MDIC_REG_SHIFT) |
(phy->addr << E1000_MDIC_PHY_SHIFT) | (phy->addr << E1000_MDIC_PHY_SHIFT) |
(E1000_MDIC_OP_READ)); (E1000_MDIC_OP_READ));
...@@ -141,32 +157,44 @@ s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data) ...@@ -141,32 +157,44 @@ s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
* the lower time out * the lower time out
*/ */
for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) { for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
udelay(50); usleep_range(50, 60);
mdic = er32(MDIC); mdic = er32(MDIC);
if (mdic & E1000_MDIC_READY) if (mdic & E1000_MDIC_READY)
break; break;
} }
if (!(mdic & E1000_MDIC_READY)) { if (!(mdic & E1000_MDIC_READY)) {
e_dbg("MDI Read PHY Reg Address %d did not complete\n", offset); e_dbg("MDI Read PHY Reg Address %d did not complete\n",
return -E1000_ERR_PHY; offset);
success = false;
} }
if (mdic & E1000_MDIC_ERROR) { if (mdic & E1000_MDIC_ERROR) {
e_dbg("MDI Read PHY Reg Address %d Error\n", offset); e_dbg("MDI Read PHY Reg Address %d Error\n", offset);
return -E1000_ERR_PHY; success = false;
} }
if (FIELD_GET(E1000_MDIC_REG_MASK, mdic) != offset) { if (FIELD_GET(E1000_MDIC_REG_MASK, mdic) != offset) {
e_dbg("MDI Read offset error - requested %d, returned %d\n", e_dbg("MDI Read offset error - requested %d, returned %d\n",
offset, FIELD_GET(E1000_MDIC_REG_MASK, mdic)); offset, FIELD_GET(E1000_MDIC_REG_MASK, mdic));
return -E1000_ERR_PHY; success = false;
} }
*data = (u16)mdic;
/* Allow some time after each MDIC transaction to avoid /* Allow some time after each MDIC transaction to avoid
* reading duplicate data in the next MDIC transaction. * reading duplicate data in the next MDIC transaction.
*/ */
if (hw->mac.type == e1000_pch2lan) if (hw->mac.type == e1000_pch2lan)
udelay(100); usleep_range(100, 150);
if (success) {
*data = (u16)mdic;
return 0; return 0;
}
if (retry_counter != retry_max) {
e_dbg("Perform retry on PHY transaction...\n");
mdelay(10);
}
}
return -E1000_ERR_PHY;
} }
/** /**
...@@ -179,18 +207,24 @@ s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data) ...@@ -179,18 +207,24 @@ s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
**/ **/
s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data) s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
{ {
u32 i, mdic = 0, retry_counter, retry_max;
struct e1000_phy_info *phy = &hw->phy; struct e1000_phy_info *phy = &hw->phy;
u32 i, mdic = 0; bool success;
if (offset > MAX_PHY_REG_ADDRESS) { if (offset > MAX_PHY_REG_ADDRESS) {
e_dbg("PHY Address %d is out of range\n", offset); e_dbg("PHY Address %d is out of range\n", offset);
return -E1000_ERR_PARAM; return -E1000_ERR_PARAM;
} }
retry_max = phy->retry_enabled ? phy->retry_count : 0;
/* Set up Op-code, Phy Address, and register offset in the MDI /* Set up Op-code, Phy Address, and register offset in the MDI
* Control register. The MAC will take care of interfacing with the * Control register. The MAC will take care of interfacing with the
* PHY to retrieve the desired data. * PHY to retrieve the desired data.
*/ */
for (retry_counter = 0; retry_counter <= retry_max; retry_counter++) {
success = true;
mdic = (((u32)data) | mdic = (((u32)data) |
(offset << E1000_MDIC_REG_SHIFT) | (offset << E1000_MDIC_REG_SHIFT) |
(phy->addr << E1000_MDIC_PHY_SHIFT) | (phy->addr << E1000_MDIC_PHY_SHIFT) |
...@@ -203,32 +237,42 @@ s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data) ...@@ -203,32 +237,42 @@ s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
* the lower time out * the lower time out
*/ */
for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) { for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
udelay(50); usleep_range(50, 60);
mdic = er32(MDIC); mdic = er32(MDIC);
if (mdic & E1000_MDIC_READY) if (mdic & E1000_MDIC_READY)
break; break;
} }
if (!(mdic & E1000_MDIC_READY)) { if (!(mdic & E1000_MDIC_READY)) {
e_dbg("MDI Write PHY Reg Address %d did not complete\n", offset); e_dbg("MDI Write PHY Reg Address %d did not complete\n",
return -E1000_ERR_PHY; offset);
success = false;
} }
if (mdic & E1000_MDIC_ERROR) { if (mdic & E1000_MDIC_ERROR) {
e_dbg("MDI Write PHY Red Address %d Error\n", offset); e_dbg("MDI Write PHY Reg Address %d Error\n", offset);
return -E1000_ERR_PHY; success = false;
} }
if (FIELD_GET(E1000_MDIC_REG_MASK, mdic) != offset) { if (FIELD_GET(E1000_MDIC_REG_MASK, mdic) != offset) {
e_dbg("MDI Write offset error - requested %d, returned %d\n", e_dbg("MDI Write offset error - requested %d, returned %d\n",
offset, FIELD_GET(E1000_MDIC_REG_MASK, mdic)); offset, FIELD_GET(E1000_MDIC_REG_MASK, mdic));
return -E1000_ERR_PHY; success = false;
} }
/* Allow some time after each MDIC transaction to avoid /* Allow some time after each MDIC transaction to avoid
* reading duplicate data in the next MDIC transaction. * reading duplicate data in the next MDIC transaction.
*/ */
if (hw->mac.type == e1000_pch2lan) if (hw->mac.type == e1000_pch2lan)
udelay(100); usleep_range(100, 150);
if (success)
return 0; return 0;
if (retry_counter != retry_max) {
e_dbg("Perform retry on PHY transaction...\n");
mdelay(10);
}
}
return -E1000_ERR_PHY;
} }
/** /**
......
...@@ -51,6 +51,8 @@ s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data); ...@@ -51,6 +51,8 @@ s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data);
s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data); s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data);
void e1000_power_up_phy_copper(struct e1000_hw *hw); void e1000_power_up_phy_copper(struct e1000_hw *hw);
void e1000_power_down_phy_copper(struct e1000_hw *hw); void e1000_power_down_phy_copper(struct e1000_hw *hw);
void e1000e_disable_phy_retry(struct e1000_hw *hw);
void e1000e_enable_phy_retry(struct e1000_hw *hw);
s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data); s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data); s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data); s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data);
......
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