diff options
-rw-r--r-- | sys/dev/e1000/LICENSE | 2 | ||||
-rw-r--r-- | sys/dev/e1000/e1000_80003es2lan.c | 149 | ||||
-rw-r--r-- | sys/dev/e1000/e1000_80003es2lan.h | 12 | ||||
-rw-r--r-- | sys/dev/e1000/e1000_82541.c | 35 | ||||
-rw-r--r-- | sys/dev/e1000/e1000_82571.c | 198 | ||||
-rw-r--r-- | sys/dev/e1000/e1000_82575.c | 744 | ||||
-rw-r--r-- | sys/dev/e1000/e1000_82575.h | 75 | ||||
-rw-r--r-- | sys/dev/e1000/e1000_api.c | 15 | ||||
-rw-r--r-- | sys/dev/e1000/e1000_defines.h | 99 | ||||
-rw-r--r-- | sys/dev/e1000/e1000_hw.h | 29 | ||||
-rw-r--r-- | sys/dev/e1000/e1000_ich8lan.c | 834 | ||||
-rw-r--r-- | sys/dev/e1000/e1000_ich8lan.h | 28 | ||||
-rw-r--r-- | sys/dev/e1000/e1000_mac.c | 23 | ||||
-rw-r--r-- | sys/dev/e1000/e1000_manage.c | 10 | ||||
-rw-r--r-- | sys/dev/e1000/e1000_osdep.h | 44 | ||||
-rw-r--r-- | sys/dev/e1000/e1000_phy.c | 757 | ||||
-rw-r--r-- | sys/dev/e1000/e1000_phy.h | 21 | ||||
-rw-r--r-- | sys/dev/e1000/e1000_regs.h | 42 | ||||
-rw-r--r-- | sys/dev/e1000/if_em.c | 586 | ||||
-rw-r--r-- | sys/dev/e1000/if_em.h | 13 | ||||
-rw-r--r-- | sys/dev/e1000/if_igb.c | 1196 | ||||
-rw-r--r-- | sys/dev/e1000/if_igb.h | 34 |
22 files changed, 3148 insertions, 1798 deletions
diff --git a/sys/dev/e1000/LICENSE b/sys/dev/e1000/LICENSE index d3f8bf5..f271dae 100644 --- a/sys/dev/e1000/LICENSE +++ b/sys/dev/e1000/LICENSE @@ -1,6 +1,6 @@ $FreeBSD$ - Copyright (c) 2001-2008, Intel Corporation + Copyright (c) 2001-2009, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/sys/dev/e1000/e1000_80003es2lan.c b/sys/dev/e1000/e1000_80003es2lan.c index 5c06086..cee3164 100644 --- a/sys/dev/e1000/e1000_80003es2lan.c +++ b/sys/dev/e1000/e1000_80003es2lan.c @@ -171,7 +171,7 @@ static s32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw) break; } - nvm->type = e1000_nvm_eeprom_spi; + nvm->type = e1000_nvm_eeprom_spi; size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >> E1000_EECD_SIZE_EX_SHIFT); @@ -206,17 +206,22 @@ static s32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw) static s32 e1000_init_mac_params_80003es2lan(struct e1000_hw *hw) { struct e1000_mac_info *mac = &hw->mac; - s32 ret_val = E1000_SUCCESS; DEBUGFUNC("e1000_init_mac_params_80003es2lan"); - /* Set media type */ + /* Set media type and media-dependent function pointers */ switch (hw->device_id) { case E1000_DEV_ID_80003ES2LAN_SERDES_DPT: hw->phy.media_type = e1000_media_type_internal_serdes; + mac->ops.check_for_link = e1000_check_for_serdes_link_generic; + mac->ops.setup_physical_interface = + e1000_setup_fiber_serdes_link_generic; break; default: hw->phy.media_type = e1000_media_type_copper; + mac->ops.check_for_link = e1000_check_for_copper_link_generic; + mac->ops.setup_physical_interface = + e1000_setup_copper_link_80003es2lan; break; } @@ -230,6 +235,8 @@ static s32 e1000_init_mac_params_80003es2lan(struct e1000_hw *hw) mac->arc_subsystem_valid = (E1000_READ_REG(hw, E1000_FWSM) & E1000_FWSM_MODE_MASK) ? TRUE : FALSE; + /* Adaptive IFS not supported */ + mac->adaptive_ifs = FALSE; /* Function pointers */ @@ -241,27 +248,6 @@ static s32 e1000_init_mac_params_80003es2lan(struct e1000_hw *hw) mac->ops.init_hw = e1000_init_hw_80003es2lan; /* link setup */ mac->ops.setup_link = e1000_setup_link_generic; - /* physical interface link setup */ - mac->ops.setup_physical_interface = - (hw->phy.media_type == e1000_media_type_copper) - ? e1000_setup_copper_link_80003es2lan - : e1000_setup_fiber_serdes_link_generic; - /* check for link */ - switch (hw->phy.media_type) { - case e1000_media_type_copper: - mac->ops.check_for_link = e1000_check_for_copper_link_generic; - break; - case e1000_media_type_fiber: - mac->ops.check_for_link = e1000_check_for_fiber_link_generic; - break; - case e1000_media_type_internal_serdes: - mac->ops.check_for_link = e1000_check_for_serdes_link_generic; - break; - default: - ret_val = -E1000_ERR_CONFIG; - goto out; - break; - } /* check management mode */ mac->ops.check_mng_mode = e1000_check_mng_mode_generic; /* multicast address update */ @@ -290,8 +276,10 @@ static s32 e1000_init_mac_params_80003es2lan(struct e1000_hw *hw) /* link info */ mac->ops.get_link_up_info = e1000_get_link_up_info_80003es2lan; -out: - return ret_val; + /* set lan id for port to determine which phy lock to use */ + hw->mac.ops.set_lan_id(hw); + + return E1000_SUCCESS; } /** @@ -307,7 +295,6 @@ void e1000_init_function_pointers_80003es2lan(struct e1000_hw *hw) hw->mac.ops.init_params = e1000_init_mac_params_80003es2lan; hw->nvm.ops.init_params = e1000_init_nvm_params_80003es2lan; hw->phy.ops.init_params = e1000_init_phy_params_80003es2lan; - e1000_get_bus_info_pcie_generic(hw); } /** @@ -342,7 +329,6 @@ static void e1000_release_phy_80003es2lan(struct e1000_hw *hw) e1000_release_swfw_sync_80003es2lan(hw, mask); } - /** * e1000_acquire_mac_csr_80003es2lan - Acquire rights to access Kumeran register * @hw: pointer to the HW structure @@ -532,28 +518,36 @@ static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, goto out; } - /* - * The "ready" bit in the MDIC register may be incorrectly set - * before the device has completed the "Page Select" MDI - * transaction. So we wait 200us after each MDI command... - */ - usec_delay(200); + if (hw->dev_spec._80003es2lan.mdic_wa_enable == TRUE) { + /* + * The "ready" bit in the MDIC register may be incorrectly set + * before the device has completed the "Page Select" MDI + * transaction. So we wait 200us after each MDI command... + */ + usec_delay(200); - /* ...and verify the command was successful. */ - ret_val = e1000_read_phy_reg_mdic(hw, page_select, &temp); + /* ...and verify the command was successful. */ + ret_val = e1000_read_phy_reg_mdic(hw, page_select, &temp); - if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) { - ret_val = -E1000_ERR_PHY; - e1000_release_phy_80003es2lan(hw); - goto out; - } + if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) { + ret_val = -E1000_ERR_PHY; + e1000_release_phy_80003es2lan(hw); + goto out; + } + + usec_delay(200); - usec_delay(200); + ret_val = e1000_read_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); - ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, - data); + usec_delay(200); + } else { + ret_val = e1000_read_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); + } - usec_delay(200); e1000_release_phy_80003es2lan(hw); out: @@ -599,29 +593,36 @@ static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, goto out; } + if (hw->dev_spec._80003es2lan.mdic_wa_enable == TRUE) { + /* + * The "ready" bit in the MDIC register may be incorrectly set + * before the device has completed the "Page Select" MDI + * transaction. So we wait 200us after each MDI command... + */ + usec_delay(200); - /* - * The "ready" bit in the MDIC register may be incorrectly set - * before the device has completed the "Page Select" MDI - * transaction. So we wait 200us after each MDI command... - */ - usec_delay(200); + /* ...and verify the command was successful. */ + ret_val = e1000_read_phy_reg_mdic(hw, page_select, &temp); - /* ...and verify the command was successful. */ - ret_val = e1000_read_phy_reg_mdic(hw, page_select, &temp); + if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) { + ret_val = -E1000_ERR_PHY; + e1000_release_phy_80003es2lan(hw); + goto out; + } - if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) { - ret_val = -E1000_ERR_PHY; - e1000_release_phy_80003es2lan(hw); - goto out; - } + usec_delay(200); - usec_delay(200); + ret_val = e1000_write_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); - ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, - data); + usec_delay(200); + } else { + ret_val = e1000_write_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); + } - usec_delay(200); e1000_release_phy_80003es2lan(hw); out: @@ -802,13 +803,13 @@ static s32 e1000_get_cable_length_80003es2lan(struct e1000_hw *hw) index = phy_data & GG82563_DSPD_CABLE_LENGTH; - if (index >= GG82563_CABLE_LENGTH_TABLE_SIZE + 5) { - ret_val = E1000_ERR_PHY; + if (index >= GG82563_CABLE_LENGTH_TABLE_SIZE - 5) { + ret_val = -E1000_ERR_PHY; goto out; } phy->min_cable_length = e1000_gg82563_cable_length_table[index]; - phy->max_cable_length = e1000_gg82563_cable_length_table[index+5]; + phy->max_cable_length = e1000_gg82563_cable_length_table[index + 5]; phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; @@ -916,10 +917,9 @@ static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw) /* Initialize identification LED */ ret_val = mac->ops.id_led_init(hw); - if (ret_val) { + if (ret_val) DEBUGOUT("Error initializing identification LED\n"); /* This is not fatal and we should not stop init due to this */ - } /* Disabling VLAN filtering */ DEBUGOUT("Initializing the IEEE VLAN\n"); @@ -969,6 +969,19 @@ static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw) reg_data &= ~0x00100000; E1000_WRITE_REG_ARRAY(hw, E1000_FFLT, 0x0001, reg_data); + /* default to TRUE to enable the MDIC W/A */ + hw->dev_spec._80003es2lan.mdic_wa_enable = TRUE; + + ret_val = e1000_read_kmrn_reg_80003es2lan(hw, + E1000_KMRNCTRLSTA_OFFSET >> + E1000_KMRNCTRLSTA_OFFSET_SHIFT, + &i); + if (!ret_val) { + if ((i & E1000_KMRNCTRLSTA_OPMODE_MASK) == + E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO) + hw->dev_spec._80003es2lan.mdic_wa_enable = FALSE; + } + /* * Clear all of the statistics registers (clear on read). It is * important that we do this after we have tried to establish link @@ -1303,7 +1316,6 @@ static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex) tipg |= DEFAULT_TIPG_IPGT_10_100_80003ES2LAN; E1000_WRITE_REG(hw, E1000_TIPG, tipg); - do { ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, ®_data); @@ -1357,7 +1369,6 @@ static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw) tipg |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN; E1000_WRITE_REG(hw, E1000_TIPG, tipg); - do { ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, ®_data); diff --git a/sys/dev/e1000/e1000_80003es2lan.h b/sys/dev/e1000/e1000_80003es2lan.h index 7bf8d9d..3ab1ec9 100644 --- a/sys/dev/e1000/e1000_80003es2lan.h +++ b/sys/dev/e1000/e1000_80003es2lan.h @@ -1,6 +1,6 @@ -/******************************************************************************* +/****************************************************************************** - Copyright (c) 2001-2008, Intel Corporation + Copyright (c) 2001-2009, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -29,9 +29,8 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*******************************************************************************/ -/* $FreeBSD$ */ - +******************************************************************************/ +/*$FreeBSD$*/ #ifndef _E1000_80003ES2LAN_H_ #define _E1000_80003ES2LAN_H_ @@ -49,6 +48,9 @@ #define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT 0x0000 #define E1000_KMRNCTRLSTA_OPMODE_E_IDLE 0x2000 +#define E1000_KMRNCTRLSTA_OPMODE_MASK 0x000C +#define E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO 0x0004 + #define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */ #define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN 0x00010000 diff --git a/sys/dev/e1000/e1000_82541.c b/sys/dev/e1000/e1000_82541.c index 68d1b05..c58a602 100644 --- a/sys/dev/e1000/e1000_82541.c +++ b/sys/dev/e1000/e1000_82541.c @@ -59,6 +59,7 @@ static s32 e1000_set_d3_lplu_state_82541(struct e1000_hw *hw, static s32 e1000_setup_led_82541(struct e1000_hw *hw); static s32 e1000_cleanup_led_82541(struct e1000_hw *hw); static void e1000_clear_hw_cntrs_82541(struct e1000_hw *hw); +static s32 e1000_read_mac_addr_82541(struct e1000_hw *hw); static s32 e1000_config_dsp_after_link_change_82541(struct e1000_hw *hw, bool link_up); static s32 e1000_phy_init_script_82541(struct e1000_hw *hw); @@ -261,6 +262,8 @@ static s32 e1000_init_mac_params_82541(struct e1000_hw *hw) mac->ops.clear_vfta = e1000_clear_vfta_generic; /* setting MTA */ mac->ops.mta_set = e1000_mta_set_generic; + /* read mac address */ + mac->ops.read_mac_addr = e1000_read_mac_addr_82541; /* ID LED init */ mac->ops.id_led_init = e1000_id_led_init_generic; /* setup LED */ @@ -1292,3 +1295,35 @@ static void e1000_clear_hw_cntrs_82541(struct e1000_hw *hw) E1000_READ_REG(hw, E1000_MGTPDC); E1000_READ_REG(hw, E1000_MGTPTC); } + +/** + * e1000_read_mac_addr_82541 - Read device MAC address + * @hw: pointer to the HW structure + * + * Reads the device MAC address from the EEPROM and stores the value. + **/ +static s32 e1000_read_mac_addr_82541(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u16 offset, nvm_data, i; + + DEBUGFUNC("e1000_read_mac_addr"); + + for (i = 0; i < ETH_ADDR_LEN; i += 2) { + offset = i >> 1; + ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + goto out; + } + hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF); + hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8); + } + + for (i = 0; i < ETH_ADDR_LEN; i++) + hw->mac.addr[i] = hw->mac.perm_addr[i]; + +out: + return ret_val; +} + diff --git a/sys/dev/e1000/e1000_82571.c b/sys/dev/e1000/e1000_82571.c index 18fe745..be59b3b 100644 --- a/sys/dev/e1000/e1000_82571.c +++ b/sys/dev/e1000/e1000_82571.c @@ -46,7 +46,6 @@ * 82573E Gigabit Ethernet Controller (Copper) * 82573L Gigabit Ethernet Controller * 82574L Gigabit Network Connection - * 82574L Gigabit Network Connection * 82583V Gigabit Network Connection */ @@ -106,7 +105,6 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw) phy->reset_delay_us = 100; phy->ops.acquire = e1000_get_hw_semaphore_82571; - phy->ops.check_polarity = e1000_check_polarity_igp; phy->ops.check_reset_block = e1000_check_reset_block_generic; phy->ops.release = e1000_put_hw_semaphore_82571; phy->ops.reset = e1000_phy_hw_reset_generic; @@ -121,6 +119,7 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw) phy->type = e1000_phy_igp_2; phy->ops.get_cfg_done = e1000_get_cfg_done_82571; phy->ops.get_info = e1000_get_phy_info_igp; + phy->ops.check_polarity = e1000_check_polarity_igp; phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp; phy->ops.get_cable_length = e1000_get_cable_length_igp_2; phy->ops.read_reg = e1000_read_phy_reg_igp; @@ -132,6 +131,7 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw) /* Verify PHY ID */ if (phy->id != IGP01E1000_I_PHY_ID) { ret_val = -E1000_ERR_PHY; + DEBUGOUT1("PHY ID unknown: type = 0x%08x\n", phy->id); goto out; } break; @@ -139,6 +139,7 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw) phy->type = e1000_phy_m88; phy->ops.get_cfg_done = e1000_get_cfg_done_generic; phy->ops.get_info = e1000_get_phy_info_m88; + phy->ops.check_polarity = e1000_check_polarity_m88; phy->ops.commit = e1000_phy_sw_reset_generic; phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88; phy->ops.get_cable_length = e1000_get_cable_length_m88; @@ -155,11 +156,12 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw) goto out; } break; - case e1000_82583: case e1000_82574: + case e1000_82583: phy->type = e1000_phy_bm; phy->ops.get_cfg_done = e1000_get_cfg_done_generic; phy->ops.get_info = e1000_get_phy_info_m88; + phy->ops.check_polarity = e1000_check_polarity_m88; phy->ops.commit = e1000_phy_sw_reset_generic; phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88; phy->ops.get_cable_length = e1000_get_cable_length_m88; @@ -266,28 +268,42 @@ static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw) static s32 e1000_init_mac_params_82571(struct e1000_hw *hw) { struct e1000_mac_info *mac = &hw->mac; - s32 ret_val = E1000_SUCCESS; u32 swsm = 0; u32 swsm2 = 0; bool force_clear_smbi = FALSE; DEBUGFUNC("e1000_init_mac_params_82571"); - /* Set media type */ + /* Set media type and media-dependent function pointers */ switch (hw->device_id) { case E1000_DEV_ID_82571EB_FIBER: case E1000_DEV_ID_82572EI_FIBER: case E1000_DEV_ID_82571EB_QUAD_FIBER: hw->phy.media_type = e1000_media_type_fiber; + mac->ops.setup_physical_interface = + e1000_setup_fiber_serdes_link_82571; + mac->ops.check_for_link = e1000_check_for_fiber_link_generic; + mac->ops.get_link_up_info = + e1000_get_speed_and_duplex_fiber_serdes_generic; break; case E1000_DEV_ID_82571EB_SERDES: case E1000_DEV_ID_82571EB_SERDES_DUAL: case E1000_DEV_ID_82571EB_SERDES_QUAD: case E1000_DEV_ID_82572EI_SERDES: hw->phy.media_type = e1000_media_type_internal_serdes; + mac->ops.setup_physical_interface = + e1000_setup_fiber_serdes_link_82571; + mac->ops.check_for_link = e1000_check_for_serdes_link_82571; + mac->ops.get_link_up_info = + e1000_get_speed_and_duplex_fiber_serdes_generic; break; default: hw->phy.media_type = e1000_media_type_copper; + mac->ops.setup_physical_interface = + e1000_setup_copper_link_82571; + mac->ops.check_for_link = e1000_check_for_copper_link_generic; + mac->ops.get_link_up_info = + e1000_get_speed_and_duplex_copper_generic; break; } @@ -301,58 +317,19 @@ static s32 e1000_init_mac_params_82571(struct e1000_hw *hw) mac->arc_subsystem_valid = (E1000_READ_REG(hw, E1000_FWSM) & E1000_FWSM_MODE_MASK) ? TRUE : FALSE; + /* Adaptive IFS supported */ + mac->adaptive_ifs = TRUE; /* Function pointers */ /* bus type/speed/width */ mac->ops.get_bus_info = e1000_get_bus_info_pcie_generic; - /* function id */ - switch (hw->mac.type) { - case e1000_82573: - case e1000_82574: - case e1000_82583: - mac->ops.set_lan_id = e1000_set_lan_id_single_port; - break; - default: - break; - } /* reset */ mac->ops.reset_hw = e1000_reset_hw_82571; /* hw initialization */ mac->ops.init_hw = e1000_init_hw_82571; /* link setup */ mac->ops.setup_link = e1000_setup_link_82571; - /* physical interface link setup */ - mac->ops.setup_physical_interface = - (hw->phy.media_type == e1000_media_type_copper) - ? e1000_setup_copper_link_82571 - : e1000_setup_fiber_serdes_link_82571; - /* check for link */ - switch (hw->phy.media_type) { - case e1000_media_type_copper: - mac->ops.check_for_link = e1000_check_for_copper_link_generic; - break; - case e1000_media_type_fiber: - mac->ops.check_for_link = e1000_check_for_fiber_link_generic; - break; - case e1000_media_type_internal_serdes: - mac->ops.check_for_link = e1000_check_for_serdes_link_82571; - break; - default: - ret_val = -E1000_ERR_CONFIG; - goto out; - break; - } - /* check management mode */ - switch (hw->mac.type) { - case e1000_82574: - case e1000_82583: - mac->ops.check_mng_mode = e1000_check_mng_mode_82574; - break; - default: - mac->ops.check_mng_mode = e1000_check_mng_mode_generic; - break; - } /* multicast address update */ mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic; /* writing VFTA */ @@ -371,24 +348,29 @@ static s32 e1000_init_mac_params_82571(struct e1000_hw *hw) mac->ops.setup_led = e1000_setup_led_generic; /* cleanup LED */ mac->ops.cleanup_led = e1000_cleanup_led_generic; - /* turn on/off LED */ + /* turn off LED */ + mac->ops.led_off = e1000_led_off_generic; + /* clear hardware counters */ + mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82571; + + /* MAC-specific function pointers */ switch (hw->mac.type) { + case e1000_82573: + mac->ops.set_lan_id = e1000_set_lan_id_single_port; + mac->ops.check_mng_mode = e1000_check_mng_mode_generic; + mac->ops.led_on = e1000_led_on_generic; + break; case e1000_82574: case e1000_82583: + mac->ops.set_lan_id = e1000_set_lan_id_single_port; + mac->ops.check_mng_mode = e1000_check_mng_mode_82574; mac->ops.led_on = e1000_led_on_82574; break; default: + mac->ops.check_mng_mode = e1000_check_mng_mode_generic; mac->ops.led_on = e1000_led_on_generic; break; } - mac->ops.led_off = e1000_led_off_generic; - /* clear hardware counters */ - mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82571; - /* link info */ - mac->ops.get_link_up_info = - (hw->phy.media_type == e1000_media_type_copper) - ? e1000_get_speed_and_duplex_copper_generic - : e1000_get_speed_and_duplex_fiber_serdes_generic; /* * Ensure that the inter-port SWSM.SMBI lock bit is clear before @@ -434,8 +416,7 @@ static s32 e1000_init_mac_params_82571(struct e1000_hw *hw) */ hw->dev_spec._82571.smb_counter = 0; -out: - return ret_val; + return E1000_SUCCESS; } /** @@ -501,7 +482,6 @@ static s32 e1000_get_phy_id_82571(struct e1000_hw *hw) ret_val = -E1000_ERR_PHY; break; } - out: return ret_val; } @@ -512,7 +492,7 @@ out: * * Acquire the HW semaphore to access the PHY or NVM **/ -s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw) +static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw) { u32 swsm; s32 ret_val = E1000_SUCCESS; @@ -577,7 +557,7 @@ out: * * Release hardware semaphore used to access the PHY or NVM **/ -void e1000_put_hw_semaphore_82571(struct e1000_hw *hw) +static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw) { u32 swsm; @@ -610,9 +590,9 @@ static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw) goto out; switch (hw->mac.type) { + case e1000_82573: case e1000_82574: case e1000_82583: - case e1000_82573: break; default: ret_val = e1000_acquire_nvm_generic(hw); @@ -831,7 +811,8 @@ static s32 e1000_get_cfg_done_82571(struct e1000_hw *hw) DEBUGFUNC("e1000_get_cfg_done_82571"); while (timeout) { - if (E1000_READ_REG(hw, E1000_EEMNGCTL) & E1000_NVM_CFG_DONE_PORT_0) + if (E1000_READ_REG(hw, E1000_EEMNGCTL) & + E1000_NVM_CFG_DONE_PORT_0) break; msec_delay(1); timeout--; @@ -966,9 +947,9 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw) * Ownership defaults to firmware after a reset. */ switch (hw->mac.type) { + case e1000_82573: case e1000_82574: case e1000_82583: - case e1000_82573: extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; @@ -1014,9 +995,9 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw) */ switch (hw->mac.type) { + case e1000_82573: case e1000_82574: case e1000_82583: - case e1000_82573: msec_delay(25); break; default: @@ -1061,10 +1042,9 @@ static s32 e1000_init_hw_82571(struct e1000_hw *hw) /* Initialize identification LED */ ret_val = mac->ops.id_led_init(hw); - if (ret_val) { + if (ret_val) DEBUGOUT("Error initializing identification LED\n"); /* This is not fatal and we should not stop init due to this */ - } /* Disabling VLAN filtering */ DEBUGOUT("Initializing the IEEE VLAN\n"); @@ -1097,9 +1077,9 @@ static s32 e1000_init_hw_82571(struct e1000_hw *hw) /* ...for both queues. */ switch (mac->type) { + case e1000_82573: case e1000_82574: case e1000_82583: - case e1000_82573: e1000_enable_tx_pkt_filtering_generic(hw); reg_data = E1000_READ_REG(hw, E1000_GCR); reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX; @@ -1108,8 +1088,8 @@ static s32 e1000_init_hw_82571(struct e1000_hw *hw) default: reg_data = E1000_READ_REG(hw, E1000_TXDCTL(1)); reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) | - E1000_TXDCTL_FULL_TX_DESC_WB | - E1000_TXDCTL_COUNT_DESC; + E1000_TXDCTL_FULL_TX_DESC_WB | + E1000_TXDCTL_COUNT_DESC; E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg_data); break; } @@ -1178,11 +1158,10 @@ static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw) } /* Device Control */ - switch (hw->mac.type) { + case e1000_82573: case e1000_82574: case e1000_82583: - case e1000_82573: reg = E1000_READ_REG(hw, E1000_CTRL); reg &= ~(1 << 29); E1000_WRITE_REG(hw, E1000_CTRL, reg); @@ -1193,9 +1172,9 @@ static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw) /* Extended Device Control */ switch (hw->mac.type) { + case e1000_82573: case e1000_82574: case e1000_82583: - case e1000_82573: reg = E1000_READ_REG(hw, E1000_CTRL_EXT); reg &= ~(1 << 23); reg |= (1 << 22); @@ -1205,7 +1184,6 @@ static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw) break; } - if (hw->mac.type == e1000_82571) { reg = E1000_READ_REG(hw, E1000_PBA_ECC); reg |= E1000_PBA_ECC_CORR_EN; @@ -1216,7 +1194,6 @@ static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw) * Workaround for hardware errata. * Ensure that DMA Dynamic Clock gating is disabled on 82571 and 82572 */ - if ((hw->mac.type == e1000_82571) || (hw->mac.type == e1000_82572)) { reg = E1000_READ_REG(hw, E1000_CTRL_EXT); @@ -1225,13 +1202,13 @@ static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw) } /* PCI-Ex Control Registers */ - switch (hw->mac.type) { case e1000_82574: case e1000_82583: reg = E1000_READ_REG(hw, E1000_GCR); reg |= (1 << 22); E1000_WRITE_REG(hw, E1000_GCR, reg); + /* * Workaround for hardware errata. * apply workaround for hardware errata documented in errata @@ -1267,39 +1244,36 @@ static void e1000_clear_vfta_82571(struct e1000_hw *hw) DEBUGFUNC("e1000_clear_vfta_82571"); switch (hw->mac.type) { + case e1000_82573: case e1000_82574: case e1000_82583: - case e1000_82573: if (hw->mng_cookie.vlan_id != 0) { /* - *The VFTA is a 4096b bit-field, each identifying - *a single VLAN ID. The following operations - *determine which 32b entry (i.e. offset) into the - *array we want to set the VLAN ID (i.e. bit) of - *the manageability unit. - */ + * The VFTA is a 4096b bit-field, each identifying + * a single VLAN ID. The following operations + * determine which 32b entry (i.e. offset) into the + * array we want to set the VLAN ID (i.e. bit) of + * the manageability unit. + */ vfta_offset = (hw->mng_cookie.vlan_id >> E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK; vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id & E1000_VFTA_ENTRY_BIT_SHIFT_MASK); } - - for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) { - /* - *If the offset we want to clear is the same offset of - *the manageability VLAN ID, then clear all bits except - *that of the manageability unit - */ - vfta_value = (offset == vfta_offset) ? - vfta_bit_in_reg : 0; - E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, - vfta_value); - E1000_WRITE_FLUSH(hw); - } break; default: break; } + for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) { + /* + * If the offset we want to clear is the same offset of the + * manageability VLAN ID, then clear all bits except that of + * the manageability unit. + */ + vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0; + E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, vfta_value); + E1000_WRITE_FLUSH(hw); + } } /** @@ -1369,9 +1343,9 @@ static s32 e1000_setup_link_82571(struct e1000_hw *hw) * set it to full. */ switch (hw->mac.type) { + case e1000_82573: case e1000_82574: case e1000_82583: - case e1000_82573: if (hw->fc.requested_mode == e1000_fc_default) hw->fc.requested_mode = e1000_fc_full; break; @@ -1460,7 +1434,7 @@ static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw) * Reports the link state as up or down. * * If autonegotiation is supported by the link partner, the link state is - * determined by the result of autongotiation. This is the most likely case. + * determined by the result of autonegotiation. This is the most likely case. * If autonegotiation is not supported by the link partner, and the link * has a valid signal, force the link up. * @@ -1472,7 +1446,7 @@ static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw) * 4) forced_up (the link has been forced up, it did not autonegotiate) * **/ -s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) +static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) { struct e1000_mac_info *mac = &hw->mac; u32 rxcw; @@ -1524,9 +1498,10 @@ s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) case e1000_serdes_link_autoneg_progress: if (rxcw & E1000_RXCW_C) { - /* We received /C/ ordered sets, meaning the + /* + * We received /C/ ordered sets, meaning the * link partner has autonegotiated, and we can - * trust the Link Up (LU) status bit + * trust the Link Up (LU) status bit. */ if (status & E1000_STATUS_LU) { mac->serdes_link_state = @@ -1534,13 +1509,14 @@ s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) DEBUGOUT("AN_PROG -> AN_UP\n"); mac->serdes_has_link = TRUE; } else { - /* Autoneg completed, but failed */ + /* Autoneg completed, but failed. */ mac->serdes_link_state = e1000_serdes_link_down; DEBUGOUT("AN_PROG -> DOWN\n"); } } else { - /* The link partner did not autoneg. + /* + * The link partner did not autoneg. * Force link up and full duplex, and change * state to forced. */ @@ -1565,9 +1541,11 @@ s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) case e1000_serdes_link_down: default: - /* The link was down but the receiver has now gained + /* + * The link was down but the receiver has now gained * valid sync, so lets see if we can bring the link - * up. */ + * up. + */ E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw); E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU)); @@ -1583,9 +1561,9 @@ s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) DEBUGOUT("ANYSTATE -> DOWN\n"); } else { /* - * We have sync, and can tolerate one - * invalid (IV) codeword before declaring - * link down, so reread to look again + * We have sync, and can tolerate one invalid (IV) + * codeword before declaring link down, so reread + * to look again. */ usec_delay(10); rxcw = E1000_READ_REG(hw, E1000_RXCW); @@ -1621,15 +1599,15 @@ static s32 e1000_valid_led_default_82571(struct e1000_hw *hw, u16 *data) } switch (hw->mac.type) { + case e1000_82573: case e1000_82574: case e1000_82583: - case e1000_82573: - if(*data == ID_LED_RESERVED_F746) + if (*data == ID_LED_RESERVED_F746) *data = ID_LED_DEFAULT_82573; break; default: if (*data == ID_LED_RESERVED_0000 || - *data == ID_LED_RESERVED_FFFF) + *data == ID_LED_RESERVED_FFFF) *data = ID_LED_DEFAULT; break; } diff --git a/sys/dev/e1000/e1000_82575.c b/sys/dev/e1000/e1000_82575.c index 2f8e8ed..5c877c2 100644 --- a/sys/dev/e1000/e1000_82575.c +++ b/sys/dev/e1000/e1000_82575.c @@ -59,16 +59,20 @@ static s32 e1000_phy_hw_reset_sgmii_82575(struct e1000_hw *hw); static s32 e1000_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset, u16 *data); static s32 e1000_reset_hw_82575(struct e1000_hw *hw); +static s32 e1000_reset_hw_82580(struct e1000_hw *hw); +static s32 e1000_read_phy_reg_82580(struct e1000_hw *hw, + u32 offset, u16 *data); +static s32 e1000_write_phy_reg_82580(struct e1000_hw *hw, + u32 offset, u16 data); static s32 e1000_set_d0_lplu_state_82575(struct e1000_hw *hw, bool active); static s32 e1000_setup_copper_link_82575(struct e1000_hw *hw); -static s32 e1000_setup_fiber_serdes_link_82575(struct e1000_hw *hw); +static s32 e1000_setup_serdes_link_82575(struct e1000_hw *hw); static s32 e1000_valid_led_default_82575(struct e1000_hw *hw, u16 *data); static s32 e1000_write_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset, u16 data); static void e1000_clear_hw_cntrs_82575(struct e1000_hw *hw); static s32 e1000_acquire_swfw_sync_82575(struct e1000_hw *hw, u16 mask); -static s32 e1000_configure_pcs_link_82575(struct e1000_hw *hw); static s32 e1000_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw, u16 *speed, u16 *duplex); static s32 e1000_get_phy_id_82575(struct e1000_hw *hw); @@ -77,9 +81,15 @@ static bool e1000_sgmii_active_82575(struct e1000_hw *hw); static s32 e1000_reset_init_script_82575(struct e1000_hw *hw); static s32 e1000_read_mac_addr_82575(struct e1000_hw *hw); static void e1000_power_down_phy_copper_82575(struct e1000_hw *hw); -void e1000_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw); +static void e1000_shutdown_serdes_link_82575(struct e1000_hw *hw); static s32 e1000_set_pcie_completion_timeout(struct e1000_hw *hw); +static const u16 e1000_82580_rxpbs_table[] = + { 36, 72, 144, 1, 2, 4, 8, 16, + 35, 70, 140 }; +#define E1000_82580_RXPBS_TABLE_SIZE \ + (sizeof(e1000_82580_rxpbs_table)/sizeof(u16)) + /** * e1000_init_phy_params_82575 - Init PHY func ptrs. * @hw: pointer to the HW structure @@ -94,11 +104,11 @@ static s32 e1000_init_phy_params_82575(struct e1000_hw *hw) if (hw->phy.media_type != e1000_media_type_copper) { phy->type = e1000_phy_none; goto out; - } else { - phy->ops.power_up = e1000_power_up_phy_copper; - phy->ops.power_down = e1000_power_down_phy_copper_82575; } + phy->ops.power_up = e1000_power_up_phy_copper; + phy->ops.power_down = e1000_power_down_phy_copper_82575; + phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; phy->reset_delay_us = 100; @@ -112,6 +122,11 @@ static s32 e1000_init_phy_params_82575(struct e1000_hw *hw) phy->ops.reset = e1000_phy_hw_reset_sgmii_82575; phy->ops.read_reg = e1000_read_phy_reg_sgmii_82575; phy->ops.write_reg = e1000_write_phy_reg_sgmii_82575; + } else if ((hw->mac.type == e1000_82580) || + (hw->mac.type == e1000_82580er)) { + phy->ops.reset = e1000_phy_hw_reset_generic; + phy->ops.read_reg = e1000_read_phy_reg_82580; + phy->ops.write_reg = e1000_write_phy_reg_82580; } else { phy->ops.reset = e1000_phy_hw_reset_generic; phy->ops.read_reg = e1000_read_phy_reg_igp; @@ -140,6 +155,13 @@ static s32 e1000_init_phy_params_82575(struct e1000_hw *hw) phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_82575; phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_generic; break; + case I82580_I_PHY_ID: + phy->type = e1000_phy_82580; + phy->ops.check_polarity = e1000_check_polarity_82577; + phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_82577; + phy->ops.get_cable_length = e1000_get_cable_length_82577; + phy->ops.get_info = e1000_get_phy_info_82577; + break; default: ret_val = -E1000_ERR_PHY; goto out; @@ -192,7 +214,7 @@ static s32 e1000_init_nvm_params_82575(struct e1000_hw *hw) /* EEPROM access above 16k is unsupported */ if (size > 14) size = 14; - nvm->word_size = 1 << size; + nvm->word_size = 1 << size; /* Function Pointers */ nvm->ops.acquire = e1000_acquire_nvm_82575; @@ -230,24 +252,41 @@ static s32 e1000_init_mac_params_82575(struct e1000_hw *hw) dev_spec->sgmii_active = FALSE; ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); - if ((ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) == - E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES) { - hw->phy.media_type = e1000_media_type_internal_serdes; - ctrl_ext |= E1000_CTRL_I2C_ENA; - } else if (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_SGMII) { + switch (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) { + case E1000_CTRL_EXT_LINK_MODE_SGMII: dev_spec->sgmii_active = TRUE; ctrl_ext |= E1000_CTRL_I2C_ENA; - } else { + break; + case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX: + case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES: + hw->phy.media_type = e1000_media_type_internal_serdes; + ctrl_ext |= E1000_CTRL_I2C_ENA; + break; + default: ctrl_ext &= ~E1000_CTRL_I2C_ENA; + break; } + E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); + /* + * if using i2c make certain the MDICNFG register is cleared to prevent + * communications from being misrouted to the mdic registers + */ + if ((ctrl_ext & E1000_CTRL_I2C_ENA) && + ((hw->mac.type == e1000_82580) || (hw->mac.type == e1000_82580er))) + E1000_WRITE_REG(hw, E1000_MDICNFG, 0); + /* Set mta register count */ mac->mta_reg_count = 128; + /* Set uta register count */ + mac->uta_reg_count = (hw->mac.type == e1000_82575) ? 0 : 128; /* Set rar entry count */ mac->rar_entry_count = E1000_RAR_ENTRIES_82575; if (mac->type == e1000_82576) mac->rar_entry_count = E1000_RAR_ENTRIES_82576; + if ((mac->type == e1000_82580) || (mac->type == e1000_82580er)) + mac->rar_entry_count = E1000_RAR_ENTRIES_82580; /* Set if part includes ASF firmware */ mac->asf_firmware_present = TRUE; /* Set if manageability features are enabled. */ @@ -260,6 +299,9 @@ static s32 e1000_init_mac_params_82575(struct e1000_hw *hw) /* bus type/speed/width */ mac->ops.get_bus_info = e1000_get_bus_info_pcie_generic; /* reset */ + if ((mac->type == e1000_82580) || (mac->type == e1000_82580er)) + mac->ops.reset_hw = e1000_reset_hw_82580; + else mac->ops.reset_hw = e1000_reset_hw_82575; /* hw initialization */ mac->ops.init_hw = e1000_init_hw_82575; @@ -269,9 +311,9 @@ static s32 e1000_init_mac_params_82575(struct e1000_hw *hw) mac->ops.setup_physical_interface = (hw->phy.media_type == e1000_media_type_copper) ? e1000_setup_copper_link_82575 - : e1000_setup_fiber_serdes_link_82575; + : e1000_setup_serdes_link_82575; /* physical interface shutdown */ - mac->ops.shutdown_serdes = e1000_shutdown_fiber_serdes_link_82575; + mac->ops.shutdown_serdes = e1000_shutdown_serdes_link_82575; /* check for link */ mac->ops.check_for_link = e1000_check_for_link_82575; /* receive address register setting */ @@ -302,6 +344,9 @@ static s32 e1000_init_mac_params_82575(struct e1000_hw *hw) /* link info */ mac->ops.get_link_up_info = e1000_get_link_up_info_82575; + /* set lan id for port to determine which phy lock to use */ + hw->mac.ops.set_lan_id(hw); + return E1000_SUCCESS; } @@ -334,6 +379,10 @@ static s32 e1000_acquire_phy_82575(struct e1000_hw *hw) if (hw->bus.func == E1000_FUNC_1) mask = E1000_SWFW_PHY1_SM; + else if (hw->bus.func == E1000_FUNC_2) + mask = E1000_SWFW_PHY2_SM; + else if (hw->bus.func == E1000_FUNC_3) + mask = E1000_SWFW_PHY3_SM; return e1000_acquire_swfw_sync_82575(hw, mask); } @@ -352,6 +401,10 @@ static void e1000_release_phy_82575(struct e1000_hw *hw) if (hw->bus.func == E1000_FUNC_1) mask = E1000_SWFW_PHY1_SM; + else if (hw->bus.func == E1000_FUNC_2) + mask = E1000_SWFW_PHY2_SM; + else if (hw->bus.func == E1000_FUNC_3) + mask = E1000_SWFW_PHY3_SM; e1000_release_swfw_sync_82575(hw, mask); } @@ -368,47 +421,25 @@ static void e1000_release_phy_82575(struct e1000_hw *hw) static s32 e1000_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset, u16 *data) { - struct e1000_phy_info *phy = &hw->phy; - u32 i, i2ccmd = 0; + s32 ret_val = -E1000_ERR_PARAM; DEBUGFUNC("e1000_read_phy_reg_sgmii_82575"); if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) { DEBUGOUT1("PHY Address %u is out of range\n", offset); - return -E1000_ERR_PARAM; + goto out; } - /* - * Set up Op-code, Phy Address, and register address in the I2CCMD - * register. The MAC will take care of interfacing with the - * PHY to retrieve the desired data. - */ - i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) | - (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) | - (E1000_I2CCMD_OPCODE_READ)); + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; - E1000_WRITE_REG(hw, E1000_I2CCMD, i2ccmd); + ret_val = e1000_read_phy_reg_i2c(hw, offset, data); - /* Poll the ready bit to see if the I2C read completed */ - for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) { - usec_delay(50); - i2ccmd = E1000_READ_REG(hw, E1000_I2CCMD); - if (i2ccmd & E1000_I2CCMD_READY) - break; - } - if (!(i2ccmd & E1000_I2CCMD_READY)) { - DEBUGOUT("I2CCMD Read did not complete\n"); - return -E1000_ERR_PHY; - } - if (i2ccmd & E1000_I2CCMD_ERROR) { - DEBUGOUT("I2CCMD Error bit set\n"); - return -E1000_ERR_PHY; - } + hw->phy.ops.release(hw); - /* Need to byte-swap the 16-bit value. */ - *data = ((i2ccmd >> 8) & 0x00FF) | ((i2ccmd << 8) & 0xFF00); - - return E1000_SUCCESS; +out: + return ret_val; } /** @@ -423,49 +454,25 @@ static s32 e1000_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset, static s32 e1000_write_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset, u16 data) { - struct e1000_phy_info *phy = &hw->phy; - u32 i, i2ccmd = 0; - u16 phy_data_swapped; + s32 ret_val = -E1000_ERR_PARAM; DEBUGFUNC("e1000_write_phy_reg_sgmii_82575"); if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) { DEBUGOUT1("PHY Address %d is out of range\n", offset); - return -E1000_ERR_PARAM; + goto out; } - /* Swap the data bytes for the I2C interface */ - phy_data_swapped = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00); + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; - /* - * Set up Op-code, Phy Address, and register address in the I2CCMD - * register. The MAC will take care of interfacing with the - * PHY to retrieve the desired data. - */ - i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) | - (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) | - E1000_I2CCMD_OPCODE_WRITE | - phy_data_swapped); - - E1000_WRITE_REG(hw, E1000_I2CCMD, i2ccmd); - - /* Poll the ready bit to see if the I2C read completed */ - for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) { - usec_delay(50); - i2ccmd = E1000_READ_REG(hw, E1000_I2CCMD); - if (i2ccmd & E1000_I2CCMD_READY) - break; - } - if (!(i2ccmd & E1000_I2CCMD_READY)) { - DEBUGOUT("I2CCMD Write did not complete\n"); - return -E1000_ERR_PHY; - } - if (i2ccmd & E1000_I2CCMD_ERROR) { - DEBUGOUT("I2CCMD Error bit set\n"); - return -E1000_ERR_PHY; - } + ret_val = e1000_write_phy_reg_i2c(hw, offset, data); - return E1000_SUCCESS; + hw->phy.ops.release(hw); + +out: + return ret_val; } /** @@ -480,6 +487,7 @@ static s32 e1000_get_phy_id_82575(struct e1000_hw *hw) struct e1000_phy_info *phy = &hw->phy; s32 ret_val = E1000_SUCCESS; u16 phy_id; + u32 ctrl_ext; DEBUGFUNC("e1000_get_phy_id_82575"); @@ -490,12 +498,19 @@ static s32 e1000_get_phy_id_82575(struct e1000_hw *hw) * work. The result of this function should mean phy->phy_addr * and phy->id are set correctly. */ - if (!(e1000_sgmii_active_82575(hw))) { + if (!e1000_sgmii_active_82575(hw)) { phy->addr = 1; ret_val = e1000_get_phy_id(hw); goto out; } + /* Power on sgmii phy if it is disabled */ + ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); + E1000_WRITE_REG(hw, E1000_CTRL_EXT, + ctrl_ext & ~E1000_CTRL_EXT_SDP3_DATA); + E1000_WRITE_FLUSH(hw); + msec_delay(300); + /* * The address field in the I2CCMD register is 3 bits and 0 is invalid. * Therefore, we need to test 1-7 @@ -522,10 +537,12 @@ static s32 e1000_get_phy_id_82575(struct e1000_hw *hw) if (phy->addr == 8) { phy->addr = 0; ret_val = -E1000_ERR_PHY; - goto out; + } else { + ret_val = e1000_get_phy_id(hw); } - ret_val = e1000_get_phy_id(hw); + /* restore previous sfp cage power state */ + E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); out: return ret_val; @@ -792,21 +809,23 @@ static s32 e1000_get_cfg_done_82575(struct e1000_hw *hw) if (hw->bus.func == E1000_FUNC_1) mask = E1000_NVM_CFG_DONE_PORT_1; + else if (hw->bus.func == E1000_FUNC_2) + mask = E1000_NVM_CFG_DONE_PORT_2; + else if (hw->bus.func == E1000_FUNC_3) + mask = E1000_NVM_CFG_DONE_PORT_3; while (timeout) { if (E1000_READ_REG(hw, E1000_EEMNGCTL) & mask) break; msec_delay(1); timeout--; } - if (!timeout) { + if (!timeout) DEBUGOUT("MNG configuration cycle has not completed.\n"); - } /* If EEPROM is not marked present, init the PHY manually */ if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) && - (hw->phy.type == e1000_phy_igp_3)) { + (hw->phy.type == e1000_phy_igp_3)) e1000_phy_init_script_igp3(hw); - } return ret_val; } @@ -828,14 +847,12 @@ static s32 e1000_get_link_up_info_82575(struct e1000_hw *hw, u16 *speed, DEBUGFUNC("e1000_get_link_up_info_82575"); - if (hw->phy.media_type != e1000_media_type_copper || - e1000_sgmii_active_82575(hw)) { + if (hw->phy.media_type != e1000_media_type_copper) ret_val = e1000_get_pcs_speed_and_duplex_82575(hw, speed, duplex); - } else { + else ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex); - } return ret_val; } @@ -854,9 +871,7 @@ static s32 e1000_check_for_link_82575(struct e1000_hw *hw) DEBUGFUNC("e1000_check_for_link_82575"); - /* SGMII link check is done through the PCS register. */ - if ((hw->phy.media_type != e1000_media_type_copper) || - (e1000_sgmii_active_82575(hw))) { + if (hw->phy.media_type != e1000_media_type_copper) { ret_val = e1000_get_pcs_speed_and_duplex_82575(hw, &speed, &duplex); /* @@ -930,22 +945,28 @@ static s32 e1000_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw, } /** - * e1000_shutdown_fiber_serdes_link_82575 - Remove link during power down + * e1000_shutdown_serdes_link_82575 - Remove link during power down * @hw: pointer to the HW structure * - * In the case of fiber serdes shut down optics and PCS on driver unload + * In the case of serdes shut down sfp and PCS on driver unload * when management pass thru is not enabled. **/ -void e1000_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw) +void e1000_shutdown_serdes_link_82575(struct e1000_hw *hw) { u32 reg; u16 eeprom_data = 0; - if (hw->phy.media_type != e1000_media_type_internal_serdes) + if ((hw->phy.media_type != e1000_media_type_internal_serdes) && + !e1000_sgmii_active_82575(hw)) return; if (hw->bus.func == E1000_FUNC_0) hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data); + else if ((hw->mac.type == e1000_82580) || + (hw->mac.type == e1000_82580er)) + hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A + + NVM_82580_LAN_FUNC_OFFSET(hw->bus.func), 1, + &eeprom_data); else if (hw->bus.func == E1000_FUNC_1) hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_B, 1, &eeprom_data); @@ -962,10 +983,10 @@ void e1000_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw) /* shutdown the laser */ reg = E1000_READ_REG(hw, E1000_CTRL_EXT); - reg |= E1000_CTRL_EXT_SDP7_DATA; + reg |= E1000_CTRL_EXT_SDP3_DATA; E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg); - /* flush the write to verfiy completion */ + /* flush the write to verify completion */ E1000_WRITE_FLUSH(hw); msec_delay(1); } @@ -974,45 +995,6 @@ void e1000_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw) } /** - * e1000_vmdq_set_loopback_pf - enable or disable vmdq loopback - * @hw: pointer to the HW structure - * @enable: state to enter, either enabled or disabled - * - * enables/disables L2 switch loopback functionality - **/ -void e1000_vmdq_set_loopback_pf(struct e1000_hw *hw, bool enable) -{ - u32 reg; - - reg = E1000_READ_REG(hw, E1000_DTXSWC); - if (enable) - reg |= E1000_DTXSWC_VMDQ_LOOPBACK_EN; - else - reg &= ~(E1000_DTXSWC_VMDQ_LOOPBACK_EN); - E1000_WRITE_REG(hw, E1000_DTXSWC, reg); -} - -/** - * e1000_vmdq_set_replication_pf - enable or disable vmdq replication - * @hw: pointer to the HW structure - * @enable: state to enter, either enabled or disabled - * - * enables/disables replication of packets across multiple pools - **/ -void e1000_vmdq_set_replication_pf(struct e1000_hw *hw, bool enable) -{ - u32 reg; - - reg = E1000_READ_REG(hw, E1000_VT_CTL); - if (enable) - reg |= E1000_VT_CTL_VM_REPL_EN; - else - reg &= ~(E1000_VT_CTL_VM_REPL_EN); - - E1000_WRITE_REG(hw, E1000_VT_CTL, reg); -} - -/** * e1000_reset_hw_82575 - Reset hardware * @hw: pointer to the HW structure * @@ -1111,6 +1093,11 @@ static s32 e1000_init_hw_82575(struct e1000_hw *hw) for (i = 0; i < mac->mta_reg_count; i++) E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); + /* Zero out the Unicast HASH table */ + DEBUGOUT("Zeroing the UTA\n"); + for (i = 0; i < mac->uta_reg_count; i++) + E1000_WRITE_REG_ARRAY(hw, E1000_UTA, i, 0); + /* Setup link and flow control */ ret_val = mac->ops.setup_link(hw); @@ -1137,7 +1124,6 @@ static s32 e1000_setup_copper_link_82575(struct e1000_hw *hw) { u32 ctrl; s32 ret_val; - bool link; DEBUGFUNC("e1000_setup_copper_link_82575"); @@ -1146,6 +1132,20 @@ 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); + ret_val = e1000_setup_serdes_link_82575(hw); + if (ret_val) + goto out; + + if (e1000_sgmii_active_82575(hw) && !hw->phy.reset_disable) { + /* allow time for SFP cage time to power up phy */ + msec_delay(300); + + ret_val = hw->phy.ops.reset(hw); + if (ret_val) { + DEBUGOUT("Error resetting the PHY.\n"); + goto out; + } + } switch (hw->phy.type) { case e1000_phy_m88: ret_val = e1000_copper_link_setup_m88(hw); @@ -1153,6 +1153,9 @@ static s32 e1000_setup_copper_link_82575(struct e1000_hw *hw) case e1000_phy_igp_3: ret_val = e1000_copper_link_setup_igp(hw); break; + case e1000_phy_82580: + ret_val = e1000_copper_link_setup_82577(hw); + break; default: ret_val = -E1000_ERR_PHY; break; @@ -1161,66 +1164,30 @@ static s32 e1000_setup_copper_link_82575(struct e1000_hw *hw) if (ret_val) goto out; - if (hw->mac.autoneg) { - /* - * Setup autoneg and flow control advertisement - * and perform autonegotiation. - */ - ret_val = e1000_copper_link_autoneg(hw); - if (ret_val) - goto out; - } else { - /* - * PHY will be set to 10H, 10F, 100H or 100F - * depending on user settings. - */ - DEBUGOUT("Forcing Speed and Duplex\n"); - ret_val = hw->phy.ops.force_speed_duplex(hw); - if (ret_val) { - DEBUGOUT("Error Forcing Speed and Duplex\n"); - goto out; - } - } - - ret_val = e1000_configure_pcs_link_82575(hw); - if (ret_val) - goto out; - - /* - * Check link status. Wait up to 100 microseconds for link to become - * valid. - */ - ret_val = e1000_phy_has_link_generic(hw, - COPPER_LINK_UP_LIMIT, - 10, - &link); - if (ret_val) - goto out; - - if (link) { - DEBUGOUT("Valid link established!!!\n"); - /* Config the MAC and PHY after link is up */ - e1000_config_collision_dist_generic(hw); - ret_val = e1000_config_fc_after_link_up_generic(hw); - } else { - DEBUGOUT("Unable to establish link!!!\n"); - } - + ret_val = e1000_setup_copper_link_generic(hw); out: return ret_val; } /** - * e1000_setup_fiber_serdes_link_82575 - Setup link for fiber/serdes + * e1000_setup_serdes_link_82575 - Setup link for serdes * @hw: pointer to the HW structure * - * Configures speed and duplex for fiber and serdes links. + * Configure the physical coding sub-layer (PCS) link. The PCS link is + * used on copper connections where the serialized gigabit media independent + * interface (sgmii), or serdes fiber is being used. Configures the link + * for auto-negotiation or forces speed/duplex. **/ -static s32 e1000_setup_fiber_serdes_link_82575(struct e1000_hw *hw) +static s32 e1000_setup_serdes_link_82575(struct e1000_hw *hw) { - u32 reg; + u32 ctrl_ext, ctrl_reg, reg; + bool pcs_autoneg; + + DEBUGFUNC("e1000_setup_serdes_link_82575"); - DEBUGFUNC("e1000_setup_fiber_serdes_link_82575"); + if ((hw->phy.media_type != e1000_media_type_internal_serdes) && + !e1000_sgmii_active_82575(hw)) + return E1000_SUCCESS; /* * On the 82575, SerDes loopback mode persists until it is @@ -1230,25 +1197,54 @@ static s32 e1000_setup_fiber_serdes_link_82575(struct e1000_hw *hw) */ E1000_WRITE_REG(hw, E1000_SCTL, E1000_SCTL_DISABLE_SERDES_LOOPBACK); - /* Force link up, set 1gb */ - reg = E1000_READ_REG(hw, E1000_CTRL); - reg |= E1000_CTRL_SLU | E1000_CTRL_SPD_1000 | E1000_CTRL_FRCSPD; + /* power on the sfp cage if present */ + 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); + + ctrl_reg = E1000_READ_REG(hw, E1000_CTRL); + ctrl_reg |= E1000_CTRL_SLU; + if (hw->mac.type == e1000_82575 || hw->mac.type == e1000_82576) { /* set both sw defined pins */ - reg |= E1000_CTRL_SWDPIN0 | E1000_CTRL_SWDPIN1; + ctrl_reg |= E1000_CTRL_SWDPIN0 | E1000_CTRL_SWDPIN1; + + /* Set switch control to serdes energy detect */ + reg = E1000_READ_REG(hw, E1000_CONNSW); + reg |= E1000_CONNSW_ENRGSRC; + E1000_WRITE_REG(hw, E1000_CONNSW, reg); } - E1000_WRITE_REG(hw, E1000_CTRL, reg); - /* Power on phy for 82576 fiber adapters */ - if (hw->mac.type == e1000_82576) { - reg = E1000_READ_REG(hw, E1000_CTRL_EXT); - reg &= ~E1000_CTRL_EXT_SDP7_DATA; - E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg); + + reg = E1000_READ_REG(hw, E1000_PCS_LCTL); + + /* default pcs_autoneg to the same setting as mac autoneg */ + pcs_autoneg = hw->mac.autoneg; + + switch (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) { + case E1000_CTRL_EXT_LINK_MODE_SGMII: + /* sgmii mode lets the phy handle forcing speed/duplex */ + pcs_autoneg = TRUE; + /* autoneg time out should be disabled for SGMII mode */ + reg &= ~(E1000_PCS_LCTL_AN_TIMEOUT); + break; + case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX: + /* disable PCS autoneg and support parallel detect only */ + pcs_autoneg = FALSE; + default: + /* + * non-SGMII modes only supports a speed of 1000/Full for the + * link so it is best to just force the MAC and let the pcs + * link either autoneg or be forced to 1000/Full + */ + ctrl_reg |= E1000_CTRL_SPD_1000 | E1000_CTRL_FRCSPD | + E1000_CTRL_FD | E1000_CTRL_FRCDPX; + + /* set speed of 1000/Full if speed/duplex is forced */ + reg |= E1000_PCS_LCTL_FSV_1000 | E1000_PCS_LCTL_FDV_FULL; + break; } - /* Set switch control to serdes energy detect */ - reg = E1000_READ_REG(hw, E1000_CONNSW); - reg |= E1000_CONNSW_ENRGSRC; - E1000_WRITE_REG(hw, E1000_CONNSW, reg); + E1000_WRITE_REG(hw, E1000_CTRL, ctrl_reg); /* * New SerDes mode allows for forcing speed or autonegotiating speed @@ -1256,35 +1252,34 @@ static s32 e1000_setup_fiber_serdes_link_82575(struct e1000_hw *hw) * mode that will be compatible with older link partners and switches. * However, both are supported by the hardware and some drivers/tools. */ - reg = E1000_READ_REG(hw, E1000_PCS_LCTL); - reg &= ~(E1000_PCS_LCTL_AN_ENABLE | E1000_PCS_LCTL_FLV_LINK_UP | - E1000_PCS_LCTL_FSD | E1000_PCS_LCTL_FORCE_LINK); + E1000_PCS_LCTL_FSD | E1000_PCS_LCTL_FORCE_LINK); - if (hw->mac.autoneg) { + /* + * 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_FSV_1000 | /* Force 1000 */ - E1000_PCS_LCTL_FDV_FULL | /* SerDes Full duplex */ - E1000_PCS_LCTL_AN_ENABLE | /* Enable Autoneg */ - E1000_PCS_LCTL_AN_RESTART; /* Restart autoneg */ - DEBUGOUT1("Configuring Autoneg; PCS_LCTL = 0x%08X\n", reg); + reg |= E1000_PCS_LCTL_AN_ENABLE | /* Enable Autoneg */ + E1000_PCS_LCTL_AN_RESTART; /* Restart autoneg */ + DEBUGOUT1("Configuring Autoneg:PCS_LCTL=0x%08X\n", reg); } else { - /* Set PCS register for forced speed */ - reg |= E1000_PCS_LCTL_FLV_LINK_UP | /* Force link up */ - E1000_PCS_LCTL_FSV_1000 | /* Force 1000 */ - E1000_PCS_LCTL_FDV_FULL | /* SerDes Full duplex */ - E1000_PCS_LCTL_FSD | /* Force Speed */ - E1000_PCS_LCTL_FORCE_LINK; /* Force Link */ - DEBUGOUT1("Configuring Forced Link; PCS_LCTL = 0x%08X\n", reg); - } + /* Set PCS register for forced link */ + reg |= E1000_PCS_LCTL_FSD | /* Force Speed */ + E1000_PCS_LCTL_FORCE_LINK | /* Force Link */ + E1000_PCS_LCTL_FLV_LINK_UP; /* Force link value up */ - if (hw->mac.type == e1000_82576) { - reg |= E1000_PCS_LCTL_FORCE_FCTRL; - e1000_force_mac_fc_generic(hw); + DEBUGOUT1("Configuring Forced Link:PCS_LCTL=0x%08X\n", reg); } E1000_WRITE_REG(hw, E1000_PCS_LCTL, reg); + if (!e1000_sgmii_active_82575(hw)) + e1000_force_mac_fc_generic(hw); + return E1000_SUCCESS; } @@ -1324,72 +1319,6 @@ out: } /** - * e1000_configure_pcs_link_82575 - Configure PCS link - * @hw: pointer to the HW structure - * - * Configure the physical coding sub-layer (PCS) link. The PCS link is - * only used on copper connections where the serialized gigabit media - * independent interface (sgmii) is being used. Configures the link - * for auto-negotiation or forces speed/duplex. - **/ -static s32 e1000_configure_pcs_link_82575(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - u32 reg = 0; - - DEBUGFUNC("e1000_configure_pcs_link_82575"); - - if (hw->phy.media_type != e1000_media_type_copper || - !(e1000_sgmii_active_82575(hw))) - goto out; - - /* For SGMII, we need to issue a PCS autoneg restart */ - reg = E1000_READ_REG(hw, E1000_PCS_LCTL); - - /* AN time out should be disabled for SGMII mode */ - reg &= ~(E1000_PCS_LCTL_AN_TIMEOUT); - - if (mac->autoneg) { - /* Make sure forced speed and force link are not set */ - reg &= ~(E1000_PCS_LCTL_FSD | E1000_PCS_LCTL_FORCE_LINK); - - /* - * The PHY should be setup prior to calling this function. - * All we need to do is restart autoneg and enable autoneg. - */ - reg |= E1000_PCS_LCTL_AN_RESTART | E1000_PCS_LCTL_AN_ENABLE; - } else { - /* Set PCS register for forced speed */ - - /* Turn off bits for full duplex, speed, and autoneg */ - reg &= ~(E1000_PCS_LCTL_FSV_1000 | - E1000_PCS_LCTL_FSV_100 | - E1000_PCS_LCTL_FDV_FULL | - E1000_PCS_LCTL_AN_ENABLE); - - /* Check for duplex first */ - if (mac->forced_speed_duplex & E1000_ALL_FULL_DUPLEX) - reg |= E1000_PCS_LCTL_FDV_FULL; - - /* Now set speed */ - if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) - reg |= E1000_PCS_LCTL_FSV_100; - - /* Force speed and force link */ - reg |= E1000_PCS_LCTL_FSD | - E1000_PCS_LCTL_FORCE_LINK | - E1000_PCS_LCTL_FLV_LINK_UP; - - DEBUGOUT1("Wrote 0x%08X to PCS_LCTL to configure forced link\n", - reg); - } - E1000_WRITE_REG(hw, E1000_PCS_LCTL, reg); - -out: - return E1000_SUCCESS; -} - -/** * e1000_sgmii_active_82575 - Return sgmii state * @hw: pointer to the HW structure * @@ -1548,7 +1477,8 @@ static void e1000_clear_hw_cntrs_82575(struct e1000_hw *hw) E1000_READ_REG(hw, E1000_LENERRS); /* This register should not be read in copper configurations */ - if (hw->phy.media_type == e1000_media_type_internal_serdes) + if ((hw->phy.media_type == e1000_media_type_internal_serdes) || + e1000_sgmii_active_82575(hw)) E1000_READ_REG(hw, E1000_SCVPC); } @@ -1677,3 +1607,235 @@ out: return ret_val; } +/** + * e1000_vmdq_set_loopback_pf - enable or disable vmdq loopback + * @hw: pointer to the hardware struct + * @enable: state to enter, either enabled or disabled + * + * enables/disables L2 switch loopback functionality. + **/ +void e1000_vmdq_set_loopback_pf(struct e1000_hw *hw, bool enable) +{ + u32 dtxswc = E1000_READ_REG(hw, E1000_DTXSWC); + + if (enable) + dtxswc |= E1000_DTXSWC_VMDQ_LOOPBACK_EN; + else + dtxswc &= ~E1000_DTXSWC_VMDQ_LOOPBACK_EN; + + E1000_WRITE_REG(hw, E1000_DTXSWC, dtxswc); +} + +/** + * e1000_vmdq_set_replication_pf - enable or disable vmdq replication + * @hw: pointer to the hardware struct + * @enable: state to enter, either enabled or disabled + * + * enables/disables replication of packets across multiple pools. + **/ +void e1000_vmdq_set_replication_pf(struct e1000_hw *hw, bool enable) +{ + u32 vt_ctl = E1000_READ_REG(hw, E1000_VT_CTL); + + if (enable) + vt_ctl |= E1000_VT_CTL_VM_REPL_EN; + else + vt_ctl &= ~E1000_VT_CTL_VM_REPL_EN; + + E1000_WRITE_REG(hw, E1000_VT_CTL, vt_ctl); +} + +/** + * e1000_read_phy_reg_82580 - Read 82580 MDI control register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Reads the MDI control register in the PHY at offset and stores the + * information read to data. + **/ +static s32 e1000_read_phy_reg_82580(struct e1000_hw *hw, u32 offset, u16 *data) +{ + u32 mdicnfg = 0; + s32 ret_val; + + DEBUGFUNC("e1000_read_phy_reg_82580"); + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + + /* + * We config the phy address in MDICNFG register now. Same bits + * as before. The values in MDIC can be written but will be + * ignored. This allows us to call the old function after + * configuring the PHY address in the new register + */ + mdicnfg = (hw->phy.addr << E1000_MDIC_PHY_SHIFT); + E1000_WRITE_REG(hw, E1000_MDICNFG, mdicnfg); + + ret_val = e1000_read_phy_reg_mdic(hw, offset, data); + + hw->phy.ops.release(hw); + +out: + return ret_val; +} + +/** + * e1000_write_phy_reg_82580 - Write 82580 MDI control register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write to register at offset + * + * Writes data to MDI control register in the PHY at offset. + **/ +static s32 e1000_write_phy_reg_82580(struct e1000_hw *hw, u32 offset, u16 data) +{ + u32 mdicnfg = 0; + s32 ret_val; + + DEBUGFUNC("e1000_write_phy_reg_82580"); + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + + /* + * We config the phy address in MDICNFG register now. Same bits + * as before. The values in MDIC can be written but will be + * ignored. This allows us to call the old function after + * configuring the PHY address in the new register + */ + mdicnfg = (hw->phy.addr << E1000_MDIC_PHY_SHIFT); + E1000_WRITE_REG(hw, E1000_MDICNFG, mdicnfg); + + ret_val = e1000_write_phy_reg_mdic(hw, offset, data); + + hw->phy.ops.release(hw); + +out: + return ret_val; +} +/** + * e1000_reset_hw_82580 - Reset hardware + * @hw: pointer to the HW structure + * + * This resets function or entire device (all ports, etc.) + * to a known state. + **/ +static s32 e1000_reset_hw_82580(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + /* BH SW mailbox bit in SW_FW_SYNC */ + u16 swmbsw_mask = E1000_SW_SYNCH_MB; + u32 ctrl, icr; + bool global_device_reset = hw->dev_spec._82575.global_device_reset; + + DEBUGFUNC("e1000_reset_hw_82580"); + + hw->dev_spec._82575.global_device_reset = FALSE; + + /* Get current control state. */ + ctrl = E1000_READ_REG(hw, E1000_CTRL); + + /* + * Prevent the PCI-E bus from sticking if there is no TLP connection + * on the last TLP read/write transaction when MAC is reset. + */ + ret_val = e1000_disable_pcie_master_generic(hw); + if (ret_val) + DEBUGOUT("PCI-E Master disable polling has failed.\n"); + + DEBUGOUT("Masking off all interrupts\n"); + E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); + E1000_WRITE_REG(hw, E1000_RCTL, 0); + E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP); + E1000_WRITE_FLUSH(hw); + + msec_delay(10); + + /* Determine whether or not a global dev reset is requested */ + if (global_device_reset && + e1000_acquire_swfw_sync_82575(hw, swmbsw_mask)) + global_device_reset = FALSE; + + if (global_device_reset && + !(E1000_READ_REG(hw, E1000_STATUS) & E1000_STAT_DEV_RST_SET)) + ctrl |= E1000_CTRL_DEV_RST; + else + ctrl |= E1000_CTRL_RST; + + E1000_WRITE_REG(hw, E1000_CTRL, ctrl); + + /* Add delay to insure DEV_RST has time to complete */ + if (global_device_reset) + msec_delay(5); + + ret_val = e1000_get_auto_rd_done_generic(hw); + if (ret_val) { + /* + * When auto config read does not complete, do not + * return with an error. This can happen in situations + * where there is no eeprom and prevents getting link. + */ + DEBUGOUT("Auto Read Done did not complete\n"); + } + + /* If EEPROM is not present, run manual init scripts */ + if ((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) + e1000_reset_init_script_82575(hw); + + /* clear global device reset status bit */ + E1000_WRITE_REG(hw, E1000_STATUS, E1000_STAT_DEV_RST_SET); + + /* Clear any pending interrupt events. */ + E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); + icr = E1000_READ_REG(hw, E1000_ICR); + + /* Install any alternate MAC address into RAR0 */ + ret_val = e1000_check_alt_mac_addr_generic(hw); + + /* Release semaphore */ + if (global_device_reset) + e1000_release_swfw_sync_82575(hw, swmbsw_mask); + + return ret_val; +} + +/** + * e1000_rxpbs_adjust_82580 - adjust RXPBS value to reflect actual RX PBA size + * @data: data received by reading RXPBS register + * + * The 82580 uses a table based approach for packet buffer allocation sizes. + * This function converts the retrieved value into the correct table value + * 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 + * 0x0 36 72 144 1 2 4 8 16 + * 0x8 35 70 140 rsv rsv rsv rsv rsv + */ +u16 e1000_rxpbs_adjust_82580(u32 data) +{ + u16 ret_val = 0; + + if (data < E1000_82580_RXPBS_TABLE_SIZE) + ret_val = e1000_82580_rxpbs_table[data]; + + return ret_val; +} +/** + * e1000_erfuse_check_82580 - ER Fuse check + * @hw: pointer to the HW structure + * + * This function returns the status of the ER Fuse + **/ +s32 e1000_erfuse_check_82580(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + s32 ufuse_reg; + + ufuse_reg = E1000_READ_REG(hw, E1000_UFUSE); + if ((ufuse_reg & E1000_ERFUSE) == E1000_ERFUSE) + ret_val = E1000_ERFUSE_FAILURE; + + return ret_val; +} diff --git a/sys/dev/e1000/e1000_82575.h b/sys/dev/e1000/e1000_82575.h index 34e0d29..f22a963f 100644 --- a/sys/dev/e1000/e1000_82575.h +++ b/sys/dev/e1000/e1000_82575.h @@ -51,10 +51,14 @@ */ #define E1000_RAR_ENTRIES_82575 16 #define E1000_RAR_ENTRIES_82576 24 +#define E1000_RAR_ENTRIES_82580 24 +#define E1000_SW_SYNCH_MB 0x00000100 +#define E1000_STAT_DEV_RST_SET 0x00100000 +#define E1000_CTRL_DEV_RST 0x20000000 #ifdef E1000_BIT_FIELDS struct e1000_adv_data_desc { - u64 buffer_addr; /* Address of the descriptor's data buffer */ + __le64 buffer_addr; /* Address of the descriptor's data buffer */ union { u32 data; struct { @@ -128,6 +132,7 @@ struct e1000_adv_context_desc { #define E1000_SRRCTL_DESCTYPE_HDR_REPLICATION 0x06000000 #define E1000_SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT 0x08000000 #define E1000_SRRCTL_DESCTYPE_MASK 0x0E000000 +#define E1000_SRRCTL_TIMESTAMP 0x40000000 #define E1000_SRRCTL_DROP_EN 0x80000000 #define E1000_SRRCTL_BSIZEPKT_MASK 0x0000007F @@ -142,6 +147,7 @@ struct e1000_adv_context_desc { #define E1000_MRQC_RSS_FIELD_IPV4_UDP 0x00400000 #define E1000_MRQC_RSS_FIELD_IPV6_UDP 0x00800000 #define E1000_MRQC_RSS_FIELD_IPV6_UDP_EX 0x01000000 +#define E1000_MRQC_ENABLE_RSS_8Q 0x00000002 #define E1000_VMRCTL_MIRROR_PORT_SHIFT 8 #define E1000_VMRCTL_MIRROR_DSTPORT_MASK (7 << E1000_VMRCTL_MIRROR_PORT_SHIFT) @@ -185,31 +191,31 @@ struct e1000_adv_context_desc { /* Receive Descriptor - Advanced */ union e1000_adv_rx_desc { struct { - u64 pkt_addr; /* Packet buffer address */ - u64 hdr_addr; /* Header buffer address */ + __le64 pkt_addr; /* Packet buffer address */ + __le64 hdr_addr; /* Header buffer address */ } read; struct { struct { union { - u32 data; + __le32 data; struct { - u16 pkt_info; /* RSS type, Packet type */ - u16 hdr_info; /* Split Header, - * header buffer length */ + __le16 pkt_info; /*RSS type, Pkt type*/ + __le16 hdr_info; /* Split Header, + * header buffer len*/ } hs_rss; } lo_dword; union { - u32 rss; /* RSS Hash */ + __le32 rss; /* RSS Hash */ struct { - u16 ip_id; /* IP id */ - u16 csum; /* Packet Checksum */ + __le16 ip_id; /* IP id */ + __le16 csum; /* Packet Checksum */ } csum_ip; } hi_dword; } lower; struct { - u32 status_error; /* ext status/error */ - u16 length; /* Packet length */ - u16 vlan; /* VLAN tag */ + __le32 status_error; /* ext status/error */ + __le16 length; /* Packet length */ + __le16 vlan; /* VLAN tag */ } upper; } wb; /* writeback */ }; @@ -220,6 +226,8 @@ union e1000_adv_rx_desc { #define E1000_RXDADV_HDRBUFLEN_SHIFT 5 #define E1000_RXDADV_SPLITHEADER_EN 0x00001000 #define E1000_RXDADV_SPH 0x8000 +#define E1000_RXDADV_STAT_TS 0x10000 /* Pkt was time stamped */ +#define E1000_RXDADV_STAT_TSIP 0x08000 /* timestamp in packet */ #define E1000_RXDADV_ERR_HBO 0x00800000 /* RSS Hash results */ @@ -269,14 +277,14 @@ union e1000_adv_rx_desc { /* Transmit Descriptor - Advanced */ union e1000_adv_tx_desc { struct { - u64 buffer_addr; /* Address of descriptor's data buf */ - u32 cmd_type_len; - u32 olinfo_status; + __le64 buffer_addr; /* Address of descriptor's data buf */ + __le32 cmd_type_len; + __le32 olinfo_status; } read; struct { - u64 rsvd; /* Reserved */ - u32 nxtseq_seed; - u32 status; + __le64 rsvd; /* Reserved */ + __le32 nxtseq_seed; + __le32 status; } wb; }; @@ -303,10 +311,10 @@ union e1000_adv_tx_desc { /* Context descriptors */ struct e1000_adv_tx_context_desc { - u32 vlan_macip_lens; - u32 seqnum_seed; - u32 type_tucmd_mlhl; - u32 mss_l4len_idx; + __le32 vlan_macip_lens; + __le32 seqnum_seed; + __le32 type_tucmd_mlhl; + __le32 mss_l4len_idx; }; #define E1000_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */ @@ -378,6 +386,14 @@ struct e1000_adv_tx_context_desc { */ #define E1000_ETQF_FILTER_EAPOL 0 +#define E1000_FTQF_VF_BP 0x00008000 +#define E1000_FTQF_1588_TIME_STAMP 0x08000000 +#define E1000_FTQF_MASK 0xF0000000 +#define E1000_FTQF_MASK_PROTO_BP 0x10000000 +#define E1000_FTQF_MASK_SOURCE_ADDR_BP 0x20000000 +#define E1000_FTQF_MASK_DEST_ADDR_BP 0x40000000 +#define E1000_FTQF_MASK_SOURCE_PORT_BP 0x80000000 + #define E1000_NVM_APME_82575 0x0400 #define MAX_NUM_VFS 8 @@ -416,6 +432,9 @@ struct e1000_adv_tx_context_desc { #define E1000_VLVF_LVLAN 0x00100000 #define E1000_VLVF_VLANID_ENABLE 0x80000000 +#define E1000_VMVIR_VLANA_DEFAULT 0x40000000 /* Always use default VLAN */ +#define E1000_VMVIR_VLANA_NEVER 0x80000000 /* Never insert VLAN tag */ + #define E1000_VF_INIT_TIMEOUT 200 /* Number of retries to clear RSTI */ #define E1000_IOVCTL 0x05BBC @@ -424,8 +443,18 @@ struct e1000_adv_tx_context_desc { #define E1000_RPLOLR_STRVLAN 0x40000000 #define E1000_RPLOLR_STRCRC 0x80000000 +#define E1000_DTXCTL_8023LL 0x0004 +#define E1000_DTXCTL_VLAN_ADDED 0x0008 +#define E1000_DTXCTL_OOS_ENABLE 0x0010 +#define E1000_DTXCTL_MDP_EN 0x0020 +#define E1000_DTXCTL_SPOOF_INT 0x0040 + #define ALL_QUEUES 0xFFFF +/* RX packet buffer size defines */ +#define E1000_RXPBS_SIZE_MASK_82576 0x0000007F void e1000_vmdq_set_loopback_pf(struct e1000_hw *hw, bool enable); void e1000_vmdq_set_replication_pf(struct e1000_hw *hw, bool enable); +u16 e1000_rxpbs_adjust_82580(u32 data); +s32 e1000_erfuse_check_82580(struct e1000_hw *); #endif /* _E1000_82575_H_ */ diff --git a/sys/dev/e1000/e1000_api.c b/sys/dev/e1000/e1000_api.c index 8188658..154eff9 100644 --- a/sys/dev/e1000/e1000_api.c +++ b/sys/dev/e1000/e1000_api.c @@ -232,6 +232,7 @@ s32 e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_ICH8_IGP_M_AMT: case E1000_DEV_ID_ICH8_IGP_AMT: case E1000_DEV_ID_ICH8_IGP_C: + case E1000_DEV_ID_ICH8_82567V_3: mac->type = e1000_ich8lan; break; case E1000_DEV_ID_ICH9_IFE: @@ -269,9 +270,21 @@ s32 e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_82576_SERDES: case E1000_DEV_ID_82576_QUAD_COPPER: case E1000_DEV_ID_82576_NS: + case E1000_DEV_ID_82576_NS_SERDES: case E1000_DEV_ID_82576_SERDES_QUAD: mac->type = e1000_82576; break; + case E1000_DEV_ID_82580_COPPER: + case E1000_DEV_ID_82580_FIBER: + case E1000_DEV_ID_82580_SERDES: + case E1000_DEV_ID_82580_SGMII: + case E1000_DEV_ID_82580_COPPER_DUAL: + mac->type = e1000_82580; + break; + case E1000_DEV_ID_82580_ER: + case E1000_DEV_ID_82580_ER_DUAL: + mac->type = e1000_82580er; + break; default: /* Should never have loaded on this device */ ret_val = -E1000_ERR_MAC_INIT; @@ -362,6 +375,8 @@ s32 e1000_setup_init_funcs(struct e1000_hw *hw, bool init_device) break; case e1000_82575: case e1000_82576: + case e1000_82580: + case e1000_82580er: e1000_init_function_pointers_82575(hw); break; default: diff --git a/sys/dev/e1000/e1000_defines.h b/sys/dev/e1000/e1000_defines.h index d845fb2..4636506 100644 --- a/sys/dev/e1000/e1000_defines.h +++ b/sys/dev/e1000/e1000_defines.h @@ -146,12 +146,12 @@ #define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Definable Pin 5 */ #define E1000_CTRL_EXT_PHY_INT E1000_CTRL_EXT_SDP5_DATA #define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Definable Pin 6 */ -#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Definable Pin 7 */ +#define E1000_CTRL_EXT_SDP3_DATA 0x00000080 /* Value of SW Definable Pin 3 */ /* SDP 4/5 (bits 8,9) are reserved in >= 82575 */ #define E1000_CTRL_EXT_SDP4_DIR 0x00000100 /* Direction of SDP4 0=in 1=out */ #define E1000_CTRL_EXT_SDP5_DIR 0x00000200 /* Direction of SDP5 0=in 1=out */ #define E1000_CTRL_EXT_SDP6_DIR 0x00000400 /* Direction of SDP6 0=in 1=out */ -#define E1000_CTRL_EXT_SDP7_DIR 0x00000800 /* Direction of SDP7 0=in 1=out */ +#define E1000_CTRL_EXT_SDP3_DIR 0x00000800 /* Direction of SDP3 0=in 1=out */ #define E1000_CTRL_EXT_ASDCHK 0x00001000 /* Initiate an ASD sequence */ #define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */ #define E1000_CTRL_EXT_IPS 0x00004000 /* Invert Power State */ @@ -161,6 +161,8 @@ #define E1000_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */ #define E1000_CTRL_EXT_DMA_DYN_CLK_EN 0x00080000 /* DMA Dynamic Clock Gating */ #define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000 +#define E1000_CTRL_EXT_LINK_MODE_82580_MASK 0x01C00000 /*82580 bit 24:22*/ +#define E1000_CTRL_EXT_LINK_MODE_1000BASE_KX 0x00400000 #define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000 #define E1000_CTRL_EXT_LINK_MODE_TBI 0x00C00000 #define E1000_CTRL_EXT_LINK_MODE_KMRN 0x00000000 @@ -386,6 +388,8 @@ #define E1000_SWFW_PHY0_SM 0x02 #define E1000_SWFW_PHY1_SM 0x04 #define E1000_SWFW_CSR_SM 0x08 +#define E1000_SWFW_PHY2_SM 0x20 +#define E1000_SWFW_PHY3_SM 0x40 /* FACTPS Definitions */ #define E1000_FACTPS_LFS 0x40000000 /* LAN Function Select */ @@ -697,6 +701,7 @@ /* Extended Configuration Control and Size */ #define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020 #define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001 +#define E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE 0x00000008 #define E1000_EXTCNF_CTRL_SWFLAG 0x00000020 #define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK 0x00FF0000 #define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT 16 @@ -769,6 +774,7 @@ #define E1000_ICR_ACK 0x00020000 /* Receive Ack frame */ #define E1000_ICR_MNG 0x00040000 /* Manageability event */ #define E1000_ICR_DOCK 0x00080000 /* Dock/Undock */ +#define E1000_ICR_DRSTA 0x40000000 /* Device Reset Asserted */ #define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver * should claim the interrupt */ #define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* Q0 Rx desc FIFO parity error */ @@ -789,6 +795,7 @@ #define E1000_ICR_TXQ0 0x00400000 /* Tx Queue 0 Interrupt */ #define E1000_ICR_TXQ1 0x00800000 /* Tx Queue 1 Interrupt */ #define E1000_ICR_OTHER 0x01000000 /* Other Interrupts */ +#define E1000_ICR_FER 0x00400000 /* Fatal Error */ /* PBA ECC Register */ #define E1000_PBA_ECC_COUNTER_MASK 0xFFF00000 /* ECC counter mask */ @@ -860,6 +867,7 @@ #define E1000_IMS_ACK E1000_ICR_ACK /* Receive Ack frame */ #define E1000_IMS_MNG E1000_ICR_MNG /* Manageability event */ #define E1000_IMS_DOCK E1000_ICR_DOCK /* Dock/Undock */ +#define E1000_IMS_DRSTA E1000_ICR_DRSTA /* Device Reset Asserted */ #define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO * parity error */ #define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO @@ -881,6 +889,7 @@ #define E1000_IMS_TXQ0 E1000_ICR_TXQ0 /* Tx Queue 0 Interrupt */ #define E1000_IMS_TXQ1 E1000_ICR_TXQ1 /* Tx Queue 1 Interrupt */ #define E1000_IMS_OTHER E1000_ICR_OTHER /* Other Interrupts */ +#define E1000_IMS_FER E1000_ICR_FER /* Fatal Error */ /* Extended Interrupt Mask Set */ #define E1000_EIMS_RX_QUEUE0 E1000_EICR_RX_QUEUE0 /* Rx Queue 0 Interrupt */ @@ -913,6 +922,7 @@ #define E1000_ICS_ACK E1000_ICR_ACK /* Receive Ack frame */ #define E1000_ICS_MNG E1000_ICR_MNG /* Manageability event */ #define E1000_ICS_DOCK E1000_ICR_DOCK /* Dock/Undock */ +#define E1000_ICS_DRSTA E1000_ICR_DRSTA /* Device Reset Aserted */ #define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO * parity error */ #define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO @@ -994,6 +1004,7 @@ #define E1000_ERR_SWFW_SYNC 13 #define E1000_NOT_IMPLEMENTED 14 #define E1000_ERR_MBX 15 +#define E1000_ERFUSE_FAILURE 16 /* Loop limit on how long we wait for auto-negotiation to complete */ #define FIBER_LINK_UP_LIMIT 50 @@ -1036,6 +1047,56 @@ #define E1000_RXCW_SYNCH 0x40000000 /* Receive config synch */ #define E1000_RXCW_ANC 0x80000000 /* Auto-neg complete */ +#define E1000_TSYNCTXCTL_VALID 0x00000001 /* tx timestamp valid */ +#define E1000_TSYNCTXCTL_ENABLED 0x00000010 /* enable tx timestampping */ + +#define E1000_TSYNCRXCTL_VALID 0x00000001 /* rx timestamp valid */ +#define E1000_TSYNCRXCTL_TYPE_MASK 0x0000000E /* rx type mask */ +#define E1000_TSYNCRXCTL_TYPE_L2_V2 0x00 +#define E1000_TSYNCRXCTL_TYPE_L4_V1 0x02 +#define E1000_TSYNCRXCTL_TYPE_L2_L4_V2 0x04 +#define E1000_TSYNCRXCTL_TYPE_ALL 0x08 +#define E1000_TSYNCRXCTL_TYPE_EVENT_V2 0x0A +#define E1000_TSYNCRXCTL_ENABLED 0x00000010 /* enable rx timestampping */ + +#define E1000_TSYNCRXCFG_PTP_V1_CTRLT_MASK 0x000000FF +#define E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE 0x00 +#define E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE 0x01 +#define E1000_TSYNCRXCFG_PTP_V1_FOLLOWUP_MESSAGE 0x02 +#define E1000_TSYNCRXCFG_PTP_V1_DELAY_RESP_MESSAGE 0x03 +#define E1000_TSYNCRXCFG_PTP_V1_MANAGEMENT_MESSAGE 0x04 + +#define E1000_TSYNCRXCFG_PTP_V2_MSGID_MASK 0x00000F00 +#define E1000_TSYNCRXCFG_PTP_V2_SYNC_MESSAGE 0x0000 +#define E1000_TSYNCRXCFG_PTP_V2_DELAY_REQ_MESSAGE 0x0100 +#define E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_REQ_MESSAGE 0x0200 +#define E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_RESP_MESSAGE 0x0300 +#define E1000_TSYNCRXCFG_PTP_V2_FOLLOWUP_MESSAGE 0x0800 +#define E1000_TSYNCRXCFG_PTP_V2_DELAY_RESP_MESSAGE 0x0900 +#define E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_FOLLOWUP_MESSAGE 0x0A00 +#define E1000_TSYNCRXCFG_PTP_V2_ANNOUNCE_MESSAGE 0x0B00 +#define E1000_TSYNCRXCFG_PTP_V2_SIGNALLING_MESSAGE 0x0C00 +#define E1000_TSYNCRXCFG_PTP_V2_MANAGEMENT_MESSAGE 0x0D00 + +#define E1000_TIMINCA_16NS_SHIFT 24 +/* TUPLE Filtering Configuration */ +#define E1000_TTQF_DISABLE_MASK 0xF0008000 /* TTQF Disable Mask */ +#define E1000_TTQF_QUEUE_ENABLE 0x100 /* TTQF Queue Enable Bit */ +#define E1000_TTQF_PROTOCOL_MASK 0xFF /* TTQF Protocol Mask */ +/* TTQF TCP Bit, shift with E1000_TTQF_PROTOCOL SHIFT */ +#define E1000_TTQF_PROTOCOL_TCP 0x0 +/* TTQF UDP Bit, shift with E1000_TTQF_PROTOCOL_SHIFT */ +#define E1000_TTQF_PROTOCOL_UDP 0x1 +/* TTQF SCTP Bit, shift with E1000_TTQF_PROTOCOL_SHIFT */ +#define E1000_TTQF_PROTOCOL_SCTP 0x2 +#define E1000_TTQF_PROTOCOL_SHIFT 5 /* TTQF Protocol Shift */ +#define E1000_TTQF_QUEUE_SHIFT 16 /* TTQF Queue Shfit */ +#define E1000_TTQF_RX_QUEUE_MASK 0x70000 /* TTQF Queue Mask */ +#define E1000_TTQF_MASK_ENABLE 0x10000000 /* TTQF Mask Enable Bit */ +#define E1000_IMIR_CLEAR_MASK 0xF001FFFF /* IMIR Reg Clear Mask */ +#define E1000_IMIR_PORT_BYPASS 0x20000 /* IMIR Port Bypass Bit */ +#define E1000_IMIR_PRIORITY_SHIFT 29 /* IMIR Priority Shift */ +#define E1000_IMIREXT_CLEAR_MASK 0x7FFFF /* IMIREXT Reg Clear Mask */ /* PCI Express Control */ #define E1000_GCR_RXD_NO_SNOOP 0x00000001 @@ -1227,6 +1288,10 @@ #define E1000_NVM_CFG_DONE_PORT_0 0x040000 /* MNG config cycle done */ #define E1000_NVM_CFG_DONE_PORT_1 0x080000 /* ...for second port */ +#define E1000_NVM_CFG_DONE_PORT_2 0x100000 /* ...for third port */ +#define E1000_NVM_CFG_DONE_PORT_3 0x200000 /* ...for fourth port */ + +#define NVM_82580_LAN_FUNC_OFFSET(a) (a ? (0x40 + (0x40 * a)) : 0) /* Mask bits for fields in Word 0x0f of the NVM */ #define NVM_WORD0F_PAUSE_MASK 0x3000 @@ -1346,6 +1411,7 @@ #define BME1000_E_PHY_ID_R2 0x01410CB1 #define I82577_E_PHY_ID 0x01540050 #define I82578_E_PHY_ID 0x004DD040 +#define I82580_I_PHY_ID 0x015403A0 #define IGP04E1000_E_PHY_ID 0x02A80391 #define M88_VENDOR 0x0141 @@ -1575,5 +1641,34 @@ #define E1000_LSECRXCTRL_RSV_MASK 0xFFFFFF33 +/* DMA Coalescing register fields */ +#define E1000_DMACR_DMACWT_MASK 0x00003FFF /* DMA Coalescing + * Watchdog Timer */ +#define E1000_DMACR_DMACTHR_MASK 0x00FF0000 /* DMA Coalescing Receive + * Threshold */ +#define E1000_DMACR_DMACTHR_SHIFT 16 +#define E1000_DMACR_DMAC_LX_MASK 0x30000000 /* Lx when no PCIe + * transactions */ +#define E1000_DMACR_DMAC_LX_SHIFT 28 +#define E1000_DMACR_DMAC_EN 0x80000000 /* Enable DMA Coalescing */ + +#define E1000_DMCTXTH_DMCTTHR_MASK 0x00000FFF /* DMA Coalescing Transmit + * Threshold */ + +#define E1000_DMCTLX_TTLX_MASK 0x00000FFF /* Time to LX request */ + +#define E1000_DMCRTRH_UTRESH_MASK 0x0007FFFF /* Receive Traffic Rate + * Threshold */ +#define E1000_DMCRTRH_LRPRCW 0x80000000 /* Rcv packet rate in + * current window */ + +#define E1000_DMCCNT_CCOUNT_MASK 0x01FFFFFF /* DMA Coal Rcv Traffic + * Current Cnt */ + +#define E1000_FCRTC_RTH_COAL_MASK 0x0003FFF0 /* Flow ctrl Rcv Threshold + * High val */ +#define E1000_FCRTC_RTH_COAL_SHIFT 4 +#define E1000_PCIEMISC_LX_DECISION 0x00000080 /* Lx power decision based + on DMA coal */ #endif /* _E1000_DEFINES_H_ */ diff --git a/sys/dev/e1000/e1000_hw.h b/sys/dev/e1000/e1000_hw.h index 6afa4fbb..b01c5d1 100644 --- a/sys/dev/e1000/e1000_hw.h +++ b/sys/dev/e1000/e1000_hw.h @@ -100,6 +100,7 @@ struct e1000_hw; #define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098 #define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA #define E1000_DEV_ID_80003ES2LAN_SERDES_SPT 0x10BB +#define E1000_DEV_ID_ICH8_82567V_3 0x1501 #define E1000_DEV_ID_ICH8_IGP_M_AMT 0x1049 #define E1000_DEV_ID_ICH8_IGP_AMT 0x104A #define E1000_DEV_ID_ICH8_IGP_C 0x104B @@ -130,11 +131,19 @@ struct e1000_hw; #define E1000_DEV_ID_82576_SERDES 0x10E7 #define E1000_DEV_ID_82576_QUAD_COPPER 0x10E8 #define E1000_DEV_ID_82576_NS 0x150A -#define E1000_DEV_ID_82576_SERDES_QUAD 0x150D +#define E1000_DEV_ID_82576_NS_SERDES 0x1518 +#define E1000_DEV_ID_82576_SERDES_QUAD 0x150D #define E1000_DEV_ID_82575EB_COPPER 0x10A7 #define E1000_DEV_ID_82575EB_FIBER_SERDES 0x10A9 #define E1000_DEV_ID_82575GB_QUAD_COPPER 0x10D6 #define E1000_DEV_ID_82575GB_QUAD_COPPER_PM 0x10E2 +#define E1000_DEV_ID_82580_COPPER 0x150E +#define E1000_DEV_ID_82580_FIBER 0x150F +#define E1000_DEV_ID_82580_SERDES 0x1510 +#define E1000_DEV_ID_82580_SGMII 0x1511 +#define E1000_DEV_ID_82580_COPPER_DUAL 0x1516 +#define E1000_DEV_ID_82580_ER 0x151D +#define E1000_DEV_ID_82580_ER_DUAL 0x151E #define E1000_REVISION_0 0 #define E1000_REVISION_1 1 #define E1000_REVISION_2 2 @@ -143,9 +152,13 @@ struct e1000_hw; #define E1000_FUNC_0 0 #define E1000_FUNC_1 1 +#define E1000_FUNC_2 2 +#define E1000_FUNC_3 3 #define E1000_ALT_MAC_ADDRESS_OFFSET_LAN0 0 #define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1 3 +#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN2 6 +#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN3 9 enum e1000_mac_type { e1000_undefined = 0, @@ -173,6 +186,8 @@ enum e1000_mac_type { e1000_pchlan, e1000_82575, e1000_82576, + e1000_82580, + e1000_82580er, e1000_num_macs /* List is 1-based, so subtract 1 for TRUE count. */ }; @@ -213,6 +228,7 @@ enum e1000_phy_type { e1000_phy_bm, e1000_phy_82578, e1000_phy_82577, + e1000_phy_82580, e1000_phy_vf, }; @@ -615,11 +631,13 @@ struct e1000_phy_operations { s32 (*get_cable_length)(struct e1000_hw *); s32 (*get_info)(struct e1000_hw *); s32 (*read_reg)(struct e1000_hw *, u32, u16 *); + s32 (*read_reg_locked)(struct e1000_hw *, u32, u16 *); void (*release)(struct e1000_hw *); s32 (*reset)(struct e1000_hw *); s32 (*set_d0_lplu_state)(struct e1000_hw *, bool); s32 (*set_d3_lplu_state)(struct e1000_hw *, bool); s32 (*write_reg)(struct e1000_hw *, u32, u16); + s32 (*write_reg_locked)(struct e1000_hw *, u32, u16); void (*power_up)(struct e1000_hw *); void (*power_down)(struct e1000_hw *); }; @@ -657,6 +675,7 @@ struct e1000_mac_info { u16 ifs_ratio; u16 ifs_step_size; u16 mta_reg_count; + u16 uta_reg_count; /* Maximum size of the MTA register table in all supported adapters */ #define MAX_MTA_REG 128 @@ -768,6 +787,10 @@ struct e1000_dev_spec_82571 { u32 smb_counter; }; +struct e1000_dev_spec_80003es2lan { + bool mdic_wa_enable; +}; + struct e1000_shadow_ram { u16 value; bool modified; @@ -778,6 +801,9 @@ struct e1000_shadow_ram { struct e1000_dev_spec_ich8lan { bool kmrn_lock_loss_workaround_enabled; struct e1000_shadow_ram shadow_ram[E1000_SHADOW_RAM_WORDS]; + E1000_MUTEX nvm_mutex; + E1000_MUTEX swflag_mutex; + bool nvm_k1_enabled; }; struct e1000_dev_spec_82575 { @@ -810,6 +836,7 @@ struct e1000_hw { struct e1000_dev_spec_82542 _82542; struct e1000_dev_spec_82543 _82543; struct e1000_dev_spec_82571 _82571; + struct e1000_dev_spec_80003es2lan _80003es2lan; struct e1000_dev_spec_ich8lan ich8lan; struct e1000_dev_spec_82575 _82575; struct e1000_dev_spec_vf vf; diff --git a/sys/dev/e1000/e1000_ich8lan.c b/sys/dev/e1000/e1000_ich8lan.c index a80955a..09c08eb 100644 --- a/sys/dev/e1000/e1000_ich8lan.c +++ b/sys/dev/e1000/e1000_ich8lan.c @@ -68,10 +68,12 @@ static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw); static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw); static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw); static void e1000_release_swflag_ich8lan(struct e1000_hw *hw); +static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw); +static void e1000_release_nvm_ich8lan(struct e1000_hw *hw); static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw); static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw); static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw); -static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw); +static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active); static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active); static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, @@ -95,6 +97,7 @@ static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw); static s32 e1000_led_on_ich8lan(struct e1000_hw *hw); static s32 e1000_led_off_ich8lan(struct e1000_hw *hw); +static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link); static s32 e1000_setup_led_pchlan(struct e1000_hw *hw); static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw); static s32 e1000_led_on_pchlan(struct e1000_hw *hw); @@ -103,7 +106,6 @@ static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw); static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank); static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout); static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw); -static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw); static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw); static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw); static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, @@ -120,6 +122,9 @@ static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, u8 size, u16 data); static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw); static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw); +static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw); +static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw); +static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw); /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */ /* Offset 04h HSFSTS */ @@ -179,18 +184,16 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) phy->reset_delay_us = 100; phy->ops.acquire = e1000_acquire_swflag_ich8lan; - phy->ops.check_polarity = e1000_check_polarity_ife; phy->ops.check_reset_block = e1000_check_reset_block_ich8lan; - phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife; - phy->ops.get_cable_length = e1000_get_cable_length_igp_2; phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan; - phy->ops.get_info = e1000_get_phy_info_ich8lan; phy->ops.read_reg = e1000_read_phy_reg_hv; + phy->ops.read_reg_locked = e1000_read_phy_reg_hv_locked; phy->ops.release = e1000_release_swflag_ich8lan; phy->ops.reset = e1000_phy_hw_reset_ich8lan; - phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_ich8lan; - phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_ich8lan; + phy->ops.set_d0_lplu_state = e1000_set_lplu_state_pchlan; + phy->ops.set_d3_lplu_state = e1000_set_lplu_state_pchlan; phy->ops.write_reg = e1000_write_phy_reg_hv; + phy->ops.write_reg_locked = e1000_write_phy_reg_hv_locked; phy->ops.power_up = e1000_power_up_phy_copper; phy->ops.power_down = e1000_power_down_phy_copper_ich8lan; phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; @@ -199,13 +202,23 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) e1000_get_phy_id(hw); phy->type = e1000_get_phy_type_from_id(phy->id); - if (phy->type == e1000_phy_82577) { + switch (phy->type) { + case e1000_phy_82577: phy->ops.check_polarity = e1000_check_polarity_82577; phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_82577; - phy->ops.get_cable_length = e1000_get_cable_length_82577; + phy->ops.get_cable_length = e1000_get_cable_length_82577; phy->ops.get_info = e1000_get_phy_info_82577; phy->ops.commit = e1000_phy_sw_reset_generic; + case e1000_phy_82578: + phy->ops.check_polarity = e1000_check_polarity_m88; + phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88; + phy->ops.get_cable_length = e1000_get_cable_length_m88; + phy->ops.get_info = e1000_get_phy_info_m88; + break; + default: + ret_val = -E1000_ERR_PHY; + break; } return ret_val; @@ -229,12 +242,9 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) phy->reset_delay_us = 100; phy->ops.acquire = e1000_acquire_swflag_ich8lan; - phy->ops.check_polarity = e1000_check_polarity_ife; phy->ops.check_reset_block = e1000_check_reset_block_ich8lan; - phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife; phy->ops.get_cable_length = e1000_get_cable_length_igp_2; phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan; - phy->ops.get_info = e1000_get_phy_info_ich8lan; phy->ops.read_reg = e1000_read_phy_reg_igp; phy->ops.release = e1000_release_swflag_ich8lan; phy->ops.reset = e1000_phy_hw_reset_ich8lan; @@ -273,12 +283,20 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) case IGP03E1000_E_PHY_ID: phy->type = e1000_phy_igp_3; phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; + phy->ops.read_reg_locked = e1000_read_phy_reg_igp_locked; + phy->ops.write_reg_locked = e1000_write_phy_reg_igp_locked; + phy->ops.get_info = e1000_get_phy_info_igp; + phy->ops.check_polarity = e1000_check_polarity_igp; + phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp; break; case IFE_E_PHY_ID: case IFE_PLUS_E_PHY_ID: case IFE_C_E_PHY_ID: phy->type = e1000_phy_ife; phy->autoneg_mask = E1000_ALL_NOT_GIG; + phy->ops.get_info = e1000_get_phy_info_ife; + phy->ops.check_polarity = e1000_check_polarity_ife; + phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife; break; case BME1000_E_PHY_ID: phy->type = e1000_phy_bm; @@ -286,6 +304,9 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) phy->ops.read_reg = e1000_read_phy_reg_bm; phy->ops.write_reg = e1000_write_phy_reg_bm; phy->ops.commit = e1000_phy_sw_reset_generic; + phy->ops.get_info = e1000_get_phy_info_m88; + phy->ops.check_polarity = e1000_check_polarity_m88; + phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88; break; default: ret_val = -E1000_ERR_PHY; @@ -353,10 +374,13 @@ static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw) dev_spec->shadow_ram[i].value = 0xFFFF; } + E1000_MUTEX_INIT(&dev_spec->nvm_mutex); + E1000_MUTEX_INIT(&dev_spec->swflag_mutex); + /* Function Pointers */ - nvm->ops.acquire = e1000_acquire_swflag_ich8lan; + nvm->ops.acquire = e1000_acquire_nvm_ich8lan; + nvm->ops.release = e1000_release_nvm_ich8lan; nvm->ops.read = e1000_read_nvm_ich8lan; - nvm->ops.release = e1000_release_swflag_ich8lan; nvm->ops.update = e1000_update_nvm_checksum_ich8lan; nvm->ops.valid_led_default = e1000_valid_led_default_ich8lan; nvm->ops.validate = e1000_validate_nvm_checksum_ich8lan; @@ -393,6 +417,8 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw) mac->asf_firmware_present = TRUE; /* Set if manageability features are enabled. */ mac->arc_subsystem_valid = TRUE; + /* Adaptive IFS supported */ + mac->adaptive_ifs = TRUE; /* Function pointers */ @@ -409,7 +435,7 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw) /* physical interface setup */ mac->ops.setup_physical_interface = e1000_setup_copper_link_ich8lan; /* check for link */ - mac->ops.check_for_link = e1000_check_for_copper_link_generic; + mac->ops.check_for_link = e1000_check_for_copper_link_ich8lan; /* check management mode */ mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan; /* link info */ @@ -460,11 +486,99 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw) if (mac->type == e1000_ich8lan) e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, TRUE); - return E1000_SUCCESS; } /** + * e1000_check_for_copper_link_ich8lan - Check for link (Copper) + * @hw: pointer to the HW structure + * + * Checks to see of the link status of the hardware has changed. If a + * change in link status has been detected, then we read the PHY registers + * to get the current speed/duplex if link exists. + **/ +static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val; + bool link; + + DEBUGFUNC("e1000_check_for_copper_link_ich8lan"); + + /* + * We only want to go out to the PHY registers to see if Auto-Neg + * has completed and/or if our link status has changed. The + * get_link_status flag is set upon receiving a Link Status + * Change or Rx Sequence Error interrupt. + */ + if (!mac->get_link_status) { + ret_val = E1000_SUCCESS; + goto out; + } + + /* + * First we want to see if the MII Status Register reports + * link. If so, then we want to get the current speed/duplex + * of the PHY. + */ + ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); + if (ret_val) + goto out; + + if (hw->mac.type == e1000_pchlan) { + ret_val = e1000_k1_gig_workaround_hv(hw, link); + if (ret_val) + goto out; + } + + if (!link) + goto out; /* No link detected */ + + mac->get_link_status = FALSE; + + if (hw->phy.type == e1000_phy_82578) { + ret_val = e1000_link_stall_workaround_hv(hw); + if (ret_val) + goto out; + } + + /* + * Check if there was DownShift, must be checked + * immediately after link-up + */ + e1000_check_downshift_generic(hw); + + /* + * If we are forcing speed/duplex, then we simply return since + * we have already determined whether we have link or not. + */ + if (!mac->autoneg) { + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + /* + * Auto-Neg is enabled. Auto Speed Detection takes care + * of MAC speed/duplex configuration. So we only need to + * configure Collision Distance in the MAC. + */ + e1000_config_collision_dist_generic(hw); + + /* + * 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"); + +out: + return ret_val; +} + +/** * e1000_init_function_pointers_ich8lan - Initialize ICH8 function pointers * @hw: pointer to the HW structure * @@ -491,12 +605,41 @@ void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw) } /** + * e1000_acquire_nvm_ich8lan - Acquire NVM mutex + * @hw: pointer to the HW structure + * + * Acquires the mutex for performing NVM operations. + **/ +static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw) +{ + DEBUGFUNC("e1000_acquire_nvm_ich8lan"); + + E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.nvm_mutex); + + return E1000_SUCCESS; +} + +/** + * e1000_release_nvm_ich8lan - Release NVM mutex + * @hw: pointer to the HW structure + * + * Releases the mutex used while performing NVM operations. + **/ +static void e1000_release_nvm_ich8lan(struct e1000_hw *hw) +{ + DEBUGFUNC("e1000_release_nvm_ich8lan"); + + E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.nvm_mutex); + + return; +} + +/** * e1000_acquire_swflag_ich8lan - Acquire software control flag * @hw: pointer to the HW structure * - * Acquires the software control flag for performing NVM and PHY - * operations. This is a function pointer entry point only called by - * read/write routines for the PHY and NVM parts. + * Acquires the software control flag for performing PHY and select + * MAC CSR accesses. **/ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) { @@ -505,23 +648,39 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) DEBUGFUNC("e1000_acquire_swflag_ich8lan"); + E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.swflag_mutex); + while (timeout) { extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); + if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)) + break; - if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)) { - extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; - E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); - - extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); - if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) - break; - } msec_delay_irq(1); timeout--; } if (!timeout) { DEBUGOUT("SW/FW/HW has locked the resource for too long.\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + timeout = SW_FLAG_TIMEOUT; + + extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; + E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); + + while (timeout) { + extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); + if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) + break; + + msec_delay_irq(1); + timeout--; + } + + if (!timeout) { + DEBUGOUT("Failed to acquire the semaphore.\n"); extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); ret_val = -E1000_ERR_CONFIG; @@ -529,6 +688,9 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) } out: + if (ret_val) + E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex); + return ret_val; } @@ -536,9 +698,8 @@ out: * e1000_release_swflag_ich8lan - Release software control flag * @hw: pointer to the HW structure * - * Releases the software control flag for performing NVM and PHY operations. - * This is a function pointer entry point only called by read/write - * routines for the PHY and NVM parts. + * Releases the software control flag for performing PHY and select + * MAC CSR accesses. **/ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw) { @@ -550,6 +711,8 @@ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw) extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); + E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex); + return; } @@ -594,6 +757,325 @@ static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw) } /** + * e1000_sw_lcd_config_ich8lan - SW-based LCD Configuration + * @hw: pointer to the HW structure + * + * SW should configure the LCD from the NVM extended configuration region + * as a workaround for certain parts. + **/ +static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask; + s32 ret_val; + u16 word_addr, reg_data, reg_addr, phy_page = 0; + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return ret_val; + + /* + * Initialize the PHY from the NVM on ICH platforms. This + * is needed due to an issue where the NVM configuration is + * not properly autoloaded after power transitions. + * Therefore, after each PHY reset, we will load the + * configuration data out of the NVM manually. + */ + if ((hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) || + (hw->mac.type == e1000_pchlan)) { + /* Check if SW needs to configure the PHY */ + if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_M_AMT) || + (hw->device_id == E1000_DEV_ID_ICH8_IGP_M) || + (hw->mac.type == e1000_pchlan)) + sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M; + else + sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG; + + data = E1000_READ_REG(hw, E1000_FEXTNVM); + if (!(data & sw_cfg_mask)) + goto out; + + /* Wait for basic configuration completes before proceeding */ + e1000_lan_init_done_ich8lan(hw); + + /* + * Make sure HW does not configure LCD from PHY + * extended configuration before SW configuration + */ + data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); + if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE) + goto out; + + cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE); + cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK; + cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT; + if (!cnf_size) + goto out; + + cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK; + cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT; + + if (!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) && + (hw->mac.type == e1000_pchlan)) { + /* + * HW configures the SMBus address and LEDs when the + * OEM and LCD Write Enable bits are set in the NVM. + * When both NVM bits are cleared, SW will configure + * them instead. + */ + data = E1000_READ_REG(hw, E1000_STRAP); + data &= E1000_STRAP_SMBUS_ADDRESS_MASK; + reg_data = data >> E1000_STRAP_SMBUS_ADDRESS_SHIFT; + reg_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID; + ret_val = e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR, + reg_data); + if (ret_val) + goto out; + + data = E1000_READ_REG(hw, E1000_LEDCTL); + ret_val = e1000_write_phy_reg_hv_locked(hw, + HV_LED_CONFIG, + (u16)data); + if (ret_val) + goto out; + } + + /* Configure LCD from extended configuration region. */ + + /* cnf_base_addr is in DWORD */ + word_addr = (u16)(cnf_base_addr << 1); + + for (i = 0; i < cnf_size; i++) { + ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2), 1, + ®_data); + if (ret_val) + goto out; + + ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2 + 1), + 1, ®_addr); + if (ret_val) + goto out; + + /* Save off the PHY page for future writes. */ + if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) { + phy_page = reg_data; + continue; + } + + reg_addr &= PHY_REG_MASK; + reg_addr |= phy_page; + + ret_val = phy->ops.write_reg_locked(hw, (u32)reg_addr, + reg_data); + if (ret_val) + goto out; + } + } + +out: + hw->phy.ops.release(hw); + return ret_val; +} + +/** + * e1000_k1_gig_workaround_hv - K1 Si workaround + * @hw: pointer to the HW structure + * @link: link up bool flag + * + * If K1 is enabled for 1Gbps, the MAC might stall when transitioning + * from a lower speed. This workaround disables K1 whenever link is at 1Gig + * If link is down, the function will restore the default K1 setting located + * in the NVM. + **/ +static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link) +{ + s32 ret_val = E1000_SUCCESS; + u16 status_reg = 0; + bool k1_enable = hw->dev_spec.ich8lan.nvm_k1_enabled; + + DEBUGFUNC("e1000_k1_gig_workaround_hv"); + + if (hw->mac.type != e1000_pchlan) + goto out; + + /* Wrap the whole flow with the sw flag */ + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + + /* Disable K1 when link is 1Gbps, otherwise use the NVM setting */ + if (link) { + if (hw->phy.type == e1000_phy_82578) { + ret_val = hw->phy.ops.read_reg_locked(hw, BM_CS_STATUS, + &status_reg); + if (ret_val) + goto release; + + status_reg &= BM_CS_STATUS_LINK_UP | + BM_CS_STATUS_RESOLVED | + BM_CS_STATUS_SPEED_MASK; + + if (status_reg == (BM_CS_STATUS_LINK_UP | + BM_CS_STATUS_RESOLVED | + BM_CS_STATUS_SPEED_1000)) + k1_enable = FALSE; + } + + if (hw->phy.type == e1000_phy_82577) { + ret_val = hw->phy.ops.read_reg_locked(hw, HV_M_STATUS, + &status_reg); + if (ret_val) + goto release; + + status_reg &= HV_M_STATUS_LINK_UP | + HV_M_STATUS_AUTONEG_COMPLETE | + HV_M_STATUS_SPEED_MASK; + + if (status_reg == (HV_M_STATUS_LINK_UP | + HV_M_STATUS_AUTONEG_COMPLETE | + HV_M_STATUS_SPEED_1000)) + k1_enable = FALSE; + } + + /* Link stall fix for link up */ + ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19), + 0x0100); + if (ret_val) + goto release; + + } else { + /* Link stall fix for link down */ + ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19), + 0x4100); + if (ret_val) + goto release; + } + + ret_val = e1000_configure_k1_ich8lan(hw, k1_enable); + +release: + hw->phy.ops.release(hw); +out: + return ret_val; +} + +/** + * e1000_configure_k1_ich8lan - Configure K1 power state + * @hw: pointer to the HW structure + * @enable: K1 state to configure + * + * Configure the K1 power state based on the provided parameter. + * Assumes semaphore already acquired. + * + * Success returns 0, Failure returns -E1000_ERR_PHY (-2) + **/ +s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable) +{ + s32 ret_val = E1000_SUCCESS; + u32 ctrl_reg = 0; + u32 ctrl_ext = 0; + u32 reg = 0; + u16 kmrn_reg = 0; + + ret_val = e1000_read_kmrn_reg_locked(hw, + E1000_KMRNCTRLSTA_K1_CONFIG, + &kmrn_reg); + if (ret_val) + goto out; + + if (k1_enable) + kmrn_reg |= E1000_KMRNCTRLSTA_K1_ENABLE; + else + kmrn_reg &= ~E1000_KMRNCTRLSTA_K1_ENABLE; + + ret_val = e1000_write_kmrn_reg_locked(hw, + E1000_KMRNCTRLSTA_K1_CONFIG, + kmrn_reg); + if (ret_val) + goto out; + + usec_delay(20); + ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); + ctrl_reg = E1000_READ_REG(hw, E1000_CTRL); + + reg = ctrl_reg & ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); + reg |= E1000_CTRL_FRCSPD; + E1000_WRITE_REG(hw, E1000_CTRL, reg); + + E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_SPD_BYPS); + usec_delay(20); + E1000_WRITE_REG(hw, E1000_CTRL, ctrl_reg); + E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); + usec_delay(20); + +out: + return ret_val; +} + +/** + * e1000_oem_bits_config_ich8lan - SW-based LCD Configuration + * @hw: pointer to the HW structure + * @d0_state: boolean if entering d0 or d3 device state + * + * SW will configure Gbe Disable and LPLU based on the NVM. The four bits are + * collectively called OEM bits. The OEM Write Enable bit and SW Config bit + * in NVM determines whether HW should configure LPLU and Gbe Disable. + **/ +s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state) +{ + s32 ret_val = 0; + u32 mac_reg; + u16 oem_reg; + + if (hw->mac.type != e1000_pchlan) + return ret_val; + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return ret_val; + + mac_reg = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); + if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) + goto out; + + mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM); + if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M)) + goto out; + + mac_reg = E1000_READ_REG(hw, E1000_PHY_CTRL); + + ret_val = hw->phy.ops.read_reg_locked(hw, HV_OEM_BITS, &oem_reg); + if (ret_val) + goto out; + + oem_reg &= ~(HV_OEM_BITS_GBE_DIS | HV_OEM_BITS_LPLU); + + if (d0_state) { + if (mac_reg & E1000_PHY_CTRL_GBE_DISABLE) + oem_reg |= HV_OEM_BITS_GBE_DIS; + + if (mac_reg & E1000_PHY_CTRL_D0A_LPLU) + oem_reg |= HV_OEM_BITS_LPLU; + } else { + if (mac_reg & E1000_PHY_CTRL_NOND0A_GBE_DISABLE) + oem_reg |= HV_OEM_BITS_GBE_DIS; + + if (mac_reg & E1000_PHY_CTRL_NOND0A_LPLU) + oem_reg |= HV_OEM_BITS_LPLU; + } + /* Restart auto-neg to activate the bits */ + if (!hw->phy.ops.check_reset_block(hw)) + oem_reg |= HV_OEM_BITS_RESTART_AN; + ret_val = hw->phy.ops.write_reg_locked(hw, HV_OEM_BITS, oem_reg); + +out: + hw->phy.ops.release(hw); + + return ret_val; +} + + +/** * e1000_hv_phy_powerdown_workaround_ich8lan - Power down workaround on Sx * @hw: pointer to the HW structure **/ @@ -614,7 +1096,7 @@ static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw) s32 ret_val = E1000_SUCCESS; if (hw->mac.type != e1000_pchlan) - return ret_val; + goto out; /* Hanksville M Phy init for IEEE. */ if ((hw->revision_id == 2) && @@ -648,12 +1130,12 @@ static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw) /* Disable generation of early preamble */ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 25), 0x4431); if (ret_val) - return ret_val; + goto out; /* Preamble tuning for SSC */ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(770, 16), 0xA204); if (ret_val) - return ret_val; + goto out; } if (hw->phy.type == e1000_phy_82578) { @@ -662,13 +1144,13 @@ static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw) ret_val = hw->phy.ops.write_reg(hw, (1 << 6) | 0x29, 0x66C0); if (ret_val) - return ret_val; + goto out; /* PHY config */ ret_val = hw->phy.ops.write_reg(hw, (1 << 6) | 0x1E, 0xFFFF); if (ret_val) - return ret_val; + goto out; } /* @@ -691,20 +1173,30 @@ static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw) */ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(768, 25), 0x0400); if (ret_val) - return ret_val; + goto out; ret_val = hw->phy.ops.write_reg(hw, PHY_REG(768, 25), 0x0400); if (ret_val) - return ret_val; + goto out; } /* Select page 0 */ ret_val = hw->phy.ops.acquire(hw); if (ret_val) - return ret_val; + goto out; + hw->phy.addr = 1; - e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0); + ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0); + if (ret_val) + goto out; hw->phy.ops.release(hw); + /* + * Configure the K1 Si workaround during phy reset assuming there is + * link so that it disables K1 if link is in 1Gbps. + */ + ret_val = e1000_k1_gig_workaround_hv(hw, TRUE); + +out: return ret_val; } @@ -752,10 +1244,8 @@ static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw) **/ static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw) { - struct e1000_phy_info *phy = &hw->phy; - u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask; - s32 ret_val; - u16 word_addr, reg_data, reg_addr, phy_page = 0; + s32 ret_val = E1000_SUCCESS; + u16 reg; DEBUGFUNC("e1000_phy_hw_reset_ich8lan"); @@ -772,162 +1262,52 @@ static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw) goto out; } - /* - * Initialize the PHY from the NVM on ICH platforms. This - * is needed due to an issue where the NVM configuration is - * not properly autoloaded after power transitions. - * Therefore, after each PHY reset, we will load the - * configuration data out of the NVM manually. - */ - if (hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) { - /* Check if SW needs configure the PHY */ - if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_M_AMT) || - (hw->device_id == E1000_DEV_ID_ICH8_IGP_M)) - sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M; - else - sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG; - - data = E1000_READ_REG(hw, E1000_FEXTNVM); - if (!(data & sw_cfg_mask)) - goto out; - - /* Wait for basic configuration completes before proceeding */ - e1000_lan_init_done_ich8lan(hw); - - /* - * Make sure HW does not configure LCD from PHY - * extended configuration before SW configuration - */ - data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); - if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE) - goto out; - - cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE); - cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK; - cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT; - if (!cnf_size) - goto out; - - cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK; - cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT; - - /* Configure LCD from extended configuration region. */ - - /* cnf_base_addr is in DWORD */ - word_addr = (u16)(cnf_base_addr << 1); - - for (i = 0; i < cnf_size; i++) { - ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2), 1, - ®_data); - if (ret_val) - goto out; - - ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2 + 1), - 1, ®_addr); - if (ret_val) - goto out; - - /* Save off the PHY page for future writes. */ - if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) { - phy_page = reg_data; - continue; - } + /* Dummy read to clear the phy wakeup bit after lcd reset */ + if (hw->mac.type == e1000_pchlan) + hw->phy.ops.read_reg(hw, BM_WUC, ®); - reg_addr |= phy_page; + /* Configure the LCD with the extended configuration region in NVM */ + ret_val = e1000_sw_lcd_config_ich8lan(hw); + if (ret_val) + goto out; - ret_val = phy->ops.write_reg(hw, (u32)reg_addr, reg_data); - if (ret_val) - goto out; - } - } + /* Configure the LCD with the OEM bits in NVM */ + if (hw->mac.type == e1000_pchlan) + ret_val = e1000_oem_bits_config_ich8lan(hw, TRUE); out: return ret_val; } /** - * e1000_get_phy_info_ich8lan - Calls appropriate PHY type get_phy_info - * @hw: pointer to the HW structure - * - * Wrapper for calling the get_phy_info routines for the appropriate phy type. - **/ -static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw) -{ - s32 ret_val = -E1000_ERR_PHY_TYPE; - - DEBUGFUNC("e1000_get_phy_info_ich8lan"); - - switch (hw->phy.type) { - case e1000_phy_ife: - ret_val = e1000_get_phy_info_ife_ich8lan(hw); - break; - case e1000_phy_igp_3: - case e1000_phy_bm: - case e1000_phy_82578: - case e1000_phy_82577: - ret_val = e1000_get_phy_info_igp(hw); - break; - default: - break; - } - - return ret_val; -} - -/** - * e1000_get_phy_info_ife_ich8lan - Retrieves various IFE PHY states + * e1000_set_lplu_state_pchlan - Set Low Power Link Up state * @hw: pointer to the HW structure + * @active: TRUE to enable LPLU, FALSE to disable * - * Populates "phy" structure with various feature states. - * This function is only called by other family-specific - * routines. + * Sets the LPLU state according to the active flag. For PCH, if OEM write + * bit are disabled in the NVM, writing the LPLU bits in the MAC will not set + * the phy speed. This function will manually set the LPLU bit and restart + * auto-neg as hw would do. D3 and D0 LPLU will call the same function + * since it configures the same bit. **/ -static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw) +static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active) { - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 data; - bool link; - - DEBUGFUNC("e1000_get_phy_info_ife_ich8lan"); - - ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); - if (ret_val) - goto out; - - if (!link) { - DEBUGOUT("Phy info is only valid if link is up\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - ret_val = phy->ops.read_reg(hw, IFE_PHY_SPECIAL_CONTROL, &data); - if (ret_val) - goto out; - phy->polarity_correction = (data & IFE_PSC_AUTO_POLARITY_DISABLE) - ? FALSE : TRUE; + s32 ret_val = E1000_SUCCESS; + u16 oem_reg; - if (phy->polarity_correction) { - ret_val = e1000_check_polarity_ife(hw); - if (ret_val) - goto out; - } else { - /* Polarity is forced */ - phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY) - ? e1000_rev_polarity_reversed - : e1000_rev_polarity_normal; - } + DEBUGFUNC("e1000_set_lplu_state_pchlan"); - ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data); + ret_val = hw->phy.ops.read_reg(hw, HV_OEM_BITS, &oem_reg); if (ret_val) goto out; - phy->is_mdix = (data & IFE_PMC_MDIX_STATUS) ? TRUE : FALSE; + if (active) + oem_reg |= HV_OEM_BITS_LPLU; + else + oem_reg &= ~HV_OEM_BITS_LPLU; - /* The following parameters are undefined for 10/100 operation. */ - phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; - phy->local_rx = e1000_1000t_rx_status_undefined; - phy->remote_rx = e1000_1000t_rx_status_undefined; + oem_reg |= HV_OEM_BITS_RESTART_AN; + ret_val = hw->phy.ops.write_reg(hw, HV_OEM_BITS, oem_reg); out: return ret_val; @@ -1170,7 +1550,7 @@ static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank) if (ret_val) goto out; if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == - E1000_ICH_NVM_SIG_VALUE) { + E1000_ICH_NVM_SIG_VALUE) { *bank = 0; goto out; } @@ -1178,11 +1558,11 @@ static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank) /* Check bank 1 */ ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset + bank1_offset, - &sig_byte); + &sig_byte); if (ret_val) goto out; if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == - E1000_ICH_NVM_SIG_VALUE) { + E1000_ICH_NVM_SIG_VALUE) { *bank = 1; goto out; } @@ -1223,17 +1603,18 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, goto out; } - ret_val = nvm->ops.acquire(hw); - if (ret_val) - goto out; + nvm->ops.acquire(hw); ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); - if (ret_val != E1000_SUCCESS) - goto release; + if (ret_val != E1000_SUCCESS) { + DEBUGOUT("Could not detect valid bank, assuming bank 0\n"); + bank = 0; + } act_offset = (bank) ? nvm->flash_bank_size : 0; act_offset += offset; + ret_val = E1000_SUCCESS; for (i = 0; i < words; i++) { if ((dev_spec->shadow_ram) && (dev_spec->shadow_ram[offset+i].modified)) { @@ -1248,7 +1629,6 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, } } -release: nvm->ops.release(hw); out: @@ -1534,9 +1914,7 @@ static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, goto out; } - ret_val = nvm->ops.acquire(hw); - if (ret_val) - goto out; + nvm->ops.acquire(hw); for (i = 0; i < words; i++) { dev_spec->shadow_ram[offset+i].modified = TRUE; @@ -1577,9 +1955,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) if (nvm->type != e1000_nvm_flash_sw) goto out; - ret_val = nvm->ops.acquire(hw); - if (ret_val) - goto out; + nvm->ops.acquire(hw); /* * We're writing to the opposite bank so if we're on bank 1, @@ -1588,8 +1964,8 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) */ ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); if (ret_val != E1000_SUCCESS) { - nvm->ops.release(hw); - goto out; + DEBUGOUT("Could not detect valid bank, assuming bank 0\n"); + bank = 0; } if (bank == 0) { @@ -1678,6 +2054,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) nvm->ops.release(hw); goto out; } + data &= 0xBFFF; ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset * 2 + 1, @@ -1829,10 +2206,10 @@ static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, * try...ICH_FLASH_CYCLE_REPEAT_COUNT times. */ hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); - if (hsfsts.hsf_status.flcerr == 1) { + if (hsfsts.hsf_status.flcerr == 1) /* Repeat for some time before giving up. */ continue; - } else if (hsfsts.hsf_status.flcdone == 0) { + if (hsfsts.hsf_status.flcdone == 0) { DEBUGOUT("Timeout error - flash cycle " "did not complete."); break; @@ -1960,7 +2337,7 @@ static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank) /* Start with the base address, then add the sector offset. */ flash_linear_addr = hw->nvm.flash_base_addr; - flash_linear_addr += (bank) ? (sector_size * iteration) : 0; + flash_linear_addr += (bank) ? flash_bank_size : 0; for (j = 0; j < iteration ; j++) { do { @@ -2153,6 +2530,8 @@ static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw) **/ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) { + struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; + u16 reg; u32 ctrl, icr, kab; s32 ret_val; @@ -2188,6 +2567,18 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) E1000_WRITE_REG(hw, E1000_PBS, E1000_PBS_16K); } + if (hw->mac.type == e1000_pchlan) { + /* Save the NVM K1 bit setting*/ + ret_val = e1000_read_nvm(hw, E1000_NVM_K1_CONFIG, 1, ®); + if (ret_val) + return ret_val; + + if (reg & E1000_NVM_K1_ENABLE) + dev_spec->nvm_k1_enabled = TRUE; + else + dev_spec->nvm_k1_enabled = FALSE; + } + ctrl = E1000_READ_REG(hw, E1000_CTRL); if (!hw->phy.ops.check_reset_block(hw) && !hw->phy.reset_disable) { @@ -2229,6 +2620,26 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) DEBUGOUT("Auto Read Done did not complete\n"); } } + /* Dummy read to clear the phy wakeup bit after lcd reset */ + if (hw->mac.type == e1000_pchlan) + hw->phy.ops.read_reg(hw, BM_WUC, ®); + + ret_val = e1000_sw_lcd_config_ich8lan(hw); + if (ret_val) + goto out; + + if (hw->mac.type == e1000_pchlan) { + ret_val = e1000_oem_bits_config_ich8lan(hw, TRUE); + if (ret_val) + goto out; + } + /* + * For PCH, this write will make sure that any noise + * will be detected as a CRC error and be dropped rather than show up + * as a bad packet to the DMA engine. + */ + if (hw->mac.type == e1000_pchlan) + E1000_WRITE_REG(hw, E1000_CRC_OFFSET, 0x65656565); E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); icr = E1000_READ_REG(hw, E1000_ICR); @@ -2240,6 +2651,7 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) if (hw->mac.type == e1000_pchlan) ret_val = e1000_hv_phy_workarounds_ich8lan(hw); +out: return ret_val; } @@ -2269,8 +2681,8 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw) /* Initialize identification LED */ ret_val = mac->ops.id_led_init(hw); if (ret_val) - /* This is not fatal and we should not stop init due to this */ DEBUGOUT("Error initializing identification LED\n"); + /* This is not fatal and we should not stop init due to this */ /* Setup the receive address. */ e1000_init_rx_addrs_generic(hw, mac->rar_entry_count); @@ -2316,7 +2728,7 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw) if (mac->type == e1000_ich8lan) snoop = PCIE_ICH8_SNOOP_ALL; else - snoop = (u32)~(PCIE_NO_SNOOP_ALL); + snoop = (u32) ~(PCIE_NO_SNOOP_ALL); e1000_set_pcie_no_snoop_generic(hw, snoop); ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); @@ -2473,8 +2885,7 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw) * and increase the max iterations when polling the phy; * this fixes erroneous timeouts at 10Mbps. */ - ret_val = e1000_write_kmrn_reg_generic(hw, - E1000_KMRNCTRLSTA_TIMEOUTS, + ret_val = e1000_write_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_TIMEOUTS, 0xFFFF); if (ret_val) goto out; @@ -2788,6 +3199,7 @@ void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw) u32 phy_ctrl; switch (hw->mac.type) { + case e1000_ich8lan: case e1000_ich9lan: case e1000_ich10lan: case e1000_pchlan: @@ -2796,9 +3208,8 @@ void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw) E1000_PHY_CTRL_GBE_DISABLE; E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); - /* Workaround SWFLAG unexpectedly set during S0->Sx */ if (hw->mac.type == e1000_pchlan) - usec_delay(500); + e1000_phy_hw_reset_ich8lan(hw); default: break; } @@ -2982,18 +3393,17 @@ static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw) if (hw->mac.type >= e1000_pchlan) { u32 status = E1000_READ_REG(hw, E1000_STATUS); - if (status & E1000_STATUS_PHYRA) { + if (status & E1000_STATUS_PHYRA) E1000_WRITE_REG(hw, E1000_STATUS, status & ~E1000_STATUS_PHYRA); - } else + else DEBUGOUT("PHY Reset Asserted not set - needs delay\n"); } e1000_get_cfg_done_generic(hw); /* If EEPROM is not marked present, init the IGP 3 PHY manually */ - if ((hw->mac.type != e1000_ich10lan) && - (hw->mac.type != e1000_pchlan)) { + if (hw->mac.type <= e1000_ich9lan) { if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) && (hw->phy.type == e1000_phy_igp_3)) { e1000_phy_init_script_igp3(hw); diff --git a/sys/dev/e1000/e1000_ich8lan.h b/sys/dev/e1000/e1000_ich8lan.h index 5416eeb..33398c4 100644 --- a/sys/dev/e1000/e1000_ich8lan.h +++ b/sys/dev/e1000/e1000_ich8lan.h @@ -140,6 +140,31 @@ #define HV_TNCRS_UPPER PHY_REG(778, 29) /* Transmit with no CRS */ #define HV_TNCRS_LOWER PHY_REG(778, 30) +#define E1000_FCRTV_PCH 0x05F40 /* PCH Flow Control Refresh Timer Value */ + +#define E1000_NVM_K1_CONFIG 0x1B /* NVM K1 Config Word */ +#define E1000_NVM_K1_ENABLE 0x1 /* NVM Enable K1 bit */ + +/* SMBus Address Phy Register */ +#define HV_SMB_ADDR PHY_REG(768, 26) +#define HV_SMB_ADDR_PEC_EN 0x0200 +#define HV_SMB_ADDR_VALID 0x0080 + +/* Strapping Option Register - RO */ +#define E1000_STRAP 0x0000C +#define E1000_STRAP_SMBUS_ADDRESS_MASK 0x00FE0000 +#define E1000_STRAP_SMBUS_ADDRESS_SHIFT 17 + +/* OEM Bits Phy Register */ +#define HV_OEM_BITS PHY_REG(768, 25) +#define HV_OEM_BITS_LPLU 0x0004 /* Low Power Link Up */ +#define HV_OEM_BITS_GBE_DIS 0x0040 /* Gigabit Disable */ +#define HV_OEM_BITS_RESTART_AN 0x0400 /* Restart Auto-negotiation */ + +#define LCD_CFG_PHY_ADDR_BIT 0x0020 /* Phy address bit from LCD Config word */ + +#define SW_FLAG_TIMEOUT 1000 /* SW Semaphore flag timeout in milliseconds */ + /* * Additional interrupts need to be handled for ICH family: * DSW = The FW changed the status of the DISSW bit in FWSM @@ -169,6 +194,7 @@ void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw); void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw); void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw); +s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable); +s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_config); s32 e1000_hv_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw); - #endif diff --git a/sys/dev/e1000/e1000_mac.c b/sys/dev/e1000/e1000_mac.c index db6e5f52..f311565 100644 --- a/sys/dev/e1000/e1000_mac.c +++ b/sys/dev/e1000/e1000_mac.c @@ -230,7 +230,6 @@ s32 e1000_get_bus_info_pcie_generic(struct e1000_hw *hw) { struct e1000_mac_info *mac = &hw->mac; struct e1000_bus_info *bus = &hw->bus; - s32 ret_val; u16 pcie_link_status; @@ -408,6 +407,11 @@ s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw) if (hw->bus.func == E1000_FUNC_1) nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1; + if (hw->bus.func == E1000_FUNC_2) + nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN2; + + if (hw->bus.func == E1000_FUNC_3) + nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN3; for (i = 0; i < ETH_ADDR_LEN; i += 2) { offset = nvm_alt_mac_addr_offset + (i >> 1); ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data); @@ -750,12 +754,6 @@ s32 e1000_check_for_copper_link_generic(struct e1000_hw *hw) mac->get_link_status = FALSE; - if (hw->phy.type == e1000_phy_82578) { - ret_val = e1000_link_stall_workaround_hv(hw); - if (ret_val) - goto out; - } - /* * Check if there was DownShift, must be checked * immediately after link-up @@ -994,9 +992,8 @@ s32 e1000_setup_link_generic(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 (hw->phy.ops.check_reset_block) - if (hw->phy.ops.check_reset_block(hw)) - goto out; + if (e1000_check_reset_block(hw)) + goto out; /* * If requested flow control is set to default, set flow control @@ -1512,7 +1509,7 @@ s32 e1000_config_fc_after_link_up_generic(struct e1000_hw *hw) /* * 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 + * 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. */ @@ -2033,7 +2030,7 @@ out: * e1000_disable_pcie_master_generic - Disables PCI-express master access * @hw: pointer to the HW structure * - * Returns 0 (E1000_SUCCESS) if successful, else returns -10 + * Returns E1000_SUCCESS if successful, else returns -10 * (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused * the master requests to be disabled. * @@ -2151,7 +2148,7 @@ out: * Verify that when not using auto-negotiation that MDI/MDIx is correctly * set, which is forced to MDI mode only. **/ -s32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw) +static s32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw) { s32 ret_val = E1000_SUCCESS; diff --git a/sys/dev/e1000/e1000_manage.c b/sys/dev/e1000/e1000_manage.c index b1f6541..aa0a0d4 100644 --- a/sys/dev/e1000/e1000_manage.c +++ b/sys/dev/e1000/e1000_manage.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2008, Intel Corporation + Copyright (c) 2001-2009, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -123,7 +123,7 @@ bool e1000_check_mng_mode_generic(struct e1000_hw *hw) } /** - * e1000_enable_tx_pkt_filtering_generic - Enable packet filtering on TX + * e1000_enable_tx_pkt_filtering_generic - Enable packet filtering on Tx * @hw: pointer to the HW structure * * Enables packet filtering on transmit packets if manageability is enabled @@ -159,11 +159,9 @@ bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw) /* Read in the header. Length and offset are in dwords. */ len = E1000_MNG_DHCP_COOKIE_LENGTH >> 2; offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2; - for (i = 0; i < len; i++) { - *(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw, - E1000_HOST_IF, + for (i = 0; i < len; i++) + *(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i); - } hdr_csum = hdr->checksum; hdr->checksum = 0; csum = e1000_calculate_checksum((u8 *)hdr, diff --git a/sys/dev/e1000/e1000_osdep.h b/sys/dev/e1000/e1000_osdep.h index b478f29..fcfe8f5 100644 --- a/sys/dev/e1000/e1000_osdep.h +++ b/sys/dev/e1000/e1000_osdep.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2008, Intel Corporation + Copyright (c) 2001-2009, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -39,6 +39,8 @@ #include <sys/types.h> #include <sys/param.h> #include <sys/systm.h> +#include <sys/lock.h> +#include <sys/mutex.h> #include <sys/mbuf.h> #include <sys/protosw.h> #include <sys/socket.h> @@ -57,10 +59,8 @@ #define ASSERT(x) if(!(x)) panic("EM: x") -/* The happy-fun DELAY macro is defined in /usr/src/sys/i386/include/clock.h */ #define usec_delay(x) DELAY(x) #define msec_delay(x) DELAY(1000*(x)) -/* TODO: Should we be paranoid about delaying in interrupt context? */ #define msec_delay_irq(x) DELAY(1000*(x)) #define MSGOUT(S, A, B) printf(S "\n", A, B) @@ -73,16 +73,22 @@ #define STATIC static #define FALSE 0 -#define false FALSE /* shared code stupidity */ +#define false FALSE #define TRUE 1 #define true TRUE #define CMD_MEM_WRT_INVALIDATE 0x0010 /* BIT_4 */ #define PCI_COMMAND_REGISTER PCIR_COMMAND -/* -** These typedefs are necessary due to the new -** shared code, they are native to Linux. -*/ +/* Mutex used in the shared code */ +#define E1000_MUTEX struct mtx +#define E1000_MUTEX_INIT(mutex) mtx_init((mutex), #mutex, \ + MTX_NETWORK_LOCK, \ + MTX_DEF | MTX_SPIN) +#define E1000_MUTEX_DESTROY(mutex) mtx_destroy(mutex) +#define E1000_MUTEX_LOCK(mutex) mtx_lock(mutex) +#define E1000_MUTEX_TRYLOCK(mutex) mtx_trylock(mutex) +#define E1000_MUTEX_UNLOCK(mutex) mtx_unlock(mutex) + typedef uint64_t u64; typedef uint32_t u32; typedef uint16_t u16; @@ -97,6 +103,28 @@ typedef boolean_t bool; #define __le32 u32 #define __le64 u64 +#if __FreeBSD_version < 800000 /* Now in HEAD */ +#if defined(__i386__) || defined(__amd64__) +#define mb() __asm volatile("mfence" ::: "memory") +#define wmb() __asm volatile("sfence" ::: "memory") +#define rmb() __asm volatile("lfence" ::: "memory") +#else +#define mb() +#define rmb() +#define wmb() +#endif +#endif /*__FreeBSD_version < 800000 */ + +#if defined(__i386__) || defined(__amd64__) +static __inline +void prefetch(void *x) +{ + __asm volatile("prefetcht0 %0" :: "m" (*(unsigned long *)x)); +} +#else +#define prefetch(x) +#endif + struct e1000_osdep { bus_space_tag_t mem_bus_space_tag; diff --git a/sys/dev/e1000/e1000_phy.c b/sys/dev/e1000/e1000_phy.c index 513f2e6..51504e2 100644 --- a/sys/dev/e1000/e1000_phy.c +++ b/sys/dev/e1000/e1000_phy.c @@ -83,11 +83,13 @@ void e1000_init_phy_ops_generic(struct e1000_hw *hw) phy->ops.get_cable_length = e1000_null_ops_generic; phy->ops.get_info = e1000_null_ops_generic; phy->ops.read_reg = e1000_null_read_reg; + phy->ops.read_reg_locked = e1000_null_read_reg; phy->ops.release = e1000_null_phy_generic; phy->ops.reset = e1000_null_ops_generic; phy->ops.set_d0_lplu_state = e1000_null_lplu_state; phy->ops.set_d3_lplu_state = e1000_null_lplu_state; phy->ops.write_reg = e1000_null_write_reg; + phy->ops.write_reg_locked = e1000_null_write_reg; phy->ops.power_up = e1000_null_phy_generic; phy->ops.power_down = e1000_null_phy_generic; phy->ops.cfg_on_link_up = e1000_null_ops_generic; @@ -190,20 +192,30 @@ s32 e1000_get_phy_id(struct e1000_hw *hw) goto out; /* - * If the PHY ID is still unknown, we may have an 82577 without link. - * We will try again after setting Slow MDIC mode. No harm in trying - * again in this case since the PHY ID is unknown at this point anyway + * If the PHY ID is still unknown, we may have an 82577 + * without link. We will try again after setting Slow MDIC + * mode. No harm in trying again in this case since the PHY + * ID is unknown at this point anyway. */ + ret_val = phy->ops.acquire(hw); + if (ret_val) + goto out; ret_val = e1000_set_mdio_slow_mode_hv(hw, TRUE); if (ret_val) goto out; + phy->ops.release(hw); retry_count++; } out: /* Revert to MDIO fast mode, if applicable */ - if (retry_count) + if (retry_count) { + ret_val = phy->ops.acquire(hw); + if (ret_val) + return ret_val; ret_val = e1000_set_mdio_slow_mode_hv(hw, FALSE); + phy->ops.release(hw); + } return ret_val; } @@ -351,6 +363,105 @@ out: } /** + * e1000_read_phy_reg_i2c - Read PHY register using i2c + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Reads the PHY register at offset using the i2c interface and stores the + * retrieved information in data. + **/ +s32 e1000_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data) +{ + struct e1000_phy_info *phy = &hw->phy; + u32 i, i2ccmd = 0; + + DEBUGFUNC("e1000_read_phy_reg_i2c"); + + /* + * Set up Op-code, Phy Address, and register address in the I2CCMD + * register. The MAC will take care of interfacing with the + * PHY to retrieve the desired data. + */ + i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) | + (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) | + (E1000_I2CCMD_OPCODE_READ)); + + E1000_WRITE_REG(hw, E1000_I2CCMD, i2ccmd); + + /* Poll the ready bit to see if the I2C read completed */ + for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) { + usec_delay(50); + i2ccmd = E1000_READ_REG(hw, E1000_I2CCMD); + if (i2ccmd & E1000_I2CCMD_READY) + break; + } + if (!(i2ccmd & E1000_I2CCMD_READY)) { + DEBUGOUT("I2CCMD Read did not complete\n"); + return -E1000_ERR_PHY; + } + if (i2ccmd & E1000_I2CCMD_ERROR) { + DEBUGOUT("I2CCMD Error bit set\n"); + return -E1000_ERR_PHY; + } + + /* Need to byte-swap the 16-bit value. */ + *data = ((i2ccmd >> 8) & 0x00FF) | ((i2ccmd << 8) & 0xFF00); + + return E1000_SUCCESS; +} + +/** + * e1000_write_phy_reg_i2c - Write PHY register using i2c + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Writes the data to PHY register at the offset using the i2c interface. + **/ +s32 e1000_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data) +{ + struct e1000_phy_info *phy = &hw->phy; + u32 i, i2ccmd = 0; + u16 phy_data_swapped; + + DEBUGFUNC("e1000_write_phy_reg_i2c"); + + /* Swap the data bytes for the I2C interface */ + phy_data_swapped = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00); + + /* + * Set up Op-code, Phy Address, and register address in the I2CCMD + * register. The MAC will take care of interfacing with the + * PHY to retrieve the desired data. + */ + i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) | + (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) | + E1000_I2CCMD_OPCODE_WRITE | + phy_data_swapped); + + E1000_WRITE_REG(hw, E1000_I2CCMD, i2ccmd); + + /* Poll the ready bit to see if the I2C read completed */ + for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) { + usec_delay(50); + i2ccmd = E1000_READ_REG(hw, E1000_I2CCMD); + if (i2ccmd & E1000_I2CCMD_READY) + break; + } + if (!(i2ccmd & E1000_I2CCMD_READY)) { + DEBUGOUT("I2CCMD Write did not complete\n"); + return -E1000_ERR_PHY; + } + if (i2ccmd & E1000_I2CCMD_ERROR) { + DEBUGOUT("I2CCMD Error bit set\n"); + return -E1000_ERR_PHY; + } + + return E1000_SUCCESS; +} + +/** * e1000_read_phy_reg_m88 - Read m88 PHY register * @hw: pointer to the HW structure * @offset: register offset to be read @@ -414,111 +525,179 @@ out: } /** - * e1000_read_phy_reg_igp - Read igp PHY register + * __e1000_read_phy_reg_igp - Read igp PHY register * @hw: pointer to the HW structure * @offset: register offset to be read * @data: pointer to the read data + * @locked: semaphore has already been acquired or not * * Acquires semaphore, if necessary, then reads the PHY register at offset - * and storing the retrieved information in data. Release any acquired + * and stores the retrieved information in data. Release any acquired * semaphores before exiting. **/ -s32 e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data) +static s32 __e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data, + bool locked) { s32 ret_val = E1000_SUCCESS; - DEBUGFUNC("e1000_read_phy_reg_igp"); + DEBUGFUNC("__e1000_read_phy_reg_igp"); - if (!(hw->phy.ops.acquire)) - goto out; + if (!locked) { + if (!(hw->phy.ops.acquire)) + goto out; - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + } if (offset > MAX_PHY_MULTI_PAGE_REG) { ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, (u16)offset); - if (ret_val) { - hw->phy.ops.release(hw); - goto out; - } + if (ret_val) + goto release; } ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, data); - hw->phy.ops.release(hw); - +release: + if (!locked) + hw->phy.ops.release(hw); out: return ret_val; } /** + * e1000_read_phy_reg_igp - Read igp PHY register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Acquires semaphore then reads the PHY register at offset and stores the + * retrieved information in data. + * Release the acquired semaphore before exiting. + **/ +s32 e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data) +{ + return __e1000_read_phy_reg_igp(hw, offset, data, FALSE); +} + +/** + * e1000_read_phy_reg_igp_locked - Read igp PHY register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Reads the PHY register at offset and stores the retrieved information + * in data. Assumes semaphore already acquired. + **/ +s32 e1000_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 *data) +{ + return __e1000_read_phy_reg_igp(hw, offset, data, TRUE); +} + +/** * e1000_write_phy_reg_igp - Write igp PHY register * @hw: pointer to the HW structure * @offset: register offset to write to * @data: data to write at register offset + * @locked: semaphore has already been acquired or not * * Acquires semaphore, if necessary, then writes the data to PHY register * at the offset. Release any acquired semaphores before exiting. **/ -s32 e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data) +static s32 __e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data, + bool locked) { s32 ret_val = E1000_SUCCESS; DEBUGFUNC("e1000_write_phy_reg_igp"); - if (!(hw->phy.ops.acquire)) - goto out; + if (!locked) { + if (!(hw->phy.ops.acquire)) + goto out; - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + } if (offset > MAX_PHY_MULTI_PAGE_REG) { ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, (u16)offset); - if (ret_val) { - hw->phy.ops.release(hw); - goto out; - } + if (ret_val) + goto release; } ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, data); - hw->phy.ops.release(hw); +release: + if (!locked) + hw->phy.ops.release(hw); out: return ret_val; } /** - * e1000_read_kmrn_reg_generic - Read kumeran register + * e1000_write_phy_reg_igp - Write igp PHY register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquires semaphore then writes the data to PHY register + * at the offset. Release any acquired semaphores before exiting. + **/ +s32 e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data) +{ + return __e1000_write_phy_reg_igp(hw, offset, data, FALSE); +} + +/** + * e1000_write_phy_reg_igp_locked - Write igp PHY register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Writes the data to PHY register at the offset. + * Assumes semaphore already acquired. + **/ +s32 e1000_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 data) +{ + return __e1000_write_phy_reg_igp(hw, offset, data, TRUE); +} + +/** + * __e1000_read_kmrn_reg - Read kumeran register * @hw: pointer to the HW structure * @offset: register offset to be read * @data: pointer to the read data + * @locked: semaphore has already been acquired or not * * Acquires semaphore, if necessary. Then reads the PHY register at offset * using the kumeran interface. The information retrieved is stored in data. * Release any acquired semaphores before exiting. **/ -s32 e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data) +static s32 __e1000_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data, + bool locked) { u32 kmrnctrlsta; s32 ret_val = E1000_SUCCESS; - DEBUGFUNC("e1000_read_kmrn_reg_generic"); + DEBUGFUNC("__e1000_read_kmrn_reg"); - if (!(hw->phy.ops.acquire)) - goto out; + if (!locked) { + if (!(hw->phy.ops.acquire)) + goto out; - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + } kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN; @@ -529,48 +708,113 @@ s32 e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data) kmrnctrlsta = E1000_READ_REG(hw, E1000_KMRNCTRLSTA); *data = (u16)kmrnctrlsta; - hw->phy.ops.release(hw); + if (!locked) + hw->phy.ops.release(hw); out: return ret_val; } /** - * e1000_write_kmrn_reg_generic - Write kumeran register + * e1000_read_kmrn_reg_generic - Read kumeran register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Acquires semaphore then reads the PHY register at offset using the + * kumeran interface. The information retrieved is stored in data. + * Release the acquired semaphore before exiting. + **/ +s32 e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data) +{ + return __e1000_read_kmrn_reg(hw, offset, data, FALSE); +} + +/** + * e1000_read_kmrn_reg_locked - Read kumeran register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Reads the PHY register at offset using the kumeran interface. The + * information retrieved is stored in data. + * Assumes semaphore already acquired. + **/ +s32 e1000_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data) +{ + return __e1000_read_kmrn_reg(hw, offset, data, TRUE); +} + +/** + * __e1000_write_kmrn_reg - Write kumeran register * @hw: pointer to the HW structure * @offset: register offset to write to * @data: data to write at register offset + * @locked: semaphore has already been acquired or not * * Acquires semaphore, if necessary. Then write the data to PHY register * at the offset using the kumeran interface. Release any acquired semaphores * before exiting. **/ -s32 e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data) +static s32 __e1000_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data, + bool locked) { u32 kmrnctrlsta; s32 ret_val = E1000_SUCCESS; DEBUGFUNC("e1000_write_kmrn_reg_generic"); - if (!(hw->phy.ops.acquire)) - goto out; + if (!locked) { + if (!(hw->phy.ops.acquire)) + goto out; - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + } kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & E1000_KMRNCTRLSTA_OFFSET) | data; E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta); usec_delay(2); - hw->phy.ops.release(hw); + + if (!locked) + hw->phy.ops.release(hw); out: return ret_val; } /** + * e1000_write_kmrn_reg_generic - Write kumeran register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquires semaphore then writes the data to the PHY register at the offset + * using the kumeran interface. Release the acquired semaphore before exiting. + **/ +s32 e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data) +{ + return __e1000_write_kmrn_reg(hw, offset, data, FALSE); +} + +/** + * e1000_write_kmrn_reg_locked - Write kumeran register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Write the data to PHY register at the offset using the kumeran interface. + * Assumes semaphore already acquired. + **/ +s32 e1000_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data) +{ + return __e1000_write_kmrn_reg(hw, offset, data, TRUE); +} + +/** * e1000_copper_link_setup_82577 - Setup 82577 PHY for copper link * @hw: pointer to the HW structure * @@ -589,6 +833,14 @@ s32 e1000_copper_link_setup_82577(struct e1000_hw *hw) goto out; } + if (phy->type == e1000_phy_82580) { + ret_val = hw->phy.ops.reset(hw); + if (ret_val) { + DEBUGOUT("Error resetting the PHY.\n"); + goto out; + } + } + /* Enable CRS on TX. This must be set for half-duplex operation. */ ret_val = phy->ops.read_reg(hw, I82577_CFG_REG, &phy_data); if (ret_val) @@ -600,15 +852,6 @@ s32 e1000_copper_link_setup_82577(struct e1000_hw *hw) phy_data |= I82577_CFG_ENABLE_DOWNSHIFT; ret_val = phy->ops.write_reg(hw, I82577_CFG_REG, phy_data); - if (ret_val) - goto out; - - /* Set number of link attempts before downshift */ - ret_val = phy->ops.read_reg(hw, I82577_CTRL_REG, &phy_data); - if (ret_val) - goto out; - phy_data &= ~I82577_CTRL_DOWNSHIFT_MASK; - ret_val = phy->ops.write_reg(hw, I82577_CTRL_REG, phy_data); out: return ret_val; @@ -1326,18 +1569,22 @@ s32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw) goto out; if (!link) { - /* - * We didn't get link. - * Reset the DSP and cross our fingers. - */ - ret_val = phy->ops.write_reg(hw, - M88E1000_PHY_PAGE_SELECT, - 0x001d); - if (ret_val) - goto out; - ret_val = e1000_phy_reset_dsp_generic(hw); - if (ret_val) - goto out; + if (hw->phy.type != e1000_phy_m88) { + DEBUGOUT("Link taking longer than expected.\n"); + } else { + /* + * We didn't get link. + * Reset the DSP and cross our fingers. + */ + ret_val = phy->ops.write_reg(hw, + M88E1000_PHY_PAGE_SELECT, + 0x001d); + if (ret_val) + goto out; + ret_val = e1000_phy_reset_dsp_generic(hw); + if (ret_val) + goto out; + } } /* Try once more */ @@ -1347,6 +1594,9 @@ s32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw) goto out; } + if (hw->phy.type != e1000_phy_m88) + goto out; + ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); if (ret_val) goto out; @@ -1393,11 +1643,6 @@ s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw) DEBUGFUNC("e1000_phy_force_speed_duplex_ife"); - if (phy->type != e1000_phy_ife) { - ret_val = e1000_phy_force_speed_duplex_igp(hw); - goto out; - } - ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &data); if (ret_val) goto out; @@ -1625,12 +1870,11 @@ s32 e1000_check_downshift_generic(struct e1000_hw *hw) case e1000_phy_gg82563: case e1000_phy_bm: case e1000_phy_82578: - case e1000_phy_82577: offset = M88E1000_PHY_SPEC_STATUS; mask = M88E1000_PSSR_DOWNSHIFT; break; - case e1000_phy_igp_2: case e1000_phy_igp: + case e1000_phy_igp_2: case e1000_phy_igp_3: offset = IGP01E1000_PHY_LINK_HEALTH; mask = IGP01E1000_PLHR_SS_DOWNGRADE; @@ -1825,16 +2069,14 @@ s32 e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, * it across the board. */ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); - if (ret_val) { + if (ret_val) /* * If the first read fails, another entity may have * ownership of the resources, wait and try again to * see if they have relinquished the resources yet. */ usec_delay(usec_interval); - ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, - &phy_status); - } + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); if (ret_val) break; if (phy_status & MII_SR_LINK_STATUS) @@ -1879,13 +2121,13 @@ s32 e1000_get_cable_length_m88(struct e1000_hw *hw) index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >> M88E1000_PSSR_CABLE_LENGTH_SHIFT; - if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE + 1) { - ret_val = E1000_ERR_PHY; + if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) { + ret_val = -E1000_ERR_PHY; goto out; } phy->min_cable_length = e1000_m88_cable_length_table[index]; - phy->max_cable_length = e1000_m88_cable_length_table[index+1]; + phy->max_cable_length = e1000_m88_cable_length_table[index + 1]; phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; @@ -1986,7 +2228,7 @@ s32 e1000_get_phy_info_m88(struct e1000_hw *hw) DEBUGFUNC("e1000_get_phy_info_m88"); - if (hw->phy.media_type != e1000_media_type_copper) { + if (phy->media_type != e1000_media_type_copper) { DEBUGOUT("Phy info is only valid for copper media\n"); ret_val = -E1000_ERR_CONFIG; goto out; @@ -2088,7 +2330,7 @@ s32 e1000_get_phy_info_igp(struct e1000_hw *hw) if ((data & IGP01E1000_PSSR_SPEED_MASK) == IGP01E1000_PSSR_SPEED_1000MBPS) { - ret_val = hw->phy.ops.get_cable_length(hw); + ret_val = phy->ops.get_cable_length(hw); if (ret_val) goto out; @@ -2114,6 +2356,63 @@ out: } /** + * e1000_get_phy_info_ife - Retrieves various IFE PHY states + * @hw: pointer to the HW structure + * + * Populates "phy" structure with various feature states. + **/ +s32 e1000_get_phy_info_ife(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + bool link; + + DEBUGFUNC("e1000_get_phy_info_ife"); + + ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); + if (ret_val) + goto out; + + if (!link) { + DEBUGOUT("Phy info is only valid if link is up\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + ret_val = phy->ops.read_reg(hw, IFE_PHY_SPECIAL_CONTROL, &data); + if (ret_val) + goto out; + phy->polarity_correction = (data & IFE_PSC_AUTO_POLARITY_DISABLE) + ? FALSE : TRUE; + + if (phy->polarity_correction) { + ret_val = e1000_check_polarity_ife(hw); + if (ret_val) + goto out; + } else { + /* Polarity is forced */ + phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY) + ? e1000_rev_polarity_reversed + : e1000_rev_polarity_normal; + } + + ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data); + if (ret_val) + goto out; + + phy->is_mdix = (data & IFE_PMC_MDIX_STATUS) ? TRUE : FALSE; + + /* The following parameters are undefined for 10/100 operation. */ + phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; + phy->local_rx = e1000_1000t_rx_status_undefined; + phy->remote_rx = e1000_1000t_rx_status_undefined; + +out: + return ret_val; +} + +/** * e1000_phy_sw_reset_generic - PHY software reset * @hw: pointer to the HW structure * @@ -2302,7 +2601,7 @@ enum e1000_phy_type e1000_get_phy_type_from_id(u32 phy_id) { enum e1000_phy_type phy_type = e1000_phy_unknown; - switch (phy_id) { + switch (phy_id) { case M88E1000_I_PHY_ID: case M88E1000_E_PHY_ID: case M88E1111_I_PHY_ID: @@ -2333,6 +2632,9 @@ enum e1000_phy_type e1000_get_phy_type_from_id(u32 phy_id) case I82577_E_PHY_ID: phy_type = e1000_phy_82577; break; + case I82580_I_PHY_ID: + phy_type = e1000_phy_82580; + break; default: phy_type = e1000_phy_unknown; break; @@ -2416,6 +2718,10 @@ s32 e1000_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data) DEBUGFUNC("e1000_write_phy_reg_bm"); + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return ret_val; + /* Page 800 works differently than the rest so it has its own func */ if (page == BM_WUC_PAGE) { ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data, @@ -2423,10 +2729,6 @@ s32 e1000_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data) goto out; } - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset); if (offset > MAX_PHY_MULTI_PAGE_REG) { @@ -2446,18 +2748,15 @@ s32 e1000_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data) /* Page is shifted left, PHY expects (page x 32) */ ret_val = e1000_write_phy_reg_mdic(hw, page_select, (page << page_shift)); - if (ret_val) { - hw->phy.ops.release(hw); + if (ret_val) goto out; - } } ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, data); - hw->phy.ops.release(hw); - out: + hw->phy.ops.release(hw); return ret_val; } @@ -2480,6 +2779,10 @@ s32 e1000_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data) DEBUGFUNC("e1000_read_phy_reg_bm"); + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return ret_val; + /* Page 800 works differently than the rest so it has its own func */ if (page == BM_WUC_PAGE) { ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data, @@ -2487,10 +2790,6 @@ s32 e1000_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data) goto out; } - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset); if (offset > MAX_PHY_MULTI_PAGE_REG) { @@ -2510,17 +2809,14 @@ s32 e1000_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data) /* Page is shifted left, PHY expects (page x 32) */ ret_val = e1000_write_phy_reg_mdic(hw, page_select, (page << page_shift)); - if (ret_val) { - hw->phy.ops.release(hw); + if (ret_val) goto out; - } } ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, data); - hw->phy.ops.release(hw); - out: + hw->phy.ops.release(hw); return ret_val; } @@ -2541,6 +2837,10 @@ s32 e1000_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data) DEBUGFUNC("e1000_write_phy_reg_bm2"); + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return ret_val; + /* Page 800 works differently than the rest so it has its own func */ if (page == BM_WUC_PAGE) { ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data, @@ -2548,10 +2848,6 @@ s32 e1000_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data) goto out; } - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - hw->phy.addr = 1; if (offset > MAX_PHY_MULTI_PAGE_REG) { @@ -2560,17 +2856,14 @@ s32 e1000_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data) ret_val = e1000_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT, page); - if (ret_val) { - hw->phy.ops.release(hw); + if (ret_val) goto out; - } } ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, data); - hw->phy.ops.release(hw); - out: + hw->phy.ops.release(hw); return ret_val; } @@ -2590,6 +2883,10 @@ s32 e1000_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data) DEBUGFUNC("e1000_write_phy_reg_bm2"); + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return ret_val; + /* Page 800 works differently than the rest so it has its own func */ if (page == BM_WUC_PAGE) { ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data, @@ -2597,10 +2894,6 @@ s32 e1000_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data) goto out; } - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - hw->phy.addr = 1; if (offset > MAX_PHY_MULTI_PAGE_REG) { @@ -2608,18 +2901,15 @@ s32 e1000_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data) ret_val = e1000_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT, page); - if (ret_val) { - hw->phy.ops.release(hw); + if (ret_val) goto out; - } } ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, data); - hw->phy.ops.release(hw); - out: + hw->phy.ops.release(hw); return ret_val; } @@ -2639,6 +2929,8 @@ out: * 3) Write the address using the address opcode (0x11) * 4) Read or write the data using the data opcode (0x12) * 5) Restore 769_17.2 to its original value + * + * Assumes semaphore already acquired. **/ static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data, bool read) @@ -2646,7 +2938,6 @@ static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset, s32 ret_val; u16 reg = BM_PHY_REG_NUM(offset); u16 phy_reg = 0; - u8 phy_acquired = 1; DEBUGFUNC("e1000_access_phy_wakeup_reg_bm"); @@ -2655,13 +2946,6 @@ static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset, (!(E1000_READ_REG(hw, E1000_PHY_CTRL) & E1000_PHY_CTRL_GBE_DISABLE))) DEBUGOUT("Attempting to access page 800 while gig enabled.\n"); - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) { - DEBUGOUT("Could not acquire PHY\n"); - phy_acquired = 0; - goto out; - } - /* All operations in this function are phy address 1 */ hw->phy.addr = 1; @@ -2733,8 +3017,6 @@ static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset, } out: - if (phy_acquired == 1) - hw->phy.ops.release(hw); return ret_val; } @@ -2775,46 +3057,51 @@ void e1000_power_down_phy_copper(struct e1000_hw *hw) msec_delay(1); } +/** + * e1000_set_mdio_slow_mode_hv - Set slow MDIO access mode + * @hw: pointer to the HW structure + * @slow: TRUE for slow mode, FALSE for normal mode + * + * Assumes semaphore already acquired. + **/ s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow) { s32 ret_val = E1000_SUCCESS; u16 data = 0; - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - return ret_val; - /* Set MDIO mode - page 769, register 16: 0x2580==slow, 0x2180==fast */ hw->phy.addr = 1; ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, (BM_PORT_CTRL_PAGE << IGP_PAGE_SHIFT)); - if (ret_val) { - hw->phy.ops.release(hw); - return ret_val; - } + if (ret_val) + goto out; + ret_val = e1000_write_phy_reg_mdic(hw, BM_CS_CTRL1, (0x2180 | (slow << 10))); + if (ret_val) + goto out; /* dummy read when reverting to fast mode - throw away result */ if (!slow) - e1000_read_phy_reg_mdic(hw, BM_CS_CTRL1, &data); - - hw->phy.ops.release(hw); + ret_val = e1000_read_phy_reg_mdic(hw, BM_CS_CTRL1, &data); +out: return ret_val; } /** - * e1000_read_phy_reg_hv - Read HV PHY register + * __e1000_read_phy_reg_hv - Read HV PHY register * @hw: pointer to the HW structure * @offset: register offset to be read * @data: pointer to the read data + * @locked: semaphore has already been acquired or not * * Acquires semaphore, if necessary, then reads the PHY register at offset - * and storing the retrieved information in data. Release any acquired + * and stores the retrieved information in data. Release any acquired * semaphore before exiting. **/ -s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data) +static s32 __e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data, + bool locked) { s32 ret_val; u16 page = BM_PHY_REG_PAGE(offset); @@ -2823,6 +3110,12 @@ s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data) DEBUGFUNC("e1000_read_phy_reg_hv"); + if (!locked) { + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return ret_val; + } + /* Workaround failure in MDIO access while cable is disconnected */ if ((hw->phy.type == e1000_phy_82577) && !(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) { @@ -2846,57 +3139,80 @@ s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data) goto out; } - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - hw->phy.addr = e1000_get_phy_addr_for_hv_page(page); if (page == HV_INTC_FC_PAGE_START) page = 0; if (reg > MAX_PHY_MULTI_PAGE_REG) { - if ((hw->phy.type != e1000_phy_82578) || - ((reg != I82578_ADDR_REG) && - (reg != I82578_ADDR_REG + 1))) { - u32 phy_addr = hw->phy.addr; - - hw->phy.addr = 1; - - /* Page is shifted left, PHY expects (page x 32) */ - ret_val = e1000_write_phy_reg_mdic(hw, - IGP01E1000_PHY_PAGE_SELECT, - (page << IGP_PAGE_SHIFT)); - if (ret_val) { - hw->phy.ops.release(hw); - goto out; - } - hw->phy.addr = phy_addr; - } + u32 phy_addr = hw->phy.addr; + + hw->phy.addr = 1; + + /* Page is shifted left, PHY expects (page x 32) */ + ret_val = e1000_write_phy_reg_mdic(hw, + IGP01E1000_PHY_PAGE_SELECT, + (page << IGP_PAGE_SHIFT)); + hw->phy.addr = phy_addr; + + if (ret_val) + goto out; } ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg, data); - hw->phy.ops.release(hw); - out: /* Revert to MDIO fast mode, if applicable */ if ((hw->phy.type == e1000_phy_82577) && in_slow_mode) - ret_val = e1000_set_mdio_slow_mode_hv(hw, FALSE); + ret_val |= e1000_set_mdio_slow_mode_hv(hw, FALSE); + + if (!locked) + hw->phy.ops.release(hw); return ret_val; } /** - * e1000_write_phy_reg_hv - Write HV PHY register + * e1000_read_phy_reg_hv - Read HV PHY register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Acquires semaphore then reads the PHY register at offset and stores + * the retrieved information in data. Release the acquired semaphore + * before exiting. + **/ +s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data) +{ + return __e1000_read_phy_reg_hv(hw, offset, data, FALSE); +} + +/** + * e1000_read_phy_reg_hv_locked - Read HV PHY register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Reads the PHY register at offset and stores the retrieved information + * in data. Assumes semaphore already acquired. + **/ +s32 e1000_read_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 *data) +{ + return __e1000_read_phy_reg_hv(hw, offset, data, TRUE); +} + +/** + * __e1000_write_phy_reg_hv - Write HV PHY register * @hw: pointer to the HW structure * @offset: register offset to write to * @data: data to write at register offset + * @locked: semaphore has already been acquired or not * * Acquires semaphore, if necessary, then writes the data to PHY register * at the offset. Release any acquired semaphores before exiting. **/ -s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data) +static s32 __e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data, + bool locked) { s32 ret_val; u16 page = BM_PHY_REG_PAGE(offset); @@ -2905,6 +3221,12 @@ s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data) DEBUGFUNC("e1000_write_phy_reg_hv"); + if (!locked) { + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return ret_val; + } + /* Workaround failure in MDIO access while cable is disconnected */ if ((hw->phy.type == e1000_phy_82577) && !(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) { @@ -2928,10 +3250,6 @@ s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data) goto out; } - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - hw->phy.addr = e1000_get_phy_addr_for_hv_page(page); if (page == HV_INTC_FC_PAGE_START) @@ -2947,50 +3265,70 @@ s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data) ((MAX_PHY_REG_ADDRESS & reg) == 0) && (data & (1 << 11))) { u16 data2 = 0x7EFF; - hw->phy.ops.release(hw); ret_val = e1000_access_phy_debug_regs_hv(hw, (1 << 6) | 0x3, &data2, FALSE); if (ret_val) goto out; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; } if (reg > MAX_PHY_MULTI_PAGE_REG) { - if ((hw->phy.type != e1000_phy_82578) || - ((reg != I82578_ADDR_REG) && - (reg != I82578_ADDR_REG + 1))) { - u32 phy_addr = hw->phy.addr; - - hw->phy.addr = 1; - - /* Page is shifted left, PHY expects (page x 32) */ - ret_val = e1000_write_phy_reg_mdic(hw, - IGP01E1000_PHY_PAGE_SELECT, - (page << IGP_PAGE_SHIFT)); - if (ret_val) { - hw->phy.ops.release(hw); - goto out; - } - hw->phy.addr = phy_addr; - } + u32 phy_addr = hw->phy.addr; + + hw->phy.addr = 1; + + /* Page is shifted left, PHY expects (page x 32) */ + ret_val = e1000_write_phy_reg_mdic(hw, + IGP01E1000_PHY_PAGE_SELECT, + (page << IGP_PAGE_SHIFT)); + hw->phy.addr = phy_addr; + + if (ret_val) + goto out; } ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg, data); - hw->phy.ops.release(hw); out: /* Revert to MDIO fast mode, if applicable */ if ((hw->phy.type == e1000_phy_82577) && in_slow_mode) - ret_val = e1000_set_mdio_slow_mode_hv(hw, FALSE); + ret_val |= e1000_set_mdio_slow_mode_hv(hw, FALSE); + + if (!locked) + hw->phy.ops.release(hw); return ret_val; } /** + * e1000_write_phy_reg_hv - Write HV PHY register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquires semaphore then writes the data to PHY register at the offset. + * Release the acquired semaphores before exiting. + **/ +s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data) +{ + return __e1000_write_phy_reg_hv(hw, offset, data, FALSE); +} + +/** + * e1000_write_phy_reg_hv_locked - Write HV PHY register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Writes the data to PHY register at the offset. Assumes semaphore + * already acquired. + **/ +s32 e1000_write_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 data) +{ + return __e1000_write_phy_reg_hv(hw, offset, data, TRUE); +} + +/** * e1000_get_phy_addr_for_hv_page - Get PHY adrress based on page * @page: page to be accessed **/ @@ -3011,10 +3349,9 @@ static u32 e1000_get_phy_addr_for_hv_page(u32 page) * @data: pointer to the data to be read or written * @read: determines if operation is read or written * - * Acquires semaphore, if necessary, then reads the PHY register at offset - * and storing the retreived information in data. Release any acquired - * semaphores before exiting. Note that the procedure to read these regs - * uses the address port and data port to read/write. + * Reads the PHY register at offset and stores the retreived information + * in data. Assumes semaphore already acquired. Note that the procedure + * to read these regs uses the address port and data port to read/write. **/ static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset, u16 *data, bool read) @@ -3022,7 +3359,6 @@ static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset, s32 ret_val; u32 addr_reg = 0; u32 data_reg = 0; - u8 phy_acquired = 1; DEBUGFUNC("e1000_access_phy_debug_regs_hv"); @@ -3031,13 +3367,6 @@ static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset, I82578_ADDR_REG : I82577_ADDR_REG; data_reg = addr_reg + 1; - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) { - DEBUGOUT("Could not acquire PHY\n"); - phy_acquired = 0; - goto out; - } - /* All operations in this function are phy address 2 */ hw->phy.addr = 2; @@ -3060,8 +3389,6 @@ static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset, } out: - if (phy_acquired == 1) - hw->phy.ops.release(hw); return ret_val; } @@ -3090,7 +3417,7 @@ s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw) hw->phy.ops.read_reg(hw, PHY_CONTROL, &data); if (data & PHY_CONTROL_LB) goto out; - + /* check if link is up and at 1Gbps */ ret_val = hw->phy.ops.read_reg(hw, BM_CS_STATUS, &data); if (ret_val) @@ -3309,7 +3636,7 @@ s32 e1000_get_cable_length_82577(struct e1000_hw *hw) I82577_DSTATUS_CABLE_LENGTH_SHIFT; if (length == E1000_CABLE_LENGTH_UNDEFINED) - ret_val = E1000_ERR_PHY; + ret_val = -E1000_ERR_PHY; phy->cable_length = length; diff --git a/sys/dev/e1000/e1000_phy.h b/sys/dev/e1000/e1000_phy.h index 28ed0c1..01e91d6 100644 --- a/sys/dev/e1000/e1000_phy.h +++ b/sys/dev/e1000/e1000_phy.h @@ -45,6 +45,7 @@ s32 e1000_check_polarity_m88(struct e1000_hw *hw); s32 e1000_check_polarity_igp(struct e1000_hw *hw); s32 e1000_check_polarity_ife(struct e1000_hw *hw); s32 e1000_check_reset_block_generic(struct e1000_hw *hw); +s32 e1000_phy_setup_autoneg(struct e1000_hw *hw); s32 e1000_copper_link_autoneg(struct e1000_hw *hw); s32 e1000_copper_link_setup_igp(struct e1000_hw *hw); s32 e1000_copper_link_setup_m88(struct e1000_hw *hw); @@ -57,19 +58,23 @@ s32 e1000_get_cfg_done_generic(struct e1000_hw *hw); s32 e1000_get_phy_id(struct e1000_hw *hw); s32 e1000_get_phy_info_igp(struct e1000_hw *hw); s32 e1000_get_phy_info_m88(struct e1000_hw *hw); +s32 e1000_get_phy_info_ife(struct e1000_hw *hw); s32 e1000_phy_sw_reset_generic(struct e1000_hw *hw); void e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl); s32 e1000_phy_hw_reset_generic(struct e1000_hw *hw); s32 e1000_phy_reset_dsp_generic(struct e1000_hw *hw); -s32 e1000_phy_setup_autoneg(struct e1000_hw *hw); s32 e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data); +s32 e1000_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data); s32 e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data); +s32 e1000_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 *data); s32 e1000_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data); s32 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active); s32 e1000_setup_copper_link_generic(struct e1000_hw *hw); s32 e1000_wait_autoneg_generic(struct e1000_hw *hw); s32 e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data); +s32 e1000_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data); s32 e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data); +s32 e1000_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 data); s32 e1000_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data); s32 e1000_phy_reset_dsp(struct e1000_hw *hw); s32 e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, @@ -85,8 +90,12 @@ void e1000_power_up_phy_copper(struct e1000_hw *hw); void e1000_power_down_phy_copper(struct e1000_hw *hw); s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data); s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data); +s32 e1000_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data); +s32 e1000_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data); s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data); +s32 e1000_read_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 *data); s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data); +s32 e1000_write_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 data); s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow); s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw); s32 e1000_copper_link_setup_82577(struct e1000_hw *hw); @@ -140,7 +149,6 @@ s32 e1000_get_cable_length_82577(struct e1000_hw *hw); #define I82577_CFG_ASSERT_CRS_ON_TX (1 << 15) #define I82577_CFG_ENABLE_DOWNSHIFT (3 << 10) /* auto downshift 100/10 */ #define I82577_CTRL_REG 23 -#define I82577_CTRL_DOWNSHIFT_MASK (7 << 10) /* 82577 specific PHY registers */ #define I82577_PHY_CTRL_2 18 @@ -175,6 +183,13 @@ s32 e1000_get_cable_length_82577(struct e1000_hw *hw); #define BM_CS_STATUS_SPEED_MASK 0xC000 #define BM_CS_STATUS_SPEED_1000 0x8000 +/* 82577 Mobile Phy Status Register */ +#define HV_M_STATUS 26 +#define HV_M_STATUS_AUTONEG_COMPLETE 0x1000 +#define HV_M_STATUS_SPEED_MASK 0x0300 +#define HV_M_STATUS_SPEED_1000 0x0200 +#define HV_M_STATUS_LINK_UP 0x0040 + #define IGP01E1000_PHY_PCS_INIT_REG 0x00B4 #define IGP01E1000_PHY_POLARITY_MASK 0x0078 @@ -220,6 +235,8 @@ s32 e1000_get_cable_length_82577(struct e1000_hw *hw); #define E1000_KMRNCTRLSTA_TIMEOUTS 0x4 /* Kumeran Timeouts */ #define E1000_KMRNCTRLSTA_INBAND_PARAM 0x9 /* Kumeran InBand Parameters */ #define E1000_KMRNCTRLSTA_DIAG_NELPBK 0x1000 /* Nearend Loopback mode */ +#define E1000_KMRNCTRLSTA_K1_CONFIG 0x7 +#define E1000_KMRNCTRLSTA_K1_ENABLE 0x0002 #define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10 #define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY Special Control */ diff --git a/sys/dev/e1000/e1000_regs.h b/sys/dev/e1000/e1000_regs.h index 3a62d0a..9b0bb91 100644 --- a/sys/dev/e1000/e1000_regs.h +++ b/sys/dev/e1000/e1000_regs.h @@ -43,6 +43,12 @@ #define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */ #define E1000_FLA 0x0001C /* Flash Access - RW */ #define E1000_MDIC 0x00020 /* MDI Control - RW */ +#define E1000_MDICNFG 0x00E04 /* MDI Config - RW */ +#define E1000_REGISTER_SET_SIZE 0x20000 /* CSR Size */ +#define E1000_EEPROM_INIT_CTRL_WORD_2 0x0F /* EEPROM Init Ctrl Word 2 */ +#define E1000_BARCTRL 0x5BBC /* BAR ctrl reg */ +#define E1000_BARCTRL_FLSIZE 0x0700 /* BAR ctrl Flsize */ +#define E1000_BARCTRL_CSRSIZE 0x2000 /* BAR ctrl CSR size */ #define E1000_SCTL 0x00024 /* SerDes Control - RW */ #define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ #define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ @@ -121,11 +127,7 @@ #define E1000_RDPUCTL 0x025DC /* DMA Rx Descriptor uC Control - RW */ #define E1000_PBDIAG 0x02458 /* Packet Buffer Diagnostic - RW */ #define E1000_RXPBS 0x02404 /* Rx Packet Buffer Size - RW */ -#define E1000_RXCTL(_n) (0x0C014 + (0x40 * (_n))) -#define E1000_RQDPC(_n) (0x0C030 + (0x40 * (_n))) -#define E1000_TXCTL(_n) (0x0E014 + (0x40 * (_n))) -#define E1000_RXCTL(_n) (0x0C014 + (0x40 * (_n))) -#define E1000_RQDPC(_n) (0x0C030 + (0x40 * (_n))) +#define E1000_IRPBS 0x02404 /* Same as RXPBS, renamed for newer adapters - RW */ #define E1000_RDTR 0x02820 /* Rx Delay Timer - RW */ #define E1000_RADV 0x0282C /* Rx Interrupt Absolute Delay Timer - RW */ /* @@ -146,10 +148,15 @@ (0x0C00C + ((_n) * 0x40))) #define E1000_RDH(_n) ((_n) < 4 ? (0x02810 + ((_n) * 0x100)) : \ (0x0C010 + ((_n) * 0x40))) +#define E1000_RXCTL(_n) ((_n) < 4 ? (0x02814 + ((_n) * 0x100)) : \ + (0x0C014 + ((_n) * 0x40))) +#define E1000_DCA_RXCTRL(_n) E1000_RXCTL(_n) #define E1000_RDT(_n) ((_n) < 4 ? (0x02818 + ((_n) * 0x100)) : \ (0x0C018 + ((_n) * 0x40))) #define E1000_RXDCTL(_n) ((_n) < 4 ? (0x02828 + ((_n) * 0x100)) : \ (0x0C028 + ((_n) * 0x40))) +#define E1000_RQDPC(_n) ((_n) < 4 ? (0x02830 + ((_n) * 0x100)) : \ + (0x0C030 + ((_n) * 0x40))) #define E1000_TDBAL(_n) ((_n) < 4 ? (0x03800 + ((_n) * 0x100)) : \ (0x0E000 + ((_n) * 0x40))) #define E1000_TDBAH(_n) ((_n) < 4 ? (0x03804 + ((_n) * 0x100)) : \ @@ -158,17 +165,18 @@ (0x0E008 + ((_n) * 0x40))) #define E1000_TDH(_n) ((_n) < 4 ? (0x03810 + ((_n) * 0x100)) : \ (0x0E010 + ((_n) * 0x40))) +#define E1000_TXCTL(_n) ((_n) < 4 ? (0x03814 + ((_n) * 0x100)) : \ + (0x0E014 + ((_n) * 0x40))) +#define E1000_DCA_TXCTRL(_n) E1000_TXCTL(_n) #define E1000_TDT(_n) ((_n) < 4 ? (0x03818 + ((_n) * 0x100)) : \ (0x0E018 + ((_n) * 0x40))) #define E1000_TXDCTL(_n) ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) : \ (0x0E028 + ((_n) * 0x40))) -#define E1000_TARC(_n) (0x03840 + (_n << 8)) -#define E1000_DCA_TXCTRL(_n) (0x03814 + (_n << 8)) -#define E1000_DCA_RXCTRL(_n) (0x02814 + (_n << 8)) #define E1000_TDWBAL(_n) ((_n) < 4 ? (0x03838 + ((_n) * 0x100)) : \ (0x0E038 + ((_n) * 0x40))) #define E1000_TDWBAH(_n) ((_n) < 4 ? (0x0383C + ((_n) * 0x100)) : \ (0x0E03C + ((_n) * 0x40))) +#define E1000_TARC(_n) (0x03840 + ((_n) * 0x100)) #define E1000_RSRPD 0x02C00 /* Rx Small Packet Detect - RW */ #define E1000_RAID 0x02C08 /* Receive Ack Interrupt Delay - RW */ #define E1000_TXDMAC 0x03000 /* Tx DMA Control - RW */ @@ -187,6 +195,7 @@ #define E1000_PBSLAC 0x03100 /* Packet Buffer Slave Access Control */ #define E1000_PBSLAD(_n) (0x03110 + (0x4 * (_n))) /* Packet Buffer DWORD (_n) */ #define E1000_TXPBS 0x03404 /* Tx Packet Buffer Size - RW */ +#define E1000_ITPBS 0x03404 /* Same as TXPBS, renamed for newer adpaters - RW */ #define E1000_TDFH 0x03410 /* Tx Data FIFO Head - RW */ #define E1000_TDFT 0x03418 /* Tx Data FIFO Tail - RW */ #define E1000_TDFHS 0x03420 /* Tx Data FIFO Head Saved - RW */ @@ -271,6 +280,7 @@ #define E1000_ICTXQMTC 0x0411C /* Interrupt Cause Tx Queue Min Thresh Count */ #define E1000_ICRXDMTC 0x04120 /* Interrupt Cause Rx Desc Min Thresh Count */ #define E1000_ICRXOC 0x04124 /* Interrupt Cause Receiver Overrun Count */ +#define E1000_CRC_OFFSET 0x05F50 /* CRC Offset register */ #define E1000_LSECTXUT 0x04300 /* LinkSec Tx Untagged Packet Count - OutPktsUntagged */ #define E1000_LSECTXPKTE 0x04304 /* LinkSec Encrypted Tx Packets Count - OutPktsEncrypted */ @@ -392,6 +402,7 @@ #define E1000_SWSM2 0x05B58 /* Driver-only SW semaphore (not used by BOOT agents) */ #define E1000_DCA_ID 0x05B70 /* DCA Requester ID Information - RO */ #define E1000_DCA_CTRL 0x05B74 /* DCA Control - RW */ +#define E1000_UFUSE 0x05B78 /* UFUSE - RO */ #define E1000_FFLT_DBG 0x05F04 /* Debug Register */ #define E1000_HICR 0x08F00 /* Host Interface Control */ @@ -437,6 +448,7 @@ #define E1000_VMOLR(_n) (0x05AD0 + (4 * (_n))) #define E1000_VLVF(_n) (0x05D00 + (4 * (_n))) /* VLAN Virtual Machine * Filter - RW */ +#define E1000_VMVIR(_n) (0x03700 + (4 * (_n))) /* Time Sync */ #define E1000_TSYNCRXCTL 0x0B620 /* Rx Time Sync Control register - RW */ #define E1000_TSYNCTXCTL 0x0B614 /* Tx Time Sync Control register - RW */ @@ -450,6 +462,8 @@ #define E1000_SYSTIML 0x0B600 /* System time register Low - RO */ #define E1000_SYSTIMH 0x0B604 /* System time register High - RO */ #define E1000_TIMINCA 0x0B608 /* Increment attributes register - RW */ +#define E1000_TSAUXC 0x0B640 /* Timesync Auxiliary Control register */ +#define E1000_SYSTIMR 0x0B6F8 /* System time register Residue */ #define E1000_RXMTRL 0x0B634 /* Time sync Rx EtherType and Msg Type - RW */ #define E1000_RXUDP 0x0B638 /* Time Sync Rx UDP Port - RW */ @@ -493,4 +507,16 @@ #define E1000_RTTBCNACH 0x0B214 /* Tx BCN Control High */ #define E1000_RTTBCNACL 0x0B210 /* Tx BCN Control Low */ +/* DMA Coalescing registers */ +#define E1000_DMACR 0x02508 /* Control Register */ +#define E1000_DMCTXTH 0x03550 /* Transmit Threshold */ +#define E1000_DMCTLX 0x02514 /* Time to Lx Request */ +#define E1000_DMCRTRH 0x05DD0 /* Receive Packet Rate Threshold */ +#define E1000_DMCCNT 0x05DD4 /* Current RX Count */ +#define E1000_FCRTC 0x02170 /* Flow Control Rx high watermark */ +#define E1000_PCIEMISC 0x05BB8 /* PCIE misc config register */ + +/* PCIe Parity Status Register */ +#define E1000_PCIEERRSTS 0x05BA8 +#define E1000_ERFUSE 0x00000400 #endif diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c index 7a2dbad..8756b0c 100644 --- a/sys/dev/e1000/if_em.c +++ b/sys/dev/e1000/if_em.c @@ -94,7 +94,7 @@ int em_display_debug_stats = 0; /********************************************************************* * Driver version: *********************************************************************/ -char em_driver_version[] = "6.9.14"; +char em_driver_version[] = "6.9.24"; /********************************************************************* @@ -194,7 +194,7 @@ static em_vendor_info_t em_vendor_info_array[] = { 0x8086, E1000_DEV_ID_ICH8_IFE_GT, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_ICH8_IFE_G, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_ICH8_IGP_M, PCI_ANY_ID, PCI_ANY_ID, 0}, - + { 0x8086, E1000_DEV_ID_ICH8_82567V_3, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_ICH9_IGP_M_AMT, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_ICH9_IGP_AMT, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_ICH9_IGP_C, PCI_ANY_ID, PCI_ANY_ID, 0}, @@ -211,6 +211,10 @@ static em_vendor_info_t em_vendor_info_array[] = { 0x8086, E1000_DEV_ID_ICH10_R_BM_V, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_ICH10_D_BM_LM, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_ICH10_D_BM_LF, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_PCH_M_HV_LM, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_PCH_M_HV_LC, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_PCH_D_HV_DM, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_PCH_D_HV_DC, PCI_ANY_ID, PCI_ANY_ID, 0}, /* required last entry */ { 0, 0, 0, 0, 0} }; @@ -240,7 +244,6 @@ static int em_mq_start_locked(struct ifnet *, struct mbuf *); static void em_qflush(struct ifnet *); #endif static int em_ioctl(struct ifnet *, u_long, caddr_t); -static void em_watchdog(struct adapter *); static void em_init(void *); static void em_init_locked(struct adapter *); static void em_stop(void *); @@ -315,7 +318,9 @@ static void em_init_manageability(struct adapter *); static void em_release_manageability(struct adapter *); static void em_get_hw_control(struct adapter *); static void em_release_hw_control(struct adapter *); +static void em_get_wakeup(device_t); static void em_enable_wakeup(device_t); +static int em_enable_phy_wakeup(struct adapter *); #ifdef EM_LEGACY_IRQ static void em_intr(void *); @@ -490,7 +495,6 @@ em_attach(device_t dev) struct adapter *adapter; int tsize, rsize; int error = 0; - u16 eeprom_data, device_id; INIT_DEBUGOUT("em_attach: begin"); @@ -531,6 +535,7 @@ em_attach(device_t dev) ** identified */ if ((adapter->hw.mac.type == e1000_ich8lan) || + (adapter->hw.mac.type == e1000_pchlan) || (adapter->hw.mac.type == e1000_ich9lan) || (adapter->hw.mac.type == e1000_ich10lan)) { int rid = EM_BAR_TYPE_FLASH; @@ -728,6 +733,11 @@ em_attach(device_t dev) if (error) goto err_rx_struct; + /* + * Get Wake-on-Lan and Management info for later use + */ + em_get_wakeup(dev); + /* Setup OS specific network interface */ em_setup_interface(dev, adapter); @@ -742,69 +752,6 @@ em_attach(device_t dev) device_printf(dev, "PHY reset is blocked due to SOL/IDER session.\n"); - /* Determine if we have to control management hardware */ - adapter->has_manage = e1000_enable_mng_pass_thru(&adapter->hw); - - /* - * Setup Wake-on-Lan - */ - switch (adapter->hw.mac.type) { - - case e1000_82542: - case e1000_82543: - break; - case e1000_82546: - case e1000_82546_rev_3: - case e1000_82571: - case e1000_80003es2lan: - if (adapter->hw.bus.func == 1) - e1000_read_nvm(&adapter->hw, - NVM_INIT_CONTROL3_PORT_B, 1, &eeprom_data); - else - e1000_read_nvm(&adapter->hw, - NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data); - eeprom_data &= EM_EEPROM_APME; - break; - default: - /* APME bit in EEPROM is mapped to WUC.APME */ - eeprom_data = E1000_READ_REG(&adapter->hw, E1000_WUC) & - E1000_WUC_APME; - break; - } - if (eeprom_data) - adapter->wol = E1000_WUFC_MAG; - /* - * We have the eeprom settings, now apply the special cases - * where the eeprom may be wrong or the board won't support - * wake on lan on a particular port - */ - device_id = pci_get_device(dev); - switch (device_id) { - case E1000_DEV_ID_82546GB_PCIE: - adapter->wol = 0; - break; - case E1000_DEV_ID_82546EB_FIBER: - case E1000_DEV_ID_82546GB_FIBER: - case E1000_DEV_ID_82571EB_FIBER: - /* Wake events only supported on port A for dual fiber - * regardless of eeprom setting */ - if (E1000_READ_REG(&adapter->hw, E1000_STATUS) & - E1000_STATUS_FUNC_1) - adapter->wol = 0; - break; - case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3: - case E1000_DEV_ID_82571EB_QUAD_COPPER: - case E1000_DEV_ID_82571EB_QUAD_FIBER: - case E1000_DEV_ID_82571EB_QUAD_COPPER_LP: - /* if quad port adapter, disable WoL on all but port A */ - if (global_quad_port_a != 0) - adapter->wol = 0; - /* Reset for multiple quad port adapters */ - if (++global_quad_port_a == 4) - global_quad_port_a = 0; - break; - } - /* Do we need workaround for 82544 PCI-X adapter? */ if (adapter->hw.bus.type == e1000_bus_type_pcix && adapter->hw.mac.type == e1000_82544) @@ -820,6 +767,10 @@ em_attach(device_t dev) em_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST); #endif + /* Non-AMT based hardware can now take control from firmware */ + if (adapter->has_manage && !adapter->has_amt) + em_get_hw_control(adapter); + /* Tell the stack that the interface is not active */ adapter->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); @@ -886,20 +837,6 @@ em_detach(device_t dev) em_release_manageability(adapter); - if (((adapter->hw.mac.type == e1000_82573) || - (adapter->hw.mac.type == e1000_82583) || - (adapter->hw.mac.type == e1000_ich8lan) || - (adapter->hw.mac.type == e1000_ich10lan) || - (adapter->hw.mac.type == e1000_ich9lan)) && - e1000_check_mng_mode(&adapter->hw)) - em_release_hw_control(adapter); - - if (adapter->wol) { - E1000_WRITE_REG(&adapter->hw, E1000_WUC, E1000_WUC_PME_EN); - E1000_WRITE_REG(&adapter->hw, E1000_WUFC, adapter->wol); - em_enable_wakeup(dev); - } - EM_TX_UNLOCK(adapter); EM_CORE_UNLOCK(adapter); @@ -934,6 +871,7 @@ em_detach(device_t dev) adapter->rx_desc_base = NULL; } + em_release_hw_control(adapter); EM_TX_LOCK_DESTROY(adapter); EM_RX_LOCK_DESTROY(adapter); EM_CORE_LOCK_DESTROY(adapter); @@ -963,25 +901,9 @@ em_suspend(device_t dev) EM_CORE_LOCK(adapter); - EM_TX_LOCK(adapter); - em_stop(adapter); - EM_TX_UNLOCK(adapter); - em_release_manageability(adapter); - - if (((adapter->hw.mac.type == e1000_82573) || - (adapter->hw.mac.type == e1000_82583) || - (adapter->hw.mac.type == e1000_ich8lan) || - (adapter->hw.mac.type == e1000_ich10lan) || - (adapter->hw.mac.type == e1000_ich9lan)) && - e1000_check_mng_mode(&adapter->hw)) - em_release_hw_control(adapter); - - if (adapter->wol) { - E1000_WRITE_REG(&adapter->hw, E1000_WUC, E1000_WUC_PME_EN); - E1000_WRITE_REG(&adapter->hw, E1000_WUFC, adapter->wol); - em_enable_wakeup(dev); - } + em_release_hw_control(adapter); + em_enable_wakeup(dev); EM_CORE_UNLOCK(adapter); @@ -1035,7 +957,7 @@ em_mq_start_locked(struct ifnet *ifp, struct mbuf *m) } else if (drbr_empty(ifp, adapter->br) && (adapter->num_tx_desc_avail > EM_TX_OP_THRESHOLD)) { if ((error = em_xmit(adapter, &m)) != 0) { - if (m != NULL) + if (m) error = drbr_enqueue(ifp, adapter->br, m); return (error); } else { @@ -1049,7 +971,7 @@ em_mq_start_locked(struct ifnet *ifp, struct mbuf *m) ** listener and set the watchdog on. */ ETHER_BPF_MTAP(ifp, m); - adapter->watchdog_timer = EM_TX_TIMEOUT; + adapter->watchdog_check = TRUE; } } else if ((error = drbr_enqueue(ifp, adapter->br, m)) != 0) return (error); @@ -1072,7 +994,7 @@ process: drbr_stats_update(ifp, next->m_pkthdr.len, next->m_flags); ETHER_BPF_MTAP(ifp, next); /* Set the watchdog */ - adapter->watchdog_timer = EM_TX_TIMEOUT; + adapter->watchdog_check = TRUE; } if (adapter->num_tx_desc_avail <= EM_TX_OP_THRESHOLD) @@ -1151,7 +1073,7 @@ em_start_locked(struct ifnet *ifp) ETHER_BPF_MTAP(ifp, m_head); /* Set timeout in case hardware has problems transmitting. */ - adapter->watchdog_timer = EM_TX_TIMEOUT; + adapter->watchdog_check = TRUE; } if (adapter->num_tx_desc_avail <= EM_TX_OP_THRESHOLD) ifp->if_drv_flags |= IFF_DRV_OACTIVE; @@ -1209,8 +1131,7 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data) em_init_locked(adapter); EM_CORE_UNLOCK(adapter); } - if (!(ifp->if_flags & IFF_NOARP)) - arp_ifinit(ifp, ifa); + arp_ifinit(ifp, ifa); } else #endif error = ether_ioctl(ifp, command, data); @@ -1244,6 +1165,9 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data) case e1000_80003es2lan: /* Limit Jumbo Frame size */ max_frame_size = 9234; break; + case e1000_pchlan: + max_frame_size = 4096; + break; /* Adapters that do not support jumbo frames */ case e1000_82542: case e1000_82583: @@ -1359,11 +1283,17 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data) reinit = 1; } #endif - if (mask & IFCAP_VLAN_HWTAGGING) { ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; reinit = 1; } + if ((mask & IFCAP_WOL) && + (ifp->if_capabilities & IFCAP_WOL) != 0) { + if (mask & IFCAP_WOL_MCAST) + ifp->if_capenable ^= IFCAP_WOL_MCAST; + if (mask & IFCAP_WOL_MAGIC) + ifp->if_capenable ^= IFCAP_WOL_MAGIC; + } if (reinit && (ifp->if_drv_flags & IFF_DRV_RUNNING)) em_init(adapter); #if __FreeBSD_version >= 700000 @@ -1380,53 +1310,6 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data) return (error); } -/********************************************************************* - * Watchdog timer: - * - * This routine is called from the local timer every second. - * As long as transmit descriptors are being cleaned the value - * is non-zero and we do nothing. Reaching 0 indicates a tx hang - * and we then reset the device. - * - **********************************************************************/ - -static void -em_watchdog(struct adapter *adapter) -{ - - EM_CORE_LOCK_ASSERT(adapter); - - /* - ** The timer is set to 5 every time start queues a packet. - ** Then txeof keeps resetting it as long as it cleans at - ** least one descriptor. - ** Finally, anytime all descriptors are clean the timer is - ** set to 0. - */ - EM_TX_LOCK(adapter); - if ((adapter->watchdog_timer == 0) || (--adapter->watchdog_timer)) { - EM_TX_UNLOCK(adapter); - return; - } - - /* If we are in this routine because of pause frames, then - * don't reset the hardware. - */ - if (E1000_READ_REG(&adapter->hw, E1000_STATUS) & - E1000_STATUS_TXOFF) { - adapter->watchdog_timer = EM_TX_TIMEOUT; - EM_TX_UNLOCK(adapter); - return; - } - - if (e1000_check_for_link(&adapter->hw) == 0) - device_printf(adapter->dev, "watchdog timeout -- resetting\n"); - adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - adapter->watchdog_events++; - EM_TX_UNLOCK(adapter); - - em_init_locked(adapter); -} /********************************************************************* * Init entry point @@ -1492,6 +1375,9 @@ em_init_locked(struct adapter *adapter) break; case e1000_ich9lan: case e1000_ich10lan: + case e1000_pchlan: + pba = E1000_PBA_10K; + break; case e1000_ich8lan: pba = E1000_PBA_8K; break; @@ -1614,6 +1500,10 @@ em_init_locked(struct adapter *adapter) #endif /* DEVICE_POLLING */ em_enable_intr(adapter); + /* AMT based hardware can now take control from firmware */ + if (adapter->has_manage && adapter->has_amt) + em_get_hw_control(adapter); + /* Don't reset the phy next time init gets called */ adapter->hw.phy.reset_disable = TRUE; } @@ -1667,7 +1557,7 @@ em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) if (!drbr_empty(ifp, adapter->br)) em_mq_start_locked(ifp, NULL); #else - if (!IFQ_DRV_IS_EMPTY(&ifp->snd)) + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) em_start_locked(ifp); #endif EM_TX_UNLOCK(adapter); @@ -1769,7 +1659,7 @@ em_handle_rxtx(void *context, int pending) if (!drbr_empty(ifp, adapter->br)) em_mq_start_locked(ifp, NULL); #else - if (!IFQ_DRV_IS_EMPTY(&ifp->snd)) + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) em_start_locked(ifp); #endif EM_TX_UNLOCK(adapter); @@ -1933,7 +1823,7 @@ em_handle_tx(void *context, int pending) if (!drbr_empty(ifp, adapter->br)) em_mq_start_locked(ifp, NULL); #else - if (!IFQ_DRV_IS_EMPTY(&ifp->snd)) + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) em_start_locked(ifp); #endif EM_TX_UNLOCK(adapter); @@ -2541,7 +2431,11 @@ em_set_multi(struct adapter *adapter) if (mta == NULL) panic("em_set_multi memory failure\n"); +#if __FreeBSD_version < 800000 + IF_ADDR_LOCK(ifp); +#else if_maddr_rlock(ifp); +#endif TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; @@ -2553,8 +2447,11 @@ em_set_multi(struct adapter *adapter) &mta[mcnt * ETH_ADDR_LEN], ETH_ADDR_LEN); mcnt++; } +#if __FreeBSD_version < 800000 + IF_ADDR_UNLOCK(ifp); +#else if_maddr_runlock(ifp); - +#endif if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES) { reg_rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL); reg_rctl |= E1000_RCTL_MPE; @@ -2605,13 +2502,21 @@ em_local_timer(void *arg) em_smartspeed(adapter); /* - * Each second we check the watchdog to - * protect against hardware hangs. + * We check the watchdog: the time since + * the last TX descriptor was cleaned. + * This implies a functional TX engine. */ - em_watchdog(adapter); + if ((adapter->watchdog_check == TRUE) && + (ticks - adapter->watchdog_time > EM_WATCHDOG)) + goto hung; callout_reset(&adapter->timer, hz, em_local_timer, adapter); - + return; +hung: + device_printf(adapter->dev, "Watchdog timeout -- resetting\n"); + adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + adapter->watchdog_events++; + em_init_locked(adapter); } static void @@ -2677,7 +2582,7 @@ em_update_link_status(struct adapter *adapter) device_printf(dev, "Link is Down\n"); adapter->link_active = 0; /* Link down, disable watchdog */ - adapter->watchdog_timer = FALSE; + adapter->watchdog_check = FALSE; if_link_state_change(ifp, LINK_STATE_DOWN); } } @@ -3093,15 +2998,6 @@ em_hardware_init(struct adapter *adapter) /* Issue a global reset */ e1000_reset_hw(&adapter->hw); - /* Get control from any management/hw control */ - if (((adapter->hw.mac.type == e1000_82573) || - (adapter->hw.mac.type == e1000_82583) || - (adapter->hw.mac.type == e1000_ich8lan) || - (adapter->hw.mac.type == e1000_ich10lan) || - (adapter->hw.mac.type == e1000_ich9lan)) && - e1000_check_mng_mode(&adapter->hw)) - em_get_hw_control(adapter); - /* When hardware is reset, fifo_head is also reset */ adapter->tx_fifo_head = 0; @@ -3151,6 +3047,9 @@ em_hardware_init(struct adapter *adapter) else adapter->hw.fc.requested_mode = e1000_fc_none; + /* Override - workaround for PCHLAN issue */ + if (adapter->hw.mac.type == e1000_pchlan) + adapter->hw.fc.requested_mode = e1000_fc_rx_pause; if (e1000_init_hw(&adapter->hw) < 0) { device_printf(dev, "Hardware Initialization Failed\n"); @@ -3233,6 +3132,12 @@ em_setup_interface(device_t dev, struct adapter *adapter) ifp->if_capabilities |= IFCAP_POLLING; #endif + /* Enable All WOL methods by default */ + if (adapter->wol) { + ifp->if_capabilities |= IFCAP_WOL; + ifp->if_capenable |= IFCAP_WOL; + } + /* * Specify the media types supported by this adapter and register * callbacks to update media and link information @@ -3299,7 +3204,7 @@ em_smartspeed(struct adapter *adapter) PHY_1000T_CTRL, phy_tmp); adapter->smartspeed++; if(adapter->hw.mac.autoneg && - !e1000_phy_setup_autoneg(&adapter->hw) && + !e1000_copper_link_autoneg(&adapter->hw) && !e1000_read_phy_reg(&adapter->hw, PHY_CONTROL, &phy_tmp)) { phy_tmp |= (MII_CR_AUTO_NEG_EN | @@ -3316,7 +3221,7 @@ em_smartspeed(struct adapter *adapter) phy_tmp |= CR_1000T_MS_ENABLE; e1000_write_phy_reg(&adapter->hw, PHY_1000T_CTRL, phy_tmp); if(adapter->hw.mac.autoneg && - !e1000_phy_setup_autoneg(&adapter->hw) && + !e1000_copper_link_autoneg(&adapter->hw) && !e1000_read_phy_reg(&adapter->hw, PHY_CONTROL, &phy_tmp)) { phy_tmp |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); @@ -3975,7 +3880,6 @@ static void em_txeof(struct adapter *adapter) { int first, last, done, num_avail; - u32 cleaned = 0; struct em_buffer *tx_buffer; struct e1000_tx_desc *tx_desc, *eop_desc; struct ifnet *ifp = adapter->ifp; @@ -4011,7 +3915,7 @@ em_txeof(struct adapter *adapter) tx_desc->upper.data = 0; tx_desc->lower.data = 0; tx_desc->buffer_addr = 0; - ++num_avail; ++cleaned; + ++num_avail; if (tx_buffer->m_head) { ifp->if_opackets++; @@ -4025,6 +3929,7 @@ em_txeof(struct adapter *adapter) tx_buffer->m_head = NULL; } tx_buffer->next_eop = -1; + adapter->watchdog_time = ticks; if (++first == adapter->num_tx_desc) first = 0; @@ -4050,20 +3955,17 @@ em_txeof(struct adapter *adapter) /* * If we have enough room, clear IFF_DRV_OACTIVE to * tell the stack that it is OK to send packets. - * If there are no pending descriptors, clear the timeout. + * If there are no pending descriptors, clear the watchdog. */ if (num_avail > EM_TX_CLEANUP_THRESHOLD) { ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; if (num_avail == adapter->num_tx_desc) { - adapter->watchdog_timer = 0; + adapter->watchdog_check = FALSE; adapter->num_tx_desc_avail = num_avail; return; } } - /* If any descriptors cleaned, reset the watchdog */ - if (cleaned) - adapter->watchdog_timer = EM_TX_TIMEOUT; adapter->num_tx_desc_avail = num_avail; return; } @@ -4071,7 +3973,7 @@ em_txeof(struct adapter *adapter) /********************************************************************* * * When Link is lost sometimes there is work still in the TX ring - * which will result in a watchdog, rather than allow that do an + * which may result in a watchdog, rather than allow that we do an * attempted cleanup and then reinit here. Note that this has been * seens mostly with fiber adapters. * @@ -4079,14 +3981,12 @@ em_txeof(struct adapter *adapter) static void em_tx_purge(struct adapter *adapter) { - if ((!adapter->link_active) && (adapter->watchdog_timer)) { + if ((!adapter->link_active) && (adapter->watchdog_check)) { EM_TX_LOCK(adapter); em_txeof(adapter); EM_TX_UNLOCK(adapter); - if (adapter->watchdog_timer) { /* Still not clean? */ - adapter->watchdog_timer = 0; + if (adapter->watchdog_check) /* Still outstanding? */ em_init_locked(adapter); - } } } @@ -4877,72 +4777,54 @@ em_release_manageability(struct adapter *adapter) } /* - * em_get_hw_control sets {CTRL_EXT|FWSM}:DRV_LOAD bit. - * For ASF and Pass Through versions of f/w this means that - * the driver is loaded. For AMT version (only with 82573) - * of the f/w this means that the network i/f is open. - * + * em_get_hw_control sets the {CTRL_EXT|FWSM}:DRV_LOAD bit. + * For ASF and Pass Through versions of f/w this means + * that the driver is loaded. For AMT version type f/w + * this means that the network i/f is open. */ static void em_get_hw_control(struct adapter *adapter) { u32 ctrl_ext, swsm; - /* Let firmware know the driver has taken over */ - switch (adapter->hw.mac.type) { - case e1000_82573: + if (adapter->hw.mac.type == e1000_82573) { swsm = E1000_READ_REG(&adapter->hw, E1000_SWSM); E1000_WRITE_REG(&adapter->hw, E1000_SWSM, swsm | E1000_SWSM_DRV_LOAD); - break; - case e1000_82571: - case e1000_82572: - case e1000_80003es2lan: - case e1000_ich8lan: - case e1000_ich9lan: - case e1000_ich10lan: - ctrl_ext = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT); - E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT, - ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); - break; - default: - break; + return; } + /* else */ + ctrl_ext = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT); + E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT, + ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); + return; } /* * em_release_hw_control resets {CTRL_EXT|FWSM}:DRV_LOAD bit. - * For ASF and Pass Through versions of f/w this means that the - * driver is no longer loaded. For AMT version (only with 82573) i - * of the f/w this means that the network i/f is closed. - * + * For ASF and Pass Through versions of f/w this means that + * the driver is no longer loaded. For AMT versions of the + * f/w this means that the network i/f is closed. */ static void em_release_hw_control(struct adapter *adapter) { u32 ctrl_ext, swsm; - /* Let firmware taken over control of h/w */ - switch (adapter->hw.mac.type) { - case e1000_82573: + if (!adapter->has_manage) + return; + + if (adapter->hw.mac.type == e1000_82573) { swsm = E1000_READ_REG(&adapter->hw, E1000_SWSM); E1000_WRITE_REG(&adapter->hw, E1000_SWSM, swsm & ~E1000_SWSM_DRV_LOAD); - break; - case e1000_82571: - case e1000_82572: - case e1000_80003es2lan: - case e1000_ich8lan: - case e1000_ich9lan: - case e1000_ich10lan: - ctrl_ext = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT); - E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT, - ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD); - break; - default: - break; - + return; } + /* else */ + ctrl_ext = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT); + E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT, + ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD); + return; } static int @@ -4958,29 +4840,251 @@ em_is_valid_ether_addr(u8 *addr) } /* +** Parse the interface capabilities with regard +** to both system management and wake-on-lan for +** later use. +*/ +static void +em_get_wakeup(device_t dev) +{ + struct adapter *adapter = device_get_softc(dev); + u16 eeprom_data = 0, device_id, apme_mask; + + adapter->has_manage = e1000_enable_mng_pass_thru(&adapter->hw); + apme_mask = EM_EEPROM_APME; + + switch (adapter->hw.mac.type) { + case e1000_82542: + case e1000_82543: + break; + case e1000_82544: + e1000_read_nvm(&adapter->hw, + NVM_INIT_CONTROL2_REG, 1, &eeprom_data); + apme_mask = EM_82544_APME; + break; + case e1000_82573: + case e1000_82583: + adapter->has_amt = TRUE; + /* Falls thru */ + case e1000_82546: + case e1000_82546_rev_3: + case e1000_82571: + case e1000_82572: + case e1000_80003es2lan: + if (adapter->hw.bus.func == 1) { + e1000_read_nvm(&adapter->hw, + NVM_INIT_CONTROL3_PORT_B, 1, &eeprom_data); + break; + } else + e1000_read_nvm(&adapter->hw, + NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data); + break; + case e1000_ich8lan: + case e1000_ich9lan: + case e1000_ich10lan: + case e1000_pchlan: + apme_mask = E1000_WUC_APME; + adapter->has_amt = TRUE; + eeprom_data = E1000_READ_REG(&adapter->hw, E1000_WUC); + break; + default: + e1000_read_nvm(&adapter->hw, + NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data); + break; + } + if (eeprom_data & apme_mask) + adapter->wol = (E1000_WUFC_MAG | E1000_WUFC_MC); + /* + * We have the eeprom settings, now apply the special cases + * where the eeprom may be wrong or the board won't support + * wake on lan on a particular port + */ + device_id = pci_get_device(dev); + switch (device_id) { + case E1000_DEV_ID_82546GB_PCIE: + adapter->wol = 0; + break; + case E1000_DEV_ID_82546EB_FIBER: + case E1000_DEV_ID_82546GB_FIBER: + case E1000_DEV_ID_82571EB_FIBER: + /* Wake events only supported on port A for dual fiber + * regardless of eeprom setting */ + if (E1000_READ_REG(&adapter->hw, E1000_STATUS) & + E1000_STATUS_FUNC_1) + adapter->wol = 0; + break; + case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3: + case E1000_DEV_ID_82571EB_QUAD_COPPER: + case E1000_DEV_ID_82571EB_QUAD_FIBER: + case E1000_DEV_ID_82571EB_QUAD_COPPER_LP: + /* if quad port adapter, disable WoL on all but port A */ + if (global_quad_port_a != 0) + adapter->wol = 0; + /* Reset for multiple quad port adapters */ + if (++global_quad_port_a == 4) + global_quad_port_a = 0; + break; + } + return; +} + + +/* * Enable PCI Wake On Lan capability */ void em_enable_wakeup(device_t dev) { - u16 cap, status; - u8 id; - - /* First find the capabilities pointer*/ - cap = pci_read_config(dev, PCIR_CAP_PTR, 2); - /* Read the PM Capabilities */ - id = pci_read_config(dev, cap, 1); - if (id != PCIY_PMG) /* Something wrong */ + struct adapter *adapter = device_get_softc(dev); + struct ifnet *ifp = adapter->ifp; + u32 pmc, ctrl, ctrl_ext, rctl; + u16 status; + + if ((pci_find_extcap(dev, PCIY_PMG, &pmc) != 0)) return; - /* OK, we have the power capabilities, so - now get the status register */ - cap += PCIR_POWER_STATUS; - status = pci_read_config(dev, cap, 2); - status |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; - pci_write_config(dev, cap, status, 2); + + /* Advertise the wakeup capability */ + ctrl = E1000_READ_REG(&adapter->hw, E1000_CTRL); + ctrl |= (E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN3); + E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl); + E1000_WRITE_REG(&adapter->hw, E1000_WUC, E1000_WUC_PME_EN); + + /* ICH workaround code */ + if ((adapter->hw.mac.type == e1000_ich8lan) || + (adapter->hw.mac.type == e1000_pchlan) || + (adapter->hw.mac.type == e1000_ich9lan) || + (adapter->hw.mac.type == e1000_ich10lan)) { + e1000_disable_gig_wol_ich8lan(&adapter->hw); + e1000_hv_phy_powerdown_workaround_ich8lan(&adapter->hw); + } + + /* Keep the laser running on Fiber adapters */ + if (adapter->hw.phy.media_type == e1000_media_type_fiber || + adapter->hw.phy.media_type == e1000_media_type_internal_serdes) { + ctrl_ext = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_SDP3_DATA; + E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT, ctrl_ext); + } + + /* + ** Determine type of Wakeup: note that wol + ** is set with all bits on by default. + */ + if ((ifp->if_capenable & IFCAP_WOL_MAGIC) == 0) + adapter->wol &= ~E1000_WUFC_MAG; + + if ((ifp->if_capenable & IFCAP_WOL_MCAST) == 0) + adapter->wol &= ~E1000_WUFC_MC; + else { + rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL); + rctl |= E1000_RCTL_MPE; + E1000_WRITE_REG(&adapter->hw, E1000_RCTL, rctl); + } + + if (adapter->hw.mac.type == e1000_pchlan) { + if (em_enable_phy_wakeup(adapter)) + return; + } else { + E1000_WRITE_REG(&adapter->hw, E1000_WUC, E1000_WUC_PME_EN); + E1000_WRITE_REG(&adapter->hw, E1000_WUFC, adapter->wol); + } + + if (adapter->hw.phy.type == e1000_phy_igp_3) + e1000_igp3_phy_powerdown_workaround_ich8lan(&adapter->hw); + + /* Request PME */ + status = pci_read_config(dev, pmc + PCIR_POWER_STATUS, 2); + status &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE); + if (ifp->if_capenable & IFCAP_WOL) + status |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; + pci_write_config(dev, pmc + PCIR_POWER_STATUS, status, 2); + return; } +/* +** WOL in the newer chipset interfaces (pchlan) +** require thing to be copied into the phy +*/ +static int +em_enable_phy_wakeup(struct adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 mreg, ret = 0; + u16 preg; + + /* copy MAC RARs to PHY RARs */ + for (int i = 0; i < adapter->hw.mac.rar_entry_count; i++) { + mreg = E1000_READ_REG(hw, E1000_RAL(i)); + e1000_write_phy_reg(hw, BM_RAR_L(i), (u16)(mreg & 0xFFFF)); + e1000_write_phy_reg(hw, BM_RAR_M(i), + (u16)((mreg >> 16) & 0xFFFF)); + mreg = E1000_READ_REG(hw, E1000_RAH(i)); + e1000_write_phy_reg(hw, BM_RAR_H(i), (u16)(mreg & 0xFFFF)); + e1000_write_phy_reg(hw, BM_RAR_CTRL(i), + (u16)((mreg >> 16) & 0xFFFF)); + } + + /* copy MAC MTA to PHY MTA */ + for (int i = 0; i < adapter->hw.mac.mta_reg_count; i++) { + mreg = E1000_READ_REG_ARRAY(hw, E1000_MTA, i); + e1000_write_phy_reg(hw, BM_MTA(i), (u16)(mreg & 0xFFFF)); + e1000_write_phy_reg(hw, BM_MTA(i) + 1, + (u16)((mreg >> 16) & 0xFFFF)); + } + + /* configure PHY Rx Control register */ + e1000_read_phy_reg(&adapter->hw, BM_RCTL, &preg); + mreg = E1000_READ_REG(hw, E1000_RCTL); + if (mreg & E1000_RCTL_UPE) + preg |= BM_RCTL_UPE; + if (mreg & E1000_RCTL_MPE) + preg |= BM_RCTL_MPE; + preg &= ~(BM_RCTL_MO_MASK); + if (mreg & E1000_RCTL_MO_3) + preg |= (((mreg & E1000_RCTL_MO_3) >> E1000_RCTL_MO_SHIFT) + << BM_RCTL_MO_SHIFT); + if (mreg & E1000_RCTL_BAM) + preg |= BM_RCTL_BAM; + if (mreg & E1000_RCTL_PMCF) + preg |= BM_RCTL_PMCF; + mreg = E1000_READ_REG(hw, E1000_CTRL); + if (mreg & E1000_CTRL_RFCE) + preg |= BM_RCTL_RFCE; + e1000_write_phy_reg(&adapter->hw, BM_RCTL, preg); + + /* enable PHY wakeup in MAC register */ + E1000_WRITE_REG(hw, E1000_WUC, + E1000_WUC_PHY_WAKE | E1000_WUC_PME_EN); + E1000_WRITE_REG(hw, E1000_WUFC, adapter->wol); + + /* configure and enable PHY wakeup in PHY registers */ + e1000_write_phy_reg(&adapter->hw, BM_WUFC, adapter->wol); + e1000_write_phy_reg(&adapter->hw, BM_WUC, E1000_WUC_PME_EN); + + /* activate PHY wakeup */ + ret = hw->phy.ops.acquire(hw); + if (ret) { + printf("Could not acquire PHY\n"); + return ret; + } + e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, + (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT)); + ret = e1000_read_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, &preg); + if (ret) { + printf("Could not read PHY page 769\n"); + goto out; + } + preg |= BM_WUC_ENABLE_BIT | BM_WUC_HOST_WU_BIT; + ret = e1000_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, preg); + if (ret) + printf("Could not set PHY Host Wakeup bit\n"); +out: + hw->phy.ops.release(hw); + + return ret; +} + /********************************************************************* * 82544 Coexistence issue workaround. diff --git a/sys/dev/e1000/if_em.h b/sys/dev/e1000/if_em.h index 7487a89..5019e0a 100644 --- a/sys/dev/e1000/if_em.h +++ b/sys/dev/e1000/if_em.h @@ -135,9 +135,9 @@ #define EM_RADV 64 /* - * This parameter controls the duration of transmit watchdog timer. + * This parameter controls the max duration of transmit watchdog. */ -#define EM_TX_TIMEOUT 5 +#define EM_WATCHDOG (5 * hz) /* * This parameter controls when the driver calls the routine to reclaim @@ -189,6 +189,7 @@ #define ETHER_ALIGN 2 #define EM_FC_PAUSE_TIME 0x0680 #define EM_EEPROM_APME 0x400; +#define EM_82544_APME 0x0004; /* Code compatilbility between 6 and 7 */ #ifndef ETHER_BPF_MTAP @@ -308,7 +309,8 @@ struct adapter { struct ifmedia media; struct callout timer; struct callout tx_fifo_timer; - int watchdog_timer; + bool watchdog_check; + int watchdog_time; int msi; int if_flags; int max_frame_size; @@ -332,8 +334,9 @@ struct adapter { #endif /* Management and WOL features */ - int wol; - int has_manage; + u32 wol; + bool has_manage; + bool has_amt; /* Info about the board itself */ uint8_t link_active; diff --git a/sys/dev/e1000/if_igb.c b/sys/dev/e1000/if_igb.c index 61743df..dc2e85f 100644 --- a/sys/dev/e1000/if_igb.c +++ b/sys/dev/e1000/if_igb.c @@ -101,7 +101,7 @@ int igb_display_debug_stats = 0; /********************************************************************* * Driver version: *********************************************************************/ -char igb_driver_version[] = "version - 1.7.3"; +char igb_driver_version[] = "version - 1.8.4"; /********************************************************************* @@ -123,12 +123,19 @@ static igb_vendor_info_t igb_vendor_info_array[] = PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_82576, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_82576_NS, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82576_NS_SERDES, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_82576_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_82576_SERDES, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_82576_SERDES_QUAD, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_82576_QUAD_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82580_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82580_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82580_SERDES, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82580_SGMII, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82580_COPPER_DUAL, + PCI_ANY_ID, PCI_ANY_ID, 0}, /* required last entry */ { 0, 0, 0, 0, 0} }; @@ -159,7 +166,6 @@ static int igb_mq_start_locked(struct ifnet *, static void igb_qflush(struct ifnet *); #endif static int igb_ioctl(struct ifnet *, u_long, caddr_t); -static void igb_watchdog(struct adapter *); static void igb_init(void *); static void igb_init_locked(struct adapter *); static void igb_stop(void *); @@ -172,7 +178,7 @@ static int igb_allocate_legacy(struct adapter *); static int igb_setup_msix(struct adapter *); static void igb_free_pci_resources(struct adapter *); static void igb_local_timer(void *); -static int igb_hardware_init(struct adapter *); +static void igb_reset(struct adapter *); static void igb_setup_interface(device_t, struct adapter *); static int igb_allocate_queues(struct adapter *); static void igb_configure_queues(struct adapter *); @@ -204,7 +210,7 @@ static void igb_disable_promisc(struct adapter *); static void igb_set_multi(struct adapter *); static void igb_print_hw_stats(struct adapter *); static void igb_update_link_status(struct adapter *); -static int igb_get_buf(struct rx_ring *, int, u8); +static int igb_get_buf(struct rx_ring *, int, int); static void igb_register_vlan(void *, struct ifnet *, u16); static void igb_unregister_vlan(void *, struct ifnet *, u16); @@ -296,11 +302,27 @@ static int igb_bulk_latency = IGB_BULK_LATENCY; TUNABLE_INT("hw.igb.bulk_latency", &igb_bulk_latency); /* + * MSIX should be the default for best performance, + * but this allows it to be forced off for testing. + */ +static int igb_enable_msix = 1; +TUNABLE_INT("hw.igb.enable_msix", &igb_enable_msix); + +/* + * Header split has seemed to be beneficial in + * all circumstances tested, so its on by default + * however this variable will allow it to be disabled + * for some debug purposes. + */ +static bool igb_header_split = TRUE; +TUNABLE_INT("hw.igb.hdr_split", &igb_header_split); + +/* ** This will autoconfigure based on the number -** of CPUs if set to 0. Only a matched pair of +** of CPUs if left at 0. Only a matched pair of ** TX and RX rings are allowed. */ -static int igb_num_queues = 1; +static int igb_num_queues = 0; TUNABLE_INT("hw.igb.num_queues", &igb_num_queues); /* How many packets rxeof tries to clean at a time */ @@ -540,17 +562,10 @@ igb_attach(device_t dev) goto err_late; } - /* Now Initialize the hardware */ - if (igb_hardware_init(adapter)) { - device_printf(dev, "Unable to initialize the hardware\n"); - error = EIO; - goto err_late; - } - /* ** Configure Interrupts */ - if (adapter->msix > 1) /* MSIX */ + if ((adapter->msix > 1) && (igb_enable_msix)) error = igb_allocate_msix(adapter); else /* MSI or Legacy */ error = igb_allocate_legacy(adapter); @@ -560,6 +575,9 @@ igb_attach(device_t dev) /* Setup OS specific network interface */ igb_setup_interface(dev, adapter); + /* Now get a good starting state */ + igb_reset(adapter); + #ifdef IGB_IEEE1588 /* ** Setup the timer: IEEE 1588 support @@ -787,8 +805,8 @@ igb_start_locked(struct tx_ring *txr, struct ifnet *ifp) /* Send a copy of the frame to the BPF listener */ ETHER_BPF_MTAP(ifp, m_head); - /* Set timeout in case hardware has problems transmitting. */ - txr->watchdog_timer = IGB_TX_TIMEOUT; + /* Set watchdog on */ + txr->watchdog_check = TRUE; } } @@ -854,17 +872,16 @@ igb_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr, struct mbuf *m) /* If nothing queued go right to xmit */ if (drbr_empty(ifp, txr->br)) { - if ((err = igb_xmit(txr, &m)) != 0) { - if (m != NULL) - err = drbr_enqueue(ifp, txr->br, m); - return (err); + if (igb_xmit(txr, &m)) { + if (m && (err = drbr_enqueue(ifp, txr->br, m)) != 0) + return (err); } else { /* Success, update stats */ drbr_stats_update(ifp, m->m_pkthdr.len, m->m_flags); /* Send a copy of the frame to the BPF listener */ ETHER_BPF_MTAP(ifp, m); /* Set the watchdog */ - txr->watchdog_timer = IGB_TX_TIMEOUT; + txr->watchdog_check = TRUE; } } else if ((err = drbr_enqueue(ifp, txr->br, m)) != 0) @@ -881,15 +898,11 @@ process: next = drbr_dequeue(ifp, txr->br); if (next == NULL) break; - if ((err = igb_xmit(txr, &next)) != 0) { - if (next != NULL) - err = drbr_enqueue(ifp, txr->br, next); + if (igb_xmit(txr, &next)) break; - } - drbr_stats_update(ifp, next->m_pkthdr.len, next->m_flags); ETHER_BPF_MTAP(ifp, next); /* Set the watchdog */ - txr->watchdog_timer = IGB_TX_TIMEOUT; + txr->watchdog_check = TRUE; } if (txr->tx_avail <= IGB_TX_OP_THRESHOLD) @@ -957,8 +970,7 @@ igb_ioctl(struct ifnet *ifp, u_long command, caddr_t data) igb_init_locked(adapter); IGB_CORE_UNLOCK(adapter); } - if (!(ifp->if_flags & IFF_NOARP)) - arp_ifinit(ifp, ifa); + arp_ifinit(ifp, ifa); } else #endif error = ether_ioctl(ifp, command, data); @@ -1049,7 +1061,7 @@ igb_ioctl(struct ifnet *ifp, u_long command, caddr_t data) ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; reinit = 1; } - if (mask & IFCAP_LRO) { + if ((mask & IFCAP_LRO) && (igb_header_split)) { ifp->if_capenable ^= IFCAP_LRO; reinit = 1; } @@ -1076,80 +1088,6 @@ igb_ioctl(struct ifnet *ifp, u_long command, caddr_t data) return (error); } -/********************************************************************* - * Watchdog timer: - * - * This routine is called from the local timer every second. - * As long as transmit descriptors are being cleaned the value - * is non-zero and we do nothing. Reaching 0 indicates a tx hang - * and we then reset the device. - * - **********************************************************************/ - -static void -igb_watchdog(struct adapter *adapter) -{ - struct tx_ring *txr = adapter->tx_rings; - bool tx_hang = FALSE; - - IGB_CORE_LOCK_ASSERT(adapter); - - /* - ** The timer is set to 5 every time start() queues a packet. - ** Then txeof keeps resetting it as long as it cleans at - ** least one descriptor. - ** Finally, anytime all descriptors are clean the timer is - ** set to 0. - ** - ** With TX Multiqueue we need to check every queue's timer, - ** if any time out we do the reset. - */ - for (int i = 0; i < adapter->num_queues; i++, txr++) { - IGB_TX_LOCK(txr); - if (txr->watchdog_timer == 0 || - (--txr->watchdog_timer)) { - IGB_TX_UNLOCK(txr); - continue; - } else { - tx_hang = TRUE; - IGB_TX_UNLOCK(txr); - break; - } - } - if (tx_hang == FALSE) - return; - - /* If we are in this routine because of pause frames, then - * don't reset the hardware. - */ - if (E1000_READ_REG(&adapter->hw, E1000_STATUS) & - E1000_STATUS_TXOFF) { - txr = adapter->tx_rings; /* reset pointer */ - for (int i = 0; i < adapter->num_queues; i++, txr++) { - IGB_TX_LOCK(txr); - txr->watchdog_timer = IGB_TX_TIMEOUT; - IGB_TX_UNLOCK(txr); - } - return; - } - - if (e1000_check_for_link(&adapter->hw) == 0) - device_printf(adapter->dev, "watchdog timeout -- resetting\n"); - - for (int i = 0; i < adapter->num_queues; i++, txr++) { - device_printf(adapter->dev, "Queue(%d) tdh = %d, tdt = %d\n", - i, E1000_READ_REG(&adapter->hw, E1000_TDH(i)), - E1000_READ_REG(&adapter->hw, E1000_TDT(i))); - device_printf(adapter->dev, "Queue(%d) desc avail = %d," - " Next Desc to Clean = %d\n", i, txr->tx_avail, - txr->next_to_clean); - } - - adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - adapter->watchdog_events++; - - igb_init_locked(adapter); -} /********************************************************************* * Init entry point @@ -1165,29 +1103,16 @@ igb_watchdog(struct adapter *adapter) static void igb_init_locked(struct adapter *adapter) { - struct rx_ring *rxr = adapter->rx_rings; - struct tx_ring *txr = adapter->tx_rings; struct ifnet *ifp = adapter->ifp; device_t dev = adapter->dev; - u32 pba = 0; INIT_DEBUGOUT("igb_init: begin"); IGB_CORE_LOCK_ASSERT(adapter); - igb_stop(adapter); + igb_disable_intr(adapter); + callout_stop(&adapter->timer); - /* - * Packet Buffer Allocation (PBA) - * Writing PBA sets the receive portion of the buffer - * the remainder is used for the transmit buffer. - */ - if (adapter->hw.mac.type == e1000_82575) { - INIT_DEBUGOUT1("igb_init: pba=%dK",pba); - pba = E1000_PBA_32K; /* 32K for Rx, 16K for Tx */ - E1000_WRITE_REG(&adapter->hw, E1000_PBA, pba); - } - /* Get the latest mac address, User can use a LAA */ bcopy(IF_LLADDR(adapter->ifp), adapter->hw.mac.addr, ETHER_ADDR_LEN); @@ -1195,15 +1120,9 @@ igb_init_locked(struct adapter *adapter) /* Put the address into the Receive Address Array */ e1000_rar_set(&adapter->hw, adapter->hw.mac.addr, 0); - /* Initialize the hardware */ - if (igb_hardware_init(adapter)) { - device_printf(dev, "Unable to initialize the hardware\n"); - return; - } + igb_reset(adapter); igb_update_link_status(adapter); - E1000_WRITE_REG(&adapter->hw, E1000_VET, ETHERTYPE_VLAN); - /* Set hardware offload abilities */ ifp->if_hwassist = 0; if (ifp->if_capenable & IFCAP_TXCSUM) { @@ -1239,7 +1158,6 @@ igb_init_locked(struct adapter *adapter) /* Prepare receive descriptors and buffers */ if (igb_setup_receive_structures(adapter)) { device_printf(dev, "Could not setup receive structures\n"); - igb_stop(adapter); return; } igb_initialize_receive_units(adapter); @@ -1259,26 +1177,10 @@ igb_init_locked(struct adapter *adapter) /* Set up VLAN tag offload and filter */ igb_setup_vlan_hw_support(adapter); - /* Set default RX interrupt moderation */ - for (int i = 0; i < adapter->num_queues; i++, rxr++) { - E1000_WRITE_REG(&adapter->hw, - E1000_EITR(rxr->msix), igb_ave_latency); - rxr->eitr_setting = igb_ave_latency; - } - - /* Set TX interrupt rate & reset TX watchdog */ - for (int i = 0; i < adapter->num_queues; i++, txr++) { - E1000_WRITE_REG(&adapter->hw, - E1000_EITR(txr->msix), igb_ave_latency); - txr->watchdog_timer = FALSE; - } - - { - /* this clears any pending interrupts */ - E1000_READ_REG(&adapter->hw, E1000_ICR); - igb_enable_intr(adapter); - E1000_WRITE_REG(&adapter->hw, E1000_ICS, E1000_ICS_LSC); - } + /* this clears any pending interrupts */ + E1000_READ_REG(&adapter->hw, E1000_ICR); + igb_enable_intr(adapter); + E1000_WRITE_REG(&adapter->hw, E1000_ICS, E1000_ICS_LSC); /* Don't reset the phy next time init gets called */ adapter->hw.phy.reset_disable = TRUE; @@ -1329,13 +1231,15 @@ igb_handle_rx(void *context, int pending) { struct rx_ring *rxr = context; struct adapter *adapter = rxr->adapter; - struct ifnet *ifp = adapter->ifp; + u32 loop = IGB_MAX_LOOP; + bool more; - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - if (igb_rxeof(rxr, adapter->rx_process_limit) != 0) - /* More to clean, schedule another task */ - taskqueue_enqueue(adapter->tq, &rxr->rx_task); + do { + more = igb_rxeof(rxr, -1); + } while (loop-- && more); + /* Reenable this interrupt */ + E1000_WRITE_REG(&adapter->hw, E1000_EIMS, rxr->eims); } static void @@ -1343,20 +1247,24 @@ igb_handle_tx(void *context, int pending) { struct tx_ring *txr = context; struct adapter *adapter = txr->adapter; - struct ifnet *ifp = adapter->ifp; + struct ifnet *ifp = adapter->ifp; + u32 loop = IGB_MAX_LOOP; + bool more; - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - IGB_TX_LOCK(txr); - igb_txeof(txr); + IGB_TX_LOCK(txr); + do { + more = igb_txeof(txr); + } while (loop-- && more); #if __FreeBSD_version >= 800000 - if (!drbr_empty(ifp, txr->br)) - igb_mq_start_locked(ifp, txr, NULL); + if (!drbr_empty(ifp, txr->br)) + igb_mq_start_locked(ifp, txr, NULL); #else - if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - igb_start_locked(txr, ifp); + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + igb_start_locked(txr, ifp); #endif - IGB_TX_UNLOCK(txr); - } + IGB_TX_UNLOCK(txr); + /* Reenable this interrupt */ + E1000_WRITE_REG(&adapter->hw, E1000_EIMS, txr->eims); } @@ -1416,23 +1324,21 @@ igb_msix_tx(void *arg) { struct tx_ring *txr = arg; struct adapter *adapter = txr->adapter; - u32 loop = IGB_MAX_LOOP; bool more; - ++txr->tx_irq; - IGB_TX_LOCK(txr); - - do { - more = igb_txeof(txr); - } while (loop-- && more); + E1000_WRITE_REG(&adapter->hw, E1000_EIMC, txr->eims); + IGB_TX_LOCK(txr); + ++txr->tx_irq; + more = igb_txeof(txr); IGB_TX_UNLOCK(txr); - /* Schedule a clean task */ - taskqueue_enqueue(adapter->tq, &txr->tx_task); - - /* Reenable this interrupt */ - E1000_WRITE_REG(&adapter->hw, E1000_EIMS, txr->eims); + /* Schedule a clean task if needed*/ + if (more) + taskqueue_enqueue(txr->tq, &txr->tx_task); + else + /* Reenable this interrupt */ + E1000_WRITE_REG(&adapter->hw, E1000_EIMS, txr->eims); return; } @@ -1447,23 +1353,23 @@ igb_msix_rx(void *arg) { struct rx_ring *rxr = arg; struct adapter *adapter = rxr->adapter; - u32 loop = IGB_MAX_LOOP; bool more; + E1000_WRITE_REG(&adapter->hw, E1000_EIMC, rxr->eims); + ++rxr->rx_irq; - do { - more = igb_rxeof(rxr, adapter->rx_process_limit); - } while (loop-- && more); + more = igb_rxeof(rxr, adapter->rx_process_limit); /* Update interrupt rate */ if (igb_enable_aim == TRUE) igb_update_aim(rxr); /* Schedule another clean */ - taskqueue_enqueue(adapter->tq, &rxr->rx_task); - - /* Reenable this interrupt */ - E1000_WRITE_REG(&adapter->hw, E1000_EIMS, rxr->eims); + if (more) + taskqueue_enqueue(rxr->tq, &rxr->rx_task); + else + /* Reenable this interrupt */ + E1000_WRITE_REG(&adapter->hw, E1000_EIMS, rxr->eims); return; } @@ -1536,11 +1442,8 @@ igb_update_aim(struct rx_ring *rxr) if (olditr != newitr) { /* Change interrupt rate */ rxr->eitr_setting = newitr; - if (adapter->hw.mac.type == e1000_82575) - newitr |= newitr << 16; - else - newitr |= 0x8000000; - E1000_WRITE_REG(&adapter->hw, E1000_EITR(rxr->me), newitr); + E1000_WRITE_REG(&adapter->hw, E1000_EITR(rxr->me), + newitr | (newitr << 16)); } rxr->bytes = 0; @@ -1789,6 +1692,10 @@ igb_xmit(struct tx_ring *txr, struct mbuf **m_headp) olinfo_status |= ((m_head->m_pkthdr.len - hdrlen) << E1000_ADVTXD_PAYLEN_SHIFT); + /* 82575 needs the queue index added */ + if (adapter->hw.mac.type == e1000_82575) + olinfo_status |= txr->me << 4; + /* Set up our transmit descriptors */ i = txr->next_avail_desc; for (j = 0; j < nsegs; j++) { @@ -1896,7 +1803,11 @@ igb_set_multi(struct adapter *adapter) IOCTL_DEBUGOUT("igb_set_multi: begin"); +#if __FreeBSD_version < 800000 + IF_ADDR_LOCK(ifp); +#else if_maddr_rlock(ifp); +#endif TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; @@ -1908,8 +1819,11 @@ igb_set_multi(struct adapter *adapter) &mta[mcnt * ETH_ADDR_LEN], ETH_ADDR_LEN); mcnt++; } +#if __FreeBSD_version < 800000 + IF_ADDR_UNLOCK(ifp); +#else if_maddr_runlock(ifp); - +#endif if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES) { reg_rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL); reg_rctl |= E1000_RCTL_MPE; @@ -1920,17 +1834,20 @@ igb_set_multi(struct adapter *adapter) /********************************************************************* - * Timer routine - * - * This routine checks for link status and updates statistics. + * Timer routine: + * This routine checks for link status, + * updates statistics, and does the watchdog. * **********************************************************************/ static void igb_local_timer(void *arg) { - struct adapter *adapter = arg; - struct ifnet *ifp = adapter->ifp; + struct adapter *adapter = arg; + struct ifnet *ifp = adapter->ifp; + device_t dev = adapter->dev; + struct tx_ring *txr = adapter->tx_rings; + IGB_CORE_LOCK_ASSERT(adapter); @@ -1940,17 +1857,32 @@ igb_local_timer(void *arg) if (igb_display_debug_stats && ifp->if_drv_flags & IFF_DRV_RUNNING) igb_print_hw_stats(adapter); - /* - * Each second we check the watchdog to - * protect against hardware hangs. - */ - igb_watchdog(adapter); + /* + ** Watchdog: check for time since any descriptor was cleaned + */ + for (int i = 0; i < adapter->num_queues; i++, txr++) { + if (txr->watchdog_check == FALSE) + continue; + if ((ticks - txr->watchdog_time) > IGB_WATCHDOG) + goto timeout; + } /* Trigger an RX interrupt on all queues */ E1000_WRITE_REG(&adapter->hw, E1000_EICS, adapter->rx_mask); - callout_reset(&adapter->timer, hz, igb_local_timer, adapter); + return; +timeout: + device_printf(adapter->dev, "Watchdog timeout -- resetting\n"); + device_printf(dev,"Queue(%d) tdh = %d, hw tdt = %d\n", txr->me, + E1000_READ_REG(&adapter->hw, E1000_TDH(txr->me)), + E1000_READ_REG(&adapter->hw, E1000_TDT(txr->me))); + device_printf(dev,"TX(%d) desc avail = %d," + "Next TX to Clean = %d\n", + txr->me, txr->tx_avail, txr->next_to_clean); + adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + adapter->watchdog_events++; + igb_init_locked(adapter); } static void @@ -2007,7 +1939,7 @@ igb_update_link_status(struct adapter *adapter) if_link_state_change(ifp, LINK_STATE_DOWN); /* Turn off watchdogs */ for (int i = 0; i < adapter->num_queues; i++, txr++) - txr->watchdog_timer = FALSE; + txr->watchdog_check = FALSE; } } @@ -2192,8 +2124,6 @@ igb_allocate_msix(struct adapter *adapter) device_printf(dev, "Failed to register TX handler"); return (error); } - /* Make tasklet for deferred handling - one per queue */ - TASK_INIT(&txr->tx_task, 0, igb_handle_tx, txr); txr->msix = vector; if (adapter->hw.mac.type == e1000_82575) txr->eims = E1000_EICR_TX_QUEUE0 << i; @@ -2205,6 +2135,12 @@ igb_allocate_msix(struct adapter *adapter) */ if (adapter->num_queues > 1) bus_bind_intr(dev, txr->res, i); + /* Make tasklet for deferred handling - one per queue */ + TASK_INIT(&txr->tx_task, 0, igb_handle_tx, txr); + txr->tq = taskqueue_create_fast("igb_txq", M_NOWAIT, + taskqueue_thread_enqueue, &txr->tq); + taskqueue_start_threads(&txr->tq, 1, PI_NET, "%s txq", + device_get_nameunit(adapter->dev)); } /* RX Setup */ @@ -2226,8 +2162,6 @@ igb_allocate_msix(struct adapter *adapter) device_printf(dev, "Failed to register RX handler"); return (error); } - /* Make tasklet for deferred handling - one per queue */ - TASK_INIT(&rxr->rx_task, 0, igb_handle_rx, rxr); rxr->msix = vector; if (adapter->hw.mac.type == e1000_82575) rxr->eims = E1000_EICR_RX_QUEUE0 << i; @@ -2244,6 +2178,13 @@ igb_allocate_msix(struct adapter *adapter) */ if (adapter->num_queues > 1) bus_bind_intr(dev, rxr->res, i); + + /* Make tasklet for deferred handling - one per queue */ + TASK_INIT(&rxr->rx_task, 0, igb_handle_rx, rxr); + rxr->tq = taskqueue_create_fast("igb_rxq", M_NOWAIT, + taskqueue_thread_enqueue, &rxr->tq); + taskqueue_start_threads(&rxr->tq, 1, PI_NET, "%s rxq", + device_get_nameunit(adapter->dev)); } /* And Link */ @@ -2263,10 +2204,6 @@ igb_allocate_msix(struct adapter *adapter) return (error); } adapter->linkvec = vector; - adapter->tq = taskqueue_create_fast("igb_taskq", M_NOWAIT, - taskqueue_thread_enqueue, &adapter->tq); - taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s taskq", - device_get_nameunit(adapter->dev)); return (0); } @@ -2278,20 +2215,55 @@ igb_configure_queues(struct adapter *adapter) struct e1000_hw *hw = &adapter->hw; struct tx_ring *txr; struct rx_ring *rxr; + u32 tmp, ivar = 0; - /* Turn on MSIX */ - /* - ** 82576 uses IVARs to route MSI/X - ** interrupts, its not very intuitive, - ** study the code carefully :) - */ - if (adapter->hw.mac.type == e1000_82576) { - u32 ivar = 0; - /* First turn on the capability */ + /* First turn on RSS capability */ + if (adapter->hw.mac.type > e1000_82575) E1000_WRITE_REG(hw, E1000_GPIE, - E1000_GPIE_MSIX_MODE | - E1000_GPIE_EIAME | + E1000_GPIE_MSIX_MODE | E1000_GPIE_EIAME | E1000_GPIE_PBA | E1000_GPIE_NSICR); + + /* Turn on MSIX */ + switch (adapter->hw.mac.type) { + case e1000_82580: + /* RX */ + for (int i = 0; i < adapter->num_queues; i++) { + u32 index = i >> 1; + ivar = E1000_READ_REG_ARRAY(hw, E1000_IVAR0, index); + rxr = &adapter->rx_rings[i]; + if (i & 1) { + ivar &= 0xFF00FFFF; + ivar |= (rxr->msix | E1000_IVAR_VALID) << 16; + } else { + ivar &= 0xFFFFFF00; + ivar |= rxr->msix | E1000_IVAR_VALID; + } + E1000_WRITE_REG_ARRAY(hw, E1000_IVAR0, index, ivar); + adapter->eims_mask |= rxr->eims; + } + /* TX */ + for (int i = 0; i < adapter->num_queues; i++) { + u32 index = i >> 1; + ivar = E1000_READ_REG_ARRAY(hw, E1000_IVAR0, index); + txr = &adapter->tx_rings[i]; + if (i & 1) { + ivar &= 0x00FFFFFF; + ivar |= (txr->msix | E1000_IVAR_VALID) << 24; + } else { + ivar &= 0xFFFF00FF; + ivar |= (txr->msix | E1000_IVAR_VALID) << 8; + } + E1000_WRITE_REG_ARRAY(hw, E1000_IVAR0, index, ivar); + adapter->eims_mask |= txr->eims; + } + + /* And for the link interrupt */ + ivar = (adapter->linkvec | E1000_IVAR_VALID) << 8; + adapter->link_mask = 1 << adapter->linkvec; + adapter->eims_mask |= adapter->link_mask; + E1000_WRITE_REG(hw, E1000_IVAR_MISC, ivar); + break; + case e1000_82576: /* RX */ for (int i = 0; i < adapter->num_queues; i++) { u32 index = i & 0x7; /* Each IVAR has two entries */ @@ -2328,11 +2300,10 @@ igb_configure_queues(struct adapter *adapter) adapter->link_mask = 1 << adapter->linkvec; adapter->eims_mask |= adapter->link_mask; E1000_WRITE_REG(hw, E1000_IVAR_MISC, ivar); - } else - { /* 82575 */ - int tmp; + break; - /* enable MSI-X PBA support*/ + case e1000_82575: + /* enable MSI-X support*/ tmp = E1000_READ_REG(hw, E1000_CTRL_EXT); tmp |= E1000_CTRL_EXT_PBA_CLR; /* Auto-Mask interrupts upon ICR read. */ @@ -2361,7 +2332,10 @@ igb_configure_queues(struct adapter *adapter) E1000_EIMS_OTHER); adapter->link_mask |= E1000_EIMS_OTHER; adapter->eims_mask |= adapter->link_mask; + default: + break; } + return; } @@ -2444,6 +2418,10 @@ igb_setup_msix(struct adapter *adapter) device_t dev = adapter->dev; int rid, want, queues, msgs; + /* tuneable override */ + if (igb_enable_msix == 0) + goto msi; + /* First try MSI/X */ rid = PCIR_BAR(IGB_MSIX_BAR); adapter->msix_mem = bus_alloc_resource_any(dev, @@ -2497,66 +2475,145 @@ msi: /********************************************************************* * - * Initialize the hardware to a configuration - * as specified by the adapter structure. + * Set up an fresh starting state * **********************************************************************/ -static int -igb_hardware_init(struct adapter *adapter) +static void +igb_reset(struct adapter *adapter) { device_t dev = adapter->dev; - u32 rx_buffer_size; - - INIT_DEBUGOUT("igb_hardware_init: begin"); + struct e1000_hw *hw = &adapter->hw; + struct e1000_fc_info *fc = &hw->fc; + struct ifnet *ifp = adapter->ifp; + u32 pba = 0; + u16 hwm; - /* Issue a global reset */ - e1000_reset_hw(&adapter->hw); + INIT_DEBUGOUT("igb_reset: begin"); /* Let the firmware know the OS is in control */ igb_get_hw_control(adapter); /* + * Packet Buffer Allocation (PBA) + * Writing PBA sets the receive portion of the buffer + * the remainder is used for the transmit buffer. + */ + switch (hw->mac.type) { + case e1000_82575: + pba = E1000_PBA_32K; + break; + case e1000_82576: + pba = E1000_PBA_64K; + break; + case e1000_82580: + pba = E1000_PBA_35K; + default: + break; + } + + /* Special needs in case of Jumbo frames */ + if ((hw->mac.type == e1000_82575) && (ifp->if_mtu > ETHERMTU)) { + u32 tx_space, min_tx, min_rx; + pba = E1000_READ_REG(hw, E1000_PBA); + tx_space = pba >> 16; + pba &= 0xffff; + min_tx = (adapter->max_frame_size + + sizeof(struct e1000_tx_desc) - ETHERNET_FCS_SIZE) * 2; + min_tx = roundup2(min_tx, 1024); + min_tx >>= 10; + min_rx = adapter->max_frame_size; + min_rx = roundup2(min_rx, 1024); + min_rx >>= 10; + if (tx_space < min_tx && + ((min_tx - tx_space) < pba)) { + pba = pba - (min_tx - tx_space); + /* + * if short on rx space, rx wins + * and must trump tx adjustment + */ + if (pba < min_rx) + pba = min_rx; + } + E1000_WRITE_REG(hw, E1000_PBA, pba); + } + + INIT_DEBUGOUT1("igb_init: pba=%dK",pba); + + /* * These parameters control the automatic generation (Tx) and * response (Rx) to Ethernet PAUSE frames. * - High water mark should allow for at least two frames to be * received after sending an XOFF. * - Low water mark works best when it is very near the high water mark. * This allows the receiver to restart by sending XON when it has - * drained a bit. Here we use an arbitary value of 1500 which will - * restart after one full frame is pulled from the buffer. There - * could be several smaller frames in the buffer and if so they will - * not trigger the XON until their total number reduces the buffer - * by 1500. - * - The pause time is fairly large at 1000 x 512ns = 512 usec. + * drained a bit. */ - if (adapter->hw.mac.type == e1000_82576) - rx_buffer_size = ((E1000_READ_REG(&adapter->hw, - E1000_RXPBS) & 0xffff) << 10 ); - else - rx_buffer_size = ((E1000_READ_REG(&adapter->hw, - E1000_PBA) & 0xffff) << 10 ); + hwm = min(((pba << 10) * 9 / 10), + ((pba << 10) - 2 * adapter->max_frame_size)); - adapter->hw.fc.high_water = rx_buffer_size - - roundup2(adapter->max_frame_size, 1024); - adapter->hw.fc.low_water = adapter->hw.fc.high_water - 1500; + if (hw->mac.type < e1000_82576) { + fc->high_water = hwm & 0xFFF8; /* 8-byte granularity */ + fc->low_water = fc->high_water - 8; + } else { + fc->high_water = hwm & 0xFFF0; /* 16-byte granularity */ + fc->low_water = fc->high_water - 16; + } - adapter->hw.fc.pause_time = IGB_FC_PAUSE_TIME; - adapter->hw.fc.send_xon = TRUE; + fc->pause_time = IGB_FC_PAUSE_TIME; + fc->send_xon = TRUE; /* Set Flow control, use the tunable location if sane */ if ((igb_fc_setting >= 0) || (igb_fc_setting < 4)) - adapter->hw.fc.requested_mode = igb_fc_setting; + fc->requested_mode = igb_fc_setting; else - adapter->hw.fc.requested_mode = e1000_fc_none; + fc->requested_mode = e1000_fc_none; + + fc->current_mode = fc->requested_mode; + + /* Issue a global reset */ + e1000_reset_hw(hw); + E1000_WRITE_REG(hw, E1000_WUC, 0); - if (e1000_init_hw(&adapter->hw) < 0) { + if (e1000_init_hw(hw) < 0) device_printf(dev, "Hardware Initialization Failed\n"); - return (EIO); - } - e1000_check_for_link(&adapter->hw); + if (hw->mac.type == e1000_82580) { + u32 reg; - return (0); + hwm = (pba << 10) - (2 * adapter->max_frame_size); + /* + * 0x80000000 - enable DMA COAL + * 0x10000000 - use L0s as low power + * 0x20000000 - use L1 as low power + * X << 16 - exit dma coal when rx data exceeds X kB + * Y - upper limit to stay in dma coal in units of 32usecs + */ + E1000_WRITE_REG(hw, E1000_DMACR, + 0xA0000006 | ((hwm << 6) & 0x00FF0000)); + + /* set hwm to PBA - 2 * max frame size */ + E1000_WRITE_REG(hw, E1000_FCRTC, hwm); + /* + * This sets the time to wait before requesting transition to + * low power state to number of usecs needed to receive 1 512 + * byte frame at gigabit line rate + */ + E1000_WRITE_REG(hw, E1000_DMCTLX, 4); + + /* free space in tx packet buffer to wake from DMA coal */ + E1000_WRITE_REG(hw, E1000_DMCTXTH, + (20480 - (2 * adapter->max_frame_size)) >> 6); + + /* make low power state decision controlled by DMA coal */ + reg = E1000_READ_REG(hw, E1000_PCIEMISC); + E1000_WRITE_REG(hw, E1000_PCIEMISC, + reg | E1000_PCIEMISC_LX_DECISION); + } + + E1000_WRITE_REG(&adapter->hw, E1000_VET, ETHERTYPE_VLAN); + e1000_get_phy_info(hw); + e1000_check_for_link(hw); + return; } /********************************************************************* @@ -2585,8 +2642,8 @@ igb_setup_interface(device_t dev, struct adapter *adapter) ifp->if_transmit = igb_mq_start; ifp->if_qflush = igb_qflush; #endif - IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 1); - ifp->if_snd.ifq_drv_maxlen = adapter->num_tx_desc - 1; + IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 2); + ifp->if_snd.ifq_drv_maxlen = adapter->num_tx_desc - 2; IFQ_SET_READY(&ifp->if_snd); ether_ifattach(ifp, adapter->hw.mac.addr); @@ -2596,6 +2653,9 @@ igb_setup_interface(device_t dev, struct adapter *adapter) ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_VLAN_MTU; ifp->if_capabilities |= IFCAP_TSO4; ifp->if_capabilities |= IFCAP_JUMBO_MTU; + if (igb_header_split) + ifp->if_capabilities |= IFCAP_LRO; + ifp->if_capenable = ifp->if_capabilities; /* @@ -2866,14 +2926,14 @@ igb_allocate_transmit_buffers(struct tx_ring *txr) /* * Setup DMA descriptor areas. */ - if ((error = bus_dma_tag_create(NULL, /* parent */ + if ((error = bus_dma_tag_create(bus_get_dma_tag(adapter->dev), 1, 0, /* alignment, bounds */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ IGB_TSO_SIZE, /* maxsize */ IGB_MAX_SCATTER, /* nsegments */ - PAGE_SIZE, /* maxsegsize */ + IGB_TSO_SEG_SIZE, /* maxsegsize */ 0, /* flags */ NULL, /* lockfunc */ NULL, /* lockfuncarg */ @@ -2977,7 +3037,10 @@ igb_initialize_transmit_units(struct adapter *adapter) INIT_DEBUGOUT("igb_initialize_transmit_units: begin"); - /* Setup the Base and Length of the Tx Descriptor Rings */ + /* Setup Transmit Descriptor Base Settings */ + adapter->txd_cmd = E1000_TXD_CMD_IFCS; + + /* Setup the Tx Descriptor Rings */ for (int i = 0; i < adapter->num_queues; i++, txr++) { u64 bus_addr = txr->txdma.dma_paddr; @@ -2996,12 +3059,15 @@ igb_initialize_transmit_units(struct adapter *adapter) E1000_READ_REG(&adapter->hw, E1000_TDBAL(i)), E1000_READ_REG(&adapter->hw, E1000_TDLEN(i))); - /* Setup Transmit Descriptor Base Settings */ - adapter->txd_cmd = E1000_TXD_CMD_IFCS; + txr->watchdog_check = FALSE; txdctl = E1000_READ_REG(&adapter->hw, E1000_TXDCTL(i)); txdctl |= E1000_TXDCTL_QUEUE_ENABLE; E1000_WRITE_REG(&adapter->hw, E1000_TXDCTL(i), txdctl); + + /* Default interrupt rate */ + E1000_WRITE_REG(&adapter->hw, E1000_EITR(txr->msix), + igb_ave_latency); } /* Program the Transmit Control Register */ @@ -3094,7 +3160,7 @@ igb_free_transmit_buffers(struct tx_ring *txr) /********************************************************************** * * Setup work for hardware segmentation offload (TSO) on - * adapters using advanced tx descriptors (82575) + * adapters using advanced tx descriptors * **********************************************************************/ static boolean_t @@ -3165,6 +3231,9 @@ igb_tso_setup(struct tx_ring *txr, struct mbuf *mp, u32 *hdrlen) /* MSS L4LEN IDX */ mss_l4len_idx |= (mp->m_pkthdr.tso_segsz << E1000_ADVTXD_MSS_SHIFT); mss_l4len_idx |= (tcp_hlen << E1000_ADVTXD_L4LEN_SHIFT); + /* 82575 needs the queue index added */ + if (adapter->hw.mac.type == e1000_82575) + mss_l4len_idx |= txr->me << 4; TXD->mss_l4len_idx = htole32(mss_l4len_idx); TXD->seqnum_seed = htole32(0); @@ -3192,7 +3261,7 @@ igb_tx_ctx_setup(struct tx_ring *txr, struct mbuf *mp) struct adapter *adapter = txr->adapter; struct e1000_adv_tx_context_desc *TXD; struct igb_tx_buffer *tx_buffer; - uint32_t vlan_macip_lens = 0, type_tucmd_mlhl = 0; + u32 vlan_macip_lens, type_tucmd_mlhl, mss_l4len_idx; struct ether_vlan_header *eh; struct ip *ip = NULL; struct ip6_hdr *ip6; @@ -3204,6 +3273,7 @@ igb_tx_ctx_setup(struct tx_ring *txr, struct mbuf *mp) if ((mp->m_pkthdr.csum_flags & CSUM_OFFLOAD) == 0) offload = FALSE; + vlan_macip_lens = type_tucmd_mlhl = mss_l4len_idx = 0; ctxd = txr->next_avail_desc; tx_buffer = &txr->tx_buffers[ctxd]; TXD = (struct e1000_adv_tx_context_desc *) &txr->tx_base[ctxd]; @@ -3283,11 +3353,15 @@ igb_tx_ctx_setup(struct tx_ring *txr, struct mbuf *mp) break; } + /* 82575 needs the queue index added */ + if (adapter->hw.mac.type == e1000_82575) + mss_l4len_idx = txr->me << 4; + /* Now copy bits into descriptor */ TXD->vlan_macip_lens |= htole32(vlan_macip_lens); TXD->type_tucmd_mlhl |= htole32(type_tucmd_mlhl); TXD->seqnum_seed = htole32(0); - TXD->mss_l4len_idx = htole32(0); + TXD->mss_l4len_idx = htole32(mss_l4len_idx); tx_buffer->m_head = NULL; tx_buffer->next_eop = -1; @@ -3314,8 +3388,7 @@ static bool igb_txeof(struct tx_ring *txr) { struct adapter *adapter = txr->adapter; - int first, last, done, num_avail; - u32 cleaned = 0; + int first, last, done; struct igb_tx_buffer *tx_buffer; struct e1000_tx_desc *tx_desc, *eop_desc; struct ifnet *ifp = adapter->ifp; @@ -3325,7 +3398,6 @@ igb_txeof(struct tx_ring *txr) if (txr->tx_avail == adapter->num_tx_desc) return FALSE; - num_avail = txr->tx_avail; first = txr->next_to_clean; tx_desc = &txr->tx_base[first]; tx_buffer = &txr->tx_buffers[first]; @@ -3343,7 +3415,7 @@ igb_txeof(struct tx_ring *txr) done = last; bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, - BUS_DMASYNC_POSTREAD); + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); while (eop_desc->upper.fields.status & E1000_TXD_STAT_DD) { /* We clean the range of the packet */ @@ -3351,7 +3423,7 @@ igb_txeof(struct tx_ring *txr) tx_desc->upper.data = 0; tx_desc->lower.data = 0; tx_desc->buffer_addr = 0; - ++num_avail; ++cleaned; + ++txr->tx_avail; if (tx_buffer->m_head) { ifp->if_opackets++; @@ -3365,6 +3437,7 @@ igb_txeof(struct tx_ring *txr) tx_buffer->m_head = NULL; } tx_buffer->next_eop = -1; + txr->watchdog_time = ticks; if (++first == adapter->num_tx_desc) first = 0; @@ -3388,141 +3461,112 @@ igb_txeof(struct tx_ring *txr) txr->next_to_clean = first; /* - * If we have enough room, clear IFF_DRV_OACTIVE to tell the stack - * that it is OK to send packets. - * If there are no pending descriptors, clear the timeout. Otherwise, - * if some descriptors have been freed, restart the timeout. + * If we have enough room, clear IFF_DRV_OACTIVE + * to tell the stack that it is OK to send packets. */ - if (num_avail > IGB_TX_CLEANUP_THRESHOLD) { + if (txr->tx_avail > IGB_TX_CLEANUP_THRESHOLD) { ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - /* All clean, turn off the timer */ - if (num_avail == adapter->num_tx_desc) { - txr->watchdog_timer = 0; - txr->tx_avail = num_avail; + /* All clean, turn off the watchdog */ + if (txr->tx_avail == adapter->num_tx_desc) { + txr->watchdog_check = FALSE; return FALSE; } } - /* Some cleaned, reset the timer */ - if (cleaned) - txr->watchdog_timer = IGB_TX_TIMEOUT; - txr->tx_avail = num_avail; return TRUE; } /********************************************************************* * - * Setup descriptor buffer(s) from system mbuf buffer pools. - * i - designates the ring index - * clean - tells the function whether to update - * the header, the packet buffer, or both. + * Refresh mbuf buffers for a range of descriptors * **********************************************************************/ static int -igb_get_buf(struct rx_ring *rxr, int i, u8 clean) +igb_get_buf(struct rx_ring *rxr, int first, int limit) { struct adapter *adapter = rxr->adapter; - struct mbuf *mh, *mp; bus_dma_segment_t seg[2]; + struct igb_rx_buf *rxbuf; + struct mbuf *mh, *mp; bus_dmamap_t map; - struct igb_rx_buffer *rx_buffer; - int error, nsegs; - int merr = 0; + int i, nsegs, error; + i = first; + while (i != limit) { + rxbuf = &rxr->rx_buffers[i]; - rx_buffer = &rxr->rx_buffers[i]; + if (rxbuf->m_head == NULL) { + mh = m_gethdr(M_DONTWAIT, MT_DATA); + if (mh == NULL) + goto failure; + } else /* reuse */ + mh = rxbuf->m_head; + + mh->m_len = MHLEN; + mh->m_flags |= M_PKTHDR; + + if (rxbuf->m_pack == NULL) { + mp = m_getjcl(M_DONTWAIT, MT_DATA, + M_PKTHDR, adapter->rx_mbuf_sz); + if (mp == NULL) + goto failure; + mp->m_len = adapter->rx_mbuf_sz; + mp->m_flags &= ~M_PKTHDR; + } else { /* reusing */ + mp = rxbuf->m_pack; + mp->m_len = adapter->rx_mbuf_sz; + mp->m_flags &= ~M_PKTHDR; + } - /* First get our header and payload mbuf */ - if (clean & IGB_CLEAN_HEADER) { - mh = m_gethdr(M_DONTWAIT, MT_DATA); - if (mh == NULL) - goto remap; - } else /* reuse */ - mh = rxr->rx_buffers[i].m_head; + /* + ** Need to create a chain for the following + ** dmamap call at this point. + */ + mh->m_next = mp; + mh->m_pkthdr.len = mh->m_len + mp->m_len; - mh->m_len = MHLEN; - mh->m_flags |= M_PKTHDR; + /* Get the memory mapping */ + error = bus_dmamap_load_mbuf_sg(rxr->rxtag, + rxr->spare_map, mh, seg, &nsegs, BUS_DMA_NOWAIT); + if (error != 0) + panic("igb_get_buf: dmamap load failure\n"); - if (clean & IGB_CLEAN_PAYLOAD) { - mp = m_getjcl(M_DONTWAIT, MT_DATA, - M_PKTHDR, adapter->rx_mbuf_sz); - if (mp == NULL) - goto remap; - mp->m_len = adapter->rx_mbuf_sz; - mp->m_flags &= ~M_PKTHDR; - } else { /* reusing */ - mp = rxr->rx_buffers[i].m_pack; - mp->m_len = adapter->rx_mbuf_sz; - mp->m_flags &= ~M_PKTHDR; - } - /* - ** Need to create a chain for the following - ** dmamap call at this point. - */ - mh->m_next = mp; - mh->m_pkthdr.len = mh->m_len + mp->m_len; - - /* Get the memory mapping */ - error = bus_dmamap_load_mbuf_sg(rxr->rxtag, - rxr->rx_spare_map, mh, seg, &nsegs, BUS_DMA_NOWAIT); - if (error != 0) { - printf("GET BUF: dmamap load failure - %d\n", error); - m_free(mh); - return (error); + /* Unload old mapping and update buffer struct */ + if (rxbuf->m_head != NULL) + bus_dmamap_unload(rxr->rxtag, rxbuf->map); + map = rxbuf->map; + rxbuf->map = rxr->spare_map; + rxr->spare_map = map; + rxbuf->m_head = mh; + rxbuf->m_pack = mp; + bus_dmamap_sync(rxr->rxtag, + rxbuf->map, BUS_DMASYNC_PREREAD); + + /* Update descriptor */ + rxr->rx_base[i].read.hdr_addr = htole64(seg[0].ds_addr); + rxr->rx_base[i].read.pkt_addr = htole64(seg[1].ds_addr); + + /* Calculate next index */ + if (++i == adapter->num_rx_desc) + i = 0; } - /* Unload old mapping and update buffer struct */ - if (rx_buffer->m_head != NULL) - bus_dmamap_unload(rxr->rxtag, rx_buffer->map); - map = rx_buffer->map; - rx_buffer->map = rxr->rx_spare_map; - rxr->rx_spare_map = map; - rx_buffer->m_head = mh; - rx_buffer->m_pack = mp; - bus_dmamap_sync(rxr->rxtag, - rx_buffer->map, BUS_DMASYNC_PREREAD); - - /* Update descriptor */ - rxr->rx_base[i].read.hdr_addr = htole64(seg[0].ds_addr); - rxr->rx_base[i].read.pkt_addr = htole64(seg[1].ds_addr); - return (0); +failure: /* - ** If we get here, we have an mbuf resource - ** issue, so we discard the incoming packet - ** and attempt to reuse existing mbufs next - ** pass thru the ring, but to do so we must - ** fix up the descriptor which had the address - ** clobbered with writeback info. + ** Its unforunate to have to panic, but + ** with the new design I see no other + ** graceful failure mode, this is ONLY + ** called in the RX clean path, and the + ** old mbuf has been used, it MUST be + ** refreshed. This should be avoided by + ** proper configuration. -jfv */ -remap: - adapter->mbuf_header_failed++; - merr = ENOBUFS; - /* Is there a reusable buffer? */ - mh = rxr->rx_buffers[i].m_head; - if (mh == NULL) /* Nope, init error */ - return (merr); - mp = rxr->rx_buffers[i].m_pack; - if (mp == NULL) /* Nope, init error */ - return (merr); - /* Get our old mapping */ - rx_buffer = &rxr->rx_buffers[i]; - error = bus_dmamap_load_mbuf_sg(rxr->rxtag, - rx_buffer->map, mh, seg, &nsegs, BUS_DMA_NOWAIT); - if (error != 0) { - /* We really have a problem */ - m_free(mh); - return (error); - } - /* Now fix the descriptor as needed */ - rxr->rx_base[i].read.hdr_addr = htole64(seg[0].ds_addr); - rxr->rx_base[i].read.pkt_addr = htole64(seg[1].ds_addr); - return (merr); + panic("igb_get_buf: ENOBUFS\n"); } - /********************************************************************* * * Allocate memory for rx_buffer structures. Since we use one @@ -3536,12 +3580,12 @@ igb_allocate_receive_buffers(struct rx_ring *rxr) { struct adapter *adapter = rxr->adapter; device_t dev = adapter->dev; - struct igb_rx_buffer *rxbuf; + struct igb_rx_buf *rxbuf; int i, bsize, error; - bsize = sizeof(struct igb_rx_buffer) * adapter->num_rx_desc; + bsize = sizeof(struct igb_rx_buf) * adapter->num_rx_desc; if (!(rxr->rx_buffers = - (struct igb_rx_buffer *) malloc(bsize, + (struct igb_rx_buf *) malloc(bsize, M_DEVBUF, M_NOWAIT | M_ZERO))) { device_printf(dev, "Unable to allocate rx_buffer memory\n"); error = ENOMEM; @@ -3553,7 +3597,7 @@ igb_allocate_receive_buffers(struct rx_ring *rxr) ** with packet split (hence the two segments, even though ** it may not always use this. */ - if ((error = bus_dma_tag_create(NULL, /* parent */ + if ((error = bus_dma_tag_create(bus_get_dma_tag(adapter->dev), 1, 0, /* alignment, bounds */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ @@ -3571,7 +3615,7 @@ igb_allocate_receive_buffers(struct rx_ring *rxr) /* Create the spare map (used by getbuf) */ error = bus_dmamap_create(rxr->rxtag, BUS_DMA_NOWAIT, - &rxr->rx_spare_map); + &rxr->spare_map); if (error) { device_printf(dev, "%s: bus_dmamap_create header spare failed: %d\n", @@ -3608,15 +3652,14 @@ igb_setup_receive_ring(struct rx_ring *rxr) struct adapter *adapter; struct ifnet *ifp; device_t dev; - struct igb_rx_buffer *rxbuf; + struct igb_rx_buf *rxbuf; + bus_dma_segment_t seg[2]; struct lro_ctrl *lro = &rxr->lro; - int j, rsize; + int rsize, nsegs, error = 0; adapter = rxr->adapter; dev = adapter->dev; ifp = adapter->ifp; - rxr->lro_enabled = FALSE; - rxr->hdr_split = FALSE; /* Clear the ring contents */ rsize = roundup2(adapter->num_rx_desc * @@ -3639,20 +3682,48 @@ igb_setup_receive_ring(struct rx_ring *rxr) rxbuf->m_pack = NULL; } - /* Next replenish the ring */ - for (j = 0; j < adapter->num_rx_desc; j++) { - if (igb_get_buf(rxr, j, IGB_CLEAN_BOTH) == ENOBUFS) { - rxr->rx_buffers[j].m_head = NULL; - rxr->rx_buffers[j].m_pack = NULL; - rxr->rx_base[j].read.hdr_addr = 0; - rxr->rx_base[j].read.pkt_addr = 0; - goto fail; - } + /* Now replenish the mbufs */ + for (int j = 0; j != adapter->num_rx_desc; ++j) { + + rxbuf = &rxr->rx_buffers[j]; + rxbuf->m_head = m_gethdr(M_DONTWAIT, MT_DATA); + if (rxbuf->m_head == NULL) + panic("RX ring hdr initialization failed!\n"); + rxbuf->m_head->m_len = MHLEN; + rxbuf->m_head->m_flags |= M_PKTHDR; + rxbuf->m_head->m_pkthdr.len = rxbuf->m_head->m_len; + + rxbuf->m_pack = m_getjcl(M_DONTWAIT, MT_DATA, + M_PKTHDR, adapter->rx_mbuf_sz); + if (rxbuf->m_pack == NULL) + panic("RX ring pkt initialization failed!\n"); + rxbuf->m_pack->m_len = adapter->rx_mbuf_sz; + rxbuf->m_head->m_next = rxbuf->m_pack; + rxbuf->m_head->m_pkthdr.len += rxbuf->m_pack->m_len; + + /* Get the memory mapping */ + error = bus_dmamap_load_mbuf_sg(rxr->rxtag, + rxbuf->map, rxbuf->m_head, seg, + &nsegs, BUS_DMA_NOWAIT); + if (error != 0) + panic("RX ring dma initialization failed!\n"); + bus_dmamap_sync(rxr->rxtag, + rxbuf->map, BUS_DMASYNC_PREREAD); + + /* Update descriptor */ + rxr->rx_base[j].read.hdr_addr = htole64(seg[0].ds_addr); + rxr->rx_base[j].read.pkt_addr = htole64(seg[1].ds_addr); } /* Setup our descriptor indices */ rxr->next_to_check = 0; rxr->last_cleaned = 0; + rxr->lro_enabled = FALSE; + + if (igb_header_split) + rxr->hdr_split = TRUE; + else + ifp->if_capabilities &= ~IFCAP_LRO; bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); @@ -3663,19 +3734,17 @@ igb_setup_receive_ring(struct rx_ring *rxr) ** is enabled, since so often they ** are undesireable in similar setups. */ - if (ifp->if_capenable & IFCAP_LRO) { + if ((ifp->if_capenable & IFCAP_LRO) && (rxr->hdr_split)) { int err = tcp_lro_init(lro); - if (err) { - device_printf(dev,"LRO Initialization failed!\n"); - goto fail; - } + if (err) + panic("LRO Initialization failed!\n"); INIT_DEBUGOUT("RX LRO Initialized\n"); rxr->lro_enabled = TRUE; - rxr->hdr_split = TRUE; lro->ifp = adapter->ifp; } return (0); +#if 0 fail: /* * We need to clean up any buffers allocated @@ -3692,6 +3761,7 @@ fail: } } return (ENOBUFS); +#endif } /********************************************************************* @@ -3720,7 +3790,7 @@ fail: rxr = adapter->rx_rings; for (--i; i > 0; i--, rxr++) { for (j = 0; j < adapter->num_rx_desc; j++) { - struct igb_rx_buffer *rxbuf; + struct igb_rx_buf *rxbuf; rxbuf = &rxr->rx_buffers[j]; if (rxbuf->m_head != NULL) { bus_dmamap_sync(rxr->rxtag, rxbuf->map, @@ -3806,6 +3876,11 @@ igb_initialize_receive_units(struct adapter *adapter) rxdctl |= IGB_RX_HTHRESH << 8; rxdctl |= IGB_RX_WTHRESH << 16; E1000_WRITE_REG(&adapter->hw, E1000_RXDCTL(i), rxdctl); + + /* Initial RX interrupt moderation */ + rxr->eitr_setting = igb_ave_latency; + E1000_WRITE_REG(&adapter->hw, + E1000_EITR(rxr->msix), igb_ave_latency); } /* @@ -3927,14 +4002,14 @@ igb_free_receive_structures(struct adapter *adapter) static void igb_free_receive_buffers(struct rx_ring *rxr) { - struct adapter *adapter = rxr->adapter; - struct igb_rx_buffer *rx_buffer; + struct adapter *adapter = rxr->adapter; + struct igb_rx_buf *rx_buffer; INIT_DEBUGOUT("free_receive_structures: begin"); - if (rxr->rx_spare_map) { - bus_dmamap_destroy(rxr->rxtag, rxr->rx_spare_map); - rxr->rx_spare_map = NULL; + if (rxr->spare_map) { + bus_dmamap_destroy(rxr->rxtag, rxr->spare_map); + rxr->spare_map = NULL; } /* Cleanup any existing buffers */ @@ -3980,20 +4055,20 @@ igb_free_receive_buffers(struct rx_ring *rxr) * * Return TRUE if more to clean, FALSE otherwise *********************************************************************/ + static bool igb_rxeof(struct rx_ring *rxr, int count) { - struct adapter *adapter = rxr->adapter; - struct ifnet *ifp; + struct adapter *adapter = rxr->adapter; + struct ifnet *ifp = adapter->ifp; struct lro_ctrl *lro = &rxr->lro; struct lro_entry *queued; - int i; + int i, processed = 0; u32 staterr; union e1000_adv_rx_desc *cur; IGB_RX_LOCK(rxr); - ifp = adapter->ifp; i = rxr->next_to_check; cur = &rxr->rx_base[i]; staterr = cur->wb.upper.status_error; @@ -4007,35 +4082,56 @@ igb_rxeof(struct rx_ring *rxr, int count) bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, BUS_DMASYNC_POSTREAD); - /* Main clean loop */ - while ((staterr & E1000_RXD_STAT_DD) && - (count != 0) && + while ((staterr & E1000_RXD_STAT_DD) && (count != 0) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) { - struct mbuf *sendmp, *mh, *mp; - u16 hlen, plen, hdr, ptype, len_adj, vtag; - u8 dopayload, accept_frame, eop; - - accept_frame = 1; - hlen = plen = len_adj = vtag = 0; - sendmp = mh = mp = NULL; - ptype = (u16)(cur->wb.lower.lo_dword.data >> 4); + struct mbuf *sendmp, *mh, *mp, *nh, *np; + struct igb_rx_buf *nxtbuf; + u32 ptype; + u16 hlen, plen, hdr, nextp, vtag; + bool accept_frame, eop, sctp = FALSE; + + + accept_frame = TRUE; + hlen = plen = nextp = 0; + sendmp = mh = mp = nh = np = NULL; + + ptype = (le32toh(cur->wb.lower.lo_dword.data) & + IGB_PKTTYPE_MASK); + if (((ptype & E1000_RXDADV_PKTTYPE_ETQF) == 0) && + ((ptype & E1000_RXDADV_PKTTYPE_SCTP) != 0)) + sctp = TRUE; /* Sync the buffers */ bus_dmamap_sync(rxr->rxtag, rxr->rx_buffers[i].map, BUS_DMASYNC_POSTREAD); + mh = rxr->rx_buffers[i].m_head; + mp = rxr->rx_buffers[i].m_pack; + vtag = le16toh(cur->wb.upper.vlan); + eop = ((staterr & E1000_RXD_STAT_EOP) != 0); + + /* Get the next descriptor we will process */ + if (!eop) { + nextp = i + 1; + if (nextp == adapter->num_rx_desc) + nextp = 0; + nxtbuf = &rxr->rx_buffers[nextp]; + prefetch(nxtbuf); + } /* ** The way the hardware is configured to ** split, it will ONLY use the header buffer ** when header split is enabled, otherwise we - ** get normal behavior, ie, both header and - ** payload are DMA'd into the payload buffer. + ** get legacy behavior, ie, both header and + ** payload are DMA'd into JUST the payload buffer. + ** + ** Rather than using the fmp/lmp global pointers + ** we now keep the head of a packet chain in the + ** m_nextpkt pointer and pass this along from one + ** descriptor to the next, until we get EOP. ** - ** The fmp test is to catch the case where a - ** packet spans multiple descriptors, in that - ** case only the first header is valid. */ - if ((rxr->hdr_split) && (rxr->fmp == NULL)){ + if ((rxr->hdr_split) && (mh->m_nextpkt == NULL)) { hdr = le16toh(cur-> wb.lower.lo_dword.hs_rss.hdr_info); hlen = (hdr & E1000_RXDADV_HDRBUFLEN_MASK) >> @@ -4043,183 +4139,136 @@ igb_rxeof(struct rx_ring *rxr, int count) if (hlen > IGB_HDR_BUF) hlen = IGB_HDR_BUF; plen = le16toh(cur->wb.upper.length); - /* Handle the header mbuf */ - mh = rxr->rx_buffers[i].m_head; mh->m_len = hlen; - dopayload = IGB_CLEAN_HEADER; + mh->m_flags |= M_PKTHDR; + mh->m_next = NULL; + mh->m_pkthdr.len = mh->m_len; + /* Null this so getbuf replenishes */ + rxr->rx_buffers[i].m_head = NULL; /* ** Get the payload length, this ** could be zero if its a small ** packet. */ if (plen) { - mp = rxr->rx_buffers[i].m_pack; mp->m_len = plen; mp->m_next = NULL; mp->m_flags &= ~M_PKTHDR; mh->m_next = mp; - mh->m_flags |= M_PKTHDR; - dopayload = IGB_CLEAN_BOTH; + mh->m_pkthdr.len += mp->m_len; + /* Null this so getbuf replenishes */ + rxr->rx_buffers[i].m_pack = NULL; rxr->rx_split_packets++; - } else { /* small packets */ - mh->m_flags &= ~M_PKTHDR; - mh->m_next = NULL; + } + /* Setup the forward chain */ + if (eop == 0) { + nh = rxr->rx_buffers[nextp].m_head; + np = rxr->rx_buffers[nextp].m_pack; + nh->m_nextpkt = mh; + if (plen) + mp->m_next = np; + else + mh->m_next = np; + } else { + sendmp = mh; + if (staterr & E1000_RXD_STAT_VP) { + sendmp->m_pkthdr.ether_vtag = vtag; + sendmp->m_flags |= M_VLANTAG; + } } } else { /* ** Either no header split, or a ** secondary piece of a fragmented - ** split packet. - */ - mh = rxr->rx_buffers[i].m_pack; - mh->m_flags |= M_PKTHDR; - mh->m_len = le16toh(cur->wb.upper.length); - dopayload = IGB_CLEAN_PAYLOAD; - } - - if (staterr & E1000_RXD_STAT_EOP) { - count--; - eop = 1; - /* - ** Strip CRC and account for frag + ** packet. */ - if (mp) { - if (mp->m_len < ETHER_CRC_LEN) { - /* a frag, how much is left? */ - len_adj = ETHER_CRC_LEN - mp->m_len; - mp->m_len = 0; - } else - mp->m_len -= ETHER_CRC_LEN; - } else { /* not split */ - if (mh->m_len < ETHER_CRC_LEN) { - len_adj = ETHER_CRC_LEN - mh->m_len; - mh->m_len = 0; - } else - mh->m_len -= ETHER_CRC_LEN; + mp->m_len = le16toh(cur->wb.upper.length); + rxr->rx_buffers[i].m_pack = NULL; + /* stored head pointer */ + sendmp = mh->m_nextpkt; + if (sendmp != NULL) { + sendmp->m_pkthdr.len += mp->m_len; + sendmp->m_nextpkt = NULL; + } else { + /* first desc of a non-ps chain */ + sendmp = mp; + sendmp->m_flags |= M_PKTHDR; + sendmp->m_pkthdr.len = mp->m_len; + if (staterr & E1000_RXD_STAT_VP) { + sendmp->m_pkthdr.ether_vtag = vtag; + sendmp->m_flags |= M_VLANTAG; + } + } + /* Carry head forward */ + if (eop == 0) { + nh = rxr->rx_buffers[nextp].m_head; + np = rxr->rx_buffers[nextp].m_pack; + nh->m_nextpkt = sendmp; + mp->m_next = np; + sendmp = NULL; } - } else - eop = 0; + mh->m_nextpkt = NULL; + } if (staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) - accept_frame = 0; -#ifdef IGB_IEEE1588 - This linux code needs to be converted to work here - ----------------------------------------------------- - if (unlikely(staterr & E1000_RXD_STAT_TS)) { - u64 regval; - u64 ns; -// Create an mtag and set it up - struct skb_shared_hwtstamps *shhwtstamps = - skb_hwtstamps(skb); - - rd32(E1000_TSYNCRXCTL) & E1000_TSYNCRXCTL_VALID), - "igb: no RX time stamp available for time stamped packet"); - regval = rd32(E1000_RXSTMPL); - regval |= (u64)rd32(E1000_RXSTMPH) << 32; -// Do time conversion from the register - ns = timecounter_cyc2time(&adapter->clock, regval); - clocksync_update(&adapter->sync, ns); - memset(shhwtstamps, 0, sizeof(*shhwtstamps)); - shhwtstamps->hwtstamp = ns_to_ktime(ns); - shhwtstamps->syststamp = - clocksync_hw2sys(&adapter->sync, ns); - } -#endif - if (accept_frame) { - /* - ** get_buf will overwrite the writeback - ** descriptor so save the VLAN tag now. - */ - vtag = le16toh(cur->wb.upper.vlan); - if (igb_get_buf(rxr, i, dopayload) != 0) { - ifp->if_iqdrops++; - goto discard; - } - /* Initial frame - setup */ - if (rxr->fmp == NULL) { - mh->m_flags |= M_PKTHDR; - mh->m_pkthdr.len = mh->m_len; - rxr->fmp = mh; /* Store the first mbuf */ - rxr->lmp = mh; - if (mp) { /* Add payload if split */ - mh->m_pkthdr.len += mp->m_len; - rxr->lmp = mh->m_next; - } - } else { - /* Chain mbuf's together */ - mh->m_flags &= ~M_PKTHDR; - rxr->lmp->m_next = mh; - rxr->lmp = rxr->lmp->m_next; - rxr->fmp->m_pkthdr.len += mh->m_len; - /* Adjust for CRC frag */ - if (len_adj) { - rxr->lmp->m_len -= len_adj; - rxr->fmp->m_pkthdr.len -= len_adj; - } - } + accept_frame = FALSE; + if (accept_frame) { + ++processed; if (eop) { - bool sctp = ((ptype & 0x40) != 0); - rxr->fmp->m_pkthdr.rcvif = ifp; + --count; + sendmp->m_pkthdr.rcvif = ifp; ifp->if_ipackets++; rxr->rx_packets++; /* capture data for AIM */ - rxr->bytes += rxr->fmp->m_pkthdr.len; - rxr->rx_bytes += rxr->fmp->m_pkthdr.len; - - igb_rx_checksum(staterr, rxr->fmp, sctp); - if (staterr & E1000_RXD_STAT_VP) { - rxr->fmp->m_pkthdr.ether_vtag = vtag; - rxr->fmp->m_flags |= M_VLANTAG; - } + rxr->bytes += sendmp->m_pkthdr.len; + rxr->rx_bytes += rxr->bytes; + if (ifp->if_capenable & IFCAP_RXCSUM) + igb_rx_checksum(staterr, sendmp, sctp); + else + sendmp->m_pkthdr.csum_flags = 0; #if __FreeBSD_version >= 800000 - rxr->fmp->m_pkthdr.flowid = curcpu; - rxr->fmp->m_flags |= M_FLOWID; + /* Get the RSS Hash */ + sendmp->m_pkthdr.flowid = + le32toh(cur->wb.lower.hi_dword.rss); + curcpu; + sendmp->m_flags |= M_FLOWID; #endif - sendmp = rxr->fmp; - rxr->fmp = NULL; - rxr->lmp = NULL; } } else { ifp->if_ierrors++; -discard: /* Reuse loaded DMA map and just update mbuf chain */ - if (hlen) { - mh = rxr->rx_buffers[i].m_head; - mh->m_len = MHLEN; - mh->m_next = NULL; - } - mp = rxr->rx_buffers[i].m_pack; + mh->m_len = MHLEN; + mh->m_flags |= M_PKTHDR; + mh->m_next = NULL; mp->m_len = mp->m_pkthdr.len = adapter->rx_mbuf_sz; mp->m_data = mp->m_ext.ext_buf; + if (mp->m_next) { /* Free chain */ + sendmp = mp->m_next; + m_free(sendmp); + } mp->m_next = NULL; if (adapter->max_frame_size <= (MCLBYTES - ETHER_ALIGN)) m_adj(mp, ETHER_ALIGN); - if (rxr->fmp != NULL) { - /* handles the whole chain */ - m_freem(rxr->fmp); - rxr->fmp = NULL; - rxr->lmp = NULL; - } sendmp = NULL; } - bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - rxr->last_cleaned = i; /* For updating tail */ - - /* Advance our pointers to the next descriptor. */ + rxr->last_cleaned = i; /* for updating tail */ if (++i == adapter->num_rx_desc) i = 0; - + /* Prefetch next descriptor */ + cur = &rxr->rx_base[i]; + prefetch(cur); + /* - ** Note that we hold the RX lock thru - ** the following call so this ring's - ** next_to_check is not gonna change. + ** Now send up to the stack, + ** note that the RX lock is + ** held thru this call. */ - if (sendmp != NULL) { + if (sendmp != NULL) { /* ** Send to the stack if: ** - LRO not enabled, or @@ -4228,17 +4277,31 @@ discard: */ if ((!rxr->lro_enabled) || ((!lro->lro_cnt) || (tcp_lro_rx(lro, sendmp, 0)))) - (*ifp->if_input)(ifp, sendmp); + (*ifp->if_input)(ifp, sendmp); } - /* Get the next descriptor */ - cur = &rxr->rx_base[i]; + /* Replenish every 4 max */ + if (processed == 4) { + igb_get_buf(rxr, rxr->next_to_check, i); + processed = 0; + E1000_WRITE_REG(&adapter->hw, + E1000_RDT(rxr->me), rxr->last_cleaned); + rxr->next_to_check = i; + } + + /* Next iteration */ staterr = cur->wb.upper.status_error; } - rxr->next_to_check = i; - /* Advance the E1000's Receive Queue #0 "Tail Pointer". */ - E1000_WRITE_REG(&adapter->hw, E1000_RDT(rxr->me), rxr->last_cleaned); + /* Replenish remaining */ + if (processed != 0) { + igb_get_buf(rxr, rxr->next_to_check, i); + processed = 0; + E1000_WRITE_REG(&adapter->hw, + E1000_RDT(rxr->me), rxr->last_cleaned); + } + + rxr->next_to_check = i; /* * Flush any outstanding LRO work @@ -4252,8 +4315,8 @@ discard: IGB_RX_UNLOCK(rxr); /* - ** We still have cleaning to do? - ** Schedule another interrupt if so. + ** Leaving with more to clean? + ** then schedule another interrupt. */ if (staterr & E1000_RXD_STAT_DD) { E1000_WRITE_REG(&adapter->hw, E1000_EICS, rxr->eims); @@ -4263,7 +4326,6 @@ discard: return FALSE; } - /********************************************************************* * * Verify that the hardware indicated that the checksum is valid. @@ -4302,7 +4364,7 @@ igb_rx_checksum(u32 staterr, struct mbuf *mp, bool sctp) /* Did it pass? */ if (!(errors & E1000_RXD_ERR_TCPE)) { mp->m_pkthdr.csum_flags |= type; - if (!sctp) + if (sctp == FALSE) mp->m_pkthdr.csum_data = htons(0xffff); } } @@ -4319,7 +4381,7 @@ igb_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) struct adapter *adapter = ifp->if_softc; u32 index, bit; - if (ifp->if_softc != arg) /* Not our event */ + if (ifp->if_softc != arg) /* Not our event */ return; if ((vtag == 0) || (vtag > 4095)) /* Invalid */ @@ -4343,7 +4405,7 @@ igb_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) struct adapter *adapter = ifp->if_softc; u32 index, bit; - if (ifp->if_softc != arg) + if (ifp->if_softc != arg) return; if ((vtag == 0) || (vtag > 4095)) /* Invalid */ diff --git a/sys/dev/e1000/if_igb.h b/sys/dev/e1000/if_igb.h index ddc4d8a..ce5b726 100644 --- a/sys/dev/e1000/if_igb.h +++ b/sys/dev/e1000/if_igb.h @@ -48,7 +48,7 @@ * (num_tx_desc * sizeof(struct e1000_tx_desc)) % 128 == 0 */ #define IGB_MIN_TXD 80 -#define IGB_DEFAULT_TXD 256 +#define IGB_DEFAULT_TXD 1024 #define IGB_MAX_TXD 4096 /* @@ -63,7 +63,7 @@ * (num_tx_desc * sizeof(struct e1000_tx_desc)) % 128 == 0 */ #define IGB_MIN_RXD 80 -#define IGB_DEFAULT_RXD 256 +#define IGB_DEFAULT_RXD 1024 #define IGB_MAX_RXD 4096 /* @@ -128,7 +128,7 @@ /* * This parameter controls the duration of transmit watchdog timer. */ -#define IGB_TX_TIMEOUT 5 /* set to 5 seconds */ +#define IGB_WATCHDOG (10 * hz) /* * This parameter controls when the driver calls the routine to reclaim @@ -225,6 +225,7 @@ #define IGB_TSO_SIZE (65535 + sizeof(struct ether_vlan_header)) #define IGB_TSO_SEG_SIZE 4096 /* Max dma segment size */ #define IGB_HDR_BUF 128 +#define IGB_PKTTYPE_MASK 0x0000FFF0 #define ETH_ZLEN 60 #define ETH_ADDR_LEN 6 @@ -235,11 +236,6 @@ #define CSUM_OFFLOAD (CSUM_IP|CSUM_TCP|CSUM_UDP) #endif -/* Header split codes for get_buf */ -#define IGB_CLEAN_HEADER 1 -#define IGB_CLEAN_PAYLOAD 2 -#define IGB_CLEAN_BOTH 3 - /* * Interrupt Moderation parameters */ @@ -280,6 +276,7 @@ struct tx_ring { struct igb_dma_alloc txdma; /* bus_dma glue for tx desc */ struct e1000_tx_desc *tx_base; struct task tx_task; /* cleanup tasklet */ + struct taskqueue *tq; u32 next_avail_desc; u32 next_to_clean; volatile u16 tx_avail; @@ -291,7 +288,8 @@ struct tx_ring { struct resource *res; void *tag; - u32 watchdog_timer; + bool watchdog_check; + int watchdog_time; u64 no_desc_avail; u64 tx_irq; u64 tx_packets; @@ -311,13 +309,14 @@ struct rx_ring { bool lro_enabled; bool hdr_split; struct task rx_task; /* cleanup tasklet */ + struct taskqueue *tq; struct mtx rx_mtx; char mtx_name[16]; u32 last_cleaned; u32 next_to_check; - struct igb_rx_buffer *rx_buffers; + struct igb_rx_buf *rx_buffers; bus_dma_tag_t rxtag; /* dma tag for tx */ - bus_dmamap_t rx_spare_map; + bus_dmamap_t spare_map; /* * First/last mbuf pointers, for * collecting multisegment RX packets. @@ -364,7 +363,6 @@ struct adapter { int min_frame_size; struct mtx core_mtx; int igb_insert_vlan_header; - struct task link_task; struct task rxtx_task; struct taskqueue *tq; /* private task queue */ u16 num_queues; @@ -445,7 +443,7 @@ struct igb_tx_buffer { bus_dmamap_t map; /* bus_dma map for packet */ }; -struct igb_rx_buffer { +struct igb_rx_buf { struct mbuf *m_head; struct mbuf *m_pack; bus_dmamap_t map; /* bus_dma map for packet */ @@ -454,12 +452,12 @@ struct igb_rx_buffer { #define IGB_CORE_LOCK_INIT(_sc, _name) \ mtx_init(&(_sc)->core_mtx, _name, "IGB Core Lock", MTX_DEF) #define IGB_CORE_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->core_mtx) -#define IGB_TX_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->tx_mtx) -#define IGB_RX_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->rx_mtx) +#define IGB_TX_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->tx_mtx) +#define IGB_RX_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->rx_mtx) #define IGB_CORE_LOCK(_sc) mtx_lock(&(_sc)->core_mtx) -#define IGB_TX_LOCK(_sc) mtx_lock(&(_sc)->tx_mtx) -#define IGB_TX_TRYLOCK(_sc) mtx_trylock(&(_sc)->tx_mtx) -#define IGB_RX_LOCK(_sc) mtx_lock(&(_sc)->rx_mtx) +#define IGB_TX_LOCK(_sc) mtx_lock(&(_sc)->tx_mtx) +#define IGB_TX_TRYLOCK(_sc) mtx_trylock(&(_sc)->tx_mtx) +#define IGB_RX_LOCK(_sc) mtx_lock(&(_sc)->rx_mtx) #define IGB_CORE_UNLOCK(_sc) mtx_unlock(&(_sc)->core_mtx) #define IGB_TX_UNLOCK(_sc) mtx_unlock(&(_sc)->tx_mtx) #define IGB_RX_UNLOCK(_sc) mtx_unlock(&(_sc)->rx_mtx) |