diff options
author | jfv <jfv@FreeBSD.org> | 2013-02-21 00:25:45 +0000 |
---|---|---|
committer | jfv <jfv@FreeBSD.org> | 2013-02-21 00:25:45 +0000 |
commit | bc67c0c4527ce6afb493c133aa64bce0a7e3c016 (patch) | |
tree | deadb805b9a3f91a6d8def332a98bf84bffbbd5e /sys/dev/e1000/e1000_82575.c | |
parent | 3c760430882730431f5870f23294cb580e98ea3f (diff) | |
download | FreeBSD-src-bc67c0c4527ce6afb493c133aa64bce0a7e3c016.zip FreeBSD-src-bc67c0c4527ce6afb493c133aa64bce0a7e3c016.tar.gz |
Refresh on the shared code for the E1000 drivers.
- bear with me, there are lots of white space changes, I would not
do them, but I am a mere consumer of this stuff and if these drivers
are to stay in shape they need to be taken.
em driver changes: support for the new i217/i218 interfaces
igb driver changes:
- TX mq start has a quick turnaround to the stack
- Link/media handling improvement
- When link status changes happen the current flow control state
will now be displayed.
- A few white space/style changes.
lem driver changes:
- the shared code uncovered a bogus write to the RLPML register
(which does not exist in this hardware) in the vlan code,this
is removed.
Diffstat (limited to 'sys/dev/e1000/e1000_82575.c')
-rw-r--r-- | sys/dev/e1000/e1000_82575.c | 284 |
1 files changed, 148 insertions, 136 deletions
diff --git a/sys/dev/e1000/e1000_82575.c b/sys/dev/e1000/e1000_82575.c index a0d48b3..5722f46 100644 --- a/sys/dev/e1000/e1000_82575.c +++ b/sys/dev/e1000/e1000_82575.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2012, Intel Corporation + Copyright (c) 2001-2013, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -144,6 +144,8 @@ static bool e1000_sgmii_uses_mdio_82575(struct e1000_hw *hw) break; case e1000_82580: case e1000_i350: + case e1000_i210: + case e1000_i211: reg = E1000_READ_REG(hw, E1000_MDICNFG); ext_mdio = !!(reg & E1000_MDICNFG_EXT_MDIO); break; @@ -332,6 +334,7 @@ s32 e1000_init_nvm_params_82575(struct e1000_hw *hw) } else { nvm->type = e1000_nvm_flash_hw; } + /* Function Pointers */ nvm->ops.acquire = e1000_acquire_nvm_82575; nvm->ops.release = e1000_release_nvm_82575; @@ -385,11 +388,16 @@ static s32 e1000_init_mac_params_82575(struct e1000_hw *hw) mac->rar_entry_count = E1000_RAR_ENTRIES_82576; if (mac->type == e1000_82580) mac->rar_entry_count = E1000_RAR_ENTRIES_82580; - if (mac->type == e1000_i350) { + if (mac->type == e1000_i350) mac->rar_entry_count = E1000_RAR_ENTRIES_I350; - /* Enable EEE default settings for i350 */ + + /* Enable EEE default settings for EEE supported devices */ + if (mac->type >= e1000_i350) dev_spec->eee_disable = FALSE; - } + + /* Allow a single clear of the SW semaphore on I210 and newer */ + if (mac->type >= e1000_i210) + dev_spec->clear_semaphore_once = TRUE; /* Set if part includes ASF firmware */ mac->asf_firmware_present = TRUE; @@ -428,7 +436,7 @@ static s32 e1000_init_mac_params_82575(struct e1000_hw *hw) mac->ops.config_collision_dist = e1000_config_collision_dist_82575; /* multicast address update */ mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic; - if (hw->mac.type == e1000_i350) { + if (mac->type == e1000_i350) { /* writing VFTA */ mac->ops.write_vfta = e1000_write_vfta_i350; /* clearing VFTA */ @@ -439,6 +447,9 @@ static s32 e1000_init_mac_params_82575(struct e1000_hw *hw) /* clearing VFTA */ mac->ops.clear_vfta = e1000_clear_vfta_generic; } + if (hw->mac.type >= e1000_82580) + mac->ops.validate_mdi_setting = + e1000_validate_mdi_setting_crossover_generic; /* ID LED init */ mac->ops.id_led_init = e1000_id_led_init_generic; /* blink LED */ @@ -634,6 +645,8 @@ static s32 e1000_get_phy_id_82575(struct e1000_hw *hw) break; case e1000_82580: case e1000_i350: + case e1000_i210: + case e1000_i211: mdic = E1000_READ_REG(hw, E1000_MDICNFG); mdic &= E1000_MDICNFG_PHY_MASK; phy->addr = mdic >> E1000_MDICNFG_PHY_SHIFT; @@ -1143,6 +1156,15 @@ static s32 e1000_check_for_link_82575(struct e1000_hw *hw) */ hw->mac.get_link_status = !hw->mac.serdes_has_link; + /* + * Configure Flow Control now that Auto-Neg has completed. + * First, we need to restore the desired flow control + * settings because we may have had to re-autoneg with a + * different link partner. + */ + ret_val = e1000_config_fc_after_link_up_generic(hw); + if (ret_val) + DEBUGOUT("Error configuring flow control\n"); } else { ret_val = e1000_check_for_copper_link_generic(hw); } @@ -1222,6 +1244,7 @@ static s32 e1000_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw, *duplex = FULL_DUPLEX; else *duplex = HALF_DUPLEX; + } else { mac->serdes_has_link = FALSE; *speed = 0; @@ -1397,7 +1420,8 @@ static s32 e1000_init_hw_82575(struct e1000_hw *hw) static s32 e1000_setup_copper_link_82575(struct e1000_hw *hw) { u32 ctrl; - s32 ret_val; + s32 ret_val; + u32 phpm_reg; DEBUGFUNC("e1000_setup_copper_link_82575"); @@ -1406,6 +1430,13 @@ static s32 e1000_setup_copper_link_82575(struct e1000_hw *hw) ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); E1000_WRITE_REG(hw, E1000_CTRL, ctrl); + /* Clear Go Link Disconnect bit */ + if (hw->mac.type >= e1000_82580) { + phpm_reg = E1000_READ_REG(hw, E1000_82580_PHY_POWER_MGMT); + phpm_reg &= ~E1000_82580_PM_GO_LINKD; + E1000_WRITE_REG(hw, E1000_82580_PHY_POWER_MGMT, phpm_reg); + } + ret_val = e1000_setup_serdes_link_82575(hw); if (ret_val) goto out; @@ -1423,12 +1454,17 @@ static s32 e1000_setup_copper_link_82575(struct e1000_hw *hw) switch (hw->phy.type) { case e1000_phy_i210: case e1000_phy_m88: - if (hw->phy.id == I347AT4_E_PHY_ID || - hw->phy.id == M88E1112_E_PHY_ID || - hw->phy.id == M88E1340M_E_PHY_ID) + switch (hw->phy.id) { + case I347AT4_E_PHY_ID: + case M88E1112_E_PHY_ID: + case M88E1340M_E_PHY_ID: + case I210_I_PHY_ID: ret_val = e1000_copper_link_setup_m88_gen2(hw); - else + break; + default: ret_val = e1000_copper_link_setup_m88(hw); + break; + } break; case e1000_phy_igp_3: ret_val = e1000_copper_link_setup_igp(hw); @@ -1460,7 +1496,7 @@ out: **/ static s32 e1000_setup_serdes_link_82575(struct e1000_hw *hw) { - u32 ctrl_ext, ctrl_reg, reg; + u32 ctrl_ext, ctrl_reg, reg, anadv_reg; bool pcs_autoneg; s32 ret_val = E1000_SUCCESS; u16 data; @@ -1544,26 +1580,47 @@ static s32 e1000_setup_serdes_link_82575(struct e1000_hw *hw) reg &= ~(E1000_PCS_LCTL_AN_ENABLE | E1000_PCS_LCTL_FLV_LINK_UP | E1000_PCS_LCTL_FSD | E1000_PCS_LCTL_FORCE_LINK); - /* - * We force flow control to prevent the CTRL register values from being - * overwritten by the autonegotiated flow control values - */ - reg |= E1000_PCS_LCTL_FORCE_FCTRL; - if (pcs_autoneg) { /* Set PCS register for autoneg */ reg |= E1000_PCS_LCTL_AN_ENABLE | /* Enable Autoneg */ E1000_PCS_LCTL_AN_RESTART; /* Restart autoneg */ + + /* Disable force flow control for autoneg */ + reg &= ~E1000_PCS_LCTL_FORCE_FCTRL; + + /* Configure flow control advertisement for autoneg */ + anadv_reg = E1000_READ_REG(hw, E1000_PCS_ANADV); + anadv_reg &= ~(E1000_TXCW_ASM_DIR | E1000_TXCW_PAUSE); + + switch (hw->fc.requested_mode) { + case e1000_fc_full: + case e1000_fc_rx_pause: + anadv_reg |= E1000_TXCW_ASM_DIR; + anadv_reg |= E1000_TXCW_PAUSE; + break; + case e1000_fc_tx_pause: + anadv_reg |= E1000_TXCW_ASM_DIR; + break; + default: + break; + } + + E1000_WRITE_REG(hw, E1000_PCS_ANADV, anadv_reg); + DEBUGOUT1("Configuring Autoneg:PCS_LCTL=0x%08X\n", reg); } else { /* Set PCS register for forced link */ reg |= E1000_PCS_LCTL_FSD; /* Force Speed */ + + /* Force flow control for forced link */ + reg |= E1000_PCS_LCTL_FORCE_FCTRL; + DEBUGOUT1("Configuring Forced Link:PCS_LCTL=0x%08X\n", reg); } E1000_WRITE_REG(hw, E1000_PCS_LCTL, reg); - if (!e1000_sgmii_active_82575(hw)) + if (!pcs_autoneg && !e1000_sgmii_active_82575(hw)) e1000_force_mac_fc_generic(hw); return ret_val; @@ -1582,137 +1639,70 @@ static s32 e1000_setup_serdes_link_82575(struct e1000_hw *hw) **/ static s32 e1000_get_media_type_82575(struct e1000_hw *hw) { - u32 lan_id = 0; - s32 ret_val = E1000_ERR_CONFIG; struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575; + s32 ret_val = E1000_SUCCESS; u32 ctrl_ext = 0; - u32 current_link_mode = 0; - u16 init_ctrl_wd_3 = 0; - u8 init_ctrl_wd_3_offset = 0; - u8 init_ctrl_wd_3_bit_offset = 0; + u32 link_mode = 0; /* Set internal phy as default */ dev_spec->sgmii_active = FALSE; dev_spec->module_plugged = FALSE; - /* - * Check if NVM access method is attached already. - * If it is then Init Control Word #3 is considered - * otherwise runtime CSR register content is taken. - */ - /* Get CSR setting */ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); - /* Get link mode setting */ - if ((hw->nvm.ops.read) && (hw->nvm.ops.read != e1000_null_read_nvm)) { - /* Take link mode from EEPROM */ - - /* - * Get LAN port ID to derive its - * adequate Init Control Word #3 - */ - lan_id = ((E1000_READ_REG(hw, E1000_STATUS) & - E1000_STATUS_LAN_ID_MASK) >> E1000_STATUS_LAN_ID_OFFSET); - /* - * Derive Init Control Word #3 offset - * and mask to pick up link mode setting. - */ - if (hw->mac.type < e1000_82580) { - init_ctrl_wd_3_offset = lan_id ? - NVM_INIT_CONTROL3_PORT_A : NVM_INIT_CONTROL3_PORT_B; - init_ctrl_wd_3_bit_offset = NVM_WORD24_LNK_MODE_OFFSET; - } else { - init_ctrl_wd_3_offset = - NVM_82580_LAN_FUNC_OFFSET(lan_id) + - NVM_INIT_CONTROL3_PORT_A; - init_ctrl_wd_3_bit_offset = - NVM_WORD24_82580_LNK_MODE_OFFSET; - } - /* Read Init Control Word #3*/ - hw->nvm.ops.read(hw, init_ctrl_wd_3_offset, 1, &init_ctrl_wd_3); - - /* - * Align link mode bits to - * their CTRL_EXT location. - */ - current_link_mode = init_ctrl_wd_3; - current_link_mode <<= (E1000_CTRL_EXT_LINK_MODE_OFFSET - - init_ctrl_wd_3_bit_offset); - current_link_mode &= E1000_CTRL_EXT_LINK_MODE_MASK; - - /* - * Switch to CSR for all but internal PHY. - */ - if (current_link_mode != E1000_CTRL_EXT_LINK_MODE_GMII) - /* Take link mode from CSR */ - current_link_mode = ctrl_ext & - E1000_CTRL_EXT_LINK_MODE_MASK; - } else { - /* Take link mode from CSR */ - current_link_mode = ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK; - } - - switch (current_link_mode) { + /* extract link mode setting */ + link_mode = ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK; + switch (link_mode) { case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX: hw->phy.media_type = e1000_media_type_internal_serdes; - current_link_mode = E1000_CTRL_EXT_LINK_MODE_1000BASE_KX; break; case E1000_CTRL_EXT_LINK_MODE_GMII: hw->phy.media_type = e1000_media_type_copper; - current_link_mode = E1000_CTRL_EXT_LINK_MODE_GMII; break; case E1000_CTRL_EXT_LINK_MODE_SGMII: - case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES: /* Get phy control interface type set (MDIO vs. I2C)*/ if (e1000_sgmii_uses_mdio_82575(hw)) { hw->phy.media_type = e1000_media_type_copper; dev_spec->sgmii_active = TRUE; - current_link_mode = E1000_CTRL_EXT_LINK_MODE_SGMII; - } else { - ret_val = e1000_set_sfp_media_type_82575(hw); - if (ret_val != E1000_SUCCESS) - goto out; - if (hw->phy.media_type == - e1000_media_type_internal_serdes) { - current_link_mode = - E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES; - } else if (hw->phy.media_type == - e1000_media_type_copper) { - current_link_mode = - E1000_CTRL_EXT_LINK_MODE_SGMII; + break; + } + /* fall through for I2C based SGMII */ + case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES: + /* read media type from SFP EEPROM */ + ret_val = e1000_set_sfp_media_type_82575(hw); + if ((ret_val != E1000_SUCCESS) || + (hw->phy.media_type == e1000_media_type_unknown)) { + /* + * If media type was not identified then return media + * type defined by the CTRL_EXT settings. + */ + hw->phy.media_type = e1000_media_type_internal_serdes; + + if (link_mode == E1000_CTRL_EXT_LINK_MODE_SGMII) { + hw->phy.media_type = e1000_media_type_copper; + dev_spec->sgmii_active = TRUE; } + + break; } - break; - default: - DEBUGOUT("Link mode mask doesn't fit bit field size\n"); - goto out; - } - /* - * Do not change current link mode setting - * if media type is fibre or has not been - * recognized. - */ - if ((hw->phy.media_type != e1000_media_type_unknown) && - (hw->phy.media_type != e1000_media_type_fiber)) { - /* Update link mode */ + + /* do not change link mode for 100BaseFX */ + if (dev_spec->eth_flags.e100_base_fx) + break; + + /* change current link mode setting */ ctrl_ext &= ~E1000_CTRL_EXT_LINK_MODE_MASK; - E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext | - current_link_mode); - } - ret_val = E1000_SUCCESS; -out: - /* - * If media type was not identified then return media type - * defined by the CTRL_EXT settings. - */ - if (hw->phy.media_type == e1000_media_type_unknown) { - if (current_link_mode == E1000_CTRL_EXT_LINK_MODE_SGMII) - hw->phy.media_type = e1000_media_type_copper; + if (hw->phy.media_type == e1000_media_type_copper) + ctrl_ext |= E1000_CTRL_EXT_LINK_MODE_SGMII; else - hw->phy.media_type = e1000_media_type_internal_serdes; + ctrl_ext |= E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES; + + E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); + + break; } return ret_val; @@ -1730,40 +1720,52 @@ static s32 e1000_set_sfp_media_type_82575(struct e1000_hw *hw) s32 ret_val = E1000_ERR_CONFIG; u32 ctrl_ext = 0; struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575; - struct sfp_e1000_flags eth_flags = {0}; + struct sfp_e1000_flags *eth_flags = &dev_spec->eth_flags; u8 tranceiver_type = 0; + s32 timeout = 3; - /* Turn I2C interface ON */ + /* Turn I2C interface ON and power on sfp cage */ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); + ctrl_ext &= ~E1000_CTRL_EXT_SDP3_DATA; E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext | E1000_CTRL_I2C_ENA); + E1000_WRITE_FLUSH(hw); + /* Read SFP module data */ - ret_val = e1000_read_sfp_data_byte(hw, + while (timeout) { + ret_val = e1000_read_sfp_data_byte(hw, E1000_I2CCMD_SFP_DATA_ADDR(E1000_SFF_IDENTIFIER_OFFSET), &tranceiver_type); + if (ret_val == E1000_SUCCESS) + break; + msec_delay(100); + timeout--; + } if (ret_val != E1000_SUCCESS) goto out; + ret_val = e1000_read_sfp_data_byte(hw, E1000_I2CCMD_SFP_DATA_ADDR(E1000_SFF_ETH_FLAGS_OFFSET), - (u8 *)ð_flags); + (u8 *)eth_flags); if (ret_val != E1000_SUCCESS) goto out; - /* - * Check if there is some SFP - * module plugged and powered - */ + + /* Check if there is some SFP module plugged and powered */ if ((tranceiver_type == E1000_SFF_IDENTIFIER_SFP) || (tranceiver_type == E1000_SFF_IDENTIFIER_SFF)) { dev_spec->module_plugged = TRUE; - if (eth_flags.e1000_base_lx || eth_flags.e1000_base_sx) { + if (eth_flags->e1000_base_lx || eth_flags->e1000_base_sx) { hw->phy.media_type = e1000_media_type_internal_serdes; - } else if (eth_flags.e1000_base_t) { + } else if (eth_flags->e100_base_fx) { + dev_spec->sgmii_active = TRUE; + hw->phy.media_type = e1000_media_type_internal_serdes; + } else if (eth_flags->e1000_base_t) { dev_spec->sgmii_active = TRUE; hw->phy.media_type = e1000_media_type_copper; } else { - hw->phy.media_type = e1000_media_type_unknown; - DEBUGOUT("PHY module has not been recognized\n"); - goto out; + hw->phy.media_type = e1000_media_type_unknown; + DEBUGOUT("PHY module has not been recognized\n"); + goto out; } } else { hw->phy.media_type = e1000_media_type_unknown; @@ -2280,7 +2282,7 @@ out: * e1000_reset_mdicnfg_82580 - Reset MDICNFG destination and com_mdio bits * @hw: pointer to the HW structure * - * This resets the MDICNFG.Destination and MDICNFG.Com_MDIO bits based on + * This resets the the MDICNFG.Destination and MDICNFG.Com_MDIO bits based on * the values found in the EEPROM. This addresses an issue in which these * bits are not restored from EEPROM after reset. **/ @@ -2334,6 +2336,10 @@ static s32 e1000_reset_hw_82580(struct e1000_hw *hw) hw->dev_spec._82575.global_device_reset = FALSE; + /* 82580 does not reliably do global_device_reset due to hw errata */ + if (hw->mac.type == e1000_82580) + global_device_reset = FALSE; + /* Get current control state. */ ctrl = E1000_READ_REG(hw, E1000_CTRL); @@ -2660,10 +2666,15 @@ s32 e1000_set_eee_i350(struct e1000_hw *hw) /* enable or disable per user setting */ if (!(hw->dev_spec._82575.eee_disable)) { + u32 eee_su = E1000_READ_REG(hw, E1000_EEE_SU); + ipcnfg |= (E1000_IPCNFG_EEE_1G_AN | E1000_IPCNFG_EEE_100M_AN); eeer |= (E1000_EEER_TX_LPI_EN | E1000_EEER_RX_LPI_EN | E1000_EEER_LPI_FC); + /* This bit should not be set in normal operation. */ + if (eee_su & E1000_EEE_SU_LPI_CLK_STP) + DEBUGOUT("LPI Clock Stop Bit should not be set!\n"); } else { ipcnfg &= ~(E1000_IPCNFG_EEE_1G_AN | E1000_IPCNFG_EEE_100M_AN); eeer &= ~(E1000_EEER_TX_LPI_EN | E1000_EEER_RX_LPI_EN | @@ -3275,3 +3286,4 @@ void e1000_i2c_bus_clear(struct e1000_hw *hw) e1000_i2c_stop(hw); } + |