Skip to content
Snippets Groups Projects
e1000.c 155 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	E1000_WRITE_REG(hw, TXCW, txcw);
    	E1000_WRITE_REG(hw, CTRL, ctrl);
    	E1000_WRITE_FLUSH(hw);
    
    	hw->txcw = txcw;
    	mdelay(1);
    
    	/* If we have a signal (the cable is plugged in) then poll for a "Link-Up"
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	 * indication in the Device Status Register.  Time-out if a link isn't
    	 * seen in 500 milliseconds seconds (Auto-negotiation should complete in
    
    	 * less than 500 milliseconds even if the other end is doing it in SW).
    	 */
    	if ((E1000_READ_REG(hw, CTRL) & E1000_CTRL_SWDPIN1) == signal) {
    		DEBUGOUT("Looking for Link\n");
    		for (i = 0; i < (LINK_UP_TIMEOUT / 10); i++) {
    			mdelay(10);
    			status = E1000_READ_REG(hw, STATUS);
    			if (status & E1000_STATUS_LU)
    				break;
    		}
    		if (i == (LINK_UP_TIMEOUT / 10)) {
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    			/* AutoNeg failed to achieve a link, so we'll call
    
    			 * e1000_check_for_link. This routine will force the link up if we
    			 * detect a signal. This will allow us to communicate with
    			 * non-autonegotiating link partners.
    			 */
    			DEBUGOUT("Never got a valid link from auto-neg!!!\n");
    			hw->autoneg_failed = 1;
    			ret_val = e1000_check_for_link(nic);
    			if (ret_val < 0) {
    				DEBUGOUT("Error while checking for link\n");
    				return ret_val;
    			}
    			hw->autoneg_failed = 0;
    		} else {
    			hw->autoneg_failed = 0;
    			DEBUGOUT("Valid Link Found\n");
    		}
    
    	} else {
    		DEBUGOUT("No Signal Detected\n");
    		return -E1000_ERR_NOLINK;
    	}
    	return 0;
    }
    
    /******************************************************************************
    * Make sure we have a valid PHY and change PHY mode before link setup.
    *
    * hw - Struct containing variables accessed by shared code
    ******************************************************************************/
    static int32_t
    e1000_copper_link_preconfig(struct e1000_hw *hw)
    {
    	uint32_t ctrl;
    	int32_t ret_val;
    	uint16_t phy_data;
    
    	DEBUGFUNC();
    
    	ctrl = E1000_READ_REG(hw, CTRL);
    	/* With 82543, we need to force speed and duplex on the MAC equal to what
    	 * the PHY speed and duplex configuration is. In addition, we need to
    	 * perform a hardware reset on the PHY to take it out of reset.
    	 */
    	if (hw->mac_type > e1000_82543) {
    		ctrl |= E1000_CTRL_SLU;
    		ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
    		E1000_WRITE_REG(hw, CTRL, ctrl);
    	} else {
    		ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX
    				| E1000_CTRL_SLU);
    		E1000_WRITE_REG(hw, CTRL, ctrl);
    		ret_val = e1000_phy_hw_reset(hw);
    		if (ret_val)
    			return ret_val;
    	}
    
    	/* Make sure we have a valid PHY */
    	ret_val = e1000_detect_gig_phy(hw);
    	if (ret_val) {
    		DEBUGOUT("Error, did not detect valid phy.\n");
    		return ret_val;
    	}
    	DEBUGOUT("Phy ID = %x \n", hw->phy_id);
    
    	/* Set PHY to class A mode (if necessary) */
    	ret_val = e1000_set_phy_mode(hw);
    	if (ret_val)
    		return ret_val;
    	if ((hw->mac_type == e1000_82545_rev_3) ||
    		(hw->mac_type == e1000_82546_rev_3)) {
    		ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
    				&phy_data);
    		phy_data |= 0x00000008;
    		ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
    				phy_data);
    	}
    
    	if (hw->mac_type <= e1000_82543 ||
    		hw->mac_type == e1000_82541 || hw->mac_type == e1000_82547 ||
    		hw->mac_type == e1000_82541_rev_2
    		|| hw->mac_type == e1000_82547_rev_2)
    
    York Sun's avatar
    York Sun committed
    			hw->phy_reset_disable = false;
    
    
    	return E1000_SUCCESS;
    }
    
    /*****************************************************************************
     *
     * This function sets the lplu state according to the active flag.  When
     * activating lplu this function also disables smart speed and vise versa.
     * lplu will not be activated unless the device autonegotiation advertisment
     * meets standards of either 10 or 10/100 or 10/100/1000 at all duplexes.
     * hw: Struct containing variables accessed by shared code
     * active - true to enable lplu false to disable lplu.
     *
     * returns: - E1000_ERR_PHY if fail to read/write the PHY
     *            E1000_SUCCESS at any other case.
     *
     ****************************************************************************/
    
    static int32_t
    
    York Sun's avatar
    York Sun committed
    e1000_set_d3_lplu_state(struct e1000_hw *hw, bool active)
    
    {
    	uint32_t phy_ctrl = 0;
    	int32_t ret_val;
    	uint16_t phy_data;
    	DEBUGFUNC();
    
    	if (hw->phy_type != e1000_phy_igp && hw->phy_type != e1000_phy_igp_2
    	    && hw->phy_type != e1000_phy_igp_3)
    		return E1000_SUCCESS;
    
    	/* During driver activity LPLU should not be used or it will attain link
    	 * from the lowest speeds starting from 10Mbps. The capability is used
    	 * for Dx transitions and states */
    	if (hw->mac_type == e1000_82541_rev_2
    			|| hw->mac_type == e1000_82547_rev_2) {
    		ret_val = e1000_read_phy_reg(hw, IGP01E1000_GMII_FIFO,
    				&phy_data);
    		if (ret_val)
    			return ret_val;
    	} else if (hw->mac_type == e1000_ich8lan) {
    		/* MAC writes into PHY register based on the state transition
    		 * and start auto-negotiation. SW driver can overwrite the
    		 * settings in CSR PHY power control E1000_PHY_CTRL register. */
    		phy_ctrl = E1000_READ_REG(hw, PHY_CTRL);
    	} else {
    		ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
    				&phy_data);
    		if (ret_val)
    			return ret_val;
    	}
    
    	if (!active) {
    		if (hw->mac_type == e1000_82541_rev_2 ||
    			hw->mac_type == e1000_82547_rev_2) {
    			phy_data &= ~IGP01E1000_GMII_FLEX_SPD;
    			ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO,
    					phy_data);
    			if (ret_val)
    				return ret_val;
    		} else {
    			if (hw->mac_type == e1000_ich8lan) {
    				phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
    				E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
    			} else {
    				phy_data &= ~IGP02E1000_PM_D3_LPLU;
    				ret_val = e1000_write_phy_reg(hw,
    					IGP02E1000_PHY_POWER_MGMT, phy_data);
    				if (ret_val)
    					return ret_val;
    			}
    		}
    
    	/* LPLU and SmartSpeed are mutually exclusive.  LPLU is used during
    	 * Dx states where the power conservation is most important.  During
    	 * driver activity we should enable SmartSpeed, so performance is
    	 * maintained. */
    		if (hw->smart_speed == e1000_smart_speed_on) {
    			ret_val = e1000_read_phy_reg(hw,
    					IGP01E1000_PHY_PORT_CONFIG, &phy_data);
    			if (ret_val)
    				return ret_val;
    
    			phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
    			ret_val = e1000_write_phy_reg(hw,
    					IGP01E1000_PHY_PORT_CONFIG, phy_data);
    			if (ret_val)
    				return ret_val;
    		} else if (hw->smart_speed == e1000_smart_speed_off) {
    			ret_val = e1000_read_phy_reg(hw,
    					IGP01E1000_PHY_PORT_CONFIG, &phy_data);
    			if (ret_val)
    				return ret_val;
    
    			phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
    			ret_val = e1000_write_phy_reg(hw,
    					IGP01E1000_PHY_PORT_CONFIG, phy_data);
    			if (ret_val)
    				return ret_val;
    		}
    
    	} else if ((hw->autoneg_advertised == AUTONEG_ADVERTISE_SPEED_DEFAULT)
    		|| (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_ALL) ||
    		(hw->autoneg_advertised == AUTONEG_ADVERTISE_10_100_ALL)) {
    
    		if (hw->mac_type == e1000_82541_rev_2 ||
    		    hw->mac_type == e1000_82547_rev_2) {
    			phy_data |= IGP01E1000_GMII_FLEX_SPD;
    			ret_val = e1000_write_phy_reg(hw,
    					IGP01E1000_GMII_FIFO, phy_data);
    			if (ret_val)
    				return ret_val;
    		} else {
    			if (hw->mac_type == e1000_ich8lan) {
    				phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
    				E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
    			} else {
    				phy_data |= IGP02E1000_PM_D3_LPLU;
    				ret_val = e1000_write_phy_reg(hw,
    					IGP02E1000_PHY_POWER_MGMT, phy_data);
    				if (ret_val)
    					return ret_val;
    			}
    		}
    
    		/* When LPLU is enabled we should disable SmartSpeed */
    		ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
    				&phy_data);
    		if (ret_val)
    			return ret_val;
    
    		phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
    		ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
    				phy_data);
    		if (ret_val)
    			return ret_val;
    	}
    	return E1000_SUCCESS;
    }
    
    /*****************************************************************************
     *
     * This function sets the lplu d0 state according to the active flag.  When
     * activating lplu this function also disables smart speed and vise versa.
     * lplu will not be activated unless the device autonegotiation advertisment
     * meets standards of either 10 or 10/100 or 10/100/1000 at all duplexes.
     * hw: Struct containing variables accessed by shared code
     * active - true to enable lplu false to disable lplu.
     *
     * returns: - E1000_ERR_PHY if fail to read/write the PHY
     *            E1000_SUCCESS at any other case.
     *
     ****************************************************************************/
    
    static int32_t
    
    York Sun's avatar
    York Sun committed
    e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active)
    
    {
    	uint32_t phy_ctrl = 0;
    	int32_t ret_val;
    	uint16_t phy_data;
    	DEBUGFUNC();
    
    	if (hw->mac_type <= e1000_82547_rev_2)
    		return E1000_SUCCESS;
    
    	if (hw->mac_type == e1000_ich8lan) {
    		phy_ctrl = E1000_READ_REG(hw, PHY_CTRL);
    	} else {
    		ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
    				&phy_data);
    		if (ret_val)
    			return ret_val;
    	}
    
    	if (!active) {
    		if (hw->mac_type == e1000_ich8lan) {
    			phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
    			E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
    		} else {
    			phy_data &= ~IGP02E1000_PM_D0_LPLU;
    			ret_val = e1000_write_phy_reg(hw,
    					IGP02E1000_PHY_POWER_MGMT, phy_data);
    			if (ret_val)
    				return ret_val;
    		}
    
    	/* LPLU and SmartSpeed are mutually exclusive.  LPLU is used during
    	 * Dx states where the power conservation is most important.  During
    	 * driver activity we should enable SmartSpeed, so performance is
    	 * maintained. */
    		if (hw->smart_speed == e1000_smart_speed_on) {
    			ret_val = e1000_read_phy_reg(hw,
    					IGP01E1000_PHY_PORT_CONFIG, &phy_data);
    			if (ret_val)
    				return ret_val;
    
    			phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
    			ret_val = e1000_write_phy_reg(hw,
    					IGP01E1000_PHY_PORT_CONFIG, phy_data);
    			if (ret_val)
    				return ret_val;
    		} else if (hw->smart_speed == e1000_smart_speed_off) {
    			ret_val = e1000_read_phy_reg(hw,
    					IGP01E1000_PHY_PORT_CONFIG, &phy_data);
    			if (ret_val)
    				return ret_val;
    
    			phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
    			ret_val = e1000_write_phy_reg(hw,
    					IGP01E1000_PHY_PORT_CONFIG, phy_data);
    			if (ret_val)
    				return ret_val;
    		}
    
    
    	} else {
    
    		if (hw->mac_type == e1000_ich8lan) {
    			phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
    			E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
    		} else {
    			phy_data |= IGP02E1000_PM_D0_LPLU;
    			ret_val = e1000_write_phy_reg(hw,
    					IGP02E1000_PHY_POWER_MGMT, phy_data);
    			if (ret_val)
    				return ret_val;
    		}
    
    		/* When LPLU is enabled we should disable SmartSpeed */
    		ret_val = e1000_read_phy_reg(hw,
    				IGP01E1000_PHY_PORT_CONFIG, &phy_data);
    		if (ret_val)
    			return ret_val;
    
    		phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
    		ret_val = e1000_write_phy_reg(hw,
    				IGP01E1000_PHY_PORT_CONFIG, phy_data);
    		if (ret_val)
    			return ret_val;
    
    	}
    	return E1000_SUCCESS;
    }
    
    /********************************************************************
    * Copper link setup for e1000_phy_igp series.
    *
    * hw - Struct containing variables accessed by shared code
    *********************************************************************/
    static int32_t
    e1000_copper_link_igp_setup(struct e1000_hw *hw)
    {
    	uint32_t led_ctrl;
    	int32_t ret_val;
    	uint16_t phy_data;
    
    
    	DEBUGFUNC();
    
    
    	if (hw->phy_reset_disable)
    		return E1000_SUCCESS;
    
    	ret_val = e1000_phy_reset(hw);
    	if (ret_val) {
    		DEBUGOUT("Error Resetting the PHY\n");
    		return ret_val;
    	}
    
    	/* Wait 15ms for MAC to configure PHY from eeprom settings */
    	mdelay(15);
    	if (hw->mac_type != e1000_ich8lan) {
    		/* Configure activity LED after PHY reset */
    		led_ctrl = E1000_READ_REG(hw, LEDCTL);
    		led_ctrl &= IGP_ACTIVITY_LED_MASK;
    		led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
    		E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
    	}
    
    	/* The NVM settings will configure LPLU in D3 for IGP2 and IGP3 PHYs */
    	if (hw->phy_type == e1000_phy_igp) {
    		/* disable lplu d3 during driver init */
    
    York Sun's avatar
    York Sun committed
    		ret_val = e1000_set_d3_lplu_state(hw, false);
    
    		if (ret_val) {
    			DEBUGOUT("Error Disabling LPLU D3\n");
    			return ret_val;
    		}
    	}
    
    	/* disable lplu d0 during driver init */
    
    York Sun's avatar
    York Sun committed
    	ret_val = e1000_set_d0_lplu_state(hw, false);
    
    	if (ret_val) {
    		DEBUGOUT("Error Disabling LPLU D0\n");
    		return ret_val;
    	}
    	/* Configure mdi-mdix settings */
    	ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
    	if (ret_val)
    		return ret_val;
    
    	if ((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
    		hw->dsp_config_state = e1000_dsp_config_disabled;
    		/* Force MDI for earlier revs of the IGP PHY */
    		phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX
    				| IGP01E1000_PSCR_FORCE_MDI_MDIX);
    		hw->mdix = 1;
    
    	} else {
    		hw->dsp_config_state = e1000_dsp_config_enabled;
    		phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
    
    		switch (hw->mdix) {
    		case 1:
    			phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
    			break;
    		case 2:
    			phy_data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
    			break;
    		case 0:
    		default:
    			phy_data |= IGP01E1000_PSCR_AUTO_MDIX;
    			break;
    		}
    	}
    	ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
    	if (ret_val)
    		return ret_val;
    
    	/* set auto-master slave resolution settings */
    	if (hw->autoneg) {
    		e1000_ms_type phy_ms_setting = hw->master_slave;
    
    		if (hw->ffe_config_state == e1000_ffe_config_active)
    			hw->ffe_config_state = e1000_ffe_config_enabled;
    
    		if (hw->dsp_config_state == e1000_dsp_config_activated)
    			hw->dsp_config_state = e1000_dsp_config_enabled;
    
    		/* when autonegotiation advertisment is only 1000Mbps then we
    		  * should disable SmartSpeed and enable Auto MasterSlave
    		  * resolution as hardware default. */
    		if (hw->autoneg_advertised == ADVERTISE_1000_FULL) {
    			/* Disable SmartSpeed */
    			ret_val = e1000_read_phy_reg(hw,
    					IGP01E1000_PHY_PORT_CONFIG, &phy_data);
    			if (ret_val)
    				return ret_val;
    			phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
    			ret_val = e1000_write_phy_reg(hw,
    					IGP01E1000_PHY_PORT_CONFIG, phy_data);
    			if (ret_val)
    				return ret_val;
    			/* Set auto Master/Slave resolution process */
    			ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL,
    					&phy_data);
    			if (ret_val)
    				return ret_val;
    			phy_data &= ~CR_1000T_MS_ENABLE;
    			ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL,
    					phy_data);
    			if (ret_val)
    				return ret_val;
    		}
    
    		ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data);
    		if (ret_val)
    			return ret_val;
    
    		/* load defaults for future use */
    		hw->original_master_slave = (phy_data & CR_1000T_MS_ENABLE) ?
    				((phy_data & CR_1000T_MS_VALUE) ?
    				e1000_ms_force_master :
    				e1000_ms_force_slave) :
    				e1000_ms_auto;
    
    		switch (phy_ms_setting) {
    		case e1000_ms_force_master:
    			phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
    			break;
    		case e1000_ms_force_slave:
    			phy_data |= CR_1000T_MS_ENABLE;
    			phy_data &= ~(CR_1000T_MS_VALUE);
    			break;
    		case e1000_ms_auto:
    			phy_data &= ~CR_1000T_MS_ENABLE;
    		default:
    			break;
    		}
    		ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
    		if (ret_val)
    			return ret_val;
    	}
    
    	return E1000_SUCCESS;
    }
    
    /*****************************************************************************
     * This function checks the mode of the firmware.
     *
    
    York Sun's avatar
    York Sun committed
     * returns  - true when the mode is IAMT or false.
    
     ****************************************************************************/
    
    York Sun's avatar
    York Sun committed
    bool
    
    e1000_check_mng_mode(struct e1000_hw *hw)
    {
    	uint32_t fwsm;
    	DEBUGFUNC();
    
    	fwsm = E1000_READ_REG(hw, FWSM);
    
    	if (hw->mac_type == e1000_ich8lan) {
    		if ((fwsm & E1000_FWSM_MODE_MASK) ==
    		    (E1000_MNG_ICH_IAMT_MODE << E1000_FWSM_MODE_SHIFT))
    
    York Sun's avatar
    York Sun committed
    			return true;
    
    	} else if ((fwsm & E1000_FWSM_MODE_MASK) ==
    		       (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT))
    
    York Sun's avatar
    York Sun committed
    			return true;
    
    York Sun's avatar
    York Sun committed
    	return false;
    
    }
    
    static int32_t
    e1000_write_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data)
    {
    
    	uint16_t swfw = E1000_SWFW_PHY0_SM;
    
    	uint32_t reg_val;
    	DEBUGFUNC();
    
    
    	if (e1000_is_second_port(hw))
    
    		swfw = E1000_SWFW_PHY1_SM;
    
    	if (e1000_swfw_sync_acquire(hw, swfw))
    		return -E1000_ERR_SWFW_SYNC;
    
    	reg_val = ((reg_addr << E1000_KUMCTRLSTA_OFFSET_SHIFT)
    			& E1000_KUMCTRLSTA_OFFSET) | data;
    	E1000_WRITE_REG(hw, KUMCTRLSTA, reg_val);
    	udelay(2);
    
    	return E1000_SUCCESS;
    }
    
    static int32_t
    e1000_read_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *data)
    {
    
    	uint16_t swfw = E1000_SWFW_PHY0_SM;
    
    	uint32_t reg_val;
    	DEBUGFUNC();
    
    
    	if (e1000_is_second_port(hw))
    
    		swfw = E1000_SWFW_PHY1_SM;
    
    	if (e1000_swfw_sync_acquire(hw, swfw))
    		return -E1000_ERR_SWFW_SYNC;
    
    	/* Write register address */
    	reg_val = ((reg_addr << E1000_KUMCTRLSTA_OFFSET_SHIFT) &
    			E1000_KUMCTRLSTA_OFFSET) | E1000_KUMCTRLSTA_REN;
    	E1000_WRITE_REG(hw, KUMCTRLSTA, reg_val);
    	udelay(2);
    
    	/* Read the data returned */
    	reg_val = E1000_READ_REG(hw, KUMCTRLSTA);
    	*data = (uint16_t)reg_val;
    
    	return E1000_SUCCESS;
    }
    
    /********************************************************************
    * Copper link setup for e1000_phy_gg82563 series.
    *
    * hw - Struct containing variables accessed by shared code
    *********************************************************************/
    static int32_t
    e1000_copper_link_ggp_setup(struct e1000_hw *hw)
    {
    	int32_t ret_val;
    	uint16_t phy_data;
    	uint32_t reg_data;
    
    	DEBUGFUNC();
    
    	if (!hw->phy_reset_disable) {
    		/* Enable CRS on TX for half-duplex operation. */
    		ret_val = e1000_read_phy_reg(hw,
    				GG82563_PHY_MAC_SPEC_CTRL, &phy_data);
    		if (ret_val)
    			return ret_val;
    
    		phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
    		/* Use 25MHz for both link down and 1000BASE-T for Tx clock */
    		phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ;
    
    		ret_val = e1000_write_phy_reg(hw,
    				GG82563_PHY_MAC_SPEC_CTRL, phy_data);
    		if (ret_val)
    			return ret_val;
    
    		/* Options:
    		 *   MDI/MDI-X = 0 (default)
    		 *   0 - Auto for all speeds
    		 *   1 - MDI mode
    		 *   2 - MDI-X mode
    		 *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
    		 */
    		ret_val = e1000_read_phy_reg(hw,
    				GG82563_PHY_SPEC_CTRL, &phy_data);
    		if (ret_val)
    			return ret_val;
    
    		phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK;
    
    		switch (hw->mdix) {
    		case 1:
    			phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDI;
    			break;
    		case 2:
    			phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDIX;
    			break;
    		case 0:
    		default:
    			phy_data |= GG82563_PSCR_CROSSOVER_MODE_AUTO;
    			break;
    		}
    
    		/* Options:
    		 *   disable_polarity_correction = 0 (default)
    		 *       Automatic Correction for Reversed Cable Polarity
    		 *   0 - Disabled
    		 *   1 - Enabled
    		 */
    		phy_data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
    		ret_val = e1000_write_phy_reg(hw,
    				GG82563_PHY_SPEC_CTRL, phy_data);
    
    		if (ret_val)
    			return ret_val;
    
    		/* SW Reset the PHY so all changes take effect */
    		ret_val = e1000_phy_reset(hw);
    		if (ret_val) {
    			DEBUGOUT("Error Resetting the PHY\n");
    			return ret_val;
    		}
    	} /* phy_reset_disable */
    
    	if (hw->mac_type == e1000_80003es2lan) {
    		/* Bypass RX and TX FIFO's */
    		ret_val = e1000_write_kmrn_reg(hw,
    				E1000_KUMCTRLSTA_OFFSET_FIFO_CTRL,
    				E1000_KUMCTRLSTA_FIFO_CTRL_RX_BYPASS
    				| E1000_KUMCTRLSTA_FIFO_CTRL_TX_BYPASS);
    		if (ret_val)
    			return ret_val;
    
    		ret_val = e1000_read_phy_reg(hw,
    				GG82563_PHY_SPEC_CTRL_2, &phy_data);
    		if (ret_val)
    			return ret_val;
    
    		phy_data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG;
    		ret_val = e1000_write_phy_reg(hw,
    				GG82563_PHY_SPEC_CTRL_2, phy_data);
    
    		if (ret_val)
    			return ret_val;
    
    		reg_data = E1000_READ_REG(hw, CTRL_EXT);
    		reg_data &= ~(E1000_CTRL_EXT_LINK_MODE_MASK);
    		E1000_WRITE_REG(hw, CTRL_EXT, reg_data);
    
    		ret_val = e1000_read_phy_reg(hw,
    				GG82563_PHY_PWR_MGMT_CTRL, &phy_data);
    		if (ret_val)
    			return ret_val;
    
    	/* Do not init these registers when the HW is in IAMT mode, since the
    	 * firmware will have already initialized them.  We only initialize
    	 * them if the HW is not in IAMT mode.
    	 */
    
    York Sun's avatar
    York Sun committed
    		if (e1000_check_mng_mode(hw) == false) {
    
    			/* Enable Electrical Idle on the PHY */
    			phy_data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE;
    			ret_val = e1000_write_phy_reg(hw,
    					GG82563_PHY_PWR_MGMT_CTRL, phy_data);
    			if (ret_val)
    				return ret_val;
    
    			ret_val = e1000_read_phy_reg(hw,
    					GG82563_PHY_KMRN_MODE_CTRL, &phy_data);
    			if (ret_val)
    				return ret_val;
    
    			phy_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
    			ret_val = e1000_write_phy_reg(hw,
    					GG82563_PHY_KMRN_MODE_CTRL, phy_data);
    
    			if (ret_val)
    				return ret_val;
    		}
    
    		/* Workaround: Disable padding in Kumeran interface in the MAC
    		 * and in the PHY to avoid CRC errors.
    		 */
    		ret_val = e1000_read_phy_reg(hw,
    				GG82563_PHY_INBAND_CTRL, &phy_data);
    		if (ret_val)
    			return ret_val;
    		phy_data |= GG82563_ICR_DIS_PADDING;
    		ret_val = e1000_write_phy_reg(hw,
    				GG82563_PHY_INBAND_CTRL, phy_data);
    		if (ret_val)
    			return ret_val;
    
    	return E1000_SUCCESS;
    
    /********************************************************************
    * Copper link setup for e1000_phy_m88 series.
    
    *
    * hw - Struct containing variables accessed by shared code
    
    *********************************************************************/
    static int32_t
    e1000_copper_link_mgp_setup(struct e1000_hw *hw)
    
    {
    	int32_t ret_val;
    	uint16_t phy_data;
    
    	DEBUGFUNC();
    
    
    	if (hw->phy_reset_disable)
    		return E1000_SUCCESS;
    
    	/* Enable CRS on TX. This must be set for half-duplex operation. */
    	ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
    	if (ret_val)
    
    		return ret_val;
    
    	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
    
    	/* Options:
    	 *   MDI/MDI-X = 0 (default)
    	 *   0 - Auto for all speeds
    	 *   1 - MDI mode
    	 *   2 - MDI-X mode
    	 *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
    	 */
    	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
    
    	switch (hw->mdix) {
    	case 1:
    		phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
    		break;
    	case 2:
    		phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
    		break;
    	case 3:
    		phy_data |= M88E1000_PSCR_AUTO_X_1000T;
    		break;
    	case 0:
    	default:
    		phy_data |= M88E1000_PSCR_AUTO_X_MODE;
    		break;
    	}
    
    	/* Options:
    	 *   disable_polarity_correction = 0 (default)
    
    	 *       Automatic Correction for Reversed Cable Polarity
    
    	 *   0 - Disabled
    	 *   1 - Enabled
    	 */
    	phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
    
    	ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
    	if (ret_val)
    		return ret_val;
    
    	if (hw->phy_revision < M88E1011_I_REV_4) {
    		/* Force TX_CLK in the Extended PHY Specific Control Register
    		 * to 25MHz clock.
    		 */
    		ret_val = e1000_read_phy_reg(hw,
    				M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
    		if (ret_val)
    			return ret_val;
    
    		phy_data |= M88E1000_EPSCR_TX_CLK_25;
    
    		if ((hw->phy_revision == E1000_REVISION_2) &&
    			(hw->phy_id == M88E1111_I_PHY_ID)) {
    			/* Vidalia Phy, set the downshift counter to 5x */
    			phy_data &= ~(M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK);
    			phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
    			ret_val = e1000_write_phy_reg(hw,
    					M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
    			if (ret_val)
    				return ret_val;
    		} else {
    			/* Configure Master and Slave downshift values */
    			phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK
    					| M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
    			phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X
    					| M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
    			ret_val = e1000_write_phy_reg(hw,
    					M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
    			if (ret_val)
    				return ret_val;
    		}
    
    	}
    
    	/* SW Reset the PHY so all changes take effect */
    	ret_val = e1000_phy_reset(hw);
    
    	if (ret_val) {
    
    		DEBUGOUT("Error Resetting the PHY\n");
    		return ret_val;
    	}
    
    
    	return E1000_SUCCESS;
    }
    
    /********************************************************************
    * Setup auto-negotiation and flow control advertisements,
    * and then perform auto-negotiation.
    *
    * hw - Struct containing variables accessed by shared code
    *********************************************************************/
    static int32_t
    e1000_copper_link_autoneg(struct e1000_hw *hw)
    {
    	int32_t ret_val;
    	uint16_t phy_data;
    
    	DEBUGFUNC();
    
    
    	/* Perform some bounds checking on the hw->autoneg_advertised
    	 * parameter.  If this variable is zero, then set it to the default.
    	 */
    	hw->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT;
    
    	/* If autoneg_advertised is zero, we assume it was not defaulted
    	 * by the calling code so we set to advertise full capability.
    	 */
    	if (hw->autoneg_advertised == 0)
    		hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
    
    
    	/* IFE phy only supports 10/100 */
    	if (hw->phy_type == e1000_phy_ife)
    		hw->autoneg_advertised &= AUTONEG_ADVERTISE_10_100_ALL;
    
    
    	DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
    	ret_val = e1000_phy_setup_autoneg(hw);
    
    	if (ret_val) {
    
    		DEBUGOUT("Error Setting up Auto-Negotiation\n");
    		return ret_val;
    	}
    	DEBUGOUT("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 = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
    	if (ret_val)
    		return ret_val;
    
    
    	phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
    
    	ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data);
    	if (ret_val)
    		return ret_val;
    
    
    	/* Does the user want to wait for Auto-Neg to complete here, or
    	 * check at a later time (for example, callback routine).
    	 */
    
    	/* If we do not wait for autonegtation to complete I
    	 * do not see a valid link status.
    	 * wait_autoneg_complete = 1 .
    	 */
    
    	if (hw->wait_autoneg_complete) {
    		ret_val = e1000_wait_autoneg(hw);
    
    		if (ret_val) {
    			DEBUGOUT("Error while waiting for autoneg"
    					"to complete\n");
    
    York Sun's avatar
    York Sun committed
    	hw->get_link_status = true;
    
    
    	return E1000_SUCCESS;
    }
    
    /******************************************************************************
    * Config the MAC and the PHY after link is up.
    *   1) Set up the MAC to the current PHY speed/duplex
    *      if we are on 82543.  If we
    *      are on newer silicon, we only need to configure
    *      collision distance in the Transmit Control Register.
    *   2) Set up flow control on the MAC to that established with
    *      the link partner.
    *   3) Config DSP to improve Gigabit link quality for some PHY revisions.
    *
    * hw - Struct containing variables accessed by shared code
    ******************************************************************************/
    static int32_t
    e1000_copper_link_postconfig(struct e1000_hw *hw)
    {
    	int32_t ret_val;
    	DEBUGFUNC();
    
    	if (hw->mac_type >= e1000_82544) {
    		e1000_config_collision_dist(hw);
    	} else {
    		ret_val = e1000_config_mac_to_phy(hw);
    		if (ret_val) {
    			DEBUGOUT("Error configuring MAC to PHY settings\n");
    			return ret_val;
    		}
    	}
    	ret_val = e1000_config_fc_after_link_up(hw);
    	if (ret_val) {
    		DEBUGOUT("Error Configuring Flow Control\n");
    
    	return E1000_SUCCESS;
    }
    
    /******************************************************************************
    * Detects which PHY is present and setup the speed and duplex
    *
    * hw - Struct containing variables accessed by shared code
    ******************************************************************************/
    static int
    e1000_setup_copper_link(struct eth_device *nic)
    {
    	struct e1000_hw *hw = nic->priv;
    	int32_t ret_val;
    	uint16_t i;
    	uint16_t phy_data;
    	uint16_t reg_data;
    
    	DEBUGFUNC();
    
    	switch (hw->mac_type) {
    	case e1000_80003es2lan:
    	case e1000_ich8lan:
    		/* Set the mac to wait the maximum time between each
    		 * iteration and increase the max iterations when
    		 * polling the phy; this fixes erroneous timeouts at 10Mbps. */
    		ret_val = e1000_write_kmrn_reg(hw,
    				GG82563_REG(0x34, 4), 0xFFFF);
    		if (ret_val)
    			return ret_val;
    		ret_val = e1000_read_kmrn_reg(hw,
    				GG82563_REG(0x34, 9), &reg_data);
    		if (ret_val)
    			return ret_val;
    		reg_data |= 0x3F;
    		ret_val = e1000_write_kmrn_reg(hw,
    				GG82563_REG(0x34, 9), reg_data);
    		if (ret_val)
    			return ret_val;
    	default:
    		break;
    	}
    
    	/* Check if it is a valid PHY and set PHY mode if necessary. */
    	ret_val = e1000_copper_link_preconfig(hw);
    	if (ret_val)
    		return ret_val;
    	switch (hw->mac_type) {
    	case e1000_80003es2lan:
    		/* Kumeran registers are written-only */
    		reg_data =
    		E1000_KUMCTRLSTA_INB_CTRL_LINK_STATUS_TX_TIMEOUT_DEFAULT;
    		reg_data |= E1000_KUMCTRLSTA_INB_CTRL_DIS_PADDING;
    		ret_val = e1000_write_kmrn_reg(hw,
    				E1000_KUMCTRLSTA_OFFSET_INB_CTRL, reg_data);
    		if (ret_val)
    			return ret_val;
    		break;
    	default:
    		break;
    	}
    
    	if (hw->phy_type == e1000_phy_igp ||
    		hw->phy_type == e1000_phy_igp_3 ||
    		hw->phy_type == e1000_phy_igp_2) {
    		ret_val = e1000_copper_link_igp_setup(hw);
    		if (ret_val)
    			return ret_val;
    	} else if (hw->phy_type == e1000_phy_m88) {
    		ret_val = e1000_copper_link_mgp_setup(hw);
    		if (ret_val)
    			return ret_val;
    	} else if (hw->phy_type == e1000_phy_gg82563) {
    		ret_val = e1000_copper_link_ggp_setup(hw);
    		if (ret_val)
    			return ret_val;
    	}
    
    	/* always auto */
    	/* Setup autoneg and flow control advertisement
    	  * and perform autonegotiation */