📄 e1000_mac.c
字号:
struct e1000_mac_info *mac = &hw->mac; u32 txcw; s32 ret_val = E1000_SUCCESS; /* * Check for a software override of the flow control settings, and * setup the device accordingly. If auto-negotiation is enabled, then * software will have to set the "PAUSE" bits to the correct value in * the Transmit Config Word Register (TXCW) and re-start auto- * negotiation. However, if auto-negotiation is disabled, then * software will have to manually configure the two flow control enable * bits in the CTRL register. * * The possible values of the "fc" parameter are: * 0: Flow control is completely disabled * 1: Rx flow control is enabled (we can receive pause frames, * but not send pause frames). * 2: Tx flow control is enabled (we can send pause frames but we * do not support receiving pause frames). * 3: Both Rx and Tx flow control (symmetric) are enabled. */ switch (hw->fc.current_mode) { case e1000_fc_none: /* Flow control completely disabled by a software over-ride. */ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD); break; case e1000_fc_rx_pause: /* * Rx Flow control is enabled and Tx Flow control is disabled * by a software over-ride. Since there really isn't a way to * advertise that we are capable of Rx Pause ONLY, we will * advertise that we support both symmetric and asymmetric RX * PAUSE. Later, we will disable the adapter's ability to send * PAUSE frames. */ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); break; case e1000_fc_tx_pause: /* * Tx Flow control is enabled, and Rx Flow control is disabled, * by a software over-ride. */ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR); break; case e1000_fc_full: /* * Flow control (both Rx and Tx) is enabled by a software * over-ride. */ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); break; default: e_dbg("Flow control param set incorrectly\n"); ret_val = -E1000_ERR_CONFIG; goto out; break; } ew32(TXCW, txcw); mac->txcw = txcw;out: return ret_val;}/** * e1000e_set_fc_watermarks - Set flow control high/low watermarks * @hw: pointer to the HW structure * * Sets the flow control high/low threshold (watermark) registers. If * flow control XON frame transmission is enabled, then set XON frame * transmission as well. **/s32 e1000e_set_fc_watermarks(struct e1000_hw *hw){ s32 ret_val = E1000_SUCCESS; u32 fcrtl = 0, fcrth = 0; /* * Set the flow control receive threshold registers. Normally, * these registers will be set to a default threshold that may be * adjusted later by the driver's runtime code. However, if the * ability to transmit pause frames is not enabled, then these * registers will be set to 0. */ if (hw->fc.current_mode & e1000_fc_tx_pause) { /* * We need to set up the Receive Threshold high and low water * marks as well as (optionally) enabling the transmission of * XON frames. */ fcrtl = hw->fc.low_water; if (hw->fc.send_xon) fcrtl |= E1000_FCRTL_XONE; fcrth = hw->fc.high_water; } ew32(FCRTL, fcrtl); ew32(FCRTH, fcrth); return ret_val;}/** * e1000_set_default_fc_generic - Set flow control default values * @hw: pointer to the HW structure * * Read the EEPROM for the default values for flow control and store the * values. **/static s32 e1000_set_default_fc_generic(struct e1000_hw *hw){ s32 ret_val = E1000_SUCCESS; u16 nvm_data; /* * Read and store word 0x0F of the EEPROM. This word contains bits * that determine the hardware's default PAUSE (flow control) mode, * a bit that determines whether the HW defaults to enabling or * disabling auto-negotiation, and the direction of the * SW defined pins. If there is no SW over-ride of the flow * control setting, then the variable hw->fc will * be initialized based on a value in the EEPROM. */ ret_val = e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data); if (ret_val) { e_dbg("NVM Read Error\n"); goto out; } if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0) hw->fc.requested_mode = e1000_fc_none; else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == NVM_WORD0F_ASM_DIR) hw->fc.requested_mode = e1000_fc_tx_pause; else hw->fc.requested_mode = e1000_fc_full;out: return ret_val;}/** * e1000e_force_mac_fc - Force the MAC's flow control settings * @hw: pointer to the HW structure * * Force the MAC's flow control settings. Sets the TFCE and RFCE bits in the * device control register to reflect the adapter settings. TFCE and RFCE * need to be explicitly set by software when a copper PHY is used because * autonegotiation is managed by the PHY rather than the MAC. Software must * also configure these bits when link is forced on a fiber connection. **/s32 e1000e_force_mac_fc(struct e1000_hw *hw){ u32 ctrl; s32 ret_val = E1000_SUCCESS; ctrl = er32(CTRL); /* * Because we didn't get link via the internal auto-negotiation * mechanism (we either forced link or we got link via PHY * auto-neg), we have to manually enable/disable transmit an * receive flow control. * * The "Case" statement below enables/disable flow control * according to the "hw->fc.current_mode" parameter. * * The possible values of the "fc" parameter are: * 0: Flow control is completely disabled * 1: Rx flow control is enabled (we can receive pause * frames but not send pause frames). * 2: Tx flow control is enabled (we can send pause frames * frames but we do not receive pause frames). * 3: Both Rx and Tx flow control (symmetric) is enabled. * other: No other values should be possible at this point. */ e_dbg("hw->fc.current_mode = %u\n", hw->fc.current_mode); switch (hw->fc.current_mode) { case e1000_fc_none: ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE)); break; case e1000_fc_rx_pause: 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: e_dbg("Flow control param set incorrectly\n"); ret_val = -E1000_ERR_CONFIG; goto out; } ew32(CTRL, ctrl);out: return ret_val;}/** * 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 = E1000_SUCCESS; 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->phy.media_type == e1000_media_type_fiber || hw->phy.media_type == e1000_media_type_internal_serdes) ret_val = e1000e_force_mac_fc(hw); } else { if (hw->phy.media_type == e1000_media_type_copper) ret_val = e1000e_force_mac_fc(hw); } if (ret_val) { e_dbg("Error forcing flow control settings\n"); goto out; } /* * 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->phy.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) goto out; ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg); if (ret_val) goto out; if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) { e_dbg("Copper PHY and Auto Neg " "has not completed.\n"); goto out; } /* * 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) goto out; ret_val = e1e_rphy(hw, PHY_LP_ABILITY, &mii_nway_lp_ability_reg); if (ret_val) goto out; /* * 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 (hw->fc.requested_mode == e1000_fc_full) { hw->fc.current_mode = e1000_fc_full; e_dbg("Flow Control = FULL.\r\n"); } else { hw->fc.current_mode = e1000_fc_rx_pause; e_dbg("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)) { hw->fc.current_mode = e1000_fc_tx_pause; e_dbg("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)) { hw->fc.current_mode = e1000_fc_rx_pause; e_dbg("Flow Control = RX PAUSE frames only.\r\n"); } else { /* * Per the IEEE spec, at this point flow control * should be disabled. */ hw->fc.current_mode = e1000_fc_none; e_dbg("Flow Control = NONE.\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) { e_dbg("Error getting link speed and duplex\n"); goto out; } if (duplex == HALF_DUPLEX) hw->fc.current_mode = 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) { e_dbg("Error forcing flow control settings\n"); goto out; } }out: return ret_val;}/** * e1000e_get_speed_and_duplex_copper - Retrieve 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; e_dbg("1000 Mbs, "); } else if (status & E1000_STATUS_SPEED_100) { *speed = SPEED_100; e_dbg("100 Mbs, "); } else { *speed = SPEED_10; e_dbg("10 Mbs, "); } if (status & E1000_STATUS_FD) { *duplex = FULL_DUPLEX; e_dbg("Full Duplex\n"); } else { *duplex = HALF_DUPLEX; e_dbg("Half Duplex\n"); } return E1000_SUCCESS;}/** * e1000_get_speed_and_duplex_fiber_generic - Retrieve 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 E1000_SUCCESS;}/** * 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 ret_val = E1000_SUCCESS; s32 timeout = hw->nvm.word_size + 1; s32 i = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -