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

📄 e1000_phy.c

📁 linux系统的网卡驱动包
💻 C
📖 第 1 页 / 共 4 页
字号:
 *  cable.  By reading the AGC registers, which reperesent the *  cobination of course and fine gain value, the value can be put *  into a lookup table to obtain the approximate cable length *  for each channel. **/s32 e1000_get_cable_length_igp_2(struct e1000_hw *hw){	struct e1000_phy_info *phy = &hw->phy;	s32 ret_val = E1000_SUCCESS;	u16 phy_data, i, agc_value = 0;	u16 cur_agc_index, max_agc_index = 0;	u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1;	u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =	                                                 {IGP02E1000_PHY_AGC_A,	                                                  IGP02E1000_PHY_AGC_B,	                                                  IGP02E1000_PHY_AGC_C,	                                                  IGP02E1000_PHY_AGC_D};	DEBUGFUNC("e1000_get_cable_length_igp_2");	/* Read the AGC registers for all channels */	for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {		ret_val = e1000_read_phy_reg(hw, agc_reg_array[i], &phy_data);		if (ret_val)			goto out;		/*		 * Getting bits 15:9, which represent the combination of		 * course and fine gain values.  The result is a number		 * that can be put into the lookup table to obtain the		 * approximate cable length.		 */		cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &		                IGP02E1000_AGC_LENGTH_MASK;		/* Array index bound check. */		if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) ||		    (cur_agc_index == 0)) {			ret_val = -E1000_ERR_PHY;			goto out;		}		/* Remove min & max AGC values from calculation. */		if (e1000_igp_2_cable_length_table[min_agc_index] >		    e1000_igp_2_cable_length_table[cur_agc_index])			min_agc_index = cur_agc_index;		if (e1000_igp_2_cable_length_table[max_agc_index] <		    e1000_igp_2_cable_length_table[cur_agc_index])			max_agc_index = cur_agc_index;		agc_value += e1000_igp_2_cable_length_table[cur_agc_index];	}	agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] +	              e1000_igp_2_cable_length_table[max_agc_index]);	agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);	/* Calculate cable length with the error range of +/- 10 meters. */	phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?	                         (agc_value - IGP02E1000_AGC_RANGE) : 0;	phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE;	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;out:	return ret_val;}/** *  e1000_get_phy_info_m88 - Retrieve PHY information *  @hw: pointer to the HW structure * *  Valid for only copper links.  Read the PHY status register (sticky read) *  to verify that link is up.  Read the PHY special control register to *  determine the polarity and 10base-T extended distance.  Read the PHY *  special status register to determine MDI/MDIx and current speed.  If *  speed is 1000, then determine cable length, local and remote receiver. **/s32 e1000_get_phy_info_m88(struct e1000_hw *hw){	struct e1000_phy_info *phy = &hw->phy;	s32  ret_val;	u16 phy_data;	bool link;	DEBUGFUNC("e1000_get_phy_info_m88");	if (hw->phy.media_type != e1000_media_type_copper) {		DEBUGOUT("Phy info is only valid for copper media\n");		ret_val = -E1000_ERR_CONFIG;		goto out;	}	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);	if (ret_val)		goto out;	if (!link) {		DEBUGOUT("Phy info is only valid if link is up\n");		ret_val = -E1000_ERR_CONFIG;		goto out;	}	ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);	if (ret_val)		goto out;	phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL)	                           ? TRUE	                           : FALSE;	ret_val = e1000_check_polarity_m88(hw);	if (ret_val)		goto out;	ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);	if (ret_val)		goto out;	phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? TRUE : FALSE;	if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {		ret_val = e1000_get_cable_length(hw);		if (ret_val)			goto out;		ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);		if (ret_val)			goto out;		phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS)		                ? e1000_1000t_rx_status_ok		                : e1000_1000t_rx_status_not_ok;		phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS)		                 ? e1000_1000t_rx_status_ok		                 : e1000_1000t_rx_status_not_ok;	} else {		/* Set values to "undefined" */		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;		phy->local_rx = e1000_1000t_rx_status_undefined;		phy->remote_rx = e1000_1000t_rx_status_undefined;	}out:	return ret_val;}/** *  e1000_get_phy_info_igp - Retrieve igp PHY information *  @hw: pointer to the HW structure * *  Read PHY status to determine if link is up.  If link is up, then *  set/determine 10base-T extended distance and polarity correction.  Read *  PHY port status to determine MDI/MDIx and speed.  Based on the speed, *  determine on the cable length, local and remote receiver. **/s32 e1000_get_phy_info_igp(struct e1000_hw *hw){	struct e1000_phy_info *phy = &hw->phy;	s32 ret_val;	u16 data;	bool link;	DEBUGFUNC("e1000_get_phy_info_igp");	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);	if (ret_val)		goto out;	if (!link) {		DEBUGOUT("Phy info is only valid if link is up\n");		ret_val = -E1000_ERR_CONFIG;		goto out;	}	phy->polarity_correction = TRUE;	ret_val = e1000_check_polarity_igp(hw);	if (ret_val)		goto out;	ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);	if (ret_val)		goto out;	phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? TRUE : FALSE;	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==	    IGP01E1000_PSSR_SPEED_1000MBPS) {		ret_val = e1000_get_cable_length(hw);		if (ret_val)			goto out;		ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS, &data);		if (ret_val)			goto out;		phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)		                ? e1000_1000t_rx_status_ok		                : e1000_1000t_rx_status_not_ok;		phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)		                 ? e1000_1000t_rx_status_ok		                 : e1000_1000t_rx_status_not_ok;	} else {		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;		phy->local_rx = e1000_1000t_rx_status_undefined;		phy->remote_rx = e1000_1000t_rx_status_undefined;	}out:	return ret_val;}/** *  e1000_phy_sw_reset_generic - PHY software reset *  @hw: pointer to the HW structure * *  Does a software reset of the PHY by reading the PHY control register and *  setting/write the control register reset bit to the PHY. **/s32 e1000_phy_sw_reset_generic(struct e1000_hw *hw){	s32 ret_val;	u16 phy_ctrl;	DEBUGFUNC("e1000_phy_sw_reset_generic");	ret_val = e1000_read_phy_reg(hw, PHY_CONTROL, &phy_ctrl);	if (ret_val)		goto out;	phy_ctrl |= MII_CR_RESET;	ret_val = e1000_write_phy_reg(hw, PHY_CONTROL, phy_ctrl);	if (ret_val)		goto out;	usec_delay(1);out:	return ret_val;}/** *  e1000_phy_hw_reset_generic - 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). **/s32 e1000_phy_hw_reset_generic(struct e1000_hw *hw){	struct e1000_phy_info *phy = &hw->phy;	s32  ret_val;	u32 ctrl;	DEBUGFUNC("e1000_phy_hw_reset_generic");	ret_val = e1000_check_reset_block(hw);	if (ret_val) {		ret_val = E1000_SUCCESS;		goto out;	}	ret_val = e1000_acquire_phy(hw);	if (ret_val)		goto out;	ctrl = E1000_READ_REG(hw, E1000_CTRL);	E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PHY_RST);	E1000_WRITE_FLUSH(hw);	usec_delay(phy->reset_delay_us);	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);	E1000_WRITE_FLUSH(hw);	usec_delay(150);	e1000_release_phy(hw);	ret_val = e1000_get_phy_cfg_done(hw);out:	return ret_val;}/** *  e1000_get_cfg_done_generic - Generic configuration done *  @hw: pointer to the HW structure * *  Generic function to wait 10 milli-seconds for configuration to complete *  and return success. **/s32 e1000_get_cfg_done_generic(struct e1000_hw *hw){	DEBUGFUNC("e1000_get_cfg_done_generic");	msec_delay_irq(10);	return E1000_SUCCESS;}/* Internal function pointers *//** *  e1000_get_phy_cfg_done - Generic PHY configuration done *  @hw: pointer to the HW structure * *  Return success if silicon family did not implement a family specific *  get_cfg_done function. **/static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw){	if (hw->func.get_cfg_done)		return hw->func.get_cfg_done(hw);	return E1000_SUCCESS;}/** *  e1000_release_phy - Generic release PHY *  @hw: pointer to the HW structure * *  Return if silicon family does not require a semaphore when accessing the *  PHY. **/static void e1000_release_phy(struct e1000_hw *hw){	if (hw->func.release_phy)		hw->func.release_phy(hw);}/** *  e1000_acquire_phy - Generic acquire PHY *  @hw: pointer to the HW structure * *  Return success if silicon family does not require a semaphore when *  accessing the PHY. **/static s32 e1000_acquire_phy(struct e1000_hw *hw){	if (hw->func.acquire_phy)		return hw->func.acquire_phy(hw);	return E1000_SUCCESS;}/** *  e1000_phy_force_speed_duplex - Generic force PHY speed/duplex *  @hw: pointer to the HW structure * *  When the silicon family has not implemented a forced speed/duplex *  function for the PHY, simply return E1000_SUCCESS. **/s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw){	if (hw->func.force_speed_duplex)		return hw->func.force_speed_duplex(hw);	return E1000_SUCCESS;}/** *  e1000_phy_init_script_igp3 - Inits the IGP3 PHY *  @hw: pointer to the HW structure * *  Initializes a Intel Gigabit PHY3 when an EEPROM is not present. **/s32 e1000_phy_init_script_igp3(struct e1000_hw *hw){	DEBUGOUT("Running IGP 3 PHY init script\n");	/* PHY init IGP 3 */	/* Enable rise/fall, 10-mode work in class-A */	e1000_write_phy_reg(hw, 0x2F5B, 0x9018);	/* Remove all caps from Replica path filter */	e1000_write_phy_reg(hw, 0x2F52, 0x0000);	/* Bias trimming for ADC, AFE and Driver (Default) */	e1000_write_phy_reg(hw, 0x2FB1, 0x8B24);	/* Increase Hybrid poly bias */	e1000_write_phy_reg(hw, 0x2FB2, 0xF8F0);	/* Add 4% to Tx amplitude in Giga mode */	e1000_write_phy_reg(hw, 0x2010, 0x10B0);	/* Disable trimming (TTT) */	e1000_write_phy_reg(hw, 0x2011, 0x0000);	/* Poly DC correction to 94.6% + 2% for all channels */	e1000_write_phy_reg(hw, 0x20DD, 0x249A);	/* ABS DC correction to 95.9% */	e1000_write_phy_reg(hw, 0x20DE, 0x00D3);	/* BG temp curve trim */	e1000_write_phy_reg(hw, 0x28B4, 0x04CE);	/* Increasing ADC OPAMP stage 1 currents to max */	e1000_write_phy_reg(hw, 0x2F70, 0x29E4);	/* Force 1000 ( required for enabling PHY regs configuration) */	e1000_write_phy_reg(hw, 0x0000, 0x0140);	/* Set upd_freq to 6 */	e1000_write_phy_reg(hw, 0x1F30, 0x1606);	/* Disable NPDFE */	e1000_write_phy_reg(hw, 0x1F31, 0xB814);	/* Disable adaptive fixed FFE (Default) */	e1000_write_phy_reg(hw, 0x1F35, 0x002A);	/* Enable FFE hysteresis */	e1000_write_phy_reg(hw, 0x1F3E, 0x0067);	/* Fixed FFE for short cable lengths */	e1000_write_phy_reg(hw, 0x1F54, 0x0065);	/* Fixed FFE for medium cable lengths */	e1000_write_phy_reg(hw, 0x1F55, 0x002A);	/* Fixed FFE for long cable lengths */	e1000_write_phy_reg(hw, 0x1F56, 0x002A);	/* Enable Adaptive Clip Threshold */	e1000_write_phy_reg(hw, 0x1F72, 0x3FB0);	/* AHT reset limit to 1 */	e1000_write_phy_reg(hw, 0x1F76, 0xC0FF);	/* Set AHT master delay to 127 msec */	e1000_write_phy_reg(hw, 0x1F77, 0x1DEC);	/* Set scan bits for AHT */	e1000_write_phy_reg(hw, 0x1F78, 0xF9EF);	/* Set AHT Preset bits */	e1000_write_phy_reg(hw, 0x1F79, 0x0210);	/* Change integ_factor of channel A to 3 */	e1000_write_phy_reg(hw, 0x1895, 0x0003);	/* Change prop_factor of channels BCD to 8 */	e1000_write_phy_reg(hw, 0x1796, 0x0008);	/* Change cg_icount + enable integbp for channels BCD */	e1000_write_phy_reg(hw, 0x1798, 0xD008);	/*	 * Change cg_icount + enable integbp + change prop_factor_master	 * to 8 for channel A	 */	e1000_write_phy_reg(hw, 0x1898, 0xD918);	/* Disable AHT in Slave mode on channel A */	e1000_write_phy_reg(hw, 0x187A, 0x0800);	/*	 * Enable LPLU and disable AN to 1000 in non-D0a states,	 * Enable SPD+B2B	 */	e1000_write_phy_reg(hw, 0x0019, 0x008D);	/* Enable restart AN on an1000_dis change */	e1000_write_phy_reg(hw, 0x001B, 0x2080);	/* Enable wh_fifo read clock in 10/100 modes */	e1000_write_phy_reg(hw, 0x0014, 0x0045);	/* Restart AN, Speed selection is 1000 */	e1000_write_phy_reg(hw, 0x0000, 0x1340);	return E1000_SUCCESS;}/** *  e1000_get_phy_type_from_id - Get PHY type from id *  @phy_id: phy_id read from the phy * *  Returns the phy type from the id. **/e1000_phy_type e1000_get_phy_type_from_id(u32 phy_id){	e1000_phy_type phy_type = e1000_phy_unknown;	switch (phy_id)	{	case M88E1000_I_PHY_ID:	case M88E1000_E_PHY_ID:	case M88E1111_I_PHY_ID:	case M88E1011_I_PHY_ID:		phy_type = e1000_phy_m88;		break;	case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */		phy_type = e1000_phy_igp_2;		break;	case GG82563_E_PHY_ID:		phy_type = e1000_phy_gg82563;		break;	case IGP03E1000_E_PHY_ID:		phy_type = e1000_phy_igp_3;		break;	case IFE_E_PHY_ID:	case IFE_PLUS_E_PHY_ID:	case IFE_C_E_PHY_ID:		phy_type = e1000_phy_ife;		break;	default:		phy_type = e1000_phy_unknown;		break;	}	return phy_type;}/** * e1000_power_up_phy_copper - Restore copper link in case of PHY power down * @hw: pointer to the HW structure * * In the case of a PHY power down to save power, or to turn off link during a * driver unload, or wake on lan is not enabled, restore the link to previous * settings. **/void e1000_power_up_phy_copper(struct e1000_hw *hw){	u16 mii_reg = 0;	/* The PHY will retain its settings across a power down/up cycle */	e1000_read_phy_reg(hw, PHY_CONTROL, &mii_reg);	mii_reg &= ~MII_CR_POWER_DOWN;	e1000_write_phy_reg(hw, PHY_CONTROL, mii_reg);}/** * e1000_power_down_phy_copper - Restore copper link in case of PHY power down * @hw: pointer to the HW structure * * In the case of a PHY power down to save power, or to turn off link during a * driver unload, or wake on lan is not enabled, restore the link to previous * settings. **/void e1000_power_down_phy_copper(struct e1000_hw *hw){	u16 mii_reg = 0;	/* The PHY will retain its settings across a power down/up cycle */	e1000_read_phy_reg(hw, PHY_CONTROL, &mii_reg);	mii_reg |= MII_CR_POWER_DOWN;	e1000_write_phy_reg(hw, PHY_CONTROL, mii_reg);	msec_delay(1);}

⌨️ 快捷键说明

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