phy.c

来自「linux 内核源代码」· C语言 代码 · 共 1,774 行 · 第 1/4 页

C
1,774
字号
		if (ret_val)			break;		ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);		if (ret_val)			break;		if (phy_status & MII_SR_LINK_STATUS)			break;		if (usec_interval >= 1000)			mdelay(usec_interval/1000);		else			udelay(usec_interval);	}	*success = (i < iterations);	return ret_val;}/** *  e1000e_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 e1000e_get_cable_length_m88(struct e1000_hw *hw){	struct e1000_phy_info *phy = &hw->phy;	s32 ret_val;	u16 phy_data, index;	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);	if (ret_val)		return ret_val;	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;	return ret_val;}/** *  e1000e_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 *  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 e1000e_get_cable_length_igp_2(struct e1000_hw *hw){	struct e1000_phy_info *phy = &hw->phy;	s32 ret_val;	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};	/* Read the AGC registers for all channels */	for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {		ret_val = e1e_rphy(hw, agc_reg_array[i], &phy_data);		if (ret_val)			return ret_val;		/* 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))			return -E1000_ERR_PHY;		/* 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;	return ret_val;}/** *  e1000e_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 e1000e_get_phy_info_m88(struct e1000_hw *hw){	struct e1000_phy_info *phy = &hw->phy;	s32  ret_val;	u16 phy_data;	bool link;	if (hw->media_type != e1000_media_type_copper) {		hw_dbg(hw, "Phy info is only valid for copper media\n");		return -E1000_ERR_CONFIG;	}	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);	if (ret_val)		return ret_val;	if (!link) {		hw_dbg(hw, "Phy info is only valid if link is up\n");		return -E1000_ERR_CONFIG;	}	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);	if (ret_val)		return ret_val;	phy->polarity_correction = (phy_data &				    M88E1000_PSCR_POLARITY_REVERSAL);	ret_val = e1000_check_polarity_m88(hw);	if (ret_val)		return ret_val;	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);	if (ret_val)		return ret_val;	phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX);	if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {		ret_val = e1000_get_cable_length(hw);		if (ret_val)			return ret_val;		ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &phy_data);		if (ret_val)			return ret_val;		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;	}	return ret_val;}/** *  e1000e_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 e1000e_get_phy_info_igp(struct e1000_hw *hw){	struct e1000_phy_info *phy = &hw->phy;	s32 ret_val;	u16 data;	bool link;	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);	if (ret_val)		return ret_val;	if (!link) {		hw_dbg(hw, "Phy info is only valid if link is up\n");		return -E1000_ERR_CONFIG;	}	phy->polarity_correction = 1;	ret_val = e1000_check_polarity_igp(hw);	if (ret_val)		return ret_val;	ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_STATUS, &data);	if (ret_val)		return ret_val;	phy->is_mdix = (data & IGP01E1000_PSSR_MDIX);	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==	    IGP01E1000_PSSR_SPEED_1000MBPS) {		ret_val = e1000_get_cable_length(hw);		if (ret_val)			return ret_val;		ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &data);		if (ret_val)			return ret_val;		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;	}	return ret_val;}/** *  e1000e_phy_sw_reset - 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 e1000e_phy_sw_reset(struct e1000_hw *hw){	s32 ret_val;	u16 phy_ctrl;	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_ctrl);	if (ret_val)		return ret_val;	phy_ctrl |= MII_CR_RESET;	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_ctrl);	if (ret_val)		return ret_val;	udelay(1);	return ret_val;}/** *  e1000e_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 e1000e_phy_hw_reset_generic(struct e1000_hw *hw){	struct e1000_phy_info *phy = &hw->phy;	s32 ret_val;	u32 ctrl;	ret_val = e1000_check_reset_block(hw);	if (ret_val)		return 0;	ret_val = phy->ops.acquire_phy(hw);	if (ret_val)		return ret_val;	ctrl = er32(CTRL);	ew32(CTRL, ctrl | E1000_CTRL_PHY_RST);	e1e_flush();	udelay(phy->reset_delay_us);	ew32(CTRL, ctrl);	e1e_flush();	udelay(150);	phy->ops.release_phy(hw);	return e1000_get_phy_cfg_done(hw);}/** *  e1000e_get_cfg_done - Generic configuration done *  @hw: pointer to the HW structure * *  Generic function to wait 10 milli-seconds for configuration to complete *  and return success. **/s32 e1000e_get_cfg_done(struct e1000_hw *hw){	mdelay(10);	return 0;}/* 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->phy.ops.get_cfg_done)		return hw->phy.ops.get_cfg_done(hw);	return 0;}/** *  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 0. **/static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw){	if (hw->phy.ops.force_speed_duplex)		return hw->phy.ops.force_speed_duplex(hw);	return 0;}/** *  e1000e_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. **/enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id){	enum 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;}/** *  e1000e_commit_phy - Soft PHY reset *  @hw: pointer to the HW structure * *  Performs a soft PHY reset on those that apply. This is a function pointer *  entry point called by drivers. **/s32 e1000e_commit_phy(struct e1000_hw *hw){	if (hw->phy.ops.commit_phy)		return hw->phy.ops.commit_phy(hw);	return 0;}/** *  e1000_set_d0_lplu_state - Sets low power link up state for D0 *  @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 D0 *  and SmartSpeed is disabled when active is true, else clear lplu for D0 *  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.  This is a function pointer entry point called by drivers. **/static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active){	if (hw->phy.ops.set_d0_lplu_state)		return hw->phy.ops.set_d0_lplu_state(hw, active);	return 0;}

⌨️ 快捷键说明

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