e1000e: fix test for PHY being accessible on 82577/8/9 and I217

Occasionally, the PHY can be initially inaccessible when the first read of
a PHY register, e.g. PHY_ID1, happens (signified by the returned value
0xFFFF) but subsequent accesses of the PHY work as expected.  Add a retry
counter similar to how it is done in the generic e1000_get_phy_id().

Also, when the PHY is completely inaccessible (i.e. when subsequent reads
of the PHY_IDx registers returns all F's) and the MDIO access mode must be
set to slow before attempting to read the PHY ID again, the functions that
do these latter two actions expect the SW/FW/HW semaphore is not already
set so the semaphore must be released before and re-acquired after calling
them otherwise there is an unnecessarily inordinate amount of delay during
device initialization.

Reported-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Tested-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
Bruce Allan 2012-07-14 04:23:58 +00:00 committed by Jeff Kirsher
parent d0efa8f23a
commit a52359b56c
1 changed files with 32 additions and 10 deletions

View File

@ -325,24 +325,46 @@ static inline void __ew32flash(struct e1000_hw *hw, unsigned long reg, u32 val)
**/ **/
static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw) static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw)
{ {
u16 phy_reg; u16 phy_reg = 0;
u32 phy_id; u32 phy_id = 0;
s32 ret_val;
u16 retry_count;
e1e_rphy_locked(hw, PHY_ID1, &phy_reg); for (retry_count = 0; retry_count < 2; retry_count++) {
phy_id = (u32)(phy_reg << 16); ret_val = e1e_rphy_locked(hw, PHY_ID1, &phy_reg);
e1e_rphy_locked(hw, PHY_ID2, &phy_reg); if (ret_val || (phy_reg == 0xFFFF))
phy_id |= (u32)(phy_reg & PHY_REVISION_MASK); continue;
phy_id = (u32)(phy_reg << 16);
ret_val = e1e_rphy_locked(hw, PHY_ID2, &phy_reg);
if (ret_val || (phy_reg == 0xFFFF)) {
phy_id = 0;
continue;
}
phy_id |= (u32)(phy_reg & PHY_REVISION_MASK);
break;
}
if (hw->phy.id) { if (hw->phy.id) {
if (hw->phy.id == phy_id) if (hw->phy.id == phy_id)
return true; return true;
} else { } else if (phy_id) {
if ((phy_id != 0) && (phy_id != PHY_REVISION_MASK)) hw->phy.id = phy_id;
hw->phy.id = phy_id; hw->phy.revision = (u32)(phy_reg & ~PHY_REVISION_MASK);
return true; return true;
} }
return false; /*
* In case the PHY needs to be in mdio slow mode,
* set slow mode and try to get the PHY id again.
*/
hw->phy.ops.release(hw);
ret_val = e1000_set_mdio_slow_mode_hv(hw);
if (!ret_val)
ret_val = e1000e_get_phy_id(hw);
hw->phy.ops.acquire(hw);
return !ret_val;
} }
/** /**