Message ID | 20180624084525.10374-1-sasha.neftin@intel.com |
---|---|
State | RFC |
Headers | show |
Series | None | expand |
On 6/24/2018 1:45 AM, Sasha Neftin wrote: > Add link establishment methods > Add auto negotiation methods > Add read MAC address method > > Sasha Neftin (v2): > minor cosmetic changes > > Sasha Neftin (v3): > removed not addressed methods > > Signed-off-by: Sasha Neftin <sasha.neftin@intel.com> > --- > drivers/net/ethernet/intel/igc/e1000_base.c | 41 +++ > drivers/net/ethernet/intel/igc/e1000_defines.h | 45 ++++ > drivers/net/ethernet/intel/igc/e1000_mac.c | 272 +++++++++++++++++++- > drivers/net/ethernet/intel/igc/e1000_mac.h | 2 + > drivers/net/ethernet/intel/igc/e1000_phy.c | 332 ++++++++++++++++++++++++- > drivers/net/ethernet/intel/igc/e1000_phy.h | 1 + > drivers/net/ethernet/intel/igc/igc.h | 1 + > drivers/net/ethernet/intel/igc/igc_main.c | 35 ++- > 8 files changed, 725 insertions(+), 4 deletions(-) > > diff --git a/drivers/net/ethernet/intel/igc/e1000_base.c b/drivers/net/ethernet/intel/igc/e1000_base.c > index 8b35e1d6c32e..6405506ff7b8 100644 > --- a/drivers/net/ethernet/intel/igc/e1000_base.c > +++ b/drivers/net/ethernet/intel/igc/e1000_base.c > @@ -17,6 +17,7 @@ static void igc_release_phy_base(struct e1000_hw *); > static s32 igc_get_phy_id_base(struct e1000_hw *); > static s32 igc_init_hw_base(struct e1000_hw *); > static s32 igc_reset_hw_base(struct e1000_hw *); > +static s32 igc_setup_copper_link_base(struct e1000_hw *); > static s32 igc_set_pcie_completion_timeout(struct e1000_hw *hw); > static s32 igc_read_mac_addr_base(struct e1000_hw *hw); > > @@ -97,6 +98,9 @@ static s32 igc_init_mac_params_base(struct e1000_hw *hw) > if (mac->type == e1000_i225) > dev_spec->clear_semaphore_once = true; > > + /* physical interface link setup */ > + mac->ops.setup_physical_interface = igc_setup_copper_link_base; > + > return 0; > } > > @@ -139,6 +143,8 @@ static s32 igc_init_phy_params_base(struct e1000_hw *hw) > if (ret_val) > return ret_val; > > + igc_check_for_link_base(hw); > + > /* Verify phy id and set remaining function pointers */ > switch (phy->id) { > case I225_I_PHY_ID: > @@ -155,10 +161,22 @@ static s32 igc_init_phy_params_base(struct e1000_hw *hw) > > static s32 igc_get_invariants_base(struct e1000_hw *hw) > { > + struct e1000_mac_info *mac = &hw->mac; > s32 ret_val = 0; > u32 ctrl_ext = 0; > u32 link_mode = 0; > > + switch (hw->device_id) { > + case E1000_DEV_ID_I225_LM: > + case E1000_DEV_ID_I225_V: > + mac->type = e1000_i225; > + break; > + default: > + return -E1000_ERR_MAC_INIT; > + } > + > + hw->phy.media_type = e1000_media_type_copper; > + > ctrl_ext = rd32(E1000_CTRL_EXT); > link_mode = ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK; > > @@ -289,6 +307,29 @@ static s32 igc_init_hw_base(struct e1000_hw *hw) > } > > /** > + * igc_setup_copper_link_base - Configure copper link settings > + * @hw: pointer to the HW structure > + * > + * Configures the link for auto-neg or forced speed and duplex. Then we check > + * for link, once link is established calls to configure collision distance > + * and flow control are called. > + **/ > +static s32 igc_setup_copper_link_base(struct e1000_hw *hw) > +{ > + s32 ret_val = 0; > + u32 ctrl; > + > + ctrl = rd32(E1000_CTRL); > + ctrl |= E1000_CTRL_SLU; > + ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); > + wr32(E1000_CTRL, ctrl); > + > + ret_val = igc_setup_copper_link(hw); > + > + return ret_val; > +} > + > +/** > * igc_read_mac_addr_base - Read device MAC address > * @hw: pointer to the HW structure > **/ > diff --git a/drivers/net/ethernet/intel/igc/e1000_defines.h b/drivers/net/ethernet/intel/igc/e1000_defines.h > index 40276ae76c9f..24c24c197d6b 100644 > --- a/drivers/net/ethernet/intel/igc/e1000_defines.h > +++ b/drivers/net/ethernet/intel/igc/e1000_defines.h > @@ -33,6 +33,11 @@ > /* Physical Func Reset Done Indication */ > #define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000 > > +/* Loop limit on how long we wait for auto-negotiation to complete */ > +#define COPPER_LINK_UP_LIMIT 10 > +#define PHY_AUTO_NEG_LIMIT 45 > +#define PHY_FORCE_LIMIT 20 > + > /* Number of 100 microseconds we wait for PCI Express master disable */ > #define MASTER_DISABLE_TIMEOUT 800 > /*Blocks new Master requests */ > @@ -74,6 +79,12 @@ > #define E1000_CTRL_RST 0x04000000 /* Global reset */ > > #define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */ > +#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ > +#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */ > +#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ > + > +#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */ > +#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */ > > /* PBA constants */ > #define E1000_PBA_34K 0x0022 > @@ -89,6 +100,40 @@ > #define E1000_SWFW_PHY2_SM 0x20 > #define E1000_SWFW_PHY3_SM 0x40 > > +/* PHY 1000 MII Register/Bit Definitions */ > +/* PHY Registers defined by IEEE */ > +#define PHY_CONTROL 0x00 /* Control Register */ > +#define PHY_STATUS 0x01 /* Status Register */ > +#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */ > +#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ > +#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */ > +#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */ > +#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */ > +#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ > + > +/* Autoneg Advertisement Register */ > +#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ > +#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ > +#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */ > +#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */ > +#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */ > +#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ > + > +/* Link Partner Ability Register (Base Page) */ > +#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */ > +#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */ > + > +/* 1000BASE-T Control Register */ > +#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */ > +#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ > +#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ > + > +/* PHY GPY 211 registers */ > +#define STANDARD_AN_REG_MASK 0x0007 /* MMD */ > +#define ANEG_MULTIGBT_AN_CTRL 0x0020 /* MULTI GBT AN Control Register */ > +#define MMD_DEVADDR_SHIFT 16 /* Shift MMD to higher bits */ > +#define CR_2500T_FD_CAPS 0x0080 /* Advertise 2500T FD capability */ > + If these are specific to this device, please use an IGC_ prefix. Otherwise, they look like something that should be defined globally for other drivers to use. > /* NVM Control */ > #define E1000_EECD_SK 0x00000001 /* NVM Clock */ > #define E1000_EECD_CS 0x00000002 /* NVM Chip Select */ > diff --git a/drivers/net/ethernet/intel/igc/e1000_mac.c b/drivers/net/ethernet/intel/igc/e1000_mac.c > index fe483211f66f..3f60810adc19 100644 > --- a/drivers/net/ethernet/intel/igc/e1000_mac.c > +++ b/drivers/net/ethernet/intel/igc/e1000_mac.c > @@ -141,6 +141,8 @@ s32 igc_setup_link(struct e1000_hw *hw) > /* In the case of the phy reset being blocked, we already have a link. > * We do not need to set it up again. > */ > + if (igc_check_reset_block(hw)) > + goto out; > > /* If requested flow control is set to default, set flow control > * based on the EEPROM flow control settings. > @@ -192,10 +194,74 @@ s32 igc_setup_link(struct e1000_hw *hw) > **/ > static s32 igc_set_default_fc(struct e1000_hw *hw) > { > + hw->fc.requested_mode = e1000_fc_full; > return 0; > } > > /** > + * igc_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 igc_force_mac_fc(struct e1000_hw *hw) > +{ > + u32 ctrl; > + s32 ret_val = 0; > + > + ctrl = rd32(E1000_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. > + */ > + hw_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: > + hw_dbg("Flow control param set incorrectly\n"); > + ret_val = -E1000_ERR_CONFIG; > + goto out; > + } > + > + wr32(E1000_CTRL, ctrl); > + > +out: > + return ret_val; > +} > + > +/** > * igc_set_fc_watermarks - Set flow control high/low watermarks > * @hw: pointer to the HW structure > * > @@ -423,7 +489,7 @@ s32 igc_check_for_copper_link(struct e1000_hw *hw) > * settings because we may have had to re-autoneg with a > * different link partner. > */ > - /* TODO ret_val = igc_config_fc_after_link_up(hw); */ > + ret_val = igc_config_fc_after_link_up(hw); > if (ret_val) > hw_dbg("Error configuring flow control\n"); > > @@ -453,6 +519,210 @@ void igc_config_collision_dist(struct e1000_hw *hw) > } > > /** > + * igc_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 igc_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->phy.media_type == e1000_media_type_copper) > + ret_val = igc_force_mac_fc(hw); > + } > + > + if (ret_val) { > + hw_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 = hw->phy.ops.read_reg(hw, PHY_STATUS, > + &mii_status_reg); > + if (ret_val) > + goto out; > + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, > + &mii_status_reg); > + if (ret_val) > + goto out; > + > + if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) { > + hw_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 = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV, > + &mii_nway_adv_reg); > + if (ret_val) > + goto out; > + ret_val = hw->phy.ops.read_reg(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; > + hw_dbg("Flow Control = FULL.\n"); > + } else { > + hw->fc.current_mode = e1000_fc_rx_pause; > + hw_dbg("Flow Control = RX PAUSE frames only.\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; > + hw_dbg("Flow Control = TX PAUSE frames only.\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; > + hw_dbg("Flow Control = RX PAUSE frames only.\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 ((hw->fc.requested_mode == e1000_fc_none) || > + (hw->fc.requested_mode == e1000_fc_tx_pause) || > + (hw->fc.strict_ieee)) { > + hw->fc.current_mode = e1000_fc_none; > + hw_dbg("Flow Control = NONE.\n"); > + } else { > + hw->fc.current_mode = e1000_fc_rx_pause; > + hw_dbg("Flow Control = RX PAUSE frames only.\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 = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex); > + if (ret_val) { > + hw_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 = igc_force_mac_fc(hw); > + if (ret_val) { > + hw_dbg("Error forcing flow control settings\n"); > + goto out; > + } > + } > + > +out: > + return 0; > +} > + > +/** > * igc_get_auto_rd_done - Check for auto read completion > * @hw: pointer to the HW structure > * > diff --git a/drivers/net/ethernet/intel/igc/e1000_mac.h b/drivers/net/ethernet/intel/igc/e1000_mac.h > index 0f17a8443125..0b32f21ce168 100644 > --- a/drivers/net/ethernet/intel/igc/e1000_mac.h > +++ b/drivers/net/ethernet/intel/igc/e1000_mac.h > @@ -14,6 +14,8 @@ > > /* forward declaration */ > s32 igc_check_for_copper_link(struct e1000_hw *hw); > +s32 igc_config_fc_after_link_up(struct e1000_hw *hw); > +s32 igc_force_mac_fc(struct e1000_hw *hw); > > s32 igc_disable_pcie_master(struct e1000_hw *hw); > void igc_init_rx_addrs(struct e1000_hw *hw, u16 rar_count); > diff --git a/drivers/net/ethernet/intel/igc/e1000_phy.c b/drivers/net/ethernet/intel/igc/e1000_phy.c > index c95efc4145e8..4f130402225f 100644 > --- a/drivers/net/ethernet/intel/igc/e1000_phy.c > +++ b/drivers/net/ethernet/intel/igc/e1000_phy.c > @@ -3,6 +3,10 @@ > > #include "e1000_phy.h" > > +/* forward declaration */ > +static s32 igc_phy_setup_autoneg(struct e1000_hw *hw); > +static s32 igc_wait_autoneg(struct e1000_hw *hw); > + > /** > * igc_check_reset_block - Check if PHY reset is blocked > * @hw: pointer to the HW structure > @@ -206,7 +210,333 @@ s32 igc_phy_hw_reset(struct e1000_hw *hw) > > phy->ops.release(hw); > > - ret_val = phy->ops.get_cfg_done(hw); > +out: > + return ret_val; > +} > + > +/** > + * igc_copper_link_autoneg - Setup/Enable autoneg for copper link > + * @hw: pointer to the HW structure > + * > + * Performs initial bounds checking on autoneg advertisement parameter, then > + * configure to advertise the full capability. Setup the PHY to autoneg > + * and restart the negotiation process between the link partner. If > + * autoneg_wait_to_complete, then wait for autoneg to complete before exiting. > + **/ > +static s32 igc_copper_link_autoneg(struct e1000_hw *hw) > +{ > + struct e1000_phy_info *phy = &hw->phy; > + s32 ret_val; > + u16 phy_ctrl; > + > + /* Perform some bounds checking on the autoneg advertisement > + * parameter. > + */ > + phy->autoneg_advertised &= phy->autoneg_mask; > + > + /* If autoneg_advertised is zero, we assume it was not defaulted > + * by the calling code so we set to advertise full capability. > + */ > + if (phy->autoneg_advertised == 0) > + phy->autoneg_advertised = phy->autoneg_mask; > + > + hw_dbg("Reconfiguring auto-neg advertisement params\n"); > + ret_val = igc_phy_setup_autoneg(hw); > + if (ret_val) { > + hw_dbg("Error Setting up Auto-Negotiation\n"); > + goto out; > + } > + hw_dbg("Restarting Auto-Neg\n"); > + > + /* Restart auto-negotiation by setting the Auto Neg Enable bit and > + * the Auto Neg Restart bit in the PHY control register. > + */ > + ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl); > + if (ret_val) > + goto out; > + > + phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); > + ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl); > + if (ret_val) > + goto out; > + > + /* Does the user want to wait for Auto-Neg to complete here, or > + * check at a later time (for example, callback routine). > + */ > + if (phy->autoneg_wait_to_complete) { > + ret_val = igc_wait_autoneg(hw); > + if (ret_val) { > + hw_dbg("Error while waiting for autoneg to complete\n"); > + goto out; > + } > + } > + > + hw->mac.get_link_status = true; > + > +out: > + return ret_val; > +} > + > +/** > + * igc_wait_autoneg - Wait for auto-neg completion > + * @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. > + **/ > +static s32 igc_wait_autoneg(struct e1000_hw *hw) > +{ > + s32 ret_val = 0; > + u16 i, phy_status; > + > + /* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */ > + for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) { > + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); > + if (ret_val) > + break; > + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); > + if (ret_val) > + break; > + if (phy_status & MII_SR_AUTONEG_COMPLETE) > + break; > + msleep(100); > + } > + > + /* PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation > + * has completed. > + */ Should you return an error value if the wait time expired? > + return ret_val; > +} > + > +/** > + * igc_phy_setup_autoneg - Configure PHY for auto-negotiation > + * @hw: pointer to the HW structure > + * > + * Reads the MII auto-neg advertisement register and/or the 1000T control > + * register and if the PHY is already setup for auto-negotiation, then > + * return successful. Otherwise, setup advertisement and flow control to > + * the appropriate values for the wanted auto-negotiation. > + **/ > +static s32 igc_phy_setup_autoneg(struct e1000_hw *hw) > +{ > + struct e1000_phy_info *phy = &hw->phy; > + s32 ret_val; > + u16 mii_autoneg_adv_reg; > + u16 mii_1000t_ctrl_reg = 0; > + u16 aneg_multigbt_an_ctrl = 0; > + > + phy->autoneg_advertised &= phy->autoneg_mask; > + > + /* Read the MII Auto-Neg Advertisement Register (Address 4). */ > + ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg); > + if (ret_val) > + return ret_val; > + > + if (phy->autoneg_mask & ADVERTISE_1000_FULL) { > + /* Read the MII 1000Base-T Control Register (Address 9). */ > + ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, > + &mii_1000t_ctrl_reg); > + if (ret_val) > + return ret_val; > + } > + > + if ((phy->autoneg_mask & ADVERTISE_2500_FULL) && > + hw->phy.id == I225_I_PHY_ID) { > + /* Read the MULTI GBT AN Control Register - reg 7.32 */ > + ret_val = phy->ops.read_reg(hw, (STANDARD_AN_REG_MASK << > + MMD_DEVADDR_SHIFT) | > + ANEG_MULTIGBT_AN_CTRL, > + &aneg_multigbt_an_ctrl); > + > + if (ret_val) > + return ret_val; > + } > + > + /* Need to parse both autoneg_advertised and fc and set up > + * the appropriate PHY registers. First we will parse for > + * autoneg_advertised software override. Since we can advertise > + * a plethora of combinations, we need to check each bit > + * individually. > + */ > + > + /* First we clear all the 10/100 mb speed bits in the Auto-Neg > + * Advertisement Register (Address 4) and the 1000 mb speed bits in > + * the 1000Base-T Control Register (Address 9). > + */ > + mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS | > + NWAY_AR_100TX_HD_CAPS | > + NWAY_AR_10T_FD_CAPS | > + NWAY_AR_10T_HD_CAPS); > + mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS); > + > + hw_dbg("autoneg_advertised %x\n", phy->autoneg_advertised); > + > + /* Do we want to advertise 10 Mb Half Duplex? */ > + if (phy->autoneg_advertised & ADVERTISE_10_HALF) { > + hw_dbg("Advertise 10mb Half duplex\n"); > + mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS; > + } > + > + /* Do we want to advertise 10 Mb Full Duplex? */ > + if (phy->autoneg_advertised & ADVERTISE_10_FULL) { > + hw_dbg("Advertise 10mb Full duplex\n"); > + mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS; > + } > + > + /* Do we want to advertise 100 Mb Half Duplex? */ > + if (phy->autoneg_advertised & ADVERTISE_100_HALF) { > + hw_dbg("Advertise 100mb Half duplex\n"); > + mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS; > + } > + > + /* Do we want to advertise 100 Mb Full Duplex? */ > + if (phy->autoneg_advertised & ADVERTISE_100_FULL) { > + hw_dbg("Advertise 100mb Full duplex\n"); > + mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS; > + } > + > + /* We do not allow the Phy to advertise 1000 Mb Half Duplex */ > + if (phy->autoneg_advertised & ADVERTISE_1000_HALF) > + hw_dbg("Advertise 1000mb Half duplex request denied!\n"); > + > + /* Do we want to advertise 1000 Mb Full Duplex? */ > + if (phy->autoneg_advertised & ADVERTISE_1000_FULL) { > + hw_dbg("Advertise 1000mb Full duplex\n"); > + mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS; > + } > + > + /* We do not allow the Phy to advertise 2500 Mb Half Duplex */ > + if (phy->autoneg_advertised & ADVERTISE_2500_HALF) > + hw_dbg("Advertise 2500mb Half duplex request denied!\n"); > + > + /* Do we want to advertise 2500 Mb Full Duplex? */ > + if (phy->autoneg_advertised & ADVERTISE_2500_FULL) { > + hw_dbg("Advertise 2500mb Full duplex\n"); > + aneg_multigbt_an_ctrl |= CR_2500T_FD_CAPS; > + } > + > + /* Check for a software override of the flow control settings, and > + * setup the PHY advertisement registers accordingly. If > + * auto-negotiation is enabled, then software will have to set the > + * "PAUSE" bits to the correct value in the Auto-Negotiation > + * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto- > + * negotiation. > + * > + * 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. > + * other: No software override. The flow control configuration > + * in the EEPROM is used. > + */ > + switch (hw->fc.current_mode) { > + case e1000_fc_none: > + /* Flow control (Rx & Tx) is completely disabled by a > + * software over-ride. > + */ > + mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); > + 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 > + * (in e1000_config_fc_after_link_up) we will disable the > + * hw's ability to send PAUSE frames. > + */ > + mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); > + break; > + case e1000_fc_tx_pause: > + /* Tx Flow control is enabled, and Rx Flow control is > + * disabled, by a software over-ride. > + */ > + mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR; > + mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE; > + break; > + case e1000_fc_full: > + /* Flow control (both Rx and Tx) is enabled by a software > + * over-ride. > + */ > + mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); > + break; > + default: > + hw_dbg("Flow control param set incorrectly\n"); > + return -E1000_ERR_CONFIG; > + } > + > + ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg); > + if (ret_val) > + return ret_val; > + > + hw_dbg("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); > + > + if (phy->autoneg_mask & ADVERTISE_1000_FULL) > + ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, > + mii_1000t_ctrl_reg); > + > + if ((phy->autoneg_mask & ADVERTISE_2500_FULL) && > + hw->phy.id == I225_I_PHY_ID) > + ret_val = phy->ops.write_reg(hw, > + (STANDARD_AN_REG_MASK << > + MMD_DEVADDR_SHIFT) | > + ANEG_MULTIGBT_AN_CTRL, > + aneg_multigbt_an_ctrl); > + > + return ret_val; > +} > + > +/** > + * igc_setup_copper_link - Configure copper link settings > + * @hw: pointer to the HW structure > + * > + * Calls the appropriate function to configure the link for auto-neg or forced > + * speed and duplex. Then we check for link, once link is established calls > + * to configure collision distance and flow control are called. If link is > + * not established, we return -E1000_ERR_PHY (-2). > + **/ > +s32 igc_setup_copper_link(struct e1000_hw *hw) > +{ > + s32 ret_val = 0; > + bool link; > + > + if (hw->mac.autoneg) { > + /* Setup autoneg and flow control advertisement and perform > + * autonegotiation. > + */ > + ret_val = igc_copper_link_autoneg(hw); > + if (ret_val) > + goto out; > + } else { > + /* PHY will be set to 10H, 10F, 100H or 100F > + * depending on user settings. > + */ > + hw_dbg("Forcing Speed and Duplex\n"); > + ret_val = hw->phy.ops.force_speed_duplex(hw); > + if (ret_val) { > + hw_dbg("Error Forcing Speed and Duplex\n"); > + goto out; > + } > + } > + > + /* Check link status. Wait up to 100 microseconds for link to become > + * valid. > + */ > + ret_val = igc_phy_has_link(hw, COPPER_LINK_UP_LIMIT, 10, &link); > + if (ret_val) > + goto out; > + > + if (link) { > + hw_dbg("Valid link established!!!\n"); > + igc_config_collision_dist(hw); > + ret_val = igc_config_fc_after_link_up(hw); > + } else { > + hw_dbg("Unable to establish link!!!\n"); > + } > > out: > return ret_val; > diff --git a/drivers/net/ethernet/intel/igc/e1000_phy.h b/drivers/net/ethernet/intel/igc/e1000_phy.h > index d04dfd0be7fd..3fddb1269ea2 100644 > --- a/drivers/net/ethernet/intel/igc/e1000_phy.h > +++ b/drivers/net/ethernet/intel/igc/e1000_phy.h > @@ -12,6 +12,7 @@ s32 igc_get_phy_id(struct e1000_hw *hw); > s32 igc_phy_has_link(struct e1000_hw *hw, u32 iterations, > u32 usec_interval, bool *success); > s32 igc_check_downshift(struct e1000_hw *hw); > +s32 igc_setup_copper_link(struct e1000_hw *hw); > void igc_power_up_phy_copper(struct e1000_hw *hw); > void igc_power_down_phy_copper(struct e1000_hw *hw); > > diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h > index 91df0a14c3a5..99bc2344b7ff 100644 > --- a/drivers/net/ethernet/intel/igc/igc.h > +++ b/drivers/net/ethernet/intel/igc/igc.h > @@ -320,6 +320,7 @@ struct igc_adapter { > struct work_struct reset_task; > struct work_struct watchdog_task; > struct work_struct dma_err_task; > + bool fc_autoneg; > > u8 tx_timeout_factor; > > diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c > index 21aed91454d4..563612910b3f 100644 > --- a/drivers/net/ethernet/intel/igc/igc_main.c > +++ b/drivers/net/ethernet/intel/igc/igc_main.c > @@ -3194,7 +3194,6 @@ static int __igc_open(struct net_device *netdev, bool resuming) > > /* start the watchdog. */ > hw->mac.get_link_status = 1; > - schedule_work(&adapter->watchdog_task); > > return E1000_SUCCESS; > > @@ -3452,6 +3451,25 @@ static int igc_probe(struct pci_dev *pdev, > netdev->min_mtu = ETH_MIN_MTU; > netdev->max_mtu = MAX_STD_JUMBO_FRAME_SIZE; > > + /* before reading the NVM, reset the controller to put the device in a > + * known good starting state > + */ > + hw->mac.ops.reset_hw(hw); > + > + if (eth_platform_get_mac_address(&pdev->dev, hw->mac.addr)) { > + /* copy the MAC address out of the NVM */ > + if (hw->mac.ops.read_mac_addr(hw)) > + dev_err(&pdev->dev, "NVM Read Error\n"); > + } > + > + memcpy(netdev->dev_addr, hw->mac.addr, netdev->addr_len); > + > + if (!is_valid_ether_addr(netdev->dev_addr)) { > + dev_err(&pdev->dev, "Invalid MAC Address\n"); > + err = -EIO; > + goto err_eeprom; > + } > + > /* configure RXPBSIZE and TXPBSIZE */ > wr32(E1000_RXPBS, I225_RXPBSIZE_DEFAULT); > wr32(E1000_TXPBS, I225_TXPBSIZE_DEFAULT); > @@ -3460,6 +3478,14 @@ static int igc_probe(struct pci_dev *pdev, > > INIT_WORK(&adapter->reset_task, igc_reset_task); > > + /* Initialize link properties that are user-changeable */ > + adapter->fc_autoneg = true; > + hw->mac.autoneg = true; > + hw->phy.autoneg_advertised = 0x2f; > + > + hw->fc.requested_mode = e1000_fc_default; > + hw->fc.current_mode = e1000_fc_default; > + > /* reset the hardware with the new settings */ > igc_reset(adapter); > > @@ -3496,6 +3522,12 @@ static int igc_probe(struct pci_dev *pdev, > > err_register: > igc_release_hw_control(adapter); > +err_eeprom: > + if (!igc_check_reset_block(hw)) > + igc_reset_phy(hw); > + > + if (hw->flash_address) > + iounmap(hw->flash_address); > err_sw_init: > igc_clear_interrupt_scheme(adapter); > iounmap(adapter->io_addr); > @@ -3530,7 +3562,6 @@ static void igc_remove(struct pci_dev *pdev) > del_timer_sync(&adapter->watchdog_timer); > > cancel_work_sync(&adapter->reset_task); > - cancel_work_sync(&adapter->watchdog_task); Why are you removing this? Yes, I see that it got put back in patch 11/11, but why take it out in the first place? > > /* Release control of h/w to f/w. If f/w is AMT enabled, this > * would have already happened in close and is redundant. >
On 6/29/2018 18:03, Shannon Nelson wrote: > On 6/24/2018 1:45 AM, Sasha Neftin wrote: >> Add link establishment methods >> Add auto negotiation methods >> Add read MAC address method >> >> Sasha Neftin (v2): >> minor cosmetic changes >> >> Sasha Neftin (v3): >> removed not addressed methods >> >> Signed-off-by: Sasha Neftin <sasha.neftin@intel.com> >> --- >> drivers/net/ethernet/intel/igc/e1000_base.c | 41 +++ >> drivers/net/ethernet/intel/igc/e1000_defines.h | 45 ++++ >> drivers/net/ethernet/intel/igc/e1000_mac.c | 272 >> +++++++++++++++++++- >> drivers/net/ethernet/intel/igc/e1000_mac.h | 2 + >> drivers/net/ethernet/intel/igc/e1000_phy.c | 332 >> ++++++++++++++++++++++++- >> drivers/net/ethernet/intel/igc/e1000_phy.h | 1 + >> drivers/net/ethernet/intel/igc/igc.h | 1 + >> drivers/net/ethernet/intel/igc/igc_main.c | 35 ++- >> 8 files changed, 725 insertions(+), 4 deletions(-) >> >> diff --git a/drivers/net/ethernet/intel/igc/e1000_base.c >> b/drivers/net/ethernet/intel/igc/e1000_base.c >> index 8b35e1d6c32e..6405506ff7b8 100644 >> --- a/drivers/net/ethernet/intel/igc/e1000_base.c >> +++ b/drivers/net/ethernet/intel/igc/e1000_base.c >> @@ -17,6 +17,7 @@ static void igc_release_phy_base(struct e1000_hw *); >> static s32 igc_get_phy_id_base(struct e1000_hw *); >> static s32 igc_init_hw_base(struct e1000_hw *); >> static s32 igc_reset_hw_base(struct e1000_hw *); >> +static s32 igc_setup_copper_link_base(struct e1000_hw *); >> static s32 igc_set_pcie_completion_timeout(struct e1000_hw *hw); >> static s32 igc_read_mac_addr_base(struct e1000_hw *hw); >> @@ -97,6 +98,9 @@ static s32 igc_init_mac_params_base(struct e1000_hw >> *hw) >> if (mac->type == e1000_i225) >> dev_spec->clear_semaphore_once = true; >> + /* physical interface link setup */ >> + mac->ops.setup_physical_interface = igc_setup_copper_link_base; >> + >> return 0; >> } >> @@ -139,6 +143,8 @@ static s32 igc_init_phy_params_base(struct >> e1000_hw *hw) >> if (ret_val) >> return ret_val; >> + igc_check_for_link_base(hw); >> + >> /* Verify phy id and set remaining function pointers */ >> switch (phy->id) { >> case I225_I_PHY_ID: >> @@ -155,10 +161,22 @@ static s32 igc_init_phy_params_base(struct >> e1000_hw *hw) >> static s32 igc_get_invariants_base(struct e1000_hw *hw) >> { >> + struct e1000_mac_info *mac = &hw->mac; >> s32 ret_val = 0; >> u32 ctrl_ext = 0; >> u32 link_mode = 0; >> + switch (hw->device_id) { >> + case E1000_DEV_ID_I225_LM: >> + case E1000_DEV_ID_I225_V: >> + mac->type = e1000_i225; >> + break; >> + default: >> + return -E1000_ERR_MAC_INIT; >> + } >> + >> + hw->phy.media_type = e1000_media_type_copper; >> + >> ctrl_ext = rd32(E1000_CTRL_EXT); >> link_mode = ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK; >> @@ -289,6 +307,29 @@ static s32 igc_init_hw_base(struct e1000_hw *hw) >> } >> /** >> + * igc_setup_copper_link_base - Configure copper link settings >> + * @hw: pointer to the HW structure >> + * >> + * Configures the link for auto-neg or forced speed and duplex. >> Then we check >> + * for link, once link is established calls to configure collision >> distance >> + * and flow control are called. >> + **/ >> +static s32 igc_setup_copper_link_base(struct e1000_hw *hw) >> +{ >> + s32 ret_val = 0; >> + u32 ctrl; >> + >> + ctrl = rd32(E1000_CTRL); >> + ctrl |= E1000_CTRL_SLU; >> + ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); >> + wr32(E1000_CTRL, ctrl); >> + >> + ret_val = igc_setup_copper_link(hw); >> + >> + return ret_val; >> +} >> + >> +/** >> * igc_read_mac_addr_base - Read device MAC address >> * @hw: pointer to the HW structure >> **/ >> diff --git a/drivers/net/ethernet/intel/igc/e1000_defines.h >> b/drivers/net/ethernet/intel/igc/e1000_defines.h >> index 40276ae76c9f..24c24c197d6b 100644 >> --- a/drivers/net/ethernet/intel/igc/e1000_defines.h >> +++ b/drivers/net/ethernet/intel/igc/e1000_defines.h >> @@ -33,6 +33,11 @@ >> /* Physical Func Reset Done Indication */ >> #define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000 >> +/* Loop limit on how long we wait for auto-negotiation to complete */ >> +#define COPPER_LINK_UP_LIMIT 10 >> +#define PHY_AUTO_NEG_LIMIT 45 >> +#define PHY_FORCE_LIMIT 20 >> + >> /* Number of 100 microseconds we wait for PCI Express master disable */ >> #define MASTER_DISABLE_TIMEOUT 800 >> /*Blocks new Master requests */ >> @@ -74,6 +79,12 @@ >> #define E1000_CTRL_RST 0x04000000 /* Global reset */ >> #define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */ >> +#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ >> +#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */ >> +#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ >> + >> +#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control >> enable */ >> +#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control >> enable */ >> /* PBA constants */ >> #define E1000_PBA_34K 0x0022 >> @@ -89,6 +100,40 @@ >> #define E1000_SWFW_PHY2_SM 0x20 >> #define E1000_SWFW_PHY3_SM 0x40 >> +/* PHY 1000 MII Register/Bit Definitions */ >> +/* PHY Registers defined by IEEE */ >> +#define PHY_CONTROL 0x00 /* Control Register */ >> +#define PHY_STATUS 0x01 /* Status Register */ >> +#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */ >> +#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ >> +#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */ >> +#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base >> Page) */ >> +#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */ >> +#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ >> + >> +/* Autoneg Advertisement Register */ >> +#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ >> +#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ >> +#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex >> Capable */ >> +#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex >> Capable */ >> +#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */ >> +#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction >> bit */ >> + >> +/* Link Partner Ability Register (Base Page) */ >> +#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */ >> +#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction >> bit */ >> + >> +/* 1000BASE-T Control Register */ >> +#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause >> bit */ >> +#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ >> +#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ >> + >> +/* PHY GPY 211 registers */ >> +#define STANDARD_AN_REG_MASK 0x0007 /* MMD */ >> +#define ANEG_MULTIGBT_AN_CTRL 0x0020 /* MULTI GBT AN Control >> Register */ >> +#define MMD_DEVADDR_SHIFT 16 /* Shift MMD to higher bits */ >> +#define CR_2500T_FD_CAPS 0x0080 /* Advertise 2500T FD capability */ >> + > > If these are specific to this device, please use an IGC_ prefix. > Otherwise, they look like something that should be defined globally for > other drivers to use. > This and all comments regard to e1000_ or igc_ prefix... I should consult with my colleagues and reply. >> /* NVM Control */ >> #define E1000_EECD_SK 0x00000001 /* NVM Clock */ >> #define E1000_EECD_CS 0x00000002 /* NVM Chip Select */ >> diff --git a/drivers/net/ethernet/intel/igc/e1000_mac.c >> b/drivers/net/ethernet/intel/igc/e1000_mac.c >> index fe483211f66f..3f60810adc19 100644 >> --- a/drivers/net/ethernet/intel/igc/e1000_mac.c >> +++ b/drivers/net/ethernet/intel/igc/e1000_mac.c >> @@ -141,6 +141,8 @@ s32 igc_setup_link(struct e1000_hw *hw) >> /* In the case of the phy reset being blocked, we already have a >> link. >> * We do not need to set it up again. >> */ >> + if (igc_check_reset_block(hw)) >> + goto out; >> /* If requested flow control is set to default, set flow control >> * based on the EEPROM flow control settings. >> @@ -192,10 +194,74 @@ s32 igc_setup_link(struct e1000_hw *hw) >> **/ >> static s32 igc_set_default_fc(struct e1000_hw *hw) >> { >> + hw->fc.requested_mode = e1000_fc_full; >> return 0; >> } >> /** >> + * igc_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 igc_force_mac_fc(struct e1000_hw *hw) >> +{ >> + u32 ctrl; >> + s32 ret_val = 0; >> + >> + ctrl = rd32(E1000_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. >> + */ >> + hw_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: >> + hw_dbg("Flow control param set incorrectly\n"); >> + ret_val = -E1000_ERR_CONFIG; >> + goto out; >> + } >> + >> + wr32(E1000_CTRL, ctrl); >> + >> +out: >> + return ret_val; >> +} >> + >> +/** >> * igc_set_fc_watermarks - Set flow control high/low watermarks >> * @hw: pointer to the HW structure >> * >> @@ -423,7 +489,7 @@ s32 igc_check_for_copper_link(struct e1000_hw *hw) >> * settings because we may have had to re-autoneg with a >> * different link partner. >> */ >> - /* TODO ret_val = igc_config_fc_after_link_up(hw); */ >> + ret_val = igc_config_fc_after_link_up(hw); >> if (ret_val) >> hw_dbg("Error configuring flow control\n"); >> @@ -453,6 +519,210 @@ void igc_config_collision_dist(struct e1000_hw *hw) >> } >> /** >> + * igc_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 igc_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->phy.media_type == e1000_media_type_copper) >> + ret_val = igc_force_mac_fc(hw); >> + } >> + >> + if (ret_val) { >> + hw_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 = hw->phy.ops.read_reg(hw, PHY_STATUS, >> + &mii_status_reg); >> + if (ret_val) >> + goto out; >> + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, >> + &mii_status_reg); >> + if (ret_val) >> + goto out; >> + >> + if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) { >> + hw_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 = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV, >> + &mii_nway_adv_reg); >> + if (ret_val) >> + goto out; >> + ret_val = hw->phy.ops.read_reg(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; >> + hw_dbg("Flow Control = FULL.\n"); >> + } else { >> + hw->fc.current_mode = e1000_fc_rx_pause; >> + hw_dbg("Flow Control = RX PAUSE frames only.\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; >> + hw_dbg("Flow Control = TX PAUSE frames only.\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; >> + hw_dbg("Flow Control = RX PAUSE frames only.\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 ((hw->fc.requested_mode == e1000_fc_none) || >> + (hw->fc.requested_mode == e1000_fc_tx_pause) || >> + (hw->fc.strict_ieee)) { >> + hw->fc.current_mode = e1000_fc_none; >> + hw_dbg("Flow Control = NONE.\n"); >> + } else { >> + hw->fc.current_mode = e1000_fc_rx_pause; >> + hw_dbg("Flow Control = RX PAUSE frames only.\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 = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex); >> + if (ret_val) { >> + hw_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 = igc_force_mac_fc(hw); >> + if (ret_val) { >> + hw_dbg("Error forcing flow control settings\n"); >> + goto out; >> + } >> + } >> + >> +out: >> + return 0; >> +} >> + >> +/** >> * igc_get_auto_rd_done - Check for auto read completion >> * @hw: pointer to the HW structure >> * >> diff --git a/drivers/net/ethernet/intel/igc/e1000_mac.h >> b/drivers/net/ethernet/intel/igc/e1000_mac.h >> index 0f17a8443125..0b32f21ce168 100644 >> --- a/drivers/net/ethernet/intel/igc/e1000_mac.h >> +++ b/drivers/net/ethernet/intel/igc/e1000_mac.h >> @@ -14,6 +14,8 @@ >> /* forward declaration */ >> s32 igc_check_for_copper_link(struct e1000_hw *hw); >> +s32 igc_config_fc_after_link_up(struct e1000_hw *hw); >> +s32 igc_force_mac_fc(struct e1000_hw *hw); >> s32 igc_disable_pcie_master(struct e1000_hw *hw); >> void igc_init_rx_addrs(struct e1000_hw *hw, u16 rar_count); >> diff --git a/drivers/net/ethernet/intel/igc/e1000_phy.c >> b/drivers/net/ethernet/intel/igc/e1000_phy.c >> index c95efc4145e8..4f130402225f 100644 >> --- a/drivers/net/ethernet/intel/igc/e1000_phy.c >> +++ b/drivers/net/ethernet/intel/igc/e1000_phy.c >> @@ -3,6 +3,10 @@ >> #include "e1000_phy.h" >> +/* forward declaration */ >> +static s32 igc_phy_setup_autoneg(struct e1000_hw *hw); >> +static s32 igc_wait_autoneg(struct e1000_hw *hw); >> + >> /** >> * igc_check_reset_block - Check if PHY reset is blocked >> * @hw: pointer to the HW structure >> @@ -206,7 +210,333 @@ s32 igc_phy_hw_reset(struct e1000_hw *hw) >> phy->ops.release(hw); >> - ret_val = phy->ops.get_cfg_done(hw); >> +out: >> + return ret_val; >> +} >> + >> +/** >> + * igc_copper_link_autoneg - Setup/Enable autoneg for copper link >> + * @hw: pointer to the HW structure >> + * >> + * Performs initial bounds checking on autoneg advertisement >> parameter, then >> + * configure to advertise the full capability. Setup the PHY to >> autoneg >> + * and restart the negotiation process between the link partner. If >> + * autoneg_wait_to_complete, then wait for autoneg to complete >> before exiting. >> + **/ >> +static s32 igc_copper_link_autoneg(struct e1000_hw *hw) >> +{ >> + struct e1000_phy_info *phy = &hw->phy; >> + s32 ret_val; >> + u16 phy_ctrl; >> + >> + /* Perform some bounds checking on the autoneg advertisement >> + * parameter. >> + */ >> + phy->autoneg_advertised &= phy->autoneg_mask; >> + >> + /* If autoneg_advertised is zero, we assume it was not defaulted >> + * by the calling code so we set to advertise full capability. >> + */ >> + if (phy->autoneg_advertised == 0) >> + phy->autoneg_advertised = phy->autoneg_mask; >> + >> + hw_dbg("Reconfiguring auto-neg advertisement params\n"); >> + ret_val = igc_phy_setup_autoneg(hw); >> + if (ret_val) { >> + hw_dbg("Error Setting up Auto-Negotiation\n"); >> + goto out; >> + } >> + hw_dbg("Restarting Auto-Neg\n"); >> + >> + /* Restart auto-negotiation by setting the Auto Neg Enable bit and >> + * the Auto Neg Restart bit in the PHY control register. >> + */ >> + ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl); >> + if (ret_val) >> + goto out; >> + >> + phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); >> + ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl); >> + if (ret_val) >> + goto out; >> + >> + /* Does the user want to wait for Auto-Neg to complete here, or >> + * check at a later time (for example, callback routine). >> + */ >> + if (phy->autoneg_wait_to_complete) { >> + ret_val = igc_wait_autoneg(hw); >> + if (ret_val) { >> + hw_dbg("Error while waiting for autoneg to complete\n"); >> + goto out; >> + } >> + } >> + >> + hw->mac.get_link_status = true; >> + >> +out: >> + return ret_val; >> +} >> + >> +/** >> + * igc_wait_autoneg - Wait for auto-neg completion >> + * @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. >> + **/ >> +static s32 igc_wait_autoneg(struct e1000_hw *hw) >> +{ >> + s32 ret_val = 0; >> + u16 i, phy_status; >> + >> + /* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */ >> + for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) { >> + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); >> + if (ret_val) >> + break; >> + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); >> + if (ret_val) >> + break; >> + if (phy_status & MII_SR_AUTONEG_COMPLETE) >> + break; >> + msleep(100); >> + } >> + >> + /* PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation >> + * has completed. >> + */ > > Should you return an error value if the wait time expired? > ret_val is returned. do you mean something else? >> + return ret_val; >> +} >> + >> +/** >> + * igc_phy_setup_autoneg - Configure PHY for auto-negotiation >> + * @hw: pointer to the HW structure >> + * >> + * Reads the MII auto-neg advertisement register and/or the 1000T >> control >> + * register and if the PHY is already setup for auto-negotiation, then >> + * return successful. Otherwise, setup advertisement and flow >> control to >> + * the appropriate values for the wanted auto-negotiation. >> + **/ >> +static s32 igc_phy_setup_autoneg(struct e1000_hw *hw) >> +{ >> + struct e1000_phy_info *phy = &hw->phy; >> + s32 ret_val; >> + u16 mii_autoneg_adv_reg; >> + u16 mii_1000t_ctrl_reg = 0; >> + u16 aneg_multigbt_an_ctrl = 0; >> + >> + phy->autoneg_advertised &= phy->autoneg_mask; >> + >> + /* Read the MII Auto-Neg Advertisement Register (Address 4). */ >> + ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, >> &mii_autoneg_adv_reg); >> + if (ret_val) >> + return ret_val; >> + >> + if (phy->autoneg_mask & ADVERTISE_1000_FULL) { >> + /* Read the MII 1000Base-T Control Register (Address 9). */ >> + ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, >> + &mii_1000t_ctrl_reg); >> + if (ret_val) >> + return ret_val; >> + } >> + >> + if ((phy->autoneg_mask & ADVERTISE_2500_FULL) && >> + hw->phy.id == I225_I_PHY_ID) { >> + /* Read the MULTI GBT AN Control Register - reg 7.32 */ >> + ret_val = phy->ops.read_reg(hw, (STANDARD_AN_REG_MASK << >> + MMD_DEVADDR_SHIFT) | >> + ANEG_MULTIGBT_AN_CTRL, >> + &aneg_multigbt_an_ctrl); >> + >> + if (ret_val) >> + return ret_val; >> + } >> + >> + /* Need to parse both autoneg_advertised and fc and set up >> + * the appropriate PHY registers. First we will parse for >> + * autoneg_advertised software override. Since we can advertise >> + * a plethora of combinations, we need to check each bit >> + * individually. >> + */ >> + >> + /* First we clear all the 10/100 mb speed bits in the Auto-Neg >> + * Advertisement Register (Address 4) and the 1000 mb speed bits in >> + * the 1000Base-T Control Register (Address 9). >> + */ >> + mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS | >> + NWAY_AR_100TX_HD_CAPS | >> + NWAY_AR_10T_FD_CAPS | >> + NWAY_AR_10T_HD_CAPS); >> + mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS); >> + >> + hw_dbg("autoneg_advertised %x\n", phy->autoneg_advertised); >> + >> + /* Do we want to advertise 10 Mb Half Duplex? */ >> + if (phy->autoneg_advertised & ADVERTISE_10_HALF) { >> + hw_dbg("Advertise 10mb Half duplex\n"); >> + mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS; >> + } >> + >> + /* Do we want to advertise 10 Mb Full Duplex? */ >> + if (phy->autoneg_advertised & ADVERTISE_10_FULL) { >> + hw_dbg("Advertise 10mb Full duplex\n"); >> + mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS; >> + } >> + >> + /* Do we want to advertise 100 Mb Half Duplex? */ >> + if (phy->autoneg_advertised & ADVERTISE_100_HALF) { >> + hw_dbg("Advertise 100mb Half duplex\n"); >> + mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS; >> + } >> + >> + /* Do we want to advertise 100 Mb Full Duplex? */ >> + if (phy->autoneg_advertised & ADVERTISE_100_FULL) { >> + hw_dbg("Advertise 100mb Full duplex\n"); >> + mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS; >> + } >> + >> + /* We do not allow the Phy to advertise 1000 Mb Half Duplex */ >> + if (phy->autoneg_advertised & ADVERTISE_1000_HALF) >> + hw_dbg("Advertise 1000mb Half duplex request denied!\n"); >> + >> + /* Do we want to advertise 1000 Mb Full Duplex? */ >> + if (phy->autoneg_advertised & ADVERTISE_1000_FULL) { >> + hw_dbg("Advertise 1000mb Full duplex\n"); >> + mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS; >> + } >> + >> + /* We do not allow the Phy to advertise 2500 Mb Half Duplex */ >> + if (phy->autoneg_advertised & ADVERTISE_2500_HALF) >> + hw_dbg("Advertise 2500mb Half duplex request denied!\n"); >> + >> + /* Do we want to advertise 2500 Mb Full Duplex? */ >> + if (phy->autoneg_advertised & ADVERTISE_2500_FULL) { >> + hw_dbg("Advertise 2500mb Full duplex\n"); >> + aneg_multigbt_an_ctrl |= CR_2500T_FD_CAPS; >> + } >> + >> + /* Check for a software override of the flow control settings, and >> + * setup the PHY advertisement registers accordingly. If >> + * auto-negotiation is enabled, then software will have to set the >> + * "PAUSE" bits to the correct value in the Auto-Negotiation >> + * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto- >> + * negotiation. >> + * >> + * 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. >> + * other: No software override. The flow control configuration >> + * in the EEPROM is used. >> + */ >> + switch (hw->fc.current_mode) { >> + case e1000_fc_none: >> + /* Flow control (Rx & Tx) is completely disabled by a >> + * software over-ride. >> + */ >> + mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); >> + 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 >> + * (in e1000_config_fc_after_link_up) we will disable the >> + * hw's ability to send PAUSE frames. >> + */ >> + mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); >> + break; >> + case e1000_fc_tx_pause: >> + /* Tx Flow control is enabled, and Rx Flow control is >> + * disabled, by a software over-ride. >> + */ >> + mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR; >> + mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE; >> + break; >> + case e1000_fc_full: >> + /* Flow control (both Rx and Tx) is enabled by a software >> + * over-ride. >> + */ >> + mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); >> + break; >> + default: >> + hw_dbg("Flow control param set incorrectly\n"); >> + return -E1000_ERR_CONFIG; >> + } >> + >> + ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, >> mii_autoneg_adv_reg); >> + if (ret_val) >> + return ret_val; >> + >> + hw_dbg("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); >> + >> + if (phy->autoneg_mask & ADVERTISE_1000_FULL) >> + ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, >> + mii_1000t_ctrl_reg); >> + >> + if ((phy->autoneg_mask & ADVERTISE_2500_FULL) && >> + hw->phy.id == I225_I_PHY_ID) >> + ret_val = phy->ops.write_reg(hw, >> + (STANDARD_AN_REG_MASK << >> + MMD_DEVADDR_SHIFT) | >> + ANEG_MULTIGBT_AN_CTRL, >> + aneg_multigbt_an_ctrl); >> + >> + return ret_val; >> +} >> + >> +/** >> + * igc_setup_copper_link - Configure copper link settings >> + * @hw: pointer to the HW structure >> + * >> + * Calls the appropriate function to configure the link for auto-neg >> or forced >> + * speed and duplex. Then we check for link, once link is >> established calls >> + * to configure collision distance and flow control are called. If >> link is >> + * not established, we return -E1000_ERR_PHY (-2). >> + **/ >> +s32 igc_setup_copper_link(struct e1000_hw *hw) >> +{ >> + s32 ret_val = 0; >> + bool link; >> + >> + if (hw->mac.autoneg) { >> + /* Setup autoneg and flow control advertisement and perform >> + * autonegotiation. >> + */ >> + ret_val = igc_copper_link_autoneg(hw); >> + if (ret_val) >> + goto out; >> + } else { >> + /* PHY will be set to 10H, 10F, 100H or 100F >> + * depending on user settings. >> + */ >> + hw_dbg("Forcing Speed and Duplex\n"); >> + ret_val = hw->phy.ops.force_speed_duplex(hw); >> + if (ret_val) { >> + hw_dbg("Error Forcing Speed and Duplex\n"); >> + goto out; >> + } >> + } >> + >> + /* Check link status. Wait up to 100 microseconds for link to become >> + * valid. >> + */ >> + ret_val = igc_phy_has_link(hw, COPPER_LINK_UP_LIMIT, 10, &link); >> + if (ret_val) >> + goto out; >> + >> + if (link) { >> + hw_dbg("Valid link established!!!\n"); >> + igc_config_collision_dist(hw); >> + ret_val = igc_config_fc_after_link_up(hw); >> + } else { >> + hw_dbg("Unable to establish link!!!\n"); >> + } >> out: >> return ret_val; >> diff --git a/drivers/net/ethernet/intel/igc/e1000_phy.h >> b/drivers/net/ethernet/intel/igc/e1000_phy.h >> index d04dfd0be7fd..3fddb1269ea2 100644 >> --- a/drivers/net/ethernet/intel/igc/e1000_phy.h >> +++ b/drivers/net/ethernet/intel/igc/e1000_phy.h >> @@ -12,6 +12,7 @@ s32 igc_get_phy_id(struct e1000_hw *hw); >> s32 igc_phy_has_link(struct e1000_hw *hw, u32 iterations, >> u32 usec_interval, bool *success); >> s32 igc_check_downshift(struct e1000_hw *hw); >> +s32 igc_setup_copper_link(struct e1000_hw *hw); >> void igc_power_up_phy_copper(struct e1000_hw *hw); >> void igc_power_down_phy_copper(struct e1000_hw *hw); >> diff --git a/drivers/net/ethernet/intel/igc/igc.h >> b/drivers/net/ethernet/intel/igc/igc.h >> index 91df0a14c3a5..99bc2344b7ff 100644 >> --- a/drivers/net/ethernet/intel/igc/igc.h >> +++ b/drivers/net/ethernet/intel/igc/igc.h >> @@ -320,6 +320,7 @@ struct igc_adapter { >> struct work_struct reset_task; >> struct work_struct watchdog_task; >> struct work_struct dma_err_task; >> + bool fc_autoneg; >> u8 tx_timeout_factor; >> diff --git a/drivers/net/ethernet/intel/igc/igc_main.c >> b/drivers/net/ethernet/intel/igc/igc_main.c >> index 21aed91454d4..563612910b3f 100644 >> --- a/drivers/net/ethernet/intel/igc/igc_main.c >> +++ b/drivers/net/ethernet/intel/igc/igc_main.c >> @@ -3194,7 +3194,6 @@ static int __igc_open(struct net_device *netdev, >> bool resuming) >> /* start the watchdog. */ >> hw->mac.get_link_status = 1; >> - schedule_work(&adapter->watchdog_task); >> return E1000_SUCCESS; >> @@ -3452,6 +3451,25 @@ static int igc_probe(struct pci_dev *pdev, >> netdev->min_mtu = ETH_MIN_MTU; >> netdev->max_mtu = MAX_STD_JUMBO_FRAME_SIZE; >> + /* before reading the NVM, reset the controller to put the device >> in a >> + * known good starting state >> + */ >> + hw->mac.ops.reset_hw(hw); >> + >> + if (eth_platform_get_mac_address(&pdev->dev, hw->mac.addr)) { >> + /* copy the MAC address out of the NVM */ >> + if (hw->mac.ops.read_mac_addr(hw)) >> + dev_err(&pdev->dev, "NVM Read Error\n"); >> + } >> + >> + memcpy(netdev->dev_addr, hw->mac.addr, netdev->addr_len); >> + >> + if (!is_valid_ether_addr(netdev->dev_addr)) { >> + dev_err(&pdev->dev, "Invalid MAC Address\n"); >> + err = -EIO; >> + goto err_eeprom; >> + } >> + >> /* configure RXPBSIZE and TXPBSIZE */ >> wr32(E1000_RXPBS, I225_RXPBSIZE_DEFAULT); >> wr32(E1000_TXPBS, I225_TXPBSIZE_DEFAULT); >> @@ -3460,6 +3478,14 @@ static int igc_probe(struct pci_dev *pdev, >> INIT_WORK(&adapter->reset_task, igc_reset_task); >> + /* Initialize link properties that are user-changeable */ >> + adapter->fc_autoneg = true; >> + hw->mac.autoneg = true; >> + hw->phy.autoneg_advertised = 0x2f; >> + >> + hw->fc.requested_mode = e1000_fc_default; >> + hw->fc.current_mode = e1000_fc_default; >> + >> /* reset the hardware with the new settings */ >> igc_reset(adapter); >> @@ -3496,6 +3522,12 @@ static int igc_probe(struct pci_dev *pdev, >> err_register: >> igc_release_hw_control(adapter); >> +err_eeprom: >> + if (!igc_check_reset_block(hw)) >> + igc_reset_phy(hw); >> + >> + if (hw->flash_address) >> + iounmap(hw->flash_address); >> err_sw_init: >> igc_clear_interrupt_scheme(adapter); >> iounmap(adapter->io_addr); >> @@ -3530,7 +3562,6 @@ static void igc_remove(struct pci_dev *pdev) >> del_timer_sync(&adapter->watchdog_timer); >> cancel_work_sync(&adapter->reset_task); >> - cancel_work_sync(&adapter->watchdog_task); > > Why are you removing this? Yes, I see that it got put back in patch > 11/11, but why take it out in the first place? > Ah... my failure. fix will be applied in v4. >> /* Release control of h/w to f/w. If f/w is AMT enabled, this >> * would have already happened in close and is redundant. >> Thanks for your comments.
On 7/4/2018 8:19 AM, Neftin, Sasha wrote: > On 6/29/2018 18:03, Shannon Nelson wrote: >> On 6/24/2018 1:45 AM, Sasha Neftin wrote: [...] >>> +/** >>> + * igc_wait_autoneg - Wait for auto-neg completion >>> + * @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. >>> + **/ >>> +static s32 igc_wait_autoneg(struct e1000_hw *hw) >>> +{ >>> + s32 ret_val = 0; >>> + u16 i, phy_status; >>> + >>> + /* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */ >>> + for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) { >>> + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); >>> + if (ret_val) >>> + break; >>> + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); >>> + if (ret_val) >>> + break; >>> + if (phy_status & MII_SR_AUTONEG_COMPLETE) >>> + break; >>> + msleep(100); >>> + } >>> + >>> + /* PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation >>> + * has completed. >>> + */ >> >> Should you return an error value if the wait time expired? >> > ret_val is returned. do you mean something else? Should some non-zero value be returned if the for-loop ran out and MII_SR_AUTONEG_COMPLETE was never set? sln
diff --git a/drivers/net/ethernet/intel/igc/e1000_base.c b/drivers/net/ethernet/intel/igc/e1000_base.c index 8b35e1d6c32e..6405506ff7b8 100644 --- a/drivers/net/ethernet/intel/igc/e1000_base.c +++ b/drivers/net/ethernet/intel/igc/e1000_base.c @@ -17,6 +17,7 @@ static void igc_release_phy_base(struct e1000_hw *); static s32 igc_get_phy_id_base(struct e1000_hw *); static s32 igc_init_hw_base(struct e1000_hw *); static s32 igc_reset_hw_base(struct e1000_hw *); +static s32 igc_setup_copper_link_base(struct e1000_hw *); static s32 igc_set_pcie_completion_timeout(struct e1000_hw *hw); static s32 igc_read_mac_addr_base(struct e1000_hw *hw); @@ -97,6 +98,9 @@ static s32 igc_init_mac_params_base(struct e1000_hw *hw) if (mac->type == e1000_i225) dev_spec->clear_semaphore_once = true; + /* physical interface link setup */ + mac->ops.setup_physical_interface = igc_setup_copper_link_base; + return 0; } @@ -139,6 +143,8 @@ static s32 igc_init_phy_params_base(struct e1000_hw *hw) if (ret_val) return ret_val; + igc_check_for_link_base(hw); + /* Verify phy id and set remaining function pointers */ switch (phy->id) { case I225_I_PHY_ID: @@ -155,10 +161,22 @@ static s32 igc_init_phy_params_base(struct e1000_hw *hw) static s32 igc_get_invariants_base(struct e1000_hw *hw) { + struct e1000_mac_info *mac = &hw->mac; s32 ret_val = 0; u32 ctrl_ext = 0; u32 link_mode = 0; + switch (hw->device_id) { + case E1000_DEV_ID_I225_LM: + case E1000_DEV_ID_I225_V: + mac->type = e1000_i225; + break; + default: + return -E1000_ERR_MAC_INIT; + } + + hw->phy.media_type = e1000_media_type_copper; + ctrl_ext = rd32(E1000_CTRL_EXT); link_mode = ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK; @@ -289,6 +307,29 @@ static s32 igc_init_hw_base(struct e1000_hw *hw) } /** + * igc_setup_copper_link_base - Configure copper link settings + * @hw: pointer to the HW structure + * + * Configures the link for auto-neg or forced speed and duplex. Then we check + * for link, once link is established calls to configure collision distance + * and flow control are called. + **/ +static s32 igc_setup_copper_link_base(struct e1000_hw *hw) +{ + s32 ret_val = 0; + u32 ctrl; + + ctrl = rd32(E1000_CTRL); + ctrl |= E1000_CTRL_SLU; + ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + wr32(E1000_CTRL, ctrl); + + ret_val = igc_setup_copper_link(hw); + + return ret_val; +} + +/** * igc_read_mac_addr_base - Read device MAC address * @hw: pointer to the HW structure **/ diff --git a/drivers/net/ethernet/intel/igc/e1000_defines.h b/drivers/net/ethernet/intel/igc/e1000_defines.h index 40276ae76c9f..24c24c197d6b 100644 --- a/drivers/net/ethernet/intel/igc/e1000_defines.h +++ b/drivers/net/ethernet/intel/igc/e1000_defines.h @@ -33,6 +33,11 @@ /* Physical Func Reset Done Indication */ #define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000 +/* Loop limit on how long we wait for auto-negotiation to complete */ +#define COPPER_LINK_UP_LIMIT 10 +#define PHY_AUTO_NEG_LIMIT 45 +#define PHY_FORCE_LIMIT 20 + /* Number of 100 microseconds we wait for PCI Express master disable */ #define MASTER_DISABLE_TIMEOUT 800 /*Blocks new Master requests */ @@ -74,6 +79,12 @@ #define E1000_CTRL_RST 0x04000000 /* Global reset */ #define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */ +#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ +#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */ +#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ + +#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */ +#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */ /* PBA constants */ #define E1000_PBA_34K 0x0022 @@ -89,6 +100,40 @@ #define E1000_SWFW_PHY2_SM 0x20 #define E1000_SWFW_PHY3_SM 0x40 +/* PHY 1000 MII Register/Bit Definitions */ +/* PHY Registers defined by IEEE */ +#define PHY_CONTROL 0x00 /* Control Register */ +#define PHY_STATUS 0x01 /* Status Register */ +#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */ +#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ +#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */ +#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */ +#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */ +#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ + +/* Autoneg Advertisement Register */ +#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ +#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ +#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */ +#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */ +#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */ +#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ + +/* Link Partner Ability Register (Base Page) */ +#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */ +#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */ + +/* 1000BASE-T Control Register */ +#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */ +#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ +#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ + +/* PHY GPY 211 registers */ +#define STANDARD_AN_REG_MASK 0x0007 /* MMD */ +#define ANEG_MULTIGBT_AN_CTRL 0x0020 /* MULTI GBT AN Control Register */ +#define MMD_DEVADDR_SHIFT 16 /* Shift MMD to higher bits */ +#define CR_2500T_FD_CAPS 0x0080 /* Advertise 2500T FD capability */ + /* NVM Control */ #define E1000_EECD_SK 0x00000001 /* NVM Clock */ #define E1000_EECD_CS 0x00000002 /* NVM Chip Select */ diff --git a/drivers/net/ethernet/intel/igc/e1000_mac.c b/drivers/net/ethernet/intel/igc/e1000_mac.c index fe483211f66f..3f60810adc19 100644 --- a/drivers/net/ethernet/intel/igc/e1000_mac.c +++ b/drivers/net/ethernet/intel/igc/e1000_mac.c @@ -141,6 +141,8 @@ s32 igc_setup_link(struct e1000_hw *hw) /* In the case of the phy reset being blocked, we already have a link. * We do not need to set it up again. */ + if (igc_check_reset_block(hw)) + goto out; /* If requested flow control is set to default, set flow control * based on the EEPROM flow control settings. @@ -192,10 +194,74 @@ s32 igc_setup_link(struct e1000_hw *hw) **/ static s32 igc_set_default_fc(struct e1000_hw *hw) { + hw->fc.requested_mode = e1000_fc_full; return 0; } /** + * igc_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 igc_force_mac_fc(struct e1000_hw *hw) +{ + u32 ctrl; + s32 ret_val = 0; + + ctrl = rd32(E1000_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. + */ + hw_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: + hw_dbg("Flow control param set incorrectly\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + wr32(E1000_CTRL, ctrl); + +out: + return ret_val; +} + +/** * igc_set_fc_watermarks - Set flow control high/low watermarks * @hw: pointer to the HW structure * @@ -423,7 +489,7 @@ s32 igc_check_for_copper_link(struct e1000_hw *hw) * settings because we may have had to re-autoneg with a * different link partner. */ - /* TODO ret_val = igc_config_fc_after_link_up(hw); */ + ret_val = igc_config_fc_after_link_up(hw); if (ret_val) hw_dbg("Error configuring flow control\n"); @@ -453,6 +519,210 @@ void igc_config_collision_dist(struct e1000_hw *hw) } /** + * igc_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 igc_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->phy.media_type == e1000_media_type_copper) + ret_val = igc_force_mac_fc(hw); + } + + if (ret_val) { + hw_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 = hw->phy.ops.read_reg(hw, PHY_STATUS, + &mii_status_reg); + if (ret_val) + goto out; + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, + &mii_status_reg); + if (ret_val) + goto out; + + if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) { + hw_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 = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV, + &mii_nway_adv_reg); + if (ret_val) + goto out; + ret_val = hw->phy.ops.read_reg(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; + hw_dbg("Flow Control = FULL.\n"); + } else { + hw->fc.current_mode = e1000_fc_rx_pause; + hw_dbg("Flow Control = RX PAUSE frames only.\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; + hw_dbg("Flow Control = TX PAUSE frames only.\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; + hw_dbg("Flow Control = RX PAUSE frames only.\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 ((hw->fc.requested_mode == e1000_fc_none) || + (hw->fc.requested_mode == e1000_fc_tx_pause) || + (hw->fc.strict_ieee)) { + hw->fc.current_mode = e1000_fc_none; + hw_dbg("Flow Control = NONE.\n"); + } else { + hw->fc.current_mode = e1000_fc_rx_pause; + hw_dbg("Flow Control = RX PAUSE frames only.\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 = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex); + if (ret_val) { + hw_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 = igc_force_mac_fc(hw); + if (ret_val) { + hw_dbg("Error forcing flow control settings\n"); + goto out; + } + } + +out: + return 0; +} + +/** * igc_get_auto_rd_done - Check for auto read completion * @hw: pointer to the HW structure * diff --git a/drivers/net/ethernet/intel/igc/e1000_mac.h b/drivers/net/ethernet/intel/igc/e1000_mac.h index 0f17a8443125..0b32f21ce168 100644 --- a/drivers/net/ethernet/intel/igc/e1000_mac.h +++ b/drivers/net/ethernet/intel/igc/e1000_mac.h @@ -14,6 +14,8 @@ /* forward declaration */ s32 igc_check_for_copper_link(struct e1000_hw *hw); +s32 igc_config_fc_after_link_up(struct e1000_hw *hw); +s32 igc_force_mac_fc(struct e1000_hw *hw); s32 igc_disable_pcie_master(struct e1000_hw *hw); void igc_init_rx_addrs(struct e1000_hw *hw, u16 rar_count); diff --git a/drivers/net/ethernet/intel/igc/e1000_phy.c b/drivers/net/ethernet/intel/igc/e1000_phy.c index c95efc4145e8..4f130402225f 100644 --- a/drivers/net/ethernet/intel/igc/e1000_phy.c +++ b/drivers/net/ethernet/intel/igc/e1000_phy.c @@ -3,6 +3,10 @@ #include "e1000_phy.h" +/* forward declaration */ +static s32 igc_phy_setup_autoneg(struct e1000_hw *hw); +static s32 igc_wait_autoneg(struct e1000_hw *hw); + /** * igc_check_reset_block - Check if PHY reset is blocked * @hw: pointer to the HW structure @@ -206,7 +210,333 @@ s32 igc_phy_hw_reset(struct e1000_hw *hw) phy->ops.release(hw); - ret_val = phy->ops.get_cfg_done(hw); +out: + return ret_val; +} + +/** + * igc_copper_link_autoneg - Setup/Enable autoneg for copper link + * @hw: pointer to the HW structure + * + * Performs initial bounds checking on autoneg advertisement parameter, then + * configure to advertise the full capability. Setup the PHY to autoneg + * and restart the negotiation process between the link partner. If + * autoneg_wait_to_complete, then wait for autoneg to complete before exiting. + **/ +static s32 igc_copper_link_autoneg(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_ctrl; + + /* Perform some bounds checking on the autoneg advertisement + * parameter. + */ + phy->autoneg_advertised &= phy->autoneg_mask; + + /* If autoneg_advertised is zero, we assume it was not defaulted + * by the calling code so we set to advertise full capability. + */ + if (phy->autoneg_advertised == 0) + phy->autoneg_advertised = phy->autoneg_mask; + + hw_dbg("Reconfiguring auto-neg advertisement params\n"); + ret_val = igc_phy_setup_autoneg(hw); + if (ret_val) { + hw_dbg("Error Setting up Auto-Negotiation\n"); + goto out; + } + hw_dbg("Restarting Auto-Neg\n"); + + /* Restart auto-negotiation by setting the Auto Neg Enable bit and + * the Auto Neg Restart bit in the PHY control register. + */ + ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl); + if (ret_val) + goto out; + + phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); + ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl); + if (ret_val) + goto out; + + /* Does the user want to wait for Auto-Neg to complete here, or + * check at a later time (for example, callback routine). + */ + if (phy->autoneg_wait_to_complete) { + ret_val = igc_wait_autoneg(hw); + if (ret_val) { + hw_dbg("Error while waiting for autoneg to complete\n"); + goto out; + } + } + + hw->mac.get_link_status = true; + +out: + return ret_val; +} + +/** + * igc_wait_autoneg - Wait for auto-neg completion + * @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. + **/ +static s32 igc_wait_autoneg(struct e1000_hw *hw) +{ + s32 ret_val = 0; + u16 i, phy_status; + + /* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */ + for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) { + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); + if (ret_val) + break; + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); + if (ret_val) + break; + if (phy_status & MII_SR_AUTONEG_COMPLETE) + break; + msleep(100); + } + + /* PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation + * has completed. + */ + return ret_val; +} + +/** + * igc_phy_setup_autoneg - Configure PHY for auto-negotiation + * @hw: pointer to the HW structure + * + * Reads the MII auto-neg advertisement register and/or the 1000T control + * register and if the PHY is already setup for auto-negotiation, then + * return successful. Otherwise, setup advertisement and flow control to + * the appropriate values for the wanted auto-negotiation. + **/ +static s32 igc_phy_setup_autoneg(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 mii_autoneg_adv_reg; + u16 mii_1000t_ctrl_reg = 0; + u16 aneg_multigbt_an_ctrl = 0; + + phy->autoneg_advertised &= phy->autoneg_mask; + + /* Read the MII Auto-Neg Advertisement Register (Address 4). */ + ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg); + if (ret_val) + return ret_val; + + if (phy->autoneg_mask & ADVERTISE_1000_FULL) { + /* Read the MII 1000Base-T Control Register (Address 9). */ + ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, + &mii_1000t_ctrl_reg); + if (ret_val) + return ret_val; + } + + if ((phy->autoneg_mask & ADVERTISE_2500_FULL) && + hw->phy.id == I225_I_PHY_ID) { + /* Read the MULTI GBT AN Control Register - reg 7.32 */ + ret_val = phy->ops.read_reg(hw, (STANDARD_AN_REG_MASK << + MMD_DEVADDR_SHIFT) | + ANEG_MULTIGBT_AN_CTRL, + &aneg_multigbt_an_ctrl); + + if (ret_val) + return ret_val; + } + + /* Need to parse both autoneg_advertised and fc and set up + * the appropriate PHY registers. First we will parse for + * autoneg_advertised software override. Since we can advertise + * a plethora of combinations, we need to check each bit + * individually. + */ + + /* First we clear all the 10/100 mb speed bits in the Auto-Neg + * Advertisement Register (Address 4) and the 1000 mb speed bits in + * the 1000Base-T Control Register (Address 9). + */ + mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS | + NWAY_AR_100TX_HD_CAPS | + NWAY_AR_10T_FD_CAPS | + NWAY_AR_10T_HD_CAPS); + mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS); + + hw_dbg("autoneg_advertised %x\n", phy->autoneg_advertised); + + /* Do we want to advertise 10 Mb Half Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_10_HALF) { + hw_dbg("Advertise 10mb Half duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS; + } + + /* Do we want to advertise 10 Mb Full Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_10_FULL) { + hw_dbg("Advertise 10mb Full duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS; + } + + /* Do we want to advertise 100 Mb Half Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_100_HALF) { + hw_dbg("Advertise 100mb Half duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS; + } + + /* Do we want to advertise 100 Mb Full Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_100_FULL) { + hw_dbg("Advertise 100mb Full duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS; + } + + /* We do not allow the Phy to advertise 1000 Mb Half Duplex */ + if (phy->autoneg_advertised & ADVERTISE_1000_HALF) + hw_dbg("Advertise 1000mb Half duplex request denied!\n"); + + /* Do we want to advertise 1000 Mb Full Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_1000_FULL) { + hw_dbg("Advertise 1000mb Full duplex\n"); + mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS; + } + + /* We do not allow the Phy to advertise 2500 Mb Half Duplex */ + if (phy->autoneg_advertised & ADVERTISE_2500_HALF) + hw_dbg("Advertise 2500mb Half duplex request denied!\n"); + + /* Do we want to advertise 2500 Mb Full Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_2500_FULL) { + hw_dbg("Advertise 2500mb Full duplex\n"); + aneg_multigbt_an_ctrl |= CR_2500T_FD_CAPS; + } + + /* Check for a software override of the flow control settings, and + * setup the PHY advertisement registers accordingly. If + * auto-negotiation is enabled, then software will have to set the + * "PAUSE" bits to the correct value in the Auto-Negotiation + * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto- + * negotiation. + * + * 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. + * other: No software override. The flow control configuration + * in the EEPROM is used. + */ + switch (hw->fc.current_mode) { + case e1000_fc_none: + /* Flow control (Rx & Tx) is completely disabled by a + * software over-ride. + */ + mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + 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 + * (in e1000_config_fc_after_link_up) we will disable the + * hw's ability to send PAUSE frames. + */ + mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + case e1000_fc_tx_pause: + /* Tx Flow control is enabled, and Rx Flow control is + * disabled, by a software over-ride. + */ + mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR; + mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE; + break; + case e1000_fc_full: + /* Flow control (both Rx and Tx) is enabled by a software + * over-ride. + */ + mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + default: + hw_dbg("Flow control param set incorrectly\n"); + return -E1000_ERR_CONFIG; + } + + ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg); + if (ret_val) + return ret_val; + + hw_dbg("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); + + if (phy->autoneg_mask & ADVERTISE_1000_FULL) + ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, + mii_1000t_ctrl_reg); + + if ((phy->autoneg_mask & ADVERTISE_2500_FULL) && + hw->phy.id == I225_I_PHY_ID) + ret_val = phy->ops.write_reg(hw, + (STANDARD_AN_REG_MASK << + MMD_DEVADDR_SHIFT) | + ANEG_MULTIGBT_AN_CTRL, + aneg_multigbt_an_ctrl); + + return ret_val; +} + +/** + * igc_setup_copper_link - Configure copper link settings + * @hw: pointer to the HW structure + * + * Calls the appropriate function to configure the link for auto-neg or forced + * speed and duplex. Then we check for link, once link is established calls + * to configure collision distance and flow control are called. If link is + * not established, we return -E1000_ERR_PHY (-2). + **/ +s32 igc_setup_copper_link(struct e1000_hw *hw) +{ + s32 ret_val = 0; + bool link; + + if (hw->mac.autoneg) { + /* Setup autoneg and flow control advertisement and perform + * autonegotiation. + */ + ret_val = igc_copper_link_autoneg(hw); + if (ret_val) + goto out; + } else { + /* PHY will be set to 10H, 10F, 100H or 100F + * depending on user settings. + */ + hw_dbg("Forcing Speed and Duplex\n"); + ret_val = hw->phy.ops.force_speed_duplex(hw); + if (ret_val) { + hw_dbg("Error Forcing Speed and Duplex\n"); + goto out; + } + } + + /* Check link status. Wait up to 100 microseconds for link to become + * valid. + */ + ret_val = igc_phy_has_link(hw, COPPER_LINK_UP_LIMIT, 10, &link); + if (ret_val) + goto out; + + if (link) { + hw_dbg("Valid link established!!!\n"); + igc_config_collision_dist(hw); + ret_val = igc_config_fc_after_link_up(hw); + } else { + hw_dbg("Unable to establish link!!!\n"); + } out: return ret_val; diff --git a/drivers/net/ethernet/intel/igc/e1000_phy.h b/drivers/net/ethernet/intel/igc/e1000_phy.h index d04dfd0be7fd..3fddb1269ea2 100644 --- a/drivers/net/ethernet/intel/igc/e1000_phy.h +++ b/drivers/net/ethernet/intel/igc/e1000_phy.h @@ -12,6 +12,7 @@ s32 igc_get_phy_id(struct e1000_hw *hw); s32 igc_phy_has_link(struct e1000_hw *hw, u32 iterations, u32 usec_interval, bool *success); s32 igc_check_downshift(struct e1000_hw *hw); +s32 igc_setup_copper_link(struct e1000_hw *hw); void igc_power_up_phy_copper(struct e1000_hw *hw); void igc_power_down_phy_copper(struct e1000_hw *hw); diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 91df0a14c3a5..99bc2344b7ff 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -320,6 +320,7 @@ struct igc_adapter { struct work_struct reset_task; struct work_struct watchdog_task; struct work_struct dma_err_task; + bool fc_autoneg; u8 tx_timeout_factor; diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 21aed91454d4..563612910b3f 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -3194,7 +3194,6 @@ static int __igc_open(struct net_device *netdev, bool resuming) /* start the watchdog. */ hw->mac.get_link_status = 1; - schedule_work(&adapter->watchdog_task); return E1000_SUCCESS; @@ -3452,6 +3451,25 @@ static int igc_probe(struct pci_dev *pdev, netdev->min_mtu = ETH_MIN_MTU; netdev->max_mtu = MAX_STD_JUMBO_FRAME_SIZE; + /* before reading the NVM, reset the controller to put the device in a + * known good starting state + */ + hw->mac.ops.reset_hw(hw); + + if (eth_platform_get_mac_address(&pdev->dev, hw->mac.addr)) { + /* copy the MAC address out of the NVM */ + if (hw->mac.ops.read_mac_addr(hw)) + dev_err(&pdev->dev, "NVM Read Error\n"); + } + + memcpy(netdev->dev_addr, hw->mac.addr, netdev->addr_len); + + if (!is_valid_ether_addr(netdev->dev_addr)) { + dev_err(&pdev->dev, "Invalid MAC Address\n"); + err = -EIO; + goto err_eeprom; + } + /* configure RXPBSIZE and TXPBSIZE */ wr32(E1000_RXPBS, I225_RXPBSIZE_DEFAULT); wr32(E1000_TXPBS, I225_TXPBSIZE_DEFAULT); @@ -3460,6 +3478,14 @@ static int igc_probe(struct pci_dev *pdev, INIT_WORK(&adapter->reset_task, igc_reset_task); + /* Initialize link properties that are user-changeable */ + adapter->fc_autoneg = true; + hw->mac.autoneg = true; + hw->phy.autoneg_advertised = 0x2f; + + hw->fc.requested_mode = e1000_fc_default; + hw->fc.current_mode = e1000_fc_default; + /* reset the hardware with the new settings */ igc_reset(adapter); @@ -3496,6 +3522,12 @@ static int igc_probe(struct pci_dev *pdev, err_register: igc_release_hw_control(adapter); +err_eeprom: + if (!igc_check_reset_block(hw)) + igc_reset_phy(hw); + + if (hw->flash_address) + iounmap(hw->flash_address); err_sw_init: igc_clear_interrupt_scheme(adapter); iounmap(adapter->io_addr); @@ -3530,7 +3562,6 @@ static void igc_remove(struct pci_dev *pdev) del_timer_sync(&adapter->watchdog_timer); cancel_work_sync(&adapter->reset_task); - cancel_work_sync(&adapter->watchdog_task); /* Release control of h/w to f/w. If f/w is AMT enabled, this * would have already happened in close and is redundant.
Add link establishment methods Add auto negotiation methods Add read MAC address method Sasha Neftin (v2): minor cosmetic changes Sasha Neftin (v3): removed not addressed methods Signed-off-by: Sasha Neftin <sasha.neftin@intel.com> --- drivers/net/ethernet/intel/igc/e1000_base.c | 41 +++ drivers/net/ethernet/intel/igc/e1000_defines.h | 45 ++++ drivers/net/ethernet/intel/igc/e1000_mac.c | 272 +++++++++++++++++++- drivers/net/ethernet/intel/igc/e1000_mac.h | 2 + drivers/net/ethernet/intel/igc/e1000_phy.c | 332 ++++++++++++++++++++++++- drivers/net/ethernet/intel/igc/e1000_phy.h | 1 + drivers/net/ethernet/intel/igc/igc.h | 1 + drivers/net/ethernet/intel/igc/igc_main.c | 35 ++- 8 files changed, 725 insertions(+), 4 deletions(-)