Commit f7235ef6 authored by David Ertman's avatar David Ertman Committed by Jeff Kirsher

e1000e: Resolve issues with Management Engine (ME) briefly blocking PHY resets

On a ME enabled system with the cable out, the driver init flow would
generate an erroneous message indicating that resets were being blocked
by an active ME session.  Cause was ME clearing the semaphore bit to
block further PHY resets for up to 50 msec during power-on/cycle.  After
this interval, ME would re-set the bit and allow PHY resets.

To resolve this, change the flow of e1000e_phy_hw_reset_generic() to
utilize a delay and retry method.  Poll the FWSM register to minimize
any extra time added to the flow.  If the delay times out at 100ms
(checked in 10msec increments), then return the value E1000_BLK_PHY_RESET,
as this is the accurate state of the PHY.  Attempting to alter just the
call to e1000e_phy_hw_reset_generic() in e1000_init_phy_workarounds_pchlan()
just caused the problem to move further down the flow.
Signed-off-by: default avatarDave Ertman <davidx.m.ertman@intel.com>
Acked-by: default avatarBruce W. Allan <bruce.w.allan@intel.com>
Tested-by: default avatarJeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent b485dbae
...@@ -247,6 +247,7 @@ static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw) ...@@ -247,6 +247,7 @@ static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw)
**/ **/
static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw) static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
{ {
struct e1000_adapter *adapter = hw->adapter;
u32 mac_reg, fwsm = er32(FWSM); u32 mac_reg, fwsm = er32(FWSM);
s32 ret_val; s32 ret_val;
...@@ -349,12 +350,31 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw) ...@@ -349,12 +350,31 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
hw->phy.ops.release(hw); hw->phy.ops.release(hw);
if (!ret_val) { if (!ret_val) {
/* Check to see if able to reset PHY. Print error if not */
if (hw->phy.ops.check_reset_block(hw)) {
e_err("Reset blocked by ME\n");
goto out;
}
/* Reset the PHY before any access to it. Doing so, ensures /* Reset the PHY before any access to it. Doing so, ensures
* that the PHY is in a known good state before we read/write * that the PHY is in a known good state before we read/write
* PHY registers. The generic reset is sufficient here, * PHY registers. The generic reset is sufficient here,
* because we haven't determined the PHY type yet. * because we haven't determined the PHY type yet.
*/ */
ret_val = e1000e_phy_hw_reset_generic(hw); ret_val = e1000e_phy_hw_reset_generic(hw);
if (ret_val)
goto out;
/* On a successful reset, possibly need to wait for the PHY
* to quiesce to an accessible state before returning control
* to the calling function. If the PHY does not quiesce, then
* return E1000E_BLK_PHY_RESET, as this is the condition that
* the PHY is in.
*/
ret_val = hw->phy.ops.check_reset_block(hw);
if (ret_val)
e_err("ME blocked access to PHY after reset\n");
} }
out: out:
...@@ -1484,11 +1504,13 @@ static void e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index) ...@@ -1484,11 +1504,13 @@ static void e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index)
**/ **/
static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw) static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
{ {
u32 fwsm; bool blocked = false;
int i = 0;
fwsm = er32(FWSM); while ((blocked = !(er32(FWSM) & E1000_ICH_FWSM_RSPCIPHY)) &&
(i++ < 10))
return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? 0 : E1000_BLK_PHY_RESET; usleep_range(10000, 20000);
return blocked ? E1000_BLK_PHY_RESET : 0;
} }
/** /**
......
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