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

📄 e1000_phy.c

📁 linux系统的网卡驱动包
💻 C
📖 第 1 页 / 共 4 页
字号:
		                                     &link);		if (ret_val)			goto out;		if (!link) {			DEBUGOUT("Link taking longer than expected.\n");		}		/* Try once more */		ret_val = e1000_phy_has_link_generic(hw,		                                     PHY_FORCE_LIMIT,		                                     100000,		                                     &link);		if (ret_val)			goto out;	}out:	return ret_val;}/** *  e1000_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY *  @hw: pointer to the HW structure * *  Calls the PHY setup function to force speed and duplex.  Clears the *  auto-crossover to force MDI manually.  Resets the PHY to commit the *  changes.  If time expires while waiting for link up, we reset the DSP. *  After reset, TX_CLK and CRS on Tx must be set.  Return successful upon *  successful completion, else return corresponding error code. **/s32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw){	struct e1000_phy_info *phy = &hw->phy;	s32 ret_val;	u16 phy_data;	bool link;	DEBUGFUNC("e1000_phy_force_speed_duplex_m88");	/*	 * Clear Auto-Crossover to force MDI manually.  M88E1000 requires MDI	 * forced whenever speed and duplex are forced.	 */	ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);	if (ret_val)		goto out;	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;	ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);	if (ret_val)		goto out;	DEBUGOUT1("M88E1000 PSCR: %X\n", phy_data);	ret_val = e1000_read_phy_reg(hw, PHY_CONTROL, &phy_data);	if (ret_val)		goto out;	e1000_phy_force_speed_duplex_setup(hw, &phy_data);	/* Reset the phy to commit changes. */	phy_data |= MII_CR_RESET;	ret_val = e1000_write_phy_reg(hw, PHY_CONTROL, phy_data);	if (ret_val)		goto out;	usec_delay(1);	if (phy->autoneg_wait_to_complete) {		DEBUGOUT("Waiting for forced speed/duplex link on M88 phy.\n");		ret_val = e1000_phy_has_link_generic(hw,		                                     PHY_FORCE_LIMIT,		                                     100000,		                                     &link);		if (ret_val)			goto out;		if (!link) {			/*			 * We didn't get link.			 * Reset the DSP and cross our fingers.			 */			ret_val = e1000_write_phy_reg(hw,			                              M88E1000_PHY_PAGE_SELECT,			                              0x001d);			if (ret_val)				goto out;			ret_val = e1000_phy_reset_dsp_generic(hw);			if (ret_val)				goto out;		}		/* Try once more */		ret_val = e1000_phy_has_link_generic(hw,		                                     PHY_FORCE_LIMIT,		                                     100000,		                                     &link);		if (ret_val)			goto out;	}	ret_val = e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);	if (ret_val)		goto out;	/*	 * Resetting the phy means we need to re-force TX_CLK in the	 * Extended PHY Specific Control Register to 25MHz clock from	 * the reset value of 2.5MHz.	 */	phy_data |= M88E1000_EPSCR_TX_CLK_25;	ret_val = e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);	if (ret_val)		goto out;	/*	 * In addition, we must re-enable CRS on Tx for both half and full	 * duplex.	 */	ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);	if (ret_val)		goto out;	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;	ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);out:	return ret_val;}/** *  e1000_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex *  @hw: pointer to the HW structure *  @phy_ctrl: pointer to current value of PHY_CONTROL * *  Forces speed and duplex on the PHY by doing the following: disable flow *  control, force speed/duplex on the MAC, disable auto speed detection, *  disable auto-negotiation, configure duplex, configure speed, configure *  the collision distance, write configuration to CTRL register.  The *  caller must write to the PHY_CONTROL register for these settings to *  take affect. **/void e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl){	struct e1000_mac_info *mac = &hw->mac;	u32 ctrl;	DEBUGFUNC("e1000_phy_force_speed_duplex_setup");	/* Turn off flow control when forcing speed/duplex */	hw->fc.type = e1000_fc_none;	/* Force speed/duplex on the mac */	ctrl = E1000_READ_REG(hw, E1000_CTRL);	ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);	ctrl &= ~E1000_CTRL_SPD_SEL;	/* Disable Auto Speed Detection */	ctrl &= ~E1000_CTRL_ASDE;	/* Disable autoneg on the phy */	*phy_ctrl &= ~MII_CR_AUTO_NEG_EN;	/* Forcing Full or Half Duplex? */	if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) {		ctrl &= ~E1000_CTRL_FD;		*phy_ctrl &= ~MII_CR_FULL_DUPLEX;		DEBUGOUT("Half Duplex\n");	} else {		ctrl |= E1000_CTRL_FD;		*phy_ctrl |= MII_CR_FULL_DUPLEX;		DEBUGOUT("Full Duplex\n");	}	/* Forcing 10mb or 100mb? */	if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) {		ctrl |= E1000_CTRL_SPD_100;		*phy_ctrl |= MII_CR_SPEED_100;		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);		DEBUGOUT("Forcing 100mb\n");	} else {		ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);		*phy_ctrl |= MII_CR_SPEED_10;		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);		DEBUGOUT("Forcing 10mb\n");	}	e1000_config_collision_dist_generic(hw);	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);}/** *  e1000_set_d3_lplu_state_generic - Sets low power link up state for D3 *  @hw: pointer to the HW structure *  @active: boolean used to enable/disable lplu * *  Success returns 0, Failure returns 1 * *  The low power link up (lplu) state is set to the power management level D3 *  and SmartSpeed is disabled when active is true, else clear lplu for D3 *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU *  is used during Dx states where the power conservation is most important. *  During driver activity, SmartSpeed should be enabled so performance is *  maintained. **/s32 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active){	struct e1000_phy_info *phy = &hw->phy;	s32 ret_val;	u16 data;	DEBUGFUNC("e1000_set_d3_lplu_state_generic");	ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data);	if (ret_val)		goto out;	if (!active) {		data &= ~IGP02E1000_PM_D3_LPLU;		ret_val = e1000_write_phy_reg(hw,		                             IGP02E1000_PHY_POWER_MGMT,		                             data);		if (ret_val)			goto out;		/*		 * 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 (phy->smart_speed == e1000_smart_speed_on) {			ret_val = e1000_read_phy_reg(hw,			                            IGP01E1000_PHY_PORT_CONFIG,			                            &data);			if (ret_val)				goto out;			data |= IGP01E1000_PSCFR_SMART_SPEED;			ret_val = e1000_write_phy_reg(hw,			                             IGP01E1000_PHY_PORT_CONFIG,			                             data);			if (ret_val)				goto out;		} else if (phy->smart_speed == e1000_smart_speed_off) {			ret_val = e1000_read_phy_reg(hw,			                             IGP01E1000_PHY_PORT_CONFIG,			                             &data);			if (ret_val)				goto out;			data &= ~IGP01E1000_PSCFR_SMART_SPEED;			ret_val = e1000_write_phy_reg(hw,			                             IGP01E1000_PHY_PORT_CONFIG,			                             data);			if (ret_val)				goto out;		}	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||	           (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||	           (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {		data |= IGP02E1000_PM_D3_LPLU;		ret_val = e1000_write_phy_reg(hw,		                              IGP02E1000_PHY_POWER_MGMT,		                              data);		if (ret_val)			goto out;		/* When LPLU is enabled, we should disable SmartSpeed */		ret_val = e1000_read_phy_reg(hw,		                             IGP01E1000_PHY_PORT_CONFIG,		                             &data);		if (ret_val)			goto out;		data &= ~IGP01E1000_PSCFR_SMART_SPEED;		ret_val = e1000_write_phy_reg(hw,		                              IGP01E1000_PHY_PORT_CONFIG,		                              data);	}out:	return ret_val;}/** *  e1000_check_downshift_generic - Checks whether a downshift in speed occured *  @hw: pointer to the HW structure * *  Success returns 0, Failure returns 1 * *  A downshift is detected by querying the PHY link health. **/s32 e1000_check_downshift_generic(struct e1000_hw *hw){	struct e1000_phy_info *phy = &hw->phy;	s32 ret_val;	u16 phy_data, offset, mask;	DEBUGFUNC("e1000_check_downshift_generic");	switch (phy->type) {	case e1000_phy_m88:	case e1000_phy_gg82563:		offset	= M88E1000_PHY_SPEC_STATUS;		mask	= M88E1000_PSSR_DOWNSHIFT;		break;	case e1000_phy_igp_2:	case e1000_phy_igp:	case e1000_phy_igp_3:		offset	= IGP01E1000_PHY_LINK_HEALTH;		mask	= IGP01E1000_PLHR_SS_DOWNGRADE;		break;	default:		/* speed downshift not supported */		phy->speed_downgraded = FALSE;		ret_val = E1000_SUCCESS;		goto out;	}	ret_val = e1000_read_phy_reg(hw, offset, &phy_data);	if (!ret_val)		phy->speed_downgraded = (phy_data & mask) ? TRUE : FALSE;out:	return ret_val;}/** *  e1000_check_polarity_m88 - Checks the polarity. *  @hw: pointer to the HW structure * *  Success returns 0, Failure returns -E1000_ERR_PHY (-2) * *  Polarity is determined based on the PHY specific status register. **/s32 e1000_check_polarity_m88(struct e1000_hw *hw){	struct e1000_phy_info *phy = &hw->phy;	s32 ret_val;	u16 data;	DEBUGFUNC("e1000_check_polarity_m88");	ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &data);	if (!ret_val)		phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY)		                      ? e1000_rev_polarity_reversed		                      : e1000_rev_polarity_normal;	return ret_val;}/** *  e1000_check_polarity_igp - Checks the polarity. *  @hw: pointer to the HW structure * *  Success returns 0, Failure returns -E1000_ERR_PHY (-2) * *  Polarity is determined based on the PHY port status register, and the *  current speed (since there is no polarity at 100Mbps). **/s32 e1000_check_polarity_igp(struct e1000_hw *hw){	struct e1000_phy_info *phy = &hw->phy;	s32 ret_val;	u16 data, offset, mask;	DEBUGFUNC("e1000_check_polarity_igp");	/*	 * Polarity is determined based on the speed of	 * our connection.	 */	ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);	if (ret_val)		goto out;	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==	    IGP01E1000_PSSR_SPEED_1000MBPS) {		offset	= IGP01E1000_PHY_PCS_INIT_REG;		mask	= IGP01E1000_PHY_POLARITY_MASK;	} else {		/*		 * This really only applies to 10Mbps since		 * there is no polarity for 100Mbps (always 0).		 */		offset	= IGP01E1000_PHY_PORT_STATUS;		mask	= IGP01E1000_PSSR_POLARITY_REVERSED;	}	ret_val = e1000_read_phy_reg(hw, offset, &data);	if (!ret_val)		phy->cable_polarity = (data & mask)		                      ? e1000_rev_polarity_reversed		                      : e1000_rev_polarity_normal;out:	return ret_val;}/** *  e1000_wait_autoneg_generic - Wait for auto-neg compeletion *  @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. **/s32 e1000_wait_autoneg_generic(struct e1000_hw *hw){	s32 ret_val = E1000_SUCCESS;	u16 i, phy_status;	DEBUGFUNC("e1000_wait_autoneg_generic");	/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */	for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {		ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_status);		if (ret_val)			break;		ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_status);		if (ret_val)			break;		if (phy_status & MII_SR_AUTONEG_COMPLETE)			break;		msec_delay(100);	}	/*	 * PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation	 * has completed.	 */	return ret_val;}/** *  e1000_phy_has_link_generic - Polls PHY for link *  @hw: pointer to the HW structure *  @iterations: number of times to poll for link *  @usec_interval: delay between polling attempts *  @success: pointer to whether polling was successful or not * *  Polls the PHY status register for link, 'iterations' number of times. **/s32 e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,                               u32 usec_interval, bool *success){	s32 ret_val = E1000_SUCCESS;	u16 i, phy_status;	DEBUGFUNC("e1000_phy_has_link_generic");	for (i = 0; i < iterations; i++) {		/*		 * Some PHYs require the PHY_STATUS register to be read		 * twice due to the link bit being sticky.  No harm doing		 * it across the board.		 */		ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_status);		if (ret_val)			break;		ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_status);		if (ret_val)			break;		if (phy_status & MII_SR_LINK_STATUS)			break;		if (usec_interval >= 1000)			msec_delay_irq(usec_interval/1000);		else			usec_delay(usec_interval);	}	*success = (i < iterations) ? TRUE : FALSE;	return ret_val;}/** *  e1000_get_cable_length_m88 - Determine cable length for m88 PHY *  @hw: pointer to the HW structure * *  Reads the PHY specific status register to retrieve the cable length *  information.  The cable length is determined by averaging the minimum and *  maximum values to get the "average" cable length.  The m88 PHY has four *  possible cable length values, which are: *	Register Value		Cable Length *	0			< 50 meters *	1			50 - 80 meters *	2			80 - 110 meters *	3			110 - 140 meters *	4			> 140 meters **/s32 e1000_get_cable_length_m88(struct e1000_hw *hw){	struct e1000_phy_info *phy = &hw->phy;	s32 ret_val;	u16 phy_data, index;	DEBUGFUNC("e1000_get_cable_length_m88");	ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);	if (ret_val)		goto out;	index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>	        M88E1000_PSSR_CABLE_LENGTH_SHIFT;	phy->min_cable_length = e1000_m88_cable_length_table[index];	phy->max_cable_length = e1000_m88_cable_length_table[index+1];	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;out:	return ret_val;}/** *  e1000_get_cable_length_igp_2 - Determine cable length for igp2 PHY *  @hw: pointer to the HW structure * *  The automatic gain control (agc) normalizes the amplitude of the *  received signal, adjusting for the attenuation produced by the

⌨️ 快捷键说明

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