⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 e1000_82541.c

📁 linux系统的网卡驱动包
💻 C
📖 第 1 页 / 共 3 页
字号:
}/** * e1000_get_link_up_info_82541 - Report speed and duplex * @hw: pointer to the HW structure * @speed: pointer to speed buffer * @duplex: pointer to duplex buffer * * Retrieve the current speed and duplex configuration. * This is a function pointer entry point called by the api module. **/static s32 e1000_get_link_up_info_82541(struct e1000_hw *hw, u16 *speed,                                        u16 *duplex){	struct e1000_phy_info *phy = &hw->phy;	s32 ret_val;	u16 data;	DEBUGFUNC("e1000_get_link_up_info_82541");	ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex);	if (ret_val)		goto out;	if (!phy->speed_downgraded)		goto out;	/*	 * IGP01 PHY may advertise full duplex operation after speed	 * downgrade even if it is operating at half duplex.	 * Here we set the duplex settings to match the duplex in the	 * link partner's capabilities.	 */	ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_EXP, &data);	if (ret_val)		goto out;	if (!(data & NWAY_ER_LP_NWAY_CAPS)) {		*duplex = HALF_DUPLEX;	} else {		ret_val = e1000_read_phy_reg(hw, PHY_LP_ABILITY, &data);		if (ret_val)			goto out;		if (*speed == SPEED_100) {			if (!(data & NWAY_LPAR_100TX_FD_CAPS))				*duplex = HALF_DUPLEX;		} else if (*speed == SPEED_10) {			if (!(data & NWAY_LPAR_10T_FD_CAPS))				*duplex = HALF_DUPLEX;		}	}out:	return ret_val;}/** *  e1000_phy_hw_reset_82541 - PHY hardware reset *  @hw: pointer to the HW structure * *  Verify the reset block is not blocking us from resetting.  Acquire *  semaphore (if necessary) and read/set/write the device control reset *  bit in the PHY.  Wait the appropriate delay time for the device to *  reset and relase the semaphore (if necessary). *  This is a function pointer entry point called by the api module. **/static s32 e1000_phy_hw_reset_82541(struct e1000_hw *hw){	s32 ret_val;	u32 ledctl;	DEBUGFUNC("e1000_phy_hw_reset_82541");	ret_val = e1000_phy_hw_reset_generic(hw);	if (ret_val)		goto out;	e1000_phy_init_script_82541(hw);	if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) {		/* Configure activity LED after PHY reset */		ledctl = E1000_READ_REG(hw, E1000_LEDCTL);		ledctl &= IGP_ACTIVITY_LED_MASK;		ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);		E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);	}out:	return ret_val;}/** *  e1000_setup_copper_link_82541 - Configure copper link settings *  @hw: pointer to the HW structure * *  Calls the appropriate function to configure the link for auto-neg or forced *  speed and duplex.  Then we check for link, once link is established calls *  to configure collision distance and flow control are called.  If link is *  not established, we return -E1000_ERR_PHY (-2).  This is a function *  pointer entry point called by the api module. **/static s32 e1000_setup_copper_link_82541(struct e1000_hw *hw){	struct e1000_phy_info *phy = &hw->phy;	struct e1000_dev_spec_82541 *dev_spec;	s32  ret_val;	u32 ctrl, ledctl;	DEBUGFUNC("e1000_setup_copper_link_82541");	ctrl = E1000_READ_REG(hw, E1000_CTRL);	ctrl |= E1000_CTRL_SLU;	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);	hw->phy.reset_disable = FALSE;	dev_spec = (struct e1000_dev_spec_82541 *)hw->dev_spec;	/* Earlier revs of the IGP phy require us to force MDI. */	if (hw->mac.type == e1000_82541 || hw->mac.type == e1000_82547) {		dev_spec->dsp_config = e1000_dsp_config_disabled;		phy->mdix = 1;	} else {		dev_spec->dsp_config = e1000_dsp_config_enabled;	}	ret_val = e1000_copper_link_setup_igp(hw);	if (ret_val)		goto out;	if (hw->mac.autoneg) {		if (dev_spec->ffe_config == e1000_ffe_config_active)			dev_spec->ffe_config = e1000_ffe_config_enabled;	}	/* Configure activity LED after Phy reset */	ledctl = E1000_READ_REG(hw, E1000_LEDCTL);	ledctl &= IGP_ACTIVITY_LED_MASK;	ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);	E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);	ret_val = e1000_setup_copper_link_generic(hw);out:	return ret_val;}/** *  e1000_check_for_link_82541 - Check/Store link connection *  @hw: pointer to the HW structure * *  This checks the link condition of the adapter and stores the *  results in the hw->mac structure. This is a function pointer entry *  point called by the api module. **/static s32 e1000_check_for_link_82541(struct e1000_hw *hw){	struct e1000_mac_info *mac = &hw->mac;	s32 ret_val;	bool link;	DEBUGFUNC("e1000_check_for_link_82541");	/*	 * We only want to go out to the PHY registers to see if Auto-Neg	 * has completed and/or if our link status has changed.  The	 * get_link_status flag is set upon receiving a Link Status	 * Change or Rx Sequence Error interrupt.	 */	if (!mac->get_link_status) {		ret_val = E1000_SUCCESS;		goto out;	}	/*	 * First we want to see if the MII Status Register reports	 * link.  If so, then we want to get the current speed/duplex	 * of the PHY.	 */	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);	if (ret_val)		goto out;	if (!link) {		ret_val = e1000_config_dsp_after_link_change_82541(hw, FALSE);		goto out; /* No link detected */	}	mac->get_link_status = FALSE;	/*	 * Check if there was DownShift, must be checked	 * immediately after link-up	 */	e1000_check_downshift_generic(hw);	/*	 * If we are forcing speed/duplex, then we simply return since	 * we have already determined whether we have link or not.	 */	if (!mac->autoneg) {		ret_val = -E1000_ERR_CONFIG;		goto out;	}	ret_val = e1000_config_dsp_after_link_change_82541(hw, TRUE);	/*	 * Auto-Neg is enabled.  Auto Speed Detection takes care	 * of MAC speed/duplex configuration.  So we only need to	 * configure Collision Distance in the MAC.	 */	e1000_config_collision_dist_generic(hw);	/*	 * Configure Flow Control now that Auto-Neg has completed.	 * First, we need to restore the desired flow control	 * settings because we may have had to re-autoneg with a	 * different link partner.	 */	ret_val = e1000_config_fc_after_link_up_generic(hw);	if (ret_val) {		DEBUGOUT("Error configuring flow control\n");	}out:	return ret_val;}/** *  e1000_config_dsp_after_link_change_82541 - Config DSP after link *  @hw: pointer to the HW structure *  @link_up: boolean flag for link up status * *  Return E1000_ERR_PHY when failing to read/write the PHY, else E1000_SUCCESS *  at any other case. * *  82541_rev_2 & 82547_rev_2 have the capability to configure the DSP when a *  gigabit link is achieved to improve link quality. *  This is a function pointer entry point called by the api module. **/static s32 e1000_config_dsp_after_link_change_82541(struct e1000_hw *hw,                                                    bool link_up){	struct e1000_phy_info *phy = &hw->phy;	struct e1000_dev_spec_82541 *dev_spec;	s32 ret_val;	u32 idle_errs = 0;	u16 phy_data, phy_saved_data, speed, duplex, i;	u16 ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_20;	u16 dsp_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =	                                           {IGP01E1000_PHY_AGC_PARAM_A,	                                            IGP01E1000_PHY_AGC_PARAM_B,	                                            IGP01E1000_PHY_AGC_PARAM_C,	                                            IGP01E1000_PHY_AGC_PARAM_D};	DEBUGFUNC("e1000_config_dsp_after_link_change_82541");	dev_spec = (struct e1000_dev_spec_82541 *)hw->dev_spec;	if (link_up) {		ret_val = e1000_get_speed_and_duplex(hw, &speed, &duplex);		if (ret_val) {			DEBUGOUT("Error getting link speed and duplex\n");			goto out;		}		if (speed != SPEED_1000) {			ret_val = E1000_SUCCESS;			goto out;		}		ret_val = e1000_get_cable_length(hw);		if (ret_val)			goto out;		if ((dev_spec->dsp_config == e1000_dsp_config_enabled) &&		    phy->min_cable_length >= 50) {			for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {				ret_val = e1000_read_phy_reg(hw,				                            dsp_reg_array[i],				                            &phy_data);				if (ret_val)					goto out;				phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;				ret_val = e1000_write_phy_reg(hw,				                             dsp_reg_array[i],				                             phy_data);				if (ret_val)					goto out;			}			dev_spec->dsp_config = e1000_dsp_config_activated;		}		if ((dev_spec->ffe_config != e1000_ffe_config_enabled) ||		    (phy->min_cable_length >= 50)) {			ret_val = E1000_SUCCESS;			goto out;		}		/* clear previous idle error counts */		ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);		if (ret_val)			goto out;		for (i = 0; i < ffe_idle_err_timeout; i++) {			usec_delay(1000);			ret_val = e1000_read_phy_reg(hw,			                            PHY_1000T_STATUS,			                            &phy_data);			if (ret_val)				goto out;			idle_errs += (phy_data & SR_1000T_IDLE_ERROR_CNT);			if (idle_errs > SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT) {				dev_spec->ffe_config = e1000_ffe_config_active;				ret_val = e1000_write_phy_reg(hw,				                  IGP01E1000_PHY_DSP_FFE,				                  IGP01E1000_PHY_DSP_FFE_CM_CP);				if (ret_val)					goto out;				break;			}			if (idle_errs)				ffe_idle_err_timeout =				                 FFE_IDLE_ERR_COUNT_TIMEOUT_100;		}	} else {		if (dev_spec->dsp_config == e1000_dsp_config_activated) {			/*			 * Save off the current value of register 0x2F5B			 * to be restored at the end of the routines.			 */			ret_val = e1000_read_phy_reg(hw,			                            0x2F5B,			                            &phy_saved_data);			if (ret_val)				goto out;			/* Disable the PHY transmitter */			ret_val = e1000_write_phy_reg(hw, 0x2F5B, 0x0003);			if (ret_val)				goto out;			msec_delay_irq(20);			ret_val = e1000_write_phy_reg(hw,			                             0x0000,			                             IGP01E1000_IEEE_FORCE_GIG);			if (ret_val)				goto out;			for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {				ret_val = e1000_read_phy_reg(hw,				                            dsp_reg_array[i],				                            &phy_data);				if (ret_val)					goto out;				phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;				phy_data |= IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS;				ret_val = e1000_write_phy_reg(hw,				                             dsp_reg_array[i],				                             phy_data);				if (ret_val)					goto out;			}			ret_val = e1000_write_phy_reg(hw,			                       0x0000,			                       IGP01E1000_IEEE_RESTART_AUTONEG);			if (ret_val)				goto out;			msec_delay_irq(20);			/* Now enable the transmitter */			ret_val = e1000_write_phy_reg(hw,			                             0x2F5B,			                             phy_saved_data);			if (ret_val)				goto out;			dev_spec->dsp_config = e1000_dsp_config_enabled;		}		if (dev_spec->ffe_config != e1000_ffe_config_active) {			ret_val = E1000_SUCCESS;			goto out;		}		/*		 * Save off the current value of register 0x2F5B		 * to be restored at the end of the routines.		 */		ret_val = e1000_read_phy_reg(hw, 0x2F5B, &phy_saved_data);		if (ret_val)			goto out;		/* Disable the PHY transmitter */		ret_val = e1000_write_phy_reg(hw, 0x2F5B, 0x0003);		if (ret_val)			goto out;		msec_delay_irq(20);		ret_val = e1000_write_phy_reg(hw,		                             0x0000,		                             IGP01E1000_IEEE_FORCE_GIG);		if (ret_val)			goto out;		ret_val = e1000_write_phy_reg(hw,		                             IGP01E1000_PHY_DSP_FFE,		                             IGP01E1000_PHY_DSP_FFE_DEFAULT);		if (ret_val)			goto out;		ret_val = e1000_write_phy_reg(hw,		                             0x0000,		                             IGP01E1000_IEEE_RESTART_AUTONEG);		if (ret_val)			goto out;		msec_delay_irq(20);		/* Now enable the transmitter */		ret_val = e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data);		if (ret_val)			goto out;		dev_spec->ffe_config = e1000_ffe_config_enabled;	}out:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -