lib.c

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

C
2,342
字号
		ctrl &= (~E1000_CTRL_TFCE);		ctrl |= E1000_CTRL_RFCE;		break;	case e1000_fc_tx_pause:		ctrl &= (~E1000_CTRL_RFCE);		ctrl |= E1000_CTRL_TFCE;		break;	case e1000_fc_full:		ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);		break;	default:		hw_dbg(hw, "Flow control param set incorrectly\n");		return -E1000_ERR_CONFIG;	}	ew32(CTRL, ctrl);	return 0;}/** *  e1000e_config_fc_after_link_up - Configures flow control after link *  @hw: pointer to the HW structure * *  Checks the status of auto-negotiation after link up to ensure that the *  speed and duplex were not forced.  If the link needed to be forced, then *  flow control needs to be forced also.  If auto-negotiation is enabled *  and did not fail, then we configure flow control based on our link *  partner. **/s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw){	struct e1000_mac_info *mac = &hw->mac;	s32 ret_val = 0;	u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;	u16 speed, duplex;	/* Check for the case where we have fiber media and auto-neg failed	 * so we had to force link.  In this case, we need to force the	 * configuration of the MAC to match the "fc" parameter.	 */	if (mac->autoneg_failed) {		if (hw->media_type == e1000_media_type_fiber ||		    hw->media_type == e1000_media_type_internal_serdes)			ret_val = e1000e_force_mac_fc(hw);	} else {		if (hw->media_type == e1000_media_type_copper)			ret_val = e1000e_force_mac_fc(hw);	}	if (ret_val) {		hw_dbg(hw, "Error forcing flow control settings\n");		return ret_val;	}	/* Check for the case where we have copper media and auto-neg is	 * enabled.  In this case, we need to check and see if Auto-Neg	 * has completed, and if so, how the PHY and link partner has	 * flow control configured.	 */	if ((hw->media_type == e1000_media_type_copper) && mac->autoneg) {		/* Read the MII Status Register and check to see if AutoNeg		 * has completed.  We read this twice because this reg has		 * some "sticky" (latched) bits.		 */		ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg);		if (ret_val)			return ret_val;		ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg);		if (ret_val)			return ret_val;		if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {			hw_dbg(hw, "Copper PHY and Auto Neg "				 "has not completed.\n");			return ret_val;		}		/* The AutoNeg process has completed, so we now need to		 * read both the Auto Negotiation Advertisement		 * Register (Address 4) and the Auto_Negotiation Base		 * Page Ability Register (Address 5) to determine how		 * flow control was negotiated.		 */		ret_val = e1e_rphy(hw, PHY_AUTONEG_ADV, &mii_nway_adv_reg);		if (ret_val)			return ret_val;		ret_val = e1e_rphy(hw, PHY_LP_ABILITY, &mii_nway_lp_ability_reg);		if (ret_val)			return ret_val;		/* Two bits in the Auto Negotiation Advertisement Register		 * (Address 4) and two bits in the Auto Negotiation Base		 * Page Ability Register (Address 5) determine flow control		 * for both the PHY and the link partner.  The following		 * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,		 * 1999, describes these PAUSE resolution bits and how flow		 * control is determined based upon these settings.		 * NOTE:  DC = Don't Care		 *		 *   LOCAL DEVICE  |   LINK PARTNER		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution		 *-------|---------|-------|---------|--------------------		 *   0   |    0    |  DC   |   DC    | e1000_fc_none		 *   0   |    1    |   0   |   DC    | e1000_fc_none		 *   0   |    1    |   1   |    0    | e1000_fc_none		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause		 *   1   |    0    |   0   |   DC    | e1000_fc_none		 *   1   |   DC    |   1   |   DC    | e1000_fc_full		 *   1   |    1    |   0   |    0    | e1000_fc_none		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause		 *		 */		/* Are both PAUSE bits set to 1?  If so, this implies		 * Symmetric Flow Control is enabled at both ends.  The		 * ASM_DIR bits are irrelevant per the spec.		 *		 * For Symmetric Flow Control:		 *		 *   LOCAL DEVICE  |   LINK PARTNER		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result		 *-------|---------|-------|---------|--------------------		 *   1   |   DC    |   1   |   DC    | E1000_fc_full		 *		 */		if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&		    (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {			/* Now we need to check if the user selected RX ONLY			 * of pause frames.  In this case, we had to advertise			 * FULL flow control because we could not advertise RX			 * ONLY. Hence, we must now check to see if we need to			 * turn OFF  the TRANSMISSION of PAUSE frames.			 */			if (mac->original_fc == e1000_fc_full) {				mac->fc = e1000_fc_full;				hw_dbg(hw, "Flow Control = FULL.\r\n");			} else {				mac->fc = e1000_fc_rx_pause;				hw_dbg(hw, "Flow Control = "					 "RX PAUSE frames only.\r\n");			}		}		/* For receiving PAUSE frames ONLY.		 *		 *   LOCAL DEVICE  |   LINK PARTNER		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result		 *-------|---------|-------|---------|--------------------		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause		 *		 */		else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&			  (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&			  (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&			  (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {			mac->fc = e1000_fc_tx_pause;			hw_dbg(hw, "Flow Control = TX PAUSE frames only.\r\n");		}		/* For transmitting PAUSE frames ONLY.		 *		 *   LOCAL DEVICE  |   LINK PARTNER		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result		 *-------|---------|-------|---------|--------------------		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause		 *		 */		else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&			 (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&			 !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&			 (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {			mac->fc = e1000_fc_rx_pause;			hw_dbg(hw, "Flow Control = RX PAUSE frames only.\r\n");		}		/* Per the IEEE spec, at this point flow control should be		 * disabled.  However, we want to consider that we could		 * be connected to a legacy switch that doesn't advertise		 * desired flow control, but can be forced on the link		 * partner.  So if we advertised no flow control, that is		 * what we will resolve to.  If we advertised some kind of		 * receive capability (Rx Pause Only or Full Flow Control)		 * and the link partner advertised none, we will configure		 * ourselves to enable Rx Flow Control only.  We can do		 * this safely for two reasons:  If the link partner really		 * didn't want flow control enabled, and we enable Rx, no		 * harm done since we won't be receiving any PAUSE frames		 * anyway.  If the intent on the link partner was to have		 * flow control enabled, then by us enabling RX only, we		 * can at least receive pause frames and process them.		 * This is a good idea because in most cases, since we are		 * predominantly a server NIC, more times than not we will		 * be asked to delay transmission of packets than asking		 * our link partner to pause transmission of frames.		 */		else if ((mac->original_fc == e1000_fc_none) ||			 (mac->original_fc == e1000_fc_tx_pause)) {			mac->fc = e1000_fc_none;			hw_dbg(hw, "Flow Control = NONE.\r\n");		} else {			mac->fc = e1000_fc_rx_pause;			hw_dbg(hw, "Flow Control = RX PAUSE frames only.\r\n");		}		/* Now we need to do one last check...  If we auto-		 * negotiated to HALF DUPLEX, flow control should not be		 * enabled per IEEE 802.3 spec.		 */		ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex);		if (ret_val) {			hw_dbg(hw, "Error getting link speed and duplex\n");			return ret_val;		}		if (duplex == HALF_DUPLEX)			mac->fc = e1000_fc_none;		/* Now we call a subroutine to actually force the MAC		 * controller to use the correct flow control settings.		 */		ret_val = e1000e_force_mac_fc(hw);		if (ret_val) {			hw_dbg(hw, "Error forcing flow control settings\n");			return ret_val;		}	}	return 0;}/** *  e1000e_get_speed_and_duplex_copper - Retreive current speed/duplex *  @hw: pointer to the HW structure *  @speed: stores the current speed *  @duplex: stores the current duplex * *  Read the status register for the current speed/duplex and store the current *  speed and duplex for copper connections. **/s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *duplex){	u32 status;	status = er32(STATUS);	if (status & E1000_STATUS_SPEED_1000) {		*speed = SPEED_1000;		hw_dbg(hw, "1000 Mbs, ");	} else if (status & E1000_STATUS_SPEED_100) {		*speed = SPEED_100;		hw_dbg(hw, "100 Mbs, ");	} else {		*speed = SPEED_10;		hw_dbg(hw, "10 Mbs, ");	}	if (status & E1000_STATUS_FD) {		*duplex = FULL_DUPLEX;		hw_dbg(hw, "Full Duplex\n");	} else {		*duplex = HALF_DUPLEX;		hw_dbg(hw, "Half Duplex\n");	}	return 0;}/** *  e1000e_get_speed_and_duplex_fiber_serdes - Retreive current speed/duplex *  @hw: pointer to the HW structure *  @speed: stores the current speed *  @duplex: stores the current duplex * *  Sets the speed and duplex to gigabit full duplex (the only possible option) *  for fiber/serdes links. **/s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw, u16 *speed, u16 *duplex){	*speed = SPEED_1000;	*duplex = FULL_DUPLEX;	return 0;}/** *  e1000e_get_hw_semaphore - Acquire hardware semaphore *  @hw: pointer to the HW structure * *  Acquire the HW semaphore to access the PHY or NVM **/s32 e1000e_get_hw_semaphore(struct e1000_hw *hw){	u32 swsm;	s32 timeout = hw->nvm.word_size + 1;	s32 i = 0;	/* Get the SW semaphore */	while (i < timeout) {		swsm = er32(SWSM);		if (!(swsm & E1000_SWSM_SMBI))			break;		udelay(50);		i++;	}	if (i == timeout) {		hw_dbg(hw, "Driver can't access device - SMBI bit is set.\n");		return -E1000_ERR_NVM;	}	/* Get the FW semaphore. */	for (i = 0; i < timeout; i++) {		swsm = er32(SWSM);		ew32(SWSM, swsm | E1000_SWSM_SWESMBI);		/* Semaphore acquired if bit latched */		if (er32(SWSM) & E1000_SWSM_SWESMBI)			break;		udelay(50);	}	if (i == timeout) {		/* Release semaphores */		e1000e_put_hw_semaphore(hw);		hw_dbg(hw, "Driver can't access the NVM\n");		return -E1000_ERR_NVM;	}	return 0;}/** *  e1000e_put_hw_semaphore - Release hardware semaphore *  @hw: pointer to the HW structure * *  Release hardware semaphore used to access the PHY or NVM **/void e1000e_put_hw_semaphore(struct e1000_hw *hw){	u32 swsm;	swsm = er32(SWSM);	swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);	ew32(SWSM, swsm);}/** *  e1000e_get_auto_rd_done - Check for auto read completion *  @hw: pointer to the HW structure * *  Check EEPROM for Auto Read done bit. **/s32 e1000e_get_auto_rd_done(struct e1000_hw *hw){	s32 i = 0;	while (i < AUTO_READ_DONE_TIMEOUT) {		if (er32(EECD) & E1000_EECD_AUTO_RD)			break;		msleep(1);		i++;	}	if (i == AUTO_READ_DONE_TIMEOUT) {		hw_dbg(hw, "Auto read by HW from NVM has not completed.\n");		return -E1000_ERR_RESET;	}	return 0;}/** *  e1000e_valid_led_default - Verify a valid default LED config *  @hw: pointer to the HW structure *  @data: pointer to the NVM (EEPROM) * *  Read the EEPROM for the current default LED configuration.  If the *  LED configuration is not valid, set to a valid LED configuration. **/s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data){	s32 ret_val;	ret_val = e1000_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data);	if (ret_val) {		hw_dbg(hw, "NVM Read Error\n");		return ret_val;	}	if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)		*data = ID_LED_DEFAULT;	return 0;}/** *  e1000e_id_led_init - *  @hw: pointer to the HW structure * **/s32 e1000e_id_led_init(struct e1000_hw *hw){	struct e1000_mac_info *mac = &hw->mac;	s32 ret_val;	const u32 ledctl_mask = 0x000000FF;	const u32 ledctl_on = E1000_LEDCTL_MODE_LED_ON;	const u32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF;	u16 data, i, temp;	const u16 led_mask = 0x0F;	ret_val = hw->nvm.ops.valid_led_default(hw, &data);	if (ret_val)		return ret_val;	mac->ledctl_default = er32(LEDCTL);	mac->ledctl_mode1 = mac->ledctl_default;	mac->ledctl_mode2 = mac->ledctl_default;	for (i = 0; i < 4; i++) {		temp = (data >> (i << 2)) & led_mask;		switch (temp) {		case ID_LED_ON1_DEF2:		case ID_LED_ON1_ON2:		case ID_LED_ON1_OFF2:			mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));			mac->ledctl_mode1 |= ledctl_on << (i << 3);			break;		case ID_LED_OFF1_DEF2:		case ID_LED_OFF1_ON2:		case ID_LED_OFF1_OFF2:			mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));			mac->ledctl_mode1 |= ledctl_off << (i << 3);			break;		default:			/* Do nothing */			break;		}		switch (temp) {		case ID_LED_DEF1_ON2:		case ID_LED_ON1_ON2:		case ID_LED_OFF1_ON2:			mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));			mac->ledctl_mode2 |= ledctl_on << (i << 3);			break;		case ID_LED_DEF1_OFF2:		case ID_LED_ON1_OFF2:		case ID_LED_OFF1_OFF2:			mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));			mac->ledctl_mode2 |= ledctl_off << (i << 3);			break;		default:			/* Do nothing */			break;		}	}	return 0;}/** *  e1000e_cleanup_led_generic - Set LED config to default operation *  @hw: pointer to the HW structure * *  Remove the current LED configuration and set the LED configuration *  to the default value, saved from the EEPROM. **/s32 e1000e_cleanup_led_generic(struct e1000_hw *hw){	ew32(LEDCTL, hw->mac.ledctl_default);	return 0;}

⌨️ 快捷键说明

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