diff options
Diffstat (limited to 'drivers/net/ethernet/intel/igc/igc_phy.c')
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_phy.c | 206 | 
1 files changed, 108 insertions, 98 deletions
| diff --git a/drivers/net/ethernet/intel/igc/igc_phy.c b/drivers/net/ethernet/intel/igc/igc_phy.c index 4c8f96a9a148..8e1799508edc 100644 --- a/drivers/net/ethernet/intel/igc/igc_phy.c +++ b/drivers/net/ethernet/intel/igc/igc_phy.c @@ -3,10 +3,6 @@  #include "igc_phy.h" -/* forward declaration */ -static s32 igc_phy_setup_autoneg(struct igc_hw *hw); -static s32 igc_wait_autoneg(struct igc_hw *hw); -  /**   * igc_check_reset_block - Check if PHY reset is blocked   * @hw: pointer to the HW structure @@ -177,6 +173,7 @@ s32 igc_check_downshift(struct igc_hw *hw)  s32 igc_phy_hw_reset(struct igc_hw *hw)  {  	struct igc_phy_info *phy = &hw->phy; +	u32 phpm = 0, timeout = 10000;  	s32  ret_val;  	u32 ctrl; @@ -190,6 +187,8 @@ s32 igc_phy_hw_reset(struct igc_hw *hw)  	if (ret_val)  		goto out; +	phpm = rd32(IGC_I225_PHPM); +  	ctrl = rd32(IGC_CTRL);  	wr32(IGC_CTRL, ctrl | IGC_CTRL_PHY_RST);  	wrfl(); @@ -199,109 +198,26 @@ s32 igc_phy_hw_reset(struct igc_hw *hw)  	wr32(IGC_CTRL, ctrl);  	wrfl(); -	usleep_range(1500, 2000); - -	phy->ops.release(hw); - -out: -	return ret_val; -} - -/** - * igc_copper_link_autoneg - Setup/Enable autoneg for copper link - * @hw: pointer to the HW structure - * - * Performs initial bounds checking on autoneg advertisement parameter, then - * configure to advertise the full capability.  Setup the PHY to autoneg - * and restart the negotiation process between the link partner.  If - * autoneg_wait_to_complete, then wait for autoneg to complete before exiting. - */ -static s32 igc_copper_link_autoneg(struct igc_hw *hw) -{ -	struct igc_phy_info *phy = &hw->phy; -	u16 phy_ctrl; -	s32 ret_val; - -	/* Perform some bounds checking on the autoneg advertisement -	 * parameter. -	 */ -	phy->autoneg_advertised &= phy->autoneg_mask; - -	/* If autoneg_advertised is zero, we assume it was not defaulted -	 * by the calling code so we set to advertise full capability. -	 */ -	if (phy->autoneg_advertised == 0) -		phy->autoneg_advertised = phy->autoneg_mask; +	/* SW should guarantee 100us for the completion of the PHY reset */ +	usleep_range(100, 150); +	do { +		phpm = rd32(IGC_I225_PHPM); +		timeout--; +		udelay(1); +	} while (!(phpm & IGC_PHY_RST_COMP) && timeout); -	hw_dbg("Reconfiguring auto-neg advertisement params\n"); -	ret_val = igc_phy_setup_autoneg(hw); -	if (ret_val) { -		hw_dbg("Error Setting up Auto-Negotiation\n"); -		goto out; -	} -	hw_dbg("Restarting Auto-Neg\n"); +	if (!timeout) +		hw_dbg("Timeout is expired after a phy reset\n"); -	/* Restart auto-negotiation by setting the Auto Neg Enable bit and -	 * the Auto Neg Restart bit in the PHY control register. -	 */ -	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl); -	if (ret_val) -		goto out; +	usleep_range(100, 150); -	phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); -	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl); -	if (ret_val) -		goto out; - -	/* Does the user want to wait for Auto-Neg to complete here, or -	 * check at a later time (for example, callback routine). -	 */ -	if (phy->autoneg_wait_to_complete) { -		ret_val = igc_wait_autoneg(hw); -		if (ret_val) { -			hw_dbg("Error while waiting for autoneg to complete\n"); -			goto out; -		} -	} - -	hw->mac.get_link_status = true; +	phy->ops.release(hw);  out:  	return ret_val;  }  /** - * igc_wait_autoneg - Wait for auto-neg completion - * @hw: pointer to the HW structure - * - * Waits for auto-negotiation to complete or for the auto-negotiation time - * limit to expire, which ever happens first. - */ -static s32 igc_wait_autoneg(struct igc_hw *hw) -{ -	u16 i, phy_status; -	s32 ret_val = 0; - -	/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */ -	for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) { -		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); -		if (ret_val) -			break; -		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); -		if (ret_val) -			break; -		if (phy_status & MII_SR_AUTONEG_COMPLETE) -			break; -		msleep(100); -	} - -	/* PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation -	 * has completed. -	 */ -	return ret_val; -} - -/**   * igc_phy_setup_autoneg - Configure PHY for auto-negotiation   * @hw: pointer to the HW structure   * @@ -486,6 +402,100 @@ static s32 igc_phy_setup_autoneg(struct igc_hw *hw)  }  /** + * igc_wait_autoneg - Wait for auto-neg completion + * @hw: pointer to the HW structure + * + * Waits for auto-negotiation to complete or for the auto-negotiation time + * limit to expire, which ever happens first. + */ +static s32 igc_wait_autoneg(struct igc_hw *hw) +{ +	u16 i, phy_status; +	s32 ret_val = 0; + +	/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */ +	for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) { +		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); +		if (ret_val) +			break; +		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); +		if (ret_val) +			break; +		if (phy_status & MII_SR_AUTONEG_COMPLETE) +			break; +		msleep(100); +	} + +	/* PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation +	 * has completed. +	 */ +	return ret_val; +} + +/** + * igc_copper_link_autoneg - Setup/Enable autoneg for copper link + * @hw: pointer to the HW structure + * + * Performs initial bounds checking on autoneg advertisement parameter, then + * configure to advertise the full capability.  Setup the PHY to autoneg + * and restart the negotiation process between the link partner.  If + * autoneg_wait_to_complete, then wait for autoneg to complete before exiting. + */ +static s32 igc_copper_link_autoneg(struct igc_hw *hw) +{ +	struct igc_phy_info *phy = &hw->phy; +	u16 phy_ctrl; +	s32 ret_val; + +	/* Perform some bounds checking on the autoneg advertisement +	 * parameter. +	 */ +	phy->autoneg_advertised &= phy->autoneg_mask; + +	/* If autoneg_advertised is zero, we assume it was not defaulted +	 * by the calling code so we set to advertise full capability. +	 */ +	if (phy->autoneg_advertised == 0) +		phy->autoneg_advertised = phy->autoneg_mask; + +	hw_dbg("Reconfiguring auto-neg advertisement params\n"); +	ret_val = igc_phy_setup_autoneg(hw); +	if (ret_val) { +		hw_dbg("Error Setting up Auto-Negotiation\n"); +		goto out; +	} +	hw_dbg("Restarting Auto-Neg\n"); + +	/* Restart auto-negotiation by setting the Auto Neg Enable bit and +	 * the Auto Neg Restart bit in the PHY control register. +	 */ +	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl); +	if (ret_val) +		goto out; + +	phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); +	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl); +	if (ret_val) +		goto out; + +	/* Does the user want to wait for Auto-Neg to complete here, or +	 * check at a later time (for example, callback routine). +	 */ +	if (phy->autoneg_wait_to_complete) { +		ret_val = igc_wait_autoneg(hw); +		if (ret_val) { +			hw_dbg("Error while waiting for autoneg to complete\n"); +			goto out; +		} +	} + +	hw->mac.get_link_status = true; + +out: +	return ret_val; +} + +/**   * igc_setup_copper_link - Configure copper link settings   * @hw: pointer to the HW structure   * | 
