From d05b20c60cbb95d7ca1748de74c18e404a2b0475 Mon Sep 17 00:00:00 2001 From: Jack F Vogel Date: Mon, 5 Apr 2010 20:39:44 +0000 Subject: [PATCH] MFC of the em/igb drivers --- sys/conf/files | 2 + sys/dev/e1000/LICENSE | 2 +- sys/dev/e1000/e1000_80003es2lan.c | 278 +- sys/dev/e1000/e1000_80003es2lan.h | 12 +- sys/dev/e1000/e1000_82540.c | 4 +- sys/dev/e1000/e1000_82541.c | 39 +- sys/dev/e1000/e1000_82542.c | 4 +- sys/dev/e1000/e1000_82543.c | 86 +- sys/dev/e1000/e1000_82571.c | 236 +- sys/dev/e1000/e1000_82575.c | 790 +++-- sys/dev/e1000/e1000_82575.h | 84 +- sys/dev/e1000/e1000_api.c | 38 +- sys/dev/e1000/e1000_api.h | 4 +- sys/dev/e1000/e1000_defines.h | 113 +- sys/dev/e1000/e1000_hw.h | 32 +- sys/dev/e1000/e1000_ich8lan.c | 1039 +++++-- sys/dev/e1000/e1000_ich8lan.h | 38 +- sys/dev/e1000/e1000_mac.c | 127 +- sys/dev/e1000/e1000_mac.h | 4 +- sys/dev/e1000/e1000_manage.c | 70 +- sys/dev/e1000/e1000_osdep.h | 43 +- sys/dev/e1000/e1000_phy.c | 890 ++++-- sys/dev/e1000/e1000_phy.h | 24 +- sys/dev/e1000/e1000_regs.h | 57 +- sys/dev/e1000/if_em.c | 3632 ++++++++++------------ sys/dev/e1000/if_em.h | 240 +- sys/dev/e1000/if_igb.c | 2424 ++++++++------- sys/dev/e1000/if_igb.h | 131 +- sys/dev/e1000/if_lem.c | 4706 +++++++++++++++++++++++++++++ sys/dev/e1000/if_lem.h | 481 +++ 30 files changed, 10816 insertions(+), 4814 deletions(-) create mode 100644 sys/dev/e1000/if_lem.c create mode 100644 sys/dev/e1000/if_lem.h diff --git a/sys/conf/files b/sys/conf/files index d4de3668a10c..86e9d4721529 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -899,6 +899,8 @@ dev/eisa/eisa_if.m standard dev/eisa/eisaconf.c optional eisa dev/e1000/if_em.c optional em inet \ compile-with "${NORMAL_C} -I$S/dev/e1000" +dev/e1000/if_lem.c optional em inet \ + compile-with "${NORMAL_C} -I$S/dev/e1000" dev/e1000/if_igb.c optional igb inet \ compile-with "${NORMAL_C} -I$S/dev/e1000" dev/e1000/e1000_80003es2lan.c optional em | igb \ diff --git a/sys/dev/e1000/LICENSE b/sys/dev/e1000/LICENSE index d3f8bf5f367e..f70a7cbd4a1d 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-2010, 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 5c060869cf96..af32ee0f1fcd 100644 --- a/sys/dev/e1000/e1000_80003es2lan.c +++ b/sys/dev/e1000/e1000_80003es2lan.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -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; } @@ -226,10 +231,14 @@ static s32 e1000_init_mac_params_80003es2lan(struct e1000_hw *hw) mac->rar_entry_count = E1000_RAR_ENTRIES; /* Set if part includes ASF firmware */ mac->asf_firmware_present = TRUE; - /* Set if manageability features are enabled. */ + /* FWSM register */ + mac->has_fwsm = TRUE; + /* ARC supported; valid only if manageability features are enabled. */ 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 +250,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 */ @@ -270,8 +258,6 @@ static s32 e1000_init_mac_params_80003es2lan(struct e1000_hw *hw) mac->ops.write_vfta = e1000_write_vfta_generic; /* clearing VFTA */ 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_80003es2lan; /* ID LED init */ @@ -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); + + 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); - - 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); + + 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); - - 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 @@ -1035,72 +1048,73 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw) DEBUGFUNC("e1000_copper_link_setup_gg82563_80003es2lan"); - if (!phy->reset_disable) { - ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, - &data); - if (ret_val) - goto out; + if (phy->reset_disable) + goto skip_reset; - data |= GG82563_MSCR_ASSERT_CRS_ON_TX; - /* Use 25MHz for both link down and 1000Base-T for Tx clock. */ - data |= GG82563_MSCR_TX_CLK_1000MBPS_25; + ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, + &data); + if (ret_val) + goto out; - ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, - data); - if (ret_val) - goto out; + data |= GG82563_MSCR_ASSERT_CRS_ON_TX; + /* Use 25MHz for both link down and 1000Base-T for Tx clock. */ + data |= GG82563_MSCR_TX_CLK_1000MBPS_25; - /* - * Options: - * MDI/MDI-X = 0 (default) - * 0 - Auto for all speeds - * 1 - MDI mode - * 2 - MDI-X mode - * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) - */ - ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_SPEC_CTRL, &data); - if (ret_val) - goto out; + ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, + data); + if (ret_val) + goto out; - data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK; + /* + * Options: + * MDI/MDI-X = 0 (default) + * 0 - Auto for all speeds + * 1 - MDI mode + * 2 - MDI-X mode + * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) + */ + ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_SPEC_CTRL, &data); + if (ret_val) + goto out; - switch (phy->mdix) { - case 1: - data |= GG82563_PSCR_CROSSOVER_MODE_MDI; - break; - case 2: - data |= GG82563_PSCR_CROSSOVER_MODE_MDIX; - break; - case 0: - default: - data |= GG82563_PSCR_CROSSOVER_MODE_AUTO; - break; - } - - /* - * Options: - * disable_polarity_correction = 0 (default) - * Automatic Correction for Reversed Cable Polarity - * 0 - Disabled - * 1 - Enabled - */ - data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE; - if (phy->disable_polarity_correction) - data |= GG82563_PSCR_POLARITY_REVERSAL_DISABLE; - - ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_SPEC_CTRL, data); - if (ret_val) - goto out; - - /* SW Reset the PHY so all changes take effect */ - ret_val = hw->phy.ops.commit(hw); - if (ret_val) { - DEBUGOUT("Error Resetting the PHY\n"); - goto out; - } + data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK; + switch (phy->mdix) { + case 1: + data |= GG82563_PSCR_CROSSOVER_MODE_MDI; + break; + case 2: + data |= GG82563_PSCR_CROSSOVER_MODE_MDIX; + break; + case 0: + default: + data |= GG82563_PSCR_CROSSOVER_MODE_AUTO; + break; } + /* + * Options: + * disable_polarity_correction = 0 (default) + * Automatic Correction for Reversed Cable Polarity + * 0 - Disabled + * 1 - Enabled + */ + data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE; + if (phy->disable_polarity_correction) + data |= GG82563_PSCR_POLARITY_REVERSAL_DISABLE; + + ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_SPEC_CTRL, data); + if (ret_val) + goto out; + + /* SW Reset the PHY so all changes take effect */ + ret_val = hw->phy.ops.commit(hw); + if (ret_val) { + DEBUGOUT("Error Resetting the PHY\n"); + goto out; + } + +skip_reset: /* Bypass Rx and Tx FIFO's */ ret_val = e1000_write_kmrn_reg_80003es2lan(hw, E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL, @@ -1303,7 +1317,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 +1370,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 7bf8d9d54362..3ab1ec9d04e1 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_82540.c b/sys/dev/e1000/e1000_82540.c index 14dcbb3e35d3..80a5877725cf 100644 --- a/sys/dev/e1000/e1000_82540.c +++ b/sys/dev/e1000/e1000_82540.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -228,8 +228,6 @@ static s32 e1000_init_mac_params_82540(struct e1000_hw *hw) mac->ops.write_vfta = e1000_write_vfta_generic; /* clearing VFTA */ 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_82540; /* ID LED init */ diff --git a/sys/dev/e1000/e1000_82541.c b/sys/dev/e1000/e1000_82541.c index 68d1b05a07b5..fd8d8ebbe746 100644 --- a/sys/dev/e1000/e1000_82541.c +++ b/sys/dev/e1000/e1000_82541.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -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); @@ -259,8 +260,8 @@ static s32 e1000_init_mac_params_82541(struct e1000_hw *hw) mac->ops.write_vfta = e1000_write_vfta_generic; /* clearing VFTA */ 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 +1293,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_82542.c b/sys/dev/e1000/e1000_82542.c index 46ef66a0a512..282814bb8934 100644 --- a/sys/dev/e1000/e1000_82542.c +++ b/sys/dev/e1000/e1000_82542.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -134,8 +134,6 @@ static s32 e1000_init_mac_params_82542(struct e1000_hw *hw) mac->ops.write_vfta = e1000_write_vfta_generic; /* clearing VFTA */ 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_82542; /* set RAR */ diff --git a/sys/dev/e1000/e1000_82543.c b/sys/dev/e1000/e1000_82543.c index 97c7f3b2044f..4bb0cbdd5c33 100644 --- a/sys/dev/e1000/e1000_82543.c +++ b/sys/dev/e1000/e1000_82543.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2008, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -63,7 +63,6 @@ static s32 e1000_led_on_82543(struct e1000_hw *hw); static s32 e1000_led_off_82543(struct e1000_hw *hw); static void e1000_write_vfta_82543(struct e1000_hw *hw, u32 offset, u32 value); -static void e1000_mta_set_82543(struct e1000_hw *hw, u32 hash_value); static void e1000_clear_hw_cntrs_82543(struct e1000_hw *hw); static s32 e1000_config_mac_to_phy_82543(struct e1000_hw *hw); static bool e1000_init_phy_disabled_82543(struct e1000_hw *hw); @@ -75,6 +74,8 @@ static void e1000_shift_out_mdi_bits_82543(struct e1000_hw *hw, u32 data, u16 count); static bool e1000_tbi_compatibility_enabled_82543(struct e1000_hw *hw); static void e1000_set_tbi_sbp_82543(struct e1000_hw *hw, bool state); +static s32 e1000_read_mac_addr_82543(struct e1000_hw *hw); + /** * e1000_init_phy_params_82543 - Init PHY func ptrs. @@ -244,8 +245,8 @@ static s32 e1000_init_mac_params_82543(struct e1000_hw *hw) mac->ops.write_vfta = e1000_write_vfta_82543; /* clearing VFTA */ mac->ops.clear_vfta = e1000_clear_vfta_generic; - /* setting MTA */ - mac->ops.mta_set = e1000_mta_set_82543; + /* read mac address */ + mac->ops.read_mac_addr = e1000_read_mac_addr_82543; /* turn on/off LED */ mac->ops.led_on = e1000_led_on_82543; mac->ops.led_off = e1000_led_off_82543; @@ -1476,45 +1477,6 @@ static void e1000_write_vfta_82543(struct e1000_hw *hw, u32 offset, u32 value) } } -/** - * e1000_mta_set_82543 - Set multicast filter table address - * @hw: pointer to the HW structure - * @hash_value: determines the MTA register and bit to set - * - * The multicast table address is a register array of 32-bit registers. - * The hash_value is used to determine what register the bit is in, the - * current value is read, the new bit is OR'd in and the new value is - * written back into the register. - **/ -static void e1000_mta_set_82543(struct e1000_hw *hw, u32 hash_value) -{ - u32 hash_bit, hash_reg, mta, temp; - - DEBUGFUNC("e1000_mta_set_82543"); - - hash_reg = (hash_value >> 5); - - /* - * If we are on an 82544 and we are trying to write an odd offset - * in the MTA, save off the previous entry before writing and - * restore the old value after writing. - */ - if ((hw->mac.type == e1000_82544) && (hash_reg & 1)) { - hash_reg &= (hw->mac.mta_reg_count - 1); - hash_bit = hash_value & 0x1F; - mta = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg); - mta |= (1 << hash_bit); - temp = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg - 1); - - E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg, mta); - E1000_WRITE_FLUSH(hw); - E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg - 1, temp); - E1000_WRITE_FLUSH(hw); - } else { - e1000_mta_set_generic(hw, hash_value); - } -} - /** * e1000_led_on_82543 - Turn on SW controllable LED * @hw: pointer to the HW structure @@ -1600,3 +1562,41 @@ static void e1000_clear_hw_cntrs_82543(struct e1000_hw *hw) E1000_READ_REG(hw, E1000_TSCTC); E1000_READ_REG(hw, E1000_TSCTFC); } + +/** + * e1000_read_mac_addr_82543 - Read device MAC address + * @hw: pointer to the HW structure + * + * Reads the device MAC address from the EEPROM and stores the value. + * Since devices with two ports use the same EEPROM, we increment the + * last bit in the MAC address for the second port. + * + **/ +s32 e1000_read_mac_addr_82543(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); + } + + /* Flip last bit of mac address if we're on second port */ + if (hw->bus.func == E1000_FUNC_1) + hw->mac.perm_addr[5] ^= 1; + + 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 18fe745b14a5..afeb1a05e5c3 100644 --- a/sys/dev/e1000/e1000_82571.c +++ b/sys/dev/e1000/e1000_82571.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -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; } @@ -297,70 +313,25 @@ static s32 e1000_init_mac_params_82571(struct e1000_hw *hw) mac->rar_entry_count = E1000_RAR_ENTRIES; /* Set if part includes ASF firmware */ mac->asf_firmware_present = TRUE; - /* Set if manageability features are enabled. */ - 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 */ mac->ops.write_vfta = e1000_write_vfta_generic; /* clearing VFTA */ mac->ops.clear_vfta = e1000_clear_vfta_82571; - /* setting MTA */ - mac->ops.mta_set = e1000_mta_set_generic; /* read mac address */ mac->ops.read_mac_addr = e1000_read_mac_addr_82571; /* ID LED init */ @@ -371,24 +342,42 @@ 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 */ - switch (hw->mac.type) { - case e1000_82574: - case e1000_82583: - mac->ops.led_on = e1000_led_on_82574; - break; - default: - mac->ops.led_on = e1000_led_on_generic; - break; - } + /* turn off LED */ 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; + + /* 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; + + /* FWSM register */ + mac->has_fwsm = TRUE; + /* + * ARC supported; valid only if manageability features are + * enabled. + */ + mac->arc_subsystem_valid = + (E1000_READ_REG(hw, E1000_FWSM) & E1000_FWSM_MODE_MASK) + ? TRUE : FALSE; + 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; + + /* FWSM register */ + mac->has_fwsm = TRUE; + break; + } /* * Ensure that the inter-port SWSM.SMBI lock bit is clear before @@ -434,8 +423,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 +489,6 @@ static s32 e1000_get_phy_id_82571(struct e1000_hw *hw) ret_val = -E1000_ERR_PHY; break; } - out: return ret_val; } @@ -512,7 +499,7 @@ static s32 e1000_get_phy_id_82571(struct e1000_hw *hw) * * 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 +564,7 @@ s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw) * * 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 +597,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 +818,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 +954,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 +1002,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 +1049,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,10 +1084,11 @@ static s32 e1000_init_hw_82571(struct e1000_hw *hw) /* ...for both queues. */ switch (mac->type) { - case e1000_82574: - case e1000_82583: case e1000_82573: e1000_enable_tx_pkt_filtering_generic(hw); + /* fall through */ + case e1000_82574: + case e1000_82583: reg_data = E1000_READ_REG(hw, E1000_GCR); reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX; E1000_WRITE_REG(hw, E1000_GCR, reg_data); @@ -1108,8 +1096,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 +1166,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 +1180,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 +1192,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 +1202,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 +1210,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 +1252,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 +1351,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; @@ -1392,7 +1374,7 @@ static s32 e1000_setup_link_82571(struct e1000_hw *hw) static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw) { u32 ctrl; - s32 ret_val; + s32 ret_val; DEBUGFUNC("e1000_setup_copper_link_82571"); @@ -1460,7 +1442,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 +1454,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 +1506,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 +1517,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 +1549,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 +1569,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 +1607,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 2f8e8ed31edb..65b3ce47a41a 100644 --- a/sys/dev/e1000/e1000_82575.c +++ b/sys/dev/e1000/e1000_82575.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -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); @@ -76,10 +80,18 @@ static void e1000_release_swfw_sync_82575(struct e1000_hw *hw, u16 mask); 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_config_collision_dist_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 void e1000_power_up_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 +106,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 +124,10 @@ 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) { + 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 +156,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 +215,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,27 +253,45 @@ 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)) + 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->rar_entry_count = E1000_RAR_ENTRIES_82580; /* Set if part includes ASF firmware */ mac->asf_firmware_present = TRUE; - /* Set if manageability features are enabled. */ + /* FWSM register */ + mac->has_fwsm = TRUE; + /* ARC supported; valid only if manageability features are enabled. */ mac->arc_subsystem_valid = (E1000_READ_REG(hw, E1000_FWSM) & E1000_FWSM_MODE_MASK) ? TRUE : FALSE; @@ -260,6 +301,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->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,23 +313,25 @@ 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; + /* physical interface power up */ + mac->ops.power_up_serdes = e1000_power_up_serdes_link_82575; /* check for link */ mac->ops.check_for_link = e1000_check_for_link_82575; /* receive address register setting */ mac->ops.rar_set = e1000_rar_set_generic; /* read mac address */ mac->ops.read_mac_addr = e1000_read_mac_addr_82575; + /* configure collision distance */ + mac->ops.config_collision_dist = e1000_config_collision_dist_82575; /* multicast address update */ mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic; /* writing VFTA */ mac->ops.write_vfta = e1000_write_vfta_generic; /* clearing VFTA */ mac->ops.clear_vfta = e1000_clear_vfta_generic; - /* setting MTA */ - mac->ops.mta_set = e1000_mta_set_generic; /* ID LED init */ mac->ops.id_led_init = e1000_id_led_init_generic; /* blink LED */ @@ -302,6 +348,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 +383,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 +405,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 +425,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 +458,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); + ret_val = e1000_write_phy_reg_i2c(hw, offset, data); - E1000_WRITE_REG(hw, E1000_I2CCMD, i2ccmd); + hw->phy.ops.release(hw); - /* 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; +out: + return ret_val; } /** @@ -480,6 +491,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 +502,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 +541,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 +813,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 +851,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 +875,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); /* @@ -872,6 +891,35 @@ static s32 e1000_check_for_link_82575(struct e1000_hw *hw) return ret_val; } +/** + * e1000_power_up_serdes_link_82575 - Power up the serdes link after shutdown + * @hw: pointer to the HW structure + **/ +static void e1000_power_up_serdes_link_82575(struct e1000_hw *hw) +{ + u32 reg; + + DEBUGFUNC("e1000_power_up_serdes_link_82575"); + + if ((hw->phy.media_type != e1000_media_type_internal_serdes) && + !e1000_sgmii_active_82575(hw)) + return; + + /* Enable PCS to turn on link */ + reg = E1000_READ_REG(hw, E1000_PCS_CFG0); + reg |= E1000_PCS_CFG_PCS_EN; + E1000_WRITE_REG(hw, E1000_PCS_CFG0, reg); + + /* Power up the laser */ + reg = E1000_READ_REG(hw, E1000_CTRL_EXT); + reg &= ~E1000_CTRL_EXT_SDP3_DATA; + E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg); + + /* flush the write to verify completion */ + E1000_WRITE_FLUSH(hw); + msec_delay(1); +} + /** * e1000_get_pcs_speed_and_duplex_82575 - Retrieve current speed/duplex * @hw: pointer to the HW structure @@ -930,31 +978,23 @@ 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) + DEBUGFUNC("e1000_shutdown_serdes_link_82575"); + + 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->bus.func == E1000_FUNC_1) - hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_B, 1, &eeprom_data); - - /* - * If APM is not enabled in the EEPROM and management interface is - * not enabled, then power down. - */ - if (!(eeprom_data & E1000_NVM_APME_82575) && - !e1000_enable_mng_pass_thru(hw)) { + if (!e1000_enable_mng_pass_thru(hw)) { /* Disable PCS to turn off link */ reg = E1000_READ_REG(hw, E1000_PCS_CFG0); reg &= ~E1000_PCS_CFG_PCS_EN; @@ -962,10 +1002,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); } @@ -973,45 +1013,6 @@ void e1000_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw) return; } -/** - * 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 +1112,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 +1143,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 +1151,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 +1172,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 +1183,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_fiber_serdes_link_82575"); + DEBUGFUNC("e1000_setup_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 +1216,48 @@ 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; - if (hw->mac.type == e1000_82575 || hw->mac.type == e1000_82576) { - /* set both sw defined pins */ - reg |= E1000_CTRL_SWDPIN0 | E1000_CTRL_SWDPIN1; - } - 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); + /* 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; + + /* set both sw defined pins on 82575/82576*/ + if (hw->mac.type == e1000_82575 || hw->mac.type == e1000_82576) + ctrl_reg |= E1000_CTRL_SWDPIN0 | E1000_CTRL_SWDPIN1; + + 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 +1265,31 @@ 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); - } - - if (hw->mac.type == e1000_82576) { - reg |= E1000_PCS_LCTL_FORCE_FCTRL; - e1000_force_mac_fc_generic(hw); + /* Set PCS register for forced link */ + reg |= E1000_PCS_LCTL_FSD; /* Force Speed */ + 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; } @@ -1323,72 +1328,6 @@ static s32 e1000_valid_led_default_82575(struct e1000_hw *hw, u16 *data) return ret_val; } -/** - * 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 @@ -1466,6 +1405,28 @@ static s32 e1000_read_mac_addr_82575(struct e1000_hw *hw) return ret_val; } +/** + * e1000_config_collision_dist_82575 - Configure collision distance + * @hw: pointer to the HW structure + * + * Configures the collision distance to the default value and is used + * during link setup. + **/ +static void e1000_config_collision_dist_82575(struct e1000_hw *hw) +{ + u32 tctl_ext; + + DEBUGFUNC("e1000_config_collision_dist_82575"); + + tctl_ext = E1000_READ_REG(hw, E1000_TCTL_EXT); + + tctl_ext &= ~E1000_TCTL_EXT_COLD; + tctl_ext |= E1000_COLLISION_DISTANCE << E1000_TCTL_EXT_COLD_SHIFT; + + E1000_WRITE_REG(hw, E1000_TCTL_EXT, tctl_ext); + E1000_WRITE_FLUSH(hw); +} + /** * e1000_power_down_phy_copper_82575 - Remove link during PHY power down * @hw: pointer to the HW structure @@ -1476,13 +1437,12 @@ static s32 e1000_read_mac_addr_82575(struct e1000_hw *hw) static void e1000_power_down_phy_copper_82575(struct e1000_hw *hw) { struct e1000_phy_info *phy = &hw->phy; - struct e1000_mac_info *mac = &hw->mac; if (!(phy->ops.check_reset_block)) return; /* If the management interface is not enabled, then power down */ - if (!(mac->ops.check_mng_mode(hw) || phy->ops.check_reset_block(hw))) + if (!(e1000_enable_mng_pass_thru(hw) || phy->ops.check_reset_block(hw))) e1000_power_down_phy_copper(hw); return; @@ -1548,7 +1508,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 +1638,208 @@ static s32 e1000_set_pcie_completion_timeout(struct e1000_hw *hw) 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; + + switch (hw->mac.type) { + case e1000_82576: + 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); + break; + default: + /* Currently no other hardware supports loopback */ + break; + } + + +} + +/** + * 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) +{ + s32 ret_val; + + DEBUGFUNC("e1000_read_phy_reg_82580"); + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + + 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) +{ + s32 ret_val; + + DEBUGFUNC("e1000_write_phy_reg_82580"); + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + + 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; +} diff --git a/sys/dev/e1000/e1000_82575.h b/sys/dev/e1000/e1000_82575.h index 34e0d29398f7..1fc7e26dd590 100644 --- a/sys/dev/e1000/e1000_82575.h +++ b/sys/dev/e1000/e1000_82575.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -49,12 +49,16 @@ * For 82576, there are an additional set of RARs that begin at an offset * separate from the first set of RARs. */ -#define E1000_RAR_ENTRIES_82575 16 -#define E1000_RAR_ENTRIES_82576 24 +#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 @@ -409,6 +425,7 @@ struct e1000_adv_tx_context_desc { #define E1000_VMOLR_STRVLAN 0x40000000 /* Vlan stripping enable */ #define E1000_VMOLR_STRCRC 0x80000000 /* CRC stripping enable */ + #define E1000_VLVF_ARRAY_SIZE 32 #define E1000_VLVF_VLANID_MASK 0x00000FFF #define E1000_VLVF_POOLSEL_SHIFT 12 @@ -416,6 +433,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 +444,20 @@ struct e1000_adv_tx_context_desc { #define E1000_RPLOLR_STRVLAN 0x40000000 #define E1000_RPLOLR_STRCRC 0x80000000 +#define E1000_TCTL_EXT_COLD 0x000FFC00 +#define E1000_TCTL_EXT_COLD_SHIFT 10 + +#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); #endif /* _E1000_82575_H_ */ diff --git a/sys/dev/e1000/e1000_api.c b/sys/dev/e1000/e1000_api.c index 8188658d6bb1..bf9fa2abb903 100644 --- a/sys/dev/e1000/e1000_api.c +++ b/sys/dev/e1000/e1000_api.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -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,17 @@ 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; default: /* Should never have loaded on this device */ ret_val = -E1000_ERR_MAC_INIT; @@ -362,6 +371,7 @@ s32 e1000_setup_init_funcs(struct e1000_hw *hw, bool init_device) break; case e1000_82575: case e1000_82576: + case e1000_82580: e1000_init_function_pointers_82575(hw); break; default: @@ -744,20 +754,6 @@ s32 e1000_validate_mdi_setting(struct e1000_hw *hw) return E1000_SUCCESS; } -/** - * e1000_mta_set - Sets multicast table bit - * @hw: pointer to the HW structure - * @hash_value: Multicast hash value. - * - * This sets the bit in the multicast table corresponding to the - * hash value. This is a function pointer entry point called by drivers. - **/ -void e1000_mta_set(struct e1000_hw *hw, u32 hash_value) -{ - if (hw->mac.ops.mta_set) - hw->mac.ops.mta_set(hw, hash_value); -} - /** * e1000_hash_mc_addr - Determines address location in multicast table * @hw: pointer to the HW structure @@ -1236,6 +1232,18 @@ void e1000_power_down_phy(struct e1000_hw *hw) hw->phy.ops.power_down(hw); } +/** + * e1000_power_up_fiber_serdes_link - Power up serdes link + * @hw: pointer to the HW structure + * + * Power on the optics and PCS. + **/ +void e1000_power_up_fiber_serdes_link(struct e1000_hw *hw) +{ + if (hw->mac.ops.power_up_serdes) + hw->mac.ops.power_up_serdes(hw); +} + /** * e1000_shutdown_fiber_serdes_link - Remove link during power down * @hw: pointer to the HW structure diff --git a/sys/dev/e1000/e1000_api.h b/sys/dev/e1000/e1000_api.h index b492e577b1a0..b7bc14c8f314 100644 --- a/sys/dev/e1000/e1000_api.h +++ b/sys/dev/e1000/e1000_api.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -47,6 +47,7 @@ extern void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw); extern void e1000_init_function_pointers_82575(struct e1000_hw *hw); extern void e1000_rx_fifo_flush_82575(struct e1000_hw *hw); extern void e1000_init_function_pointers_vf(struct e1000_hw *hw); +extern void e1000_power_up_fiber_serdes_link(struct e1000_hw *hw); extern void e1000_shutdown_fiber_serdes_link(struct e1000_hw *hw); s32 e1000_set_mac_type(struct e1000_hw *hw); @@ -67,7 +68,6 @@ s32 e1000_get_speed_and_duplex(struct e1000_hw *hw, u16 *speed, s32 e1000_disable_pcie_master(struct e1000_hw *hw); void e1000_config_collision_dist(struct e1000_hw *hw); void e1000_rar_set(struct e1000_hw *hw, u8 *addr, u32 index); -void e1000_mta_set(struct e1000_hw *hw, u32 hash_value); u32 e1000_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr); void e1000_update_mc_addr_list(struct e1000_hw *hw, u8 *mc_addr_list, u32 mc_addr_count); diff --git a/sys/dev/e1000/e1000_defines.h b/sys/dev/e1000/e1000_defines.h index d845fb23dc65..7ac5d8b8b1d7 100644 --- a/sys/dev/e1000/e1000_defines.h +++ b/sys/dev/e1000/e1000_defines.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -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 @@ -312,6 +314,11 @@ #define E1000_MANC_SMB_DATA_OUT_SHIFT 28 /* SMBus Data Out Shift */ #define E1000_MANC_SMB_CLK_OUT_SHIFT 29 /* SMBus Clock Out Shift */ +#define E1000_MANC2H_PORT_623 0x00000020 /* Port 0x26f */ +#define E1000_MANC2H_PORT_664 0x00000040 /* Port 0x298 */ +#define E1000_MDEF_PORT_623 0x00000800 /* Port 0x26f */ +#define E1000_MDEF_PORT_664 0x00000400 /* Port 0x298 */ + /* Receive Control */ #define E1000_RCTL_RST 0x00000001 /* Software reset */ #define E1000_RCTL_EN 0x00000002 /* enable */ @@ -386,6 +393,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 */ @@ -414,6 +423,8 @@ * PHYRST_N pin */ #define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external * LINK_0 and LINK_1 pins */ +#define E1000_CTRL_LANPHYPC_OVERRIDE 0x00010000 /* SW control of LANPHYPC */ +#define E1000_CTRL_LANPHYPC_VALUE 0x00020000 /* SW value of LANPHYPC */ #define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ #define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ #define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */ @@ -697,6 +708,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 +781,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 +802,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 +874,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 +896,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 +929,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 @@ -943,6 +960,8 @@ #define E1000_EICS_OTHER E1000_EICR_OTHER /* Interrupt Cause Active */ #define E1000_EITR_ITR_INT_MASK 0x0000FFFF +/* E1000_EITR_CNT_IGNR is only for 82576 and newer */ +#define E1000_EITR_CNT_IGNR 0x80000000 /* Don't reset counters on write */ /* Transmit Descriptor Control */ #define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */ @@ -1036,6 +1055,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 +1296,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 @@ -1316,6 +1389,9 @@ #define PCI_HEADER_TYPE_MULTIFUNC 0x80 #define PCIE_LINK_WIDTH_MASK 0x3F0 #define PCIE_LINK_WIDTH_SHIFT 4 +#define PCIE_LINK_SPEED_MASK 0x0F +#define PCIE_LINK_SPEED_2500 0x01 +#define PCIE_LINK_SPEED_5000 0x02 #define PCIE_DEVICE_CONTROL2_16ms 0x0005 #ifndef ETH_ADDR_LEN @@ -1346,6 +1422,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 @@ -1442,6 +1519,7 @@ #define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */ #define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */ + /* M88EC018 Rev 2 specific DownShift settings */ #define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00 #define M88EC018_EPSCR_DOWNSHIFT_COUNTER_1X 0x0000 @@ -1575,5 +1653,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 6afa4fbb8bd5..ce5dffdd67d3 100644 --- a/sys/dev/e1000/e1000_hw.h +++ b/sys/dev/e1000/e1000_hw.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -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 @@ -121,6 +122,7 @@ struct e1000_hw; #define E1000_DEV_ID_ICH10_R_BM_V 0x10CE #define E1000_DEV_ID_ICH10_D_BM_LM 0x10DE #define E1000_DEV_ID_ICH10_D_BM_LF 0x10DF + #define E1000_DEV_ID_PCH_M_HV_LM 0x10EA #define E1000_DEV_ID_PCH_M_HV_LC 0x10EB #define E1000_DEV_ID_PCH_D_HV_DM 0x10EF @@ -130,11 +132,17 @@ 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_REVISION_0 0 #define E1000_REVISION_1 1 #define E1000_REVISION_2 2 @@ -143,9 +151,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 +185,7 @@ enum e1000_mac_type { e1000_pchlan, e1000_82575, e1000_82576, + e1000_82580, e1000_num_macs /* List is 1-based, so subtract 1 for TRUE count. */ }; @@ -213,6 +226,7 @@ enum e1000_phy_type { e1000_phy_bm, e1000_phy_82578, e1000_phy_82577, + e1000_phy_82580, e1000_phy_vf, }; @@ -587,11 +601,11 @@ struct e1000_mac_operations { s32 (*reset_hw)(struct e1000_hw *); s32 (*init_hw)(struct e1000_hw *); void (*shutdown_serdes)(struct e1000_hw *); + void (*power_up_serdes)(struct e1000_hw *); s32 (*setup_link)(struct e1000_hw *); s32 (*setup_physical_interface)(struct e1000_hw *); s32 (*setup_led)(struct e1000_hw *); void (*write_vfta)(struct e1000_hw *, u32, u32); - void (*mta_set)(struct e1000_hw *, u32); void (*config_collision_dist)(struct e1000_hw *); void (*rar_set)(struct e1000_hw *, u8*, u32); s32 (*read_mac_addr)(struct e1000_hw *); @@ -615,11 +629,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 +673,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 @@ -666,6 +683,7 @@ struct e1000_mac_info { u8 forced_speed_duplex; bool adaptive_ifs; + bool has_fwsm; bool arc_subsystem_valid; bool asf_firmware_present; bool autoneg; @@ -768,6 +786,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 +800,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 +835,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 a80955a5a367..6b3c25d8218d 100644 --- a/sys/dev/e1000/e1000_ich8lan.c +++ b/sys/dev/e1000/e1000_ich8lan.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -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,10 @@ 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); +static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw); /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */ /* Offset 04h HSFSTS */ @@ -171,6 +177,7 @@ union ich8_hws_flash_regacc { static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) { struct e1000_phy_info *phy = &hw->phy; + u32 ctrl; s32 ret_val = E1000_SUCCESS; DEBUGFUNC("e1000_init_phy_params_pchlan"); @@ -179,35 +186,88 @@ 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; + if ((hw->mac.type == e1000_pchlan) && + (!(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID))) { + + /* + * The MAC-PHY interconnect may still be in SMBus mode + * after Sx->S0. Toggle the LANPHYPC Value bit to force + * the interconnect to PCIe mode, but only if there is no + * firmware present otherwise firmware will have done it. + */ + ctrl = E1000_READ_REG(hw, E1000_CTRL); + ctrl |= E1000_CTRL_LANPHYPC_OVERRIDE; + ctrl &= ~E1000_CTRL_LANPHYPC_VALUE; + E1000_WRITE_REG(hw, E1000_CTRL, ctrl); + usec_delay(10); + ctrl &= ~E1000_CTRL_LANPHYPC_OVERRIDE; + E1000_WRITE_REG(hw, E1000_CTRL, ctrl); + msec_delay(50); + } + + /* + * Reset the PHY before any acccess to it. Doing so, ensures that + * the PHY is in a known good state before we read/write PHY registers. + * The generic reset is sufficient here, because we haven't determined + * the PHY type yet. + */ + ret_val = e1000_phy_hw_reset_generic(hw); + if (ret_val) + goto out; + phy->id = e1000_phy_unknown; - e1000_get_phy_id(hw); + ret_val = e1000_get_phy_id(hw); + if (ret_val) + goto out; + if ((phy->id == 0) || (phy->id == PHY_REVISION_MASK)) { + /* + * In case the PHY needs to be in mdio slow mode (eg. 82577), + * set slow mode and try to get the PHY id again. + */ + ret_val = e1000_set_mdio_slow_mode_hv(hw); + if (ret_val) + goto out; + ret_val = e1000_get_phy_id(hw); + if (ret_val) + goto out; + } 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; + break; + 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; } +out: return ret_val; } @@ -229,12 +289,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 +330,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 +351,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 +421,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; @@ -391,8 +462,12 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw) mac->rar_entry_count--; /* Set if part includes ASF firmware */ mac->asf_firmware_present = TRUE; - /* Set if manageability features are enabled. */ - mac->arc_subsystem_valid = TRUE; + /* FWSM register */ + mac->has_fwsm = TRUE; + /* ARC subsystem not supported */ + mac->arc_subsystem_valid = FALSE; + /* Adaptive IFS supported */ + mac->adaptive_ifs = TRUE; /* Function pointers */ @@ -409,15 +484,13 @@ 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 */ mac->ops.get_link_up_info = e1000_get_link_up_info_ich8lan; /* multicast address update */ mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic; - /* setting MTA */ - mac->ops.mta_set = e1000_mta_set_generic; /* clear hardware counters */ mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan; @@ -460,10 +533,98 @@ 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 @@ -490,13 +651,42 @@ 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 +695,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 +735,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 +745,8 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) * 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 +758,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; } @@ -587,12 +797,333 @@ static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw) DEBUGFUNC("e1000_check_reset_block_ich8lan"); + if (hw->phy.reset_disable) + return E1000_BLK_PHY_RESET; + fwsm = E1000_READ_REG(hw, E1000_FWSM); return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? E1000_SUCCESS : E1000_BLK_PHY_RESET; } +/** + * 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 = E1000_SUCCESS; + u16 word_addr, reg_data, reg_addr, phy_page = 0; + + if (!(hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) && + !(hw->mac.type == e1000_pchlan)) + return ret_val; + + 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->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 @@ -605,6 +1136,26 @@ s32 e1000_hv_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw) return hw->phy.ops.write_reg(hw, PHY_REG(768, 25), 0x0444); } +/** + * e1000_set_mdio_slow_mode_hv - Set slow MDIO access mode + * @hw: pointer to the HW structure + **/ +static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw) +{ + s32 ret_val; + u16 data; + + ret_val = hw->phy.ops.read_reg(hw, HV_KMRN_MODE_CTRL, &data); + if (ret_val) + return ret_val; + + data |= HV_KMRN_MDIO_SLOW; + + ret_val = hw->phy.ops.write_reg(hw, HV_KMRN_MODE_CTRL, data); + + return ret_val; +} + /** * e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be * done after every PHY reset. @@ -612,9 +1163,17 @@ s32 e1000_hv_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw) static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw) { s32 ret_val = E1000_SUCCESS; + u16 phy_data; if (hw->mac.type != e1000_pchlan) - return ret_val; + goto out; + + /* Set MDIO slow mode before any other MDIO access */ + if (hw->phy.type == e1000_phy_82577) { + ret_val = e1000_set_mdio_slow_mode_hv(hw); + if (ret_val) + goto out; + } /* Hanksville M Phy init for IEEE. */ if ((hw->revision_id == 2) && @@ -648,12 +1207,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 +1221,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 +1250,46 @@ 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; - hw->phy.addr = 1; - e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0); - hw->phy.ops.release(hw); + goto out; + hw->phy.addr = 1; + ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0); + hw->phy.ops.release(hw); + if (ret_val) + goto out; + + /* + * 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); + if (ret_val) + goto out; + + /* Workaround for link disconnects on a busy hub in half duplex */ + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + ret_val = hw->phy.ops.read_reg_locked(hw, + PHY_REG(BM_PORT_CTRL_PAGE, 17), + &phy_data); + if (ret_val) + goto release; + ret_val = hw->phy.ops.write_reg_locked(hw, + PHY_REG(BM_PORT_CTRL_PAGE, 17), + phy_data & 0x00FF); +release: + hw->phy.ops.release(hw); +out: return ret_val; } @@ -752,10 +1337,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"); @@ -766,168 +1349,62 @@ static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw) /* Allow time for h/w to get to a quiescent state after reset */ msec_delay(10); - if (hw->mac.type == e1000_pchlan) { + /* Perform any necessary post-reset workarounds */ + switch (hw->mac.type) { + case e1000_pchlan: ret_val = e1000_hv_phy_workarounds_ich8lan(hw); if (ret_val) goto out; + break; + default: + break; } - /* - * 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; + /* 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, ®); - data = E1000_READ_REG(hw, E1000_FEXTNVM); - if (!(data & sw_cfg_mask)) - goto out; + /* Configure the LCD with the extended configuration region in NVM */ + ret_val = e1000_sw_lcd_config_ich8lan(hw); + if (ret_val) + 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; - } - - reg_addr |= phy_page; - - 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 */ + 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 + * 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 * - * Wrapper for calling the get_phy_info routines for the appropriate phy type. + * 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_ich8lan(struct e1000_hw *hw) +static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active) { - s32 ret_val = -E1000_ERR_PHY_TYPE; + s32 ret_val = E1000_SUCCESS; + u16 oem_reg; - DEBUGFUNC("e1000_get_phy_info_ich8lan"); + DEBUGFUNC("e1000_set_lplu_state_pchlan"); - 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 - * @hw: pointer to the HW structure - * - * Populates "phy" structure with various feature states. - * This function is only called by other family-specific - * routines. - **/ -static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw) -{ - 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); + ret_val = hw->phy.ops.read_reg(hw, HV_OEM_BITS, &oem_reg); 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; - } + if (active) + oem_reg |= HV_OEM_BITS_LPLU; + else + oem_reg &= ~HV_OEM_BITS_LPLU; - 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; + 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 +1647,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 +1655,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 +1700,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 +1726,6 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, } } -release: nvm->ops.release(hw); out: @@ -1534,9 +2011,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 +2052,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,26 +2061,22 @@ 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) { new_bank_offset = nvm->flash_bank_size; old_bank_offset = 0; ret_val = e1000_erase_flash_bank_ich8lan(hw, 1); - if (ret_val) { - nvm->ops.release(hw); - goto out; - } + if (ret_val) + goto release; } else { old_bank_offset = nvm->flash_bank_size; new_bank_offset = 0; ret_val = e1000_erase_flash_bank_ich8lan(hw, 0); - if (ret_val) { - nvm->ops.release(hw); - goto out; - } + if (ret_val) + goto release; } for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) { @@ -1662,8 +2131,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) */ if (ret_val) { DEBUGOUT("Flash commit failed.\n"); - nvm->ops.release(hw); - goto out; + goto release; } /* @@ -1674,18 +2142,15 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) */ act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD; ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data); - if (ret_val) { - nvm->ops.release(hw); - goto out; - } + if (ret_val) + goto release; + data &= 0xBFFF; ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset * 2 + 1, (u8)(data >> 8)); - if (ret_val) { - nvm->ops.release(hw); - goto out; - } + if (ret_val) + goto release; /* * And invalidate the previously valid segment by setting @@ -1695,10 +2160,8 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) */ act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1; ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0); - if (ret_val) { - nvm->ops.release(hw); - goto out; - } + if (ret_val) + goto release; /* Great! Everything worked, we can now clear the cached entries. */ for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) { @@ -1706,14 +2169,17 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) dev_spec->shadow_ram[i].value = 0xFFFF; } +release: nvm->ops.release(hw); /* * Reload the EEPROM, or else modifications will not appear * until after the next adapter reset. */ - nvm->ops.reload(hw); - msec_delay(10); + if (!ret_val) { + nvm->ops.reload(hw); + msec_delay(10); + } out: if (ret_val) @@ -1829,10 +2295,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 +2426,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 +2619,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 +2656,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) { @@ -2213,6 +2693,17 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) if (!ret_val) e1000_release_swflag_ich8lan(hw); + /* Perform any necessary post-reset workarounds */ + switch (hw->mac.type) { + case e1000_pchlan: + ret_val = e1000_hv_phy_workarounds_ich8lan(hw); + if (ret_val) + goto out; + break; + default: + break; + } + if (ctrl & E1000_CTRL_PHY_RST) ret_val = hw->phy.ops.get_cfg_done(hw); @@ -2229,6 +2720,24 @@ 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; + + 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); @@ -2237,9 +2746,7 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) kab |= E1000_KABGTXD_BGSQLBIAS; E1000_WRITE_REG(hw, E1000_KABGTXD, kab); - if (hw->mac.type == e1000_pchlan) - ret_val = e1000_hv_phy_workarounds_ich8lan(hw); - +out: return ret_val; } @@ -2269,8 +2776,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 +2823,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); @@ -2387,6 +2894,14 @@ static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw) E1000_WRITE_REG(hw, E1000_STATUS, reg); } + /* + * work-around descriptor data corruption issue during nfs v2 udp + * traffic, just disable the nfs filtering capability + */ + reg = E1000_READ_REG(hw, E1000_RFCTL); + reg |= (E1000_RFCTL_NFSW_DIS | E1000_RFCTL_NFSR_DIS); + E1000_WRITE_REG(hw, E1000_RFCTL, reg); + return; } @@ -2473,8 +2988,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 +3302,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 +3311,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; } @@ -2814,17 +3328,14 @@ void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw) **/ static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw) { - s32 ret_val = E1000_SUCCESS; - DEBUGFUNC("e1000_cleanup_led_ich8lan"); if (hw->phy.type == e1000_phy_ife) - ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, - 0); - else - E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default); + return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, + 0); - return ret_val; + E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default); + return E1000_SUCCESS; } /** @@ -2835,17 +3346,14 @@ static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw) **/ static s32 e1000_led_on_ich8lan(struct e1000_hw *hw) { - s32 ret_val = E1000_SUCCESS; - DEBUGFUNC("e1000_led_on_ich8lan"); if (hw->phy.type == e1000_phy_ife) - ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, + return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON)); - else - E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2); - return ret_val; + E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2); + return E1000_SUCCESS; } /** @@ -2856,18 +3364,14 @@ static s32 e1000_led_on_ich8lan(struct e1000_hw *hw) **/ static s32 e1000_led_off_ich8lan(struct e1000_hw *hw) { - s32 ret_val = E1000_SUCCESS; - DEBUGFUNC("e1000_led_off_ich8lan"); if (hw->phy.type == e1000_phy_ife) - ret_val = hw->phy.ops.write_reg(hw, - IFE_PHY_SPECIAL_CONTROL_LED, + return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF)); - else - E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1); - return ret_val; + E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1); + return E1000_SUCCESS; } /** @@ -2982,18 +3486,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 5416eeb72b29..f26b7b9f70a5 100644 --- a/sys/dev/e1000/e1000_ich8lan.h +++ b/sys/dev/e1000/e1000_ich8lan.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -140,6 +140,38 @@ #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 */ + +/* KMRN Mode Control */ +#define HV_KMRN_MODE_CTRL PHY_REG(769, 16) +#define HV_KMRN_MDIO_SLOW 0x0400 + +/* PHY Power Management Control */ +#define HV_PM_CTRL PHY_REG(770, 17) + +#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 @@ -163,12 +195,12 @@ #define E1000_RXDEXT_LINKSEC_ERROR_REPLAY_ERROR 0x40000000 #define E1000_RXDEXT_LINKSEC_ERROR_BAD_SIG 0x60000000 - void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, bool state); 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 db6e5f52e088..d4d2bec27bdc 100644 --- a/sys/dev/e1000/e1000_mac.c +++ b/sys/dev/e1000/e1000_mac.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -78,7 +78,6 @@ void e1000_init_mac_ops_generic(struct e1000_hw *hw) mac->ops.update_mc_addr_list = e1000_null_update_mc; mac->ops.clear_vfta = e1000_null_mac_generic; mac->ops.write_vfta = e1000_null_write_vfta; - mac->ops.mta_set = e1000_null_mta_set; mac->ops.rar_set = e1000_rar_set_generic; mac->ops.validate_mdi_setting = e1000_validate_mdi_setting_generic; } @@ -143,16 +142,6 @@ void e1000_null_write_vfta(struct e1000_hw *hw, u32 a, u32 b) return; } -/** - * e1000_null_set_mta - No-op function, return void - * @hw: pointer to the HW structure - **/ -void e1000_null_mta_set(struct e1000_hw *hw, u32 a) -{ - DEBUGFUNC("e1000_null_mta_set"); - return; -} - /** * e1000_null_rar_set - No-op function, return void * @hw: pointer to the HW structure @@ -230,24 +219,36 @@ 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; DEBUGFUNC("e1000_get_bus_info_pcie_generic"); bus->type = e1000_bus_type_pci_express; - bus->speed = e1000_bus_speed_2500; ret_val = e1000_read_pcie_cap_reg(hw, PCIE_LINK_STATUS, &pcie_link_status); - if (ret_val) + if (ret_val) { bus->width = e1000_bus_width_unknown; - else + bus->speed = e1000_bus_speed_unknown; + } else { + switch (pcie_link_status & PCIE_LINK_SPEED_MASK) { + case PCIE_LINK_SPEED_2500: + bus->speed = e1000_bus_speed_2500; + break; + case PCIE_LINK_SPEED_5000: + bus->speed = e1000_bus_speed_5000; + break; + default: + bus->speed = e1000_bus_speed_unknown; + break; + } + bus->width = (enum e1000_bus_width)((pcie_link_status & PCIE_LINK_WIDTH_MASK) >> PCIE_LINK_WIDTH_SHIFT); + } mac->ops.set_lan_id(hw); @@ -408,6 +409,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); @@ -477,42 +483,6 @@ void e1000_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index) E1000_WRITE_FLUSH(hw); } -/** - * e1000_mta_set_generic - Set multicast filter table address - * @hw: pointer to the HW structure - * @hash_value: determines the MTA register and bit to set - * - * The multicast table address is a register array of 32-bit registers. - * The hash_value is used to determine what register the bit is in, the - * current value is read, the new bit is OR'd in and the new value is - * written back into the register. - **/ -void e1000_mta_set_generic(struct e1000_hw *hw, u32 hash_value) -{ - u32 hash_bit, hash_reg, mta; - - DEBUGFUNC("e1000_mta_set_generic"); - /* - * The MTA is a register array of 32-bit registers. It is - * treated like an array of (32*mta_reg_count) bits. We want to - * set bit BitArray[hash_value]. So we figure out what register - * the bit is in, read it, OR in the new bit, then write - * back the new value. The (hw->mac.mta_reg_count - 1) serves as a - * mask to bits 31:5 of the hash value which gives us the - * register we're modifying. The hash bit within that register - * is determined by the lower 5 bits of the hash value. - */ - hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1); - hash_bit = hash_value & 0x1F; - - mta = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg); - - mta |= (1 << hash_bit); - - E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg, mta); - E1000_WRITE_FLUSH(hw); -} - /** * e1000_update_mc_addr_list_generic - Update Multicast addresses * @hw: pointer to the HW structure @@ -556,8 +526,7 @@ void e1000_update_mc_addr_list_generic(struct e1000_hw *hw, * @mc_addr: pointer to a multicast address * * Generates a multicast address hash value which is used to determine - * the multicast filter table array address and new table value. See - * e1000_mta_set_generic() + * the multicast filter table array address and new table value. **/ u32 e1000_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr) { @@ -750,12 +719,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 @@ -776,7 +739,7 @@ s32 e1000_check_for_copper_link_generic(struct e1000_hw *hw) * of MAC speed/duplex configuration. So we only need to * configure Collision Distance in the MAC. */ - e1000_config_collision_dist_generic(hw); + mac->ops.config_collision_dist(hw); /* * Configure Flow Control now that Auto-Neg has completed. @@ -994,9 +957,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 @@ -1050,6 +1012,7 @@ s32 e1000_setup_link_generic(struct e1000_hw *hw) **/ s32 e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw) { + struct e1000_mac_info *mac = &hw->mac; u32 ctrl; s32 ret_val = E1000_SUCCESS; @@ -1060,7 +1023,7 @@ s32 e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw) /* Take the link out of reset */ ctrl &= ~E1000_CTRL_LRST; - e1000_config_collision_dist_generic(hw); + mac->ops.config_collision_dist(hw); ret_val = e1000_commit_fc_settings_generic(hw); if (ret_val) @@ -1100,8 +1063,7 @@ s32 e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw) * @hw: pointer to the HW structure * * Configures the collision distance to the default value and is used - * during link setup. Currently no func pointer exists and all - * implementations are handled in the generic version of this function. + * during link setup. **/ void e1000_config_collision_dist_generic(struct e1000_hw *hw) { @@ -1155,7 +1117,7 @@ s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw) * link up if we detect a signal. This will allow us to * communicate with non-autonegotiating link partners. */ - ret_val = hw->mac.ops.check_for_link(hw); + ret_val = mac->ops.check_for_link(hw); if (ret_val) { DEBUGOUT("Error while checking for link\n"); goto out; @@ -1212,7 +1174,7 @@ s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw) * Rx Flow control is enabled and Tx Flow control is disabled * by a software over-ride. Since there really isn't a way to * advertise that we are capable of Rx Pause ONLY, we will - * advertise that we support both symmetric and asymmetric RX + * advertise that we support both symmetric and asymmetric Rx * PAUSE. Later, we will disable the adapter's ability to send * PAUSE frames. */ @@ -1256,7 +1218,6 @@ s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw) **/ s32 e1000_set_fc_watermarks_generic(struct e1000_hw *hw) { - s32 ret_val = E1000_SUCCESS; u32 fcrtl = 0, fcrth = 0; DEBUGFUNC("e1000_set_fc_watermarks_generic"); @@ -1283,7 +1244,7 @@ s32 e1000_set_fc_watermarks_generic(struct e1000_hw *hw) E1000_WRITE_REG(hw, E1000_FCRTL, fcrtl); E1000_WRITE_REG(hw, E1000_FCRTH, fcrth); - return ret_val; + return E1000_SUCCESS; } /** @@ -1512,7 +1473,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. */ @@ -1522,7 +1483,7 @@ s32 e1000_config_fc_after_link_up_generic(struct e1000_hw *hw) } else { hw->fc.current_mode = e1000_fc_rx_pause; DEBUGOUT("Flow Control = " - "RX PAUSE frames only.\r\n"); + "Rx PAUSE frames only.\r\n"); } } /* @@ -1538,7 +1499,7 @@ s32 e1000_config_fc_after_link_up_generic(struct e1000_hw *hw) (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { hw->fc.current_mode = e1000_fc_tx_pause; - DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n"); + DEBUGOUT("Flow Control = Tx PAUSE frames only.\r\n"); } /* * For transmitting PAUSE frames ONLY. @@ -1553,7 +1514,7 @@ s32 e1000_config_fc_after_link_up_generic(struct e1000_hw *hw) !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { hw->fc.current_mode = e1000_fc_rx_pause; - DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n"); + DEBUGOUT("Flow Control = Rx PAUSE frames only.\r\n"); } else { /* * Per the IEEE spec, at this point flow control @@ -1895,19 +1856,10 @@ s32 e1000_setup_led_generic(struct e1000_hw *hw) **/ s32 e1000_cleanup_led_generic(struct e1000_hw *hw) { - s32 ret_val = E1000_SUCCESS; - DEBUGFUNC("e1000_cleanup_led_generic"); - if (hw->mac.ops.cleanup_led != e1000_cleanup_led_generic) { - ret_val = -E1000_ERR_CONFIG; - goto out; - } - E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default); - -out: - return ret_val; + return E1000_SUCCESS; } /** @@ -2033,7 +1985,7 @@ void e1000_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop) * 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. * @@ -2066,7 +2018,6 @@ s32 e1000_disable_pcie_master_generic(struct e1000_hw *hw) if (!timeout) { DEBUGOUT("Master requests are pending.\n"); ret_val = -E1000_ERR_MASTER_REQUESTS_PENDING; - goto out; } out: @@ -2151,7 +2102,7 @@ void e1000_update_adaptive_generic(struct e1000_hw *hw) * 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_mac.h b/sys/dev/e1000/e1000_mac.h index b7a5b2c5ecb0..348d660f9734 100644 --- a/sys/dev/e1000/e1000_mac.h +++ b/sys/dev/e1000/e1000_mac.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -46,7 +46,6 @@ s32 e1000_null_link_info(struct e1000_hw *hw, u16 *s, u16 *d); bool e1000_null_mng_mode(struct e1000_hw *hw); void e1000_null_update_mc(struct e1000_hw *hw, u8 *h, u32 a); void e1000_null_write_vfta(struct e1000_hw *hw, u32 a, u32 b); -void e1000_null_mta_set(struct e1000_hw *hw, u32 a); void e1000_null_rar_set(struct e1000_hw *hw, u8 *h, u32 a); s32 e1000_blink_led_generic(struct e1000_hw *hw); s32 e1000_check_for_copper_link_generic(struct e1000_hw *hw); @@ -87,7 +86,6 @@ void e1000_clear_hw_cntrs_base_generic(struct e1000_hw *hw); void e1000_clear_vfta_generic(struct e1000_hw *hw); void e1000_config_collision_dist_generic(struct e1000_hw *hw); void e1000_init_rx_addrs_generic(struct e1000_hw *hw, u16 rar_count); -void e1000_mta_set_generic(struct e1000_hw *hw, u32 hash_value); void e1000_pcix_mmrbc_workaround_generic(struct e1000_hw *hw); void e1000_put_hw_semaphore_generic(struct e1000_hw *hw); void e1000_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index); diff --git a/sys/dev/e1000/e1000_manage.c b/sys/dev/e1000/e1000_manage.c index b1f6541ad0c1..0b295f8d384c 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-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -74,10 +74,16 @@ s32 e1000_mng_enable_host_if_generic(struct e1000_hw *hw) { u32 hicr; s32 ret_val = E1000_SUCCESS; - u8 i; + u8 i; DEBUGFUNC("e1000_mng_enable_host_if_generic"); + if (!(hw->mac.arc_subsystem_valid)) { + DEBUGOUT("ARC subsystem not valid.\n"); + ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND; + goto out; + } + /* Check that the host interface is enabled. */ hicr = E1000_READ_REG(hw, E1000_HICR); if ((hicr & E1000_HICR_EN) == 0) { @@ -112,18 +118,17 @@ s32 e1000_mng_enable_host_if_generic(struct e1000_hw *hw) **/ bool e1000_check_mng_mode_generic(struct e1000_hw *hw) { - u32 fwsm; + u32 fwsm = E1000_READ_REG(hw, E1000_FWSM); DEBUGFUNC("e1000_check_mng_mode_generic"); - fwsm = E1000_READ_REG(hw, E1000_FWSM); return (fwsm & E1000_FWSM_MODE_MASK) == (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT); } /** - * 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 @@ -136,13 +141,14 @@ bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw) u32 offset; s32 ret_val, hdr_csum, csum; u8 i, len; - bool tx_filter = TRUE; DEBUGFUNC("e1000_enable_tx_pkt_filtering_generic"); + hw->mac.tx_pkt_filtering = TRUE; + /* No manageability, no filtering */ if (!hw->mac.ops.check_mng_mode(hw)) { - tx_filter = FALSE; + hw->mac.tx_pkt_filtering = FALSE; goto out; } @@ -152,18 +158,16 @@ bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw) */ ret_val = hw->mac.ops.mng_enable_host_if(hw); if (ret_val != E1000_SUCCESS) { - tx_filter = FALSE; + hw->mac.tx_pkt_filtering = FALSE; goto out; } /* 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, @@ -173,18 +177,19 @@ bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw) * the cookie area isn't considered valid, in which case we * take the safe route of assuming Tx filtering is enabled. */ - if (hdr_csum != csum) - goto out; - if (hdr->signature != E1000_IAMT_SIGNATURE) + if ((hdr_csum != csum) || (hdr->signature != E1000_IAMT_SIGNATURE)) { + hw->mac.tx_pkt_filtering = TRUE; goto out; + } /* Cookie area is valid, make the final check for filtering. */ - if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING)) - tx_filter = FALSE; + if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING)) { + hw->mac.tx_pkt_filtering = FALSE; + goto out; + } out: - hw->mac.tx_pkt_filtering = tx_filter; - return tx_filter; + return hw->mac.tx_pkt_filtering; } /** @@ -344,10 +349,11 @@ s32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer, } /** - * e1000_enable_mng_pass_thru - Enable processing of ARP's + * e1000_enable_mng_pass_thru - Check if management passthrough is needed * @hw: pointer to the HW structure * - * Verifies the hardware needs to allow ARPs to be processed by the host. + * Verifies the hardware needs to leave interface enabled so that frames can + * be directed to and from the management interface. **/ bool e1000_enable_mng_pass_thru(struct e1000_hw *hw) { @@ -362,11 +368,10 @@ bool e1000_enable_mng_pass_thru(struct e1000_hw *hw) manc = E1000_READ_REG(hw, E1000_MANC); - if (!(manc & E1000_MANC_RCV_TCO_EN) || - !(manc & E1000_MANC_EN_MAC_ADDR_FILTER)) + if (!(manc & E1000_MANC_RCV_TCO_EN)) goto out; - if (hw->mac.arc_subsystem_valid) { + if (hw->mac.has_fwsm) { fwsm = E1000_READ_REG(hw, E1000_FWSM); factps = E1000_READ_REG(hw, E1000_FACTPS); @@ -376,12 +381,23 @@ bool e1000_enable_mng_pass_thru(struct e1000_hw *hw) ret_val = TRUE; goto out; } - } else { - if ((manc & E1000_MANC_SMBUS_EN) && - !(manc & E1000_MANC_ASF_EN)) { + } else if ((hw->mac.type == e1000_82574) || + (hw->mac.type == e1000_82583)) { + u16 data; + + factps = E1000_READ_REG(hw, E1000_FACTPS); + e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &data); + + if (!(factps & E1000_FACTPS_MNGCG) && + ((data & E1000_NVM_INIT_CTRL2_MNGM) == + (e1000_mng_mode_pt << 13))) { ret_val = TRUE; goto out; } + } else if ((manc & E1000_MANC_SMBUS_EN) && + !(manc & E1000_MANC_ASF_EN)) { + ret_val = TRUE; + goto out; } out: diff --git a/sys/dev/e1000/e1000_osdep.h b/sys/dev/e1000/e1000_osdep.h index b478f29fb0f7..ff505cc19ca1 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-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include #include #include @@ -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,21 @@ #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) +#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 +102,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 513f2e67fb4a..24ca36f6ebb0 100644 --- a/sys/dev/e1000/e1000_phy.c +++ b/sys/dev/e1000/e1000_phy.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -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; @@ -189,22 +191,9 @@ s32 e1000_get_phy_id(struct e1000_hw *hw) if (phy->id != 0 && phy->id != PHY_REVISION_MASK) 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 - */ - ret_val = e1000_set_mdio_slow_mode_hv(hw, TRUE); - if (ret_val) - goto out; - retry_count++; } out: - /* Revert to MDIO fast mode, if applicable */ - if (retry_count) - ret_val = e1000_set_mdio_slow_mode_hv(hw, FALSE); - return ret_val; } @@ -250,6 +239,11 @@ s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data) DEBUGFUNC("e1000_read_phy_reg_mdic"); + if (offset > MAX_PHY_REG_ADDRESS) { + DEBUGOUT1("PHY Address %d is out of range\n", offset); + return -E1000_ERR_PARAM; + } + /* * Set up Op-code, Phy Address, and register offset in the MDI * Control register. The MAC will take care of interfacing with the @@ -308,6 +302,11 @@ s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data) DEBUGFUNC("e1000_write_phy_reg_mdic"); + if (offset > MAX_PHY_REG_ADDRESS) { + DEBUGOUT1("PHY Address %d is out of range\n", offset); + return -E1000_ERR_PARAM; + } + /* * Set up Op-code, Phy Address, and register offset in the MDI * Control register. The MAC will take care of interfacing with the @@ -350,6 +349,105 @@ s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data) return ret_val; } +/** + * 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 @@ -414,42 +512,119 @@ s32 e1000_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data) } /** - * 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. + **/ +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 (!locked) { + if (!(hw->phy.ops.acquire)) + 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) + goto release; + } + + ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, + data); + +release: + if (!locked) + hw->phy.ops.release(hw); out: return ret_val; @@ -461,64 +636,55 @@ s32 e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data) * @offset: register offset to write to * @data: data to write at register offset * - * Acquires semaphore, if necessary, then writes the data to PHY register + * 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) { - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_write_phy_reg_igp"); - - if (!(hw->phy.ops.acquire)) - 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; - } - } - - ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, - data); - - hw->phy.ops.release(hw); - -out: - return ret_val; + return __e1000_write_phy_reg_igp(hw, offset, data, FALSE); } /** - * e1000_read_kmrn_reg_generic - Read kumeran register + * 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,47 +695,112 @@ 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 @@ -578,19 +809,26 @@ s32 e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data) **/ s32 e1000_copper_link_setup_82577(struct e1000_hw *hw) { - struct e1000_phy_info *phy = &hw->phy; s32 ret_val; u16 phy_data; DEBUGFUNC("e1000_copper_link_setup_82577"); - if (phy->reset_disable) { + if (hw->phy.reset_disable) { ret_val = E1000_SUCCESS; goto out; } + if (hw->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); + ret_val = hw->phy.ops.read_reg(hw, I82577_CFG_REG, &phy_data); if (ret_val) goto out; @@ -599,16 +837,7 @@ s32 e1000_copper_link_setup_82577(struct e1000_hw *hw) /* Enable downshift */ 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); + ret_val = hw->phy.ops.write_reg(hw, I82577_CFG_REG, phy_data); out: return ret_val; @@ -634,7 +863,7 @@ s32 e1000_copper_link_setup_m88(struct e1000_hw *hw) goto out; } - /* Enable CRS on TX. This must be set for half-duplex operation. */ + /* Enable CRS on Tx. This must be set for half-duplex operation. */ ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); if (ret_val) goto out; @@ -1326,18 +1555,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 +1580,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 +1629,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 +1856,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 +2055,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 +2107,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 +2214,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 +2316,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; @@ -2113,6 +2341,63 @@ s32 e1000_get_phy_info_igp(struct e1000_hw *hw) return ret_val; } +/** + * 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 +2587,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 +2618,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 +2704,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 +2715,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 +2734,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 +2765,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 +2776,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 +2795,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 +2823,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 +2834,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 +2842,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 +2869,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 +2880,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 +2887,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 +2915,8 @@ s32 e1000_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data) * 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 +2924,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 +2932,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 +3003,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,31 +3043,70 @@ void e1000_power_down_phy_copper(struct e1000_hw *hw) msec_delay(1); } -s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow) +/** + * __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 stores the retrieved information in data. Release any acquired + * semaphore before exiting. + **/ +static s32 __e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data, + bool locked) { - s32 ret_val = E1000_SUCCESS; - u16 data = 0; + s32 ret_val; + u16 page = BM_PHY_REG_PAGE(offset); + u16 reg = BM_PHY_REG_NUM(offset); - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - return ret_val; + DEBUGFUNC("__e1000_read_phy_reg_hv"); - /* 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 (!locked) { + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return ret_val; } - ret_val = e1000_write_phy_reg_mdic(hw, BM_CS_CTRL1, - (0x2180 | (slow << 10))); - /* dummy read when reverting to fast mode - throw away result */ - if (!slow) - e1000_read_phy_reg_mdic(hw, BM_CS_CTRL1, &data); + /* 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, TRUE); + goto out; + } - hw->phy.ops.release(hw); + if (page > 0 && page < HV_INTC_FC_PAGE_START) { + ret_val = e1000_access_phy_debug_regs_hv(hw, offset, + data, TRUE); + 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) { + 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); +out: + if (!locked) + hw->phy.ops.release(hw); return ret_val; } @@ -2810,109 +3117,52 @@ s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow) * @offset: register offset to be read * @data: pointer to the read data * - * Acquires semaphore, if necessary, then reads the PHY register at offset - * and storing the retrieved information in data. Release any acquired - * semaphore before exiting. + * 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) { - s32 ret_val; - u16 page = BM_PHY_REG_PAGE(offset); - u16 reg = BM_PHY_REG_NUM(offset); - bool in_slow_mode = FALSE; - - DEBUGFUNC("e1000_read_phy_reg_hv"); - - /* 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)) { - ret_val = e1000_set_mdio_slow_mode_hv(hw, TRUE); - if (ret_val) - goto out; - - in_slow_mode = TRUE; - } - - /* 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, TRUE); - goto out; - } - - if (page > 0 && page < HV_INTC_FC_PAGE_START) { - ret_val = e1000_access_phy_debug_regs_hv(hw, offset, - data, TRUE); - 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; - } - } - - 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); - - return ret_val; + return __e1000_read_phy_reg_hv(hw, offset, data, FALSE); } /** - * e1000_write_phy_reg_hv - Write HV PHY register + * 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); u16 reg = BM_PHY_REG_NUM(offset); - bool in_slow_mode = FALSE; - DEBUGFUNC("e1000_write_phy_reg_hv"); + DEBUGFUNC("__e1000_write_phy_reg_hv"); - /* 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)) { - ret_val = e1000_set_mdio_slow_mode_hv(hw, TRUE); + if (!locked) { + ret_val = hw->phy.ops.acquire(hw); if (ret_val) - goto out; - - in_slow_mode = TRUE; + return ret_val; } /* Page 800 works differently than the rest so it has its own func */ @@ -2928,10 +3178,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,49 +3193,65 @@ 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; + u32 phy_addr = hw->phy.addr; - hw->phy.addr = 1; + 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; - } + /* 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); + 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 +3273,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 +3283,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 +3291,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 +3313,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 +3341,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) @@ -3151,9 +3402,7 @@ s32 e1000_check_polarity_82577(struct e1000_hw *hw) * e1000_phy_force_speed_duplex_82577 - Force speed/duplex for I82577 PHY * @hw: pointer to the HW structure * - * Calls the PHY setup function to force speed and duplex. Clears the - * auto-crossover to force MDI manually. Waits for link and returns - * successful if link up is successful, else -E1000_ERR_PHY (-2). + * Calls the PHY setup function to force speed and duplex. **/ s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw) { @@ -3174,23 +3423,6 @@ s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw) if (ret_val) goto out; - /* - * Clear Auto-Crossover to force MDI manually. 82577 requires MDI - * forced whenever speed and duplex are forced. - */ - ret_val = phy->ops.read_reg(hw, I82577_PHY_CTRL_2, &phy_data); - if (ret_val) - goto out; - - phy_data &= ~I82577_PHY_CTRL2_AUTO_MDIX; - phy_data &= ~I82577_PHY_CTRL2_FORCE_MDI_MDIX; - - ret_val = phy->ops.write_reg(hw, I82577_PHY_CTRL_2, phy_data); - if (ret_val) - goto out; - - DEBUGOUT1("I82577_PHY_CTRL_2: %X\n", phy_data); - usec_delay(1); if (phy->autoneg_wait_to_complete) { @@ -3309,7 +3541,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 28ed0c15852f..692cbaa91eb9 100644 --- a/sys/dev/e1000/e1000_phy.h +++ b/sys/dev/e1000/e1000_phy.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -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,9 +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_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow); +s32 e1000_write_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 data); s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw); s32 e1000_copper_link_setup_82577(struct e1000_hw *hw); s32 e1000_check_polarity_82577(struct e1000_hw *hw); @@ -140,7 +148,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 +182,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 +234,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 3a62d0a61a3a..b2a477e82345 100644 --- a/sys/dev/e1000/e1000_regs.h +++ b/sys/dev/e1000/e1000_regs.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -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 */ @@ -59,7 +65,7 @@ #define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */ #define E1000_IVAR 0x000E4 /* Interrupt Vector Allocation Register - RW */ #define E1000_SVCR 0x000F0 -#define E1000_SVT 0x000F4 +#define E1000_SVT 0x000F4 #define E1000_RCTL 0x00100 /* Rx Control - RW */ #define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */ #define E1000_TXCW 0x00178 /* Tx Configuration Word - 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,18 @@ #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 */ + +/* Virtualization statistical counters */ +#define E1000_PFVFGPRC(_n) (0x010010 + (0x100 * (_n))) +#define E1000_PFVFGPTC(_n) (0x010014 + (0x100 * (_n))) +#define E1000_PFVFGORC(_n) (0x010018 + (0x100 * (_n))) +#define E1000_PFVFGOTC(_n) (0x010034 + (0x100 * (_n))) +#define E1000_PFVFMPRC(_n) (0x010038 + (0x100 * (_n))) +#define E1000_PFVFGPRLBC(_n) (0x010040 + (0x100 * (_n))) +#define E1000_PFVFGPTLBC(_n) (0x010044 + (0x100 * (_n))) +#define E1000_PFVFGORLBC(_n) (0x010048 + (0x100 * (_n))) +#define E1000_PFVFGOTLBC(_n) (0x010050 + (0x100 * (_n))) #define E1000_LSECTXUT 0x04300 /* LinkSec Tx Untagged Packet Count - OutPktsUntagged */ #define E1000_LSECTXPKTE 0x04304 /* LinkSec Encrypted Tx Packets Count - OutPktsEncrypted */ @@ -376,6 +397,7 @@ #define E1000_KMRNCTRLSTA 0x00034 /* MAC-PHY interface - RW */ #define E1000_MDPHYA 0x0003C /* PHY address - RW */ #define E1000_MANC2H 0x05860 /* Management Control To Host - RW */ +#define E1000_MDEF(_n) (0x05890 + (4 * (_n))) /* Mngmt Decision Filters */ #define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */ #define E1000_CCMCTL 0x05B48 /* CCM Control Register */ #define E1000_GIOCTL 0x05B44 /* GIO Analog Control Register */ @@ -392,6 +414,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 +460,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 +474,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 +519,15 @@ #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 #endif diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c index 96d0788c377e..f8329f89663c 100644 --- a/sys/dev/e1000/if_em.c +++ b/sys/dev/e1000/if_em.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -54,9 +54,7 @@ #include #include #include -#if __FreeBSD_version >= 700029 #include -#endif #include #include @@ -79,6 +77,7 @@ #include #include +#include #include #include @@ -94,7 +93,7 @@ int em_display_debug_stats = 0; /********************************************************************* * Driver version: *********************************************************************/ -char em_driver_version[] = "6.9.14"; +char em_driver_version[] = "7.0.0"; /********************************************************************* @@ -110,51 +109,6 @@ char em_driver_version[] = "6.9.14"; static em_vendor_info_t em_vendor_info_array[] = { /* Intel(R) PRO/1000 Network Connection */ - { 0x8086, E1000_DEV_ID_82540EM, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82540EM_LOM, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82540EP, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82540EP_LOM, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82540EP_LP, PCI_ANY_ID, PCI_ANY_ID, 0}, - - { 0x8086, E1000_DEV_ID_82541EI, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82541ER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82541ER_LOM, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82541EI_MOBILE, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82541GI, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82541GI_LF, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82541GI_MOBILE, PCI_ANY_ID, PCI_ANY_ID, 0}, - - { 0x8086, E1000_DEV_ID_82542, PCI_ANY_ID, PCI_ANY_ID, 0}, - - { 0x8086, E1000_DEV_ID_82543GC_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82543GC_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, - - { 0x8086, E1000_DEV_ID_82544EI_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82544EI_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82544GC_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82544GC_LOM, PCI_ANY_ID, PCI_ANY_ID, 0}, - - { 0x8086, E1000_DEV_ID_82545EM_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82545EM_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82545GM_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82545GM_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82545GM_SERDES, PCI_ANY_ID, PCI_ANY_ID, 0}, - - { 0x8086, E1000_DEV_ID_82546EB_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82546EB_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82546EB_QUAD_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82546GB_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82546GB_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82546GB_SERDES, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82546GB_PCIE, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82546GB_QUAD_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3, - PCI_ANY_ID, PCI_ANY_ID, 0}, - - { 0x8086, E1000_DEV_ID_82547EI, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82547EI_MOBILE, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82547GI, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82571EB_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_82571EB_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_82571EB_SERDES, PCI_ANY_ID, PCI_ANY_ID, 0}, @@ -194,7 +148,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 +165,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} }; @@ -233,14 +191,14 @@ static int em_shutdown(device_t); static int em_suspend(device_t); static int em_resume(device_t); static void em_start(struct ifnet *); -static void em_start_locked(struct ifnet *ifp); +static void em_start_locked(struct ifnet *, struct tx_ring *); #if __FreeBSD_version >= 800000 static int em_mq_start(struct ifnet *, struct mbuf *); -static int em_mq_start_locked(struct ifnet *, struct mbuf *); +static int em_mq_start_locked(struct ifnet *, + struct tx_ring *, 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 *); @@ -248,55 +206,49 @@ static void em_media_status(struct ifnet *, struct ifmediareq *); static int em_media_change(struct ifnet *); static void em_identify_hardware(struct adapter *); static int em_allocate_pci_resources(struct adapter *); -static int em_allocate_legacy(struct adapter *adapter); -static int em_allocate_msix(struct adapter *adapter); +static int em_allocate_legacy(struct adapter *); +static int em_allocate_msix(struct adapter *); +static int em_allocate_queues(struct adapter *); static int em_setup_msix(struct adapter *); static void em_free_pci_resources(struct adapter *); static void em_local_timer(void *); -static int em_hardware_init(struct adapter *); +static void em_reset(struct adapter *); static void em_setup_interface(device_t, struct adapter *); + static void em_setup_transmit_structures(struct adapter *); static void em_initialize_transmit_unit(struct adapter *); +static int em_allocate_transmit_buffers(struct tx_ring *); +static void em_free_transmit_structures(struct adapter *); +static void em_free_transmit_buffers(struct tx_ring *); + static int em_setup_receive_structures(struct adapter *); +static int em_allocate_receive_buffers(struct rx_ring *); static void em_initialize_receive_unit(struct adapter *); +static void em_free_receive_structures(struct adapter *); +static void em_free_receive_buffers(struct rx_ring *); + static void em_enable_intr(struct adapter *); static void em_disable_intr(struct adapter *); -static void em_free_transmit_structures(struct adapter *); -static void em_free_receive_structures(struct adapter *); static void em_update_stats_counters(struct adapter *); -static void em_txeof(struct adapter *); -static void em_tx_purge(struct adapter *); -static int em_allocate_receive_structures(struct adapter *); -static int em_allocate_transmit_structures(struct adapter *); -static int em_rxeof(struct adapter *, int); +static bool em_txeof(struct tx_ring *); +static int em_rxeof(struct rx_ring *, int); #ifndef __NO_STRICT_ALIGNMENT -static int em_fixup_rx(struct adapter *); +static int em_fixup_rx(struct rx_ring *); #endif -static void em_receive_checksum(struct adapter *, struct e1000_rx_desc *, - struct mbuf *); -static void em_transmit_checksum_setup(struct adapter *, struct mbuf *, +static void em_receive_checksum(struct e1000_rx_desc *, struct mbuf *); +static void em_transmit_checksum_setup(struct tx_ring *, struct mbuf *, u32 *, u32 *); -#if __FreeBSD_version >= 700000 -static bool em_tso_setup(struct adapter *, struct mbuf *, - u32 *, u32 *); -#endif /* FreeBSD_version >= 700000 */ +static bool em_tso_setup(struct tx_ring *, struct mbuf *, u32 *, u32 *); static void em_set_promisc(struct adapter *); static void em_disable_promisc(struct adapter *); static void em_set_multi(struct adapter *); static void em_print_hw_stats(struct adapter *); static void em_update_link_status(struct adapter *); -static int em_get_buf(struct adapter *, int); -#if __FreeBSD_version >= 700029 +static void em_refresh_mbufs(struct rx_ring *, int); static void em_register_vlan(void *, struct ifnet *, u16); static void em_unregister_vlan(void *, struct ifnet *, u16); static void em_setup_vlan_hw_support(struct adapter *); -#endif -static int em_xmit(struct adapter *, struct mbuf **); -static void em_smartspeed(struct adapter *); -static int em_82547_fifo_workaround(struct adapter *, int); -static void em_82547_update_fifo_head(struct adapter *, int); -static int em_82547_tx_fifo_reset(struct adapter *); -static void em_82547_move_tail(void *); +static int em_xmit(struct tx_ring *, struct mbuf **); static int em_dma_malloc(struct adapter *, bus_size_t, struct em_dma_alloc *, int); static void em_dma_free(struct adapter *, struct em_dma_alloc *); @@ -305,8 +257,6 @@ static void em_print_nvm_info(struct adapter *); static int em_is_valid_ether_addr(u8 *); static int em_sysctl_stats(SYSCTL_HANDLER_ARGS); static int em_sysctl_debug_info(SYSCTL_HANDLER_ARGS); -static u32 em_fill_descriptors (bus_addr_t address, u32 length, - PDESC_ARRAY desc_array); static int em_sysctl_int_delay(SYSCTL_HANDLER_ARGS); static void em_add_int_delay_sysctl(struct adapter *, const char *, const char *, struct em_int_delay_info *, int, int); @@ -315,29 +265,23 @@ 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 *); +static void em_led_func(void *, int); -#ifdef EM_LEGACY_IRQ -static void em_intr(void *); -#else /* FAST IRQ */ -#if __FreeBSD_version < 700000 -static void em_irq_fast(void *); -#else static int em_irq_fast(void *); -#endif /* MSIX handlers */ static void em_msix_tx(void *); static void em_msix_rx(void *); static void em_msix_link(void *); -static void em_handle_rx(void *context, int pending); static void em_handle_tx(void *context, int pending); - -static void em_handle_rxtx(void *context, int pending); +static void em_handle_rx(void *context, int pending); static void em_handle_link(void *context, int pending); + static void em_add_rx_process_limit(struct adapter *, const char *, const char *, int *, int); -#endif /* ~EM_LEGACY_IRQ */ #ifdef DEVICE_POLLING static poll_handler_t em_poll; @@ -362,7 +306,7 @@ static driver_t em_driver = { "em", em_methods, sizeof(struct adapter), }; -static devclass_t em_devclass; +devclass_t em_devclass; DRIVER_MODULE(em, pci, em_driver, em_devclass, 0, 0); MODULE_DEPEND(em, pci, 1, 1, 1); MODULE_DEPEND(em, ether, 1, 1, 1); @@ -382,31 +326,35 @@ MODULE_DEPEND(em, ether, 1, 1, 1); static int em_tx_int_delay_dflt = EM_TICKS_TO_USECS(EM_TIDV); static int em_rx_int_delay_dflt = EM_TICKS_TO_USECS(EM_RDTR); -static int em_tx_abs_int_delay_dflt = EM_TICKS_TO_USECS(EM_TADV); -static int em_rx_abs_int_delay_dflt = EM_TICKS_TO_USECS(EM_RADV); -static int em_rxd = EM_DEFAULT_RXD; -static int em_txd = EM_DEFAULT_TXD; -static int em_smart_pwr_down = FALSE; -/* Controls whether promiscuous also shows bad packets */ -static int em_debug_sbp = FALSE; -/* Local switch for MSI/MSIX */ -static int em_enable_msi = TRUE; - TUNABLE_INT("hw.em.tx_int_delay", &em_tx_int_delay_dflt); TUNABLE_INT("hw.em.rx_int_delay", &em_rx_int_delay_dflt); + +static int em_tx_abs_int_delay_dflt = EM_TICKS_TO_USECS(EM_TADV); +static int em_rx_abs_int_delay_dflt = EM_TICKS_TO_USECS(EM_RADV); TUNABLE_INT("hw.em.tx_abs_int_delay", &em_tx_abs_int_delay_dflt); TUNABLE_INT("hw.em.rx_abs_int_delay", &em_rx_abs_int_delay_dflt); + +static int em_rxd = EM_DEFAULT_RXD; +static int em_txd = EM_DEFAULT_TXD; TUNABLE_INT("hw.em.rxd", &em_rxd); TUNABLE_INT("hw.em.txd", &em_txd); -TUNABLE_INT("hw.em.smart_pwr_down", &em_smart_pwr_down); -TUNABLE_INT("hw.em.sbp", &em_debug_sbp); -TUNABLE_INT("hw.em.enable_msi", &em_enable_msi); -#ifndef EM_LEGACY_IRQ +static int em_smart_pwr_down = FALSE; +TUNABLE_INT("hw.em.smart_pwr_down", &em_smart_pwr_down); + +/* Controls whether promiscuous also shows bad packets */ +static int em_debug_sbp = FALSE; +TUNABLE_INT("hw.em.sbp", &em_debug_sbp); + +/* Local controls for MSI/MSIX */ +static int em_enable_msix = TRUE; +static int em_msix_queues = 2; /* for 82574, can be 1 or 2 */ +TUNABLE_INT("hw.em.enable_msix", &em_enable_msix); +TUNABLE_INT("hw.em.msix_queues", &em_msix_queues); + /* How many packets rxeof tries to clean at a time */ static int em_rx_process_limit = 100; TUNABLE_INT("hw.em.rx_process_limit", &em_rx_process_limit); -#endif /* Flow control setting - default to FULL */ static int em_fc_setting = e1000_fc_full; @@ -488,17 +436,13 @@ static int em_attach(device_t dev) { struct adapter *adapter; - int tsize, rsize; int error = 0; - u16 eeprom_data, device_id; INIT_DEBUGOUT("em_attach: begin"); adapter = device_get_softc(dev); adapter->dev = adapter->osdep.dev = dev; EM_CORE_LOCK_INIT(adapter, device_get_nameunit(dev)); - EM_TX_LOCK_INIT(adapter, device_get_nameunit(dev)); - EM_RX_LOCK_INIT(adapter, device_get_nameunit(dev)); /* SYSCTL stuff */ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), @@ -512,7 +456,6 @@ em_attach(device_t dev) em_sysctl_stats, "I", "Statistics"); callout_init_mtx(&adapter->timer, &adapter->core_mtx, 0); - callout_init_mtx(&adapter->tx_fifo_timer, &adapter->tx_mtx, 0); /* Determine hardware and mac info */ em_identify_hardware(adapter); @@ -531,6 +474,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; @@ -565,25 +509,21 @@ em_attach(device_t dev) em_add_int_delay_sysctl(adapter, "tx_int_delay", "transmit interrupt delay in usecs", &adapter->tx_int_delay, E1000_REGISTER(&adapter->hw, E1000_TIDV), em_tx_int_delay_dflt); - if (adapter->hw.mac.type >= e1000_82540) { - em_add_int_delay_sysctl(adapter, "rx_abs_int_delay", - "receive interrupt delay limit in usecs", - &adapter->rx_abs_int_delay, - E1000_REGISTER(&adapter->hw, E1000_RADV), - em_rx_abs_int_delay_dflt); - em_add_int_delay_sysctl(adapter, "tx_abs_int_delay", - "transmit interrupt delay limit in usecs", - &adapter->tx_abs_int_delay, - E1000_REGISTER(&adapter->hw, E1000_TADV), - em_tx_abs_int_delay_dflt); - } + em_add_int_delay_sysctl(adapter, "rx_abs_int_delay", + "receive interrupt delay limit in usecs", + &adapter->rx_abs_int_delay, + E1000_REGISTER(&adapter->hw, E1000_RADV), + em_rx_abs_int_delay_dflt); + em_add_int_delay_sysctl(adapter, "tx_abs_int_delay", + "transmit interrupt delay limit in usecs", + &adapter->tx_abs_int_delay, + E1000_REGISTER(&adapter->hw, E1000_TADV), + em_tx_abs_int_delay_dflt); -#ifndef EM_LEGACY_IRQ /* Sysctls for limiting the amount of work done in the taskqueue */ em_add_rx_process_limit(adapter, "rx_processing_limit", "max number of rx packets to process", &adapter->rx_process_limit, em_rx_process_limit); -#endif /* * Validate number of transmit and receive descriptors. It @@ -591,18 +531,15 @@ em_attach(device_t dev) * of E1000_DBA_ALIGN. */ if (((em_txd * sizeof(struct e1000_tx_desc)) % EM_DBA_ALIGN) != 0 || - (adapter->hw.mac.type >= e1000_82544 && em_txd > EM_MAX_TXD) || - (adapter->hw.mac.type < e1000_82544 && em_txd > EM_MAX_TXD_82543) || - (em_txd < EM_MIN_TXD)) { + (em_txd > EM_MAX_TXD) || (em_txd < EM_MIN_TXD)) { device_printf(dev, "Using %d TX descriptors instead of %d!\n", EM_DEFAULT_TXD, em_txd); adapter->num_tx_desc = EM_DEFAULT_TXD; } else adapter->num_tx_desc = em_txd; + if (((em_rxd * sizeof(struct e1000_rx_desc)) % EM_DBA_ALIGN) != 0 || - (adapter->hw.mac.type >= e1000_82544 && em_rxd > EM_MAX_RXD) || - (adapter->hw.mac.type < e1000_82544 && em_rxd > EM_MAX_RXD_82543) || - (em_rxd < EM_MIN_RXD)) { + (em_rxd > EM_MAX_RXD) || (em_rxd < EM_MIN_RXD)) { device_printf(dev, "Using %d RX descriptors instead of %d!\n", EM_DEFAULT_RXD, em_rxd); adapter->num_rx_desc = EM_DEFAULT_RXD; @@ -612,10 +549,6 @@ em_attach(device_t dev) adapter->hw.mac.autoneg = DO_AUTO_NEG; adapter->hw.phy.autoneg_wait_to_complete = FALSE; adapter->hw.phy.autoneg_advertised = AUTONEG_ADV_DEFAULT; - adapter->rx_buffer_len = 2048; - - e1000_init_script_state_82541(&adapter->hw, TRUE); - e1000_set_tbi_compatibility_82543(&adapter->hw, TRUE); /* Copper options */ if (adapter->hw.phy.media_type == e1000_media_type_copper) { @@ -637,29 +570,13 @@ em_attach(device_t dev) */ adapter->hw.mac.report_tx_early = 1; - tsize = roundup2(adapter->num_tx_desc * sizeof(struct e1000_tx_desc), - EM_DBA_ALIGN); - - /* Allocate Transmit Descriptor ring */ - if (em_dma_malloc(adapter, tsize, &adapter->txdma, BUS_DMA_NOWAIT)) { - device_printf(dev, "Unable to allocate tx_desc memory\n"); + /* + ** Get queue/ring memory + */ + if (em_allocate_queues(adapter)) { error = ENOMEM; - goto err_tx_desc; + goto err_pci; } - adapter->tx_desc_base = - (struct e1000_tx_desc *)adapter->txdma.dma_vaddr; - - rsize = roundup2(adapter->num_rx_desc * sizeof(struct e1000_rx_desc), - EM_DBA_ALIGN); - - /* Allocate Receive Descriptor ring */ - if (em_dma_malloc(adapter, rsize, &adapter->rxdma, BUS_DMA_NOWAIT)) { - device_printf(dev, "Unable to allocate rx_desc memory\n"); - error = ENOMEM; - goto err_rx_desc; - } - adapter->rx_desc_base = - (struct e1000_rx_desc *)adapter->rxdma.dma_vaddr; /* ** Start from a known state, this is @@ -679,7 +596,7 @@ em_attach(device_t dev) device_printf(dev, "The EEPROM Checksum Is Not Valid\n"); error = EIO; - goto err_hw_init; + goto err_late; } } @@ -688,49 +605,35 @@ em_attach(device_t dev) device_printf(dev, "EEPROM read error while reading MAC" " address\n"); error = EIO; - goto err_hw_init; + goto err_late; } if (!em_is_valid_ether_addr(adapter->hw.mac.addr)) { device_printf(dev, "Invalid MAC address\n"); error = EIO; - goto err_hw_init; - } - - /* Initialize the hardware */ - if (em_hardware_init(adapter)) { - device_printf(dev, "Unable to initialize the hardware\n"); - error = EIO; - goto err_hw_init; - } - - /* Allocate transmit descriptors and buffers */ - if (em_allocate_transmit_structures(adapter)) { - device_printf(dev, "Could not setup transmit structures\n"); - error = ENOMEM; - goto err_tx_struct; - } - - /* Allocate receive descriptors and buffers */ - if (em_allocate_receive_structures(adapter)) { - device_printf(dev, "Could not setup receive structures\n"); - error = ENOMEM; - goto err_rx_struct; + goto err_late; } /* ** Do interrupt configuration */ - if (adapter->msi > 1) /* Do MSI/X */ + if (adapter->msix > 1) /* Do MSIX */ error = em_allocate_msix(adapter); else /* MSI or Legacy */ error = em_allocate_legacy(adapter); if (error) - goto err_rx_struct; + goto err_late; + + /* + * Get Wake-on-Lan and Management info for later use + */ + em_get_wakeup(dev); /* Setup OS specific network interface */ em_setup_interface(dev, adapter); + em_reset(adapter); + /* Initialize statistics */ em_update_stats_counters(adapter); @@ -742,104 +645,32 @@ 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) - adapter->pcix_82544 = TRUE; - else - adapter->pcix_82544 = FALSE; - -#if __FreeBSD_version >= 700029 /* Register for VLAN events */ adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, em_register_vlan, adapter, EVENTHANDLER_PRI_FIRST); adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 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); + adapter->led_dev = led_create(em_led_func, adapter, + device_get_nameunit(dev)); + INIT_DEBUGOUT("em_attach: end"); return (0); -err_rx_struct: +err_late: em_free_transmit_structures(adapter); -err_tx_struct: -err_hw_init: + em_free_receive_structures(adapter); em_release_hw_control(adapter); - em_dma_free(adapter, &adapter->rxdma); -err_rx_desc: - em_dma_free(adapter, &adapter->txdma); -err_tx_desc: err_pci: em_free_pci_resources(adapter); - EM_TX_LOCK_DESTROY(adapter); - EM_RX_LOCK_DESTROY(adapter); EM_CORE_LOCK_DESTROY(adapter); return (error); @@ -864,11 +695,7 @@ em_detach(device_t dev) INIT_DEBUGOUT("em_detach: begin"); /* Make sure VLANS are not using driver */ -#if __FreeBSD_version >= 700000 if (adapter->ifp->if_vlantrunk != NULL) { -#else - if (adapter->ifp->if_nvlans != 0) { -#endif device_printf(dev,"Vlan in use, detach first\n"); return (EBUSY); } @@ -879,41 +706,24 @@ em_detach(device_t dev) #endif EM_CORE_LOCK(adapter); - EM_TX_LOCK(adapter); adapter->in_detach = 1; em_stop(adapter); + EM_CORE_UNLOCK(adapter); + EM_CORE_LOCK_DESTROY(adapter); + e1000_phy_hw_reset(&adapter->hw); em_release_manageability(adapter); + em_release_hw_control(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); - -#if __FreeBSD_version >= 700029 /* Unregister VLAN events */ if (adapter->vlan_attach != NULL) EVENTHANDLER_DEREGISTER(vlan_config, adapter->vlan_attach); if (adapter->vlan_detach != NULL) EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach); -#endif ether_ifdetach(adapter->ifp); callout_drain(&adapter->timer); - callout_drain(&adapter->tx_fifo_timer); em_free_pci_resources(adapter); bus_generic_detach(dev); @@ -922,21 +732,7 @@ em_detach(device_t dev) em_free_transmit_structures(adapter); em_free_receive_structures(adapter); - /* Free Transmit Descriptor ring */ - if (adapter->tx_desc_base) { - em_dma_free(adapter, &adapter->txdma); - adapter->tx_desc_base = NULL; - } - - /* Free Receive Descriptor ring */ - if (adapter->rx_desc_base) { - em_dma_free(adapter, &adapter->rxdma); - adapter->rx_desc_base = NULL; - } - - EM_TX_LOCK_DESTROY(adapter); - EM_RX_LOCK_DESTROY(adapter); - EM_CORE_LOCK_DESTROY(adapter); + em_release_hw_control(adapter); return (0); } @@ -963,25 +759,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); @@ -994,6 +774,9 @@ em_resume(device_t dev) struct adapter *adapter = device_get_softc(dev); struct ifnet *ifp = adapter->ifp; + if (adapter->led_dev != NULL) + led_destroy(adapter->led_dev); + EM_CORE_LOCK(adapter); em_init_locked(adapter); em_init_manageability(adapter); @@ -1016,69 +799,45 @@ em_resume(device_t dev) #if __FreeBSD_version >= 800000 static int -em_mq_start_locked(struct ifnet *ifp, struct mbuf *m) +em_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr, struct mbuf *m) { - struct adapter *adapter = ifp->if_softc; - struct mbuf *next; - int error = E1000_SUCCESS; + struct adapter *adapter = txr->adapter; + struct mbuf *next; + int err = 0, enq = 0; - EM_TX_LOCK_ASSERT(adapter); - /* To allow being called from a tasklet */ + if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != + IFF_DRV_RUNNING || adapter->link_active == 0) { + if (m != NULL) + err = drbr_enqueue(ifp, txr->br, m); + return (err); + } + + enq = 0; if (m == NULL) - goto process; + next = drbr_dequeue(ifp, txr->br); + else + next = m; - if (((ifp->if_drv_flags & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) != - IFF_DRV_RUNNING) - || (!adapter->link_active)) { - error = drbr_enqueue(ifp, adapter->br, m); - return (error); - } else if (!drbr_needs_enqueue(ifp, adapter->br) && - (adapter->num_tx_desc_avail > EM_TX_OP_THRESHOLD)) { - if ((error = em_xmit(adapter, &m)) != 0) { - if (m != NULL) - error = drbr_enqueue(ifp, adapter->br, m); - return (error); - } else { - /* - * We've bypassed the buf ring so we need to update - * ifp directly - */ - drbr_stats_update(ifp, m->m_pkthdr.len, m->m_flags); - /* - ** Send a copy of the frame to the BPF - ** listener and set the watchdog on. - */ - ETHER_BPF_MTAP(ifp, m); - adapter->watchdog_timer = EM_TX_TIMEOUT; - } - } else if ((error = drbr_enqueue(ifp, adapter->br, m)) != 0) - return (error); - -process: - if (drbr_empty(ifp, adapter->br)) - return(error); - /* Process the queue */ - while (TRUE) { - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) - break; - next = drbr_dequeue(ifp, adapter->br); - if (next == NULL) - break; - if ((error = em_xmit(adapter, &next)) != 0) { - if (next != NULL) - error = drbr_enqueue(ifp, adapter->br, next); + /* Process the queue */ + while (next != NULL) { + if ((err = em_xmit(txr, &next)) != 0) { + if (next != NULL) + err = drbr_enqueue(ifp, txr->br, next); break; } + enq++; drbr_stats_update(ifp, next->m_pkthdr.len, next->m_flags); - ETHER_BPF_MTAP(ifp, next); + ETHER_BPF_MTAP(ifp, next); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + break; + next = drbr_dequeue(ifp, txr->br); + } + + if (enq > 0) { /* Set the watchdog */ - adapter->watchdog_timer = EM_TX_TIMEOUT; - } - - if (adapter->num_tx_desc_avail <= EM_TX_OP_THRESHOLD) - ifp->if_drv_flags |= IFF_DRV_OACTIVE; - - return (error); + txr->watchdog_check = TRUE; + } + return (err); } /* @@ -1088,45 +847,61 @@ em_mq_start_locked(struct ifnet *ifp, struct mbuf *m) static int em_mq_start(struct ifnet *ifp, struct mbuf *m) { - - struct adapter *adapter = ifp->if_softc; - int error = 0; + struct adapter *adapter = ifp->if_softc; + struct tx_ring *txr; + int i, error = 0; - if (EM_TX_TRYLOCK(adapter)) { + /* Which queue to use */ + if ((m->m_flags & M_FLOWID) != 0) + i = m->m_pkthdr.flowid % adapter->num_queues; + else + i = curcpu % adapter->num_queues; + + txr = &adapter->tx_rings[i]; + + if (EM_TX_TRYLOCK(txr)) { if (ifp->if_drv_flags & IFF_DRV_RUNNING) - error = em_mq_start_locked(ifp, m); - EM_TX_UNLOCK(adapter); + error = em_mq_start_locked(ifp, txr, m); + EM_TX_UNLOCK(txr); } else - error = drbr_enqueue(ifp, adapter->br, m); + error = drbr_enqueue(ifp, txr->br, m); return (error); } +/* +** Flush all ring buffers +*/ static void em_qflush(struct ifnet *ifp) { - struct mbuf *m; - struct adapter *adapter = (struct adapter *)ifp->if_softc; + struct adapter *adapter = ifp->if_softc; + struct tx_ring *txr = adapter->tx_rings; + struct mbuf *m; - EM_TX_LOCK(adapter); - while ((m = buf_ring_dequeue_sc(adapter->br)) != NULL) - m_freem(m); + for (int i = 0; i < adapter->num_queues; i++, txr++) { + EM_TX_LOCK(txr); + while ((m = buf_ring_dequeue_sc(txr->br)) != NULL) + m_freem(m); + EM_TX_UNLOCK(txr); + } if_qflush(ifp); - EM_TX_UNLOCK(adapter); } + #endif /* FreeBSD_version */ static void -em_start_locked(struct ifnet *ifp) +em_start_locked(struct ifnet *ifp, struct tx_ring *txr) { struct adapter *adapter = ifp->if_softc; struct mbuf *m_head; - EM_TX_LOCK_ASSERT(adapter); + EM_TX_LOCK_ASSERT(txr); if ((ifp->if_drv_flags & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING) return; + if (!adapter->link_active) return; @@ -1139,7 +914,7 @@ em_start_locked(struct ifnet *ifp) * Encapsulation can modify our pointer, and or make it * NULL on failure. In that event, we can't requeue. */ - if (em_xmit(adapter, &m_head)) { + if (em_xmit(txr, &m_head)) { if (m_head == NULL) break; ifp->if_drv_flags |= IFF_DRV_OACTIVE; @@ -1151,10 +926,8 @@ 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; + txr->watchdog_check = TRUE; } - if (adapter->num_tx_desc_avail <= EM_TX_OP_THRESHOLD) - ifp->if_drv_flags |= IFF_DRV_OACTIVE; return; } @@ -1162,12 +935,15 @@ em_start_locked(struct ifnet *ifp) static void em_start(struct ifnet *ifp) { - struct adapter *adapter = ifp->if_softc; + struct adapter *adapter = ifp->if_softc; + struct tx_ring *txr = adapter->tx_rings; - EM_TX_LOCK(adapter); - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - em_start_locked(ifp); - EM_TX_UNLOCK(adapter); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + EM_TX_LOCK(txr); + em_start_locked(ifp, txr); + EM_TX_UNLOCK(txr); + } + return; } /********************************************************************* @@ -1209,8 +985,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); @@ -1218,34 +993,23 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data) case SIOCSIFMTU: { int max_frame_size; - u16 eeprom_data = 0; IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFMTU (Set Interface MTU)"); EM_CORE_LOCK(adapter); switch (adapter->hw.mac.type) { - case e1000_82573: - /* - * 82573 only supports jumbo frames - * if ASPM is disabled. - */ - e1000_read_nvm(&adapter->hw, - NVM_INIT_3GIO_3, 1, &eeprom_data); - if (eeprom_data & NVM_WORD1A_ASPM_MASK) { - max_frame_size = ETHER_MAX_LEN; - break; - } - /* Allow Jumbo frames - fall thru */ case e1000_82571: case e1000_82572: case e1000_ich9lan: case e1000_ich10lan: case e1000_82574: - case e1000_80003es2lan: /* Limit Jumbo Frame size */ + case e1000_80003es2lan: /* 9K 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: case e1000_ich8lan: max_frame_size = ETHER_MAX_LEN; @@ -1281,11 +1045,8 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data) } else em_init_locked(adapter); } else - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - EM_TX_LOCK(adapter); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) em_stop(adapter); - EM_TX_UNLOCK(adapter); - } adapter->if_flags = ifp->if_flags; EM_CORE_UNLOCK(adapter); break; @@ -1296,10 +1057,6 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data) EM_CORE_LOCK(adapter); em_disable_intr(adapter); em_set_multi(adapter); - if (adapter->hw.mac.type == e1000_82542 && - adapter->hw.revision_id == E1000_REVISION_2) { - em_initialize_receive_unit(adapter); - } #ifdef DEVICE_POLLING if (!(ifp->if_capenable & IFCAP_POLLING)) #endif @@ -1353,22 +1110,24 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data) ifp->if_capenable ^= IFCAP_HWCSUM; reinit = 1; } -#if __FreeBSD_version >= 700000 if (mask & IFCAP_TSO4) { ifp->if_capenable ^= IFCAP_TSO4; 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 VLAN_CAPABILITIES(ifp); -#endif break; } @@ -1380,53 +1139,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 @@ -1450,33 +1162,15 @@ em_init_locked(struct adapter *adapter) EM_CORE_LOCK_ASSERT(adapter); - EM_TX_LOCK(adapter); - em_stop(adapter); - EM_TX_UNLOCK(adapter); + em_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. - * - * Devices before the 82547 had a Packet Buffer of 64K. - * Default allocation: PBA=48K for Rx, leaving 16K for Tx. - * After the 82547 the buffer was reduced to 40K. - * Default allocation: PBA=30K for Rx, leaving 10K for Tx. - * Note: default does not leave enough room for Jumbo Frame >10k. */ switch (adapter->hw.mac.type) { - case e1000_82547: - case e1000_82547_rev_2: /* 82547: Total Packet Buffer is 40K */ - if (adapter->max_frame_size > 8192) - pba = E1000_PBA_22K; /* 22K for Rx, 18K for Tx */ - else - pba = E1000_PBA_30K; /* 30K for Rx, 10K for Tx */ - adapter->tx_fifo_head = 0; - adapter->tx_head_addr = pba << EM_TX_HEAD_ADDR_SHIFT; - adapter->tx_fifo_size = - (E1000_PBA_40K - pba) << EM_PBA_BYTES_SHIFT; - break; /* Total Packet Buffer on these is 48K */ case e1000_82571: case e1000_82572: @@ -1492,11 +1186,13 @@ 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; default: - /* Devices before 82547 had a Packet Buffer of 64K. */ if (adapter->max_frame_size > 8192) pba = E1000_PBA_40K; /* 40K for Rx, 24K for Tx */ else @@ -1526,37 +1222,21 @@ em_init_locked(struct adapter *adapter) } /* Initialize the hardware */ - if (em_hardware_init(adapter)) { - device_printf(dev, "Unable to initialize the hardware\n"); - return; - } + em_reset(adapter); em_update_link_status(adapter); /* Setup VLAN support, basic and offload if available */ E1000_WRITE_REG(&adapter->hw, E1000_VET, ETHERTYPE_VLAN); -#if __FreeBSD_version < 700029 - if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) { - u32 ctrl; - ctrl = E1000_READ_REG(&adapter->hw, E1000_CTRL); - ctrl |= E1000_CTRL_VME; - E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl); - } -#else /* Use real VLAN Filter support */ em_setup_vlan_hw_support(adapter); -#endif /* Set hardware offload abilities */ ifp->if_hwassist = 0; - if (adapter->hw.mac.type >= e1000_82543) { - if (ifp->if_capenable & IFCAP_TXCSUM) - ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); -#if __FreeBSD_version >= 700000 - if (ifp->if_capenable & IFCAP_TSO4) - ifp->if_hwassist |= CSUM_TSO; -#endif - } + if (ifp->if_capenable & IFCAP_TXCSUM) + ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); + if (ifp->if_capenable & IFCAP_TSO4) + ifp->if_hwassist |= CSUM_TSO; /* Configure for OS presence */ em_init_manageability(adapter); @@ -1571,9 +1251,7 @@ em_init_locked(struct adapter *adapter) /* Prepare receive descriptors and buffers */ if (em_setup_receive_structures(adapter)) { device_printf(dev, "Could not setup receive structures\n"); - EM_TX_LOCK(adapter); em_stop(adapter); - EM_TX_UNLOCK(adapter); return; } em_initialize_receive_unit(adapter); @@ -1593,14 +1271,8 @@ em_init_locked(struct adapter *adapter) tmp = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT); tmp |= E1000_CTRL_EXT_PBA_CLR; E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT, tmp); - /* - ** Set the IVAR - interrupt vector routing. - ** Each nibble represents a vector, high bit - ** is enable, other 3 bits are the MSIX table - ** entry, we map RXQ0 to 0, TXQ0 to 1, and - ** Link (other) to 2, hence the magic number. - */ - E1000_WRITE_REG(&adapter->hw, E1000_IVAR, 0x800A0908); + /* Set the IVAR - interrupt vector routing. */ + E1000_WRITE_REG(&adapter->hw, E1000_IVAR, adapter->ivars); } #ifdef DEVICE_POLLING @@ -1614,6 +1286,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; } @@ -1632,13 +1308,15 @@ em_init(void *arg) #ifdef DEVICE_POLLING /********************************************************************* * - * Legacy polling routine + * Legacy polling routine: note this only works with single queue * *********************************************************************/ static int em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) { struct adapter *adapter = ifp->if_softc; + struct tx_ring *txr = adapter->tx_rings; + struct rx_ring *rxr = adapter->rx_rings; u32 reg_icr, rx_done = 0; EM_CORE_LOCK(adapter); @@ -1659,137 +1337,30 @@ em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) } EM_CORE_UNLOCK(adapter); - rx_done = em_rxeof(adapter, count); + rx_done = em_rxeof(rxr, count); - EM_TX_LOCK(adapter); - em_txeof(adapter); + EM_TX_LOCK(txr); + em_txeof(txr); #if __FreeBSD_version >= 800000 - if (!drbr_empty(ifp, adapter->br)) - em_mq_start_locked(ifp, NULL); + if (!drbr_empty(ifp, txr->br)) + em_mq_start_locked(ifp, txr, NULL); #else - if (!IFQ_DRV_IS_EMPTY(&ifp->snd)) - em_start_locked(ifp); + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + em_start_locked(ifp, txr); #endif - EM_TX_UNLOCK(adapter); + EM_TX_UNLOCK(txr); + return (rx_done); } #endif /* DEVICE_POLLING */ -#ifdef EM_LEGACY_IRQ -/********************************************************************* - * - * Legacy Interrupt Service routine - * - *********************************************************************/ - -static void -em_intr(void *arg) -{ - struct adapter *adapter = arg; - struct ifnet *ifp = adapter->ifp; - u32 reg_icr; - - - if (ifp->if_capenable & IFCAP_POLLING) - return; - - EM_CORE_LOCK(adapter); - reg_icr = E1000_READ_REG(&adapter->hw, E1000_ICR); - if (reg_icr & E1000_ICR_RXO) - adapter->rx_overruns++; - if ((reg_icr == 0xffffffff) || (reg_icr == 0)|| - (adapter->hw.mac.type >= e1000_82571 && - (reg_icr & E1000_ICR_INT_ASSERTED) == 0)) - goto out; - - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) - goto out; - - if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { - callout_stop(&adapter->timer); - adapter->hw.mac.get_link_status = 1; - em_update_link_status(adapter); - /* Deal with TX cruft when link lost */ - em_tx_purge(adapter); - callout_reset(&adapter->timer, hz, - em_local_timer, adapter); - goto out; - } - - EM_TX_LOCK(adapter); - em_txeof(adapter); - em_rxeof(adapter, -1); - em_txeof(adapter); - if (ifp->if_drv_flags & IFF_DRV_RUNNING && - !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - em_start_locked(ifp); - EM_TX_UNLOCK(adapter); - -out: - EM_CORE_UNLOCK(adapter); - return; -} - -#else /* EM_FAST_IRQ, then fast interrupt routines only */ - -static void -em_handle_link(void *context, int pending) -{ - struct adapter *adapter = context; - struct ifnet *ifp = adapter->ifp; - - if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) - return; - - EM_CORE_LOCK(adapter); - callout_stop(&adapter->timer); - em_update_link_status(adapter); - /* Deal with TX cruft when link lost */ - em_tx_purge(adapter); - callout_reset(&adapter->timer, hz, em_local_timer, adapter); - EM_CORE_UNLOCK(adapter); -} - - -/* Combined RX/TX handler, used by Legacy and MSI */ -static void -em_handle_rxtx(void *context, int pending) -{ - struct adapter *adapter = context; - struct ifnet *ifp = adapter->ifp; - - - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - if (em_rxeof(adapter, adapter->rx_process_limit) != 0) - taskqueue_enqueue(adapter->tq, &adapter->rxtx_task); - EM_TX_LOCK(adapter); - em_txeof(adapter); - -#if __FreeBSD_version >= 800000 - if (!drbr_empty(ifp, adapter->br)) - em_mq_start_locked(ifp, NULL); -#else - if (!IFQ_DRV_IS_EMPTY(&ifp->snd)) - em_start_locked(ifp); -#endif - EM_TX_UNLOCK(adapter); - } - - em_enable_intr(adapter); -} /********************************************************************* * * Fast Legacy/MSI Combined Interrupt Service routine * *********************************************************************/ -#if __FreeBSD_version < 700000 -#define FILTER_STRAY -#define FILTER_HANDLED -static void -#else static int -#endif em_irq_fast(void *arg) { struct adapter *adapter = arg; @@ -1816,13 +1387,8 @@ em_irq_fast(void *arg) (reg_icr & E1000_ICR_INT_ASSERTED) == 0) return FILTER_STRAY; - /* - * Mask interrupts until the taskqueue is finished running. This is - * cheap, just assume that it is needed. This also works around the - * MSI message reordering errata on certain systems. - */ em_disable_intr(adapter); - taskqueue_enqueue(adapter->tq, &adapter->rxtx_task); + taskqueue_enqueue(adapter->tq, &adapter->que_task); /* Link status change */ if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { @@ -1835,30 +1401,64 @@ em_irq_fast(void *arg) return FILTER_HANDLED; } +/* Combined RX/TX handler, used by Legacy and MSI */ +static void +em_handle_que(void *context, int pending) +{ + struct adapter *adapter = context; + struct ifnet *ifp = adapter->ifp; + struct tx_ring *txr = adapter->tx_rings; + struct rx_ring *rxr = adapter->rx_rings; + u32 loop = EM_MAX_LOOP; + bool more_rx, more_tx; + + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + EM_TX_LOCK(txr); + do { + more_rx = em_rxeof(rxr, adapter->rx_process_limit); + more_tx = em_txeof(txr); + } while (loop-- && (more_rx || more_tx)); + +#if __FreeBSD_version >= 800000 + if (!drbr_empty(ifp, txr->br)) + em_mq_start_locked(ifp, txr, NULL); +#else + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + em_start_locked(ifp, txr); +#endif + if (more_rx || more_tx) + taskqueue_enqueue(adapter->tq, &adapter->que_task); + + EM_TX_UNLOCK(txr); + } + + em_enable_intr(adapter); + return; +} + + /********************************************************************* * * MSIX Interrupt Service Routines * **********************************************************************/ -#define EM_MSIX_TX 0x00040000 -#define EM_MSIX_RX 0x00010000 -#define EM_MSIX_LINK 0x00100000 - static void em_msix_tx(void *arg) { - struct adapter *adapter = arg; - struct ifnet *ifp = adapter->ifp; + struct tx_ring *txr = arg; + struct adapter *adapter = txr->adapter; + bool more; - ++adapter->tx_irq; - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - EM_TX_LOCK(adapter); - em_txeof(adapter); - EM_TX_UNLOCK(adapter); - taskqueue_enqueue(adapter->tq, &adapter->tx_task); - } - /* Reenable this interrupt */ - E1000_WRITE_REG(&adapter->hw, E1000_IMS, EM_MSIX_TX); + ++txr->tx_irq; + EM_TX_LOCK(txr); + more = em_txeof(txr); + EM_TX_UNLOCK(txr); + if (more) + taskqueue_enqueue(txr->tq, &txr->tx_task); + else + /* Reenable this interrupt */ + E1000_WRITE_REG(&adapter->hw, E1000_IMS, txr->ims); return; } @@ -1871,15 +1471,17 @@ em_msix_tx(void *arg) static void em_msix_rx(void *arg) { - struct adapter *adapter = arg; - struct ifnet *ifp = adapter->ifp; + struct rx_ring *rxr = arg; + struct adapter *adapter = rxr->adapter; + bool more; - ++adapter->rx_irq; - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && - (em_rxeof(adapter, adapter->rx_process_limit) != 0)) - taskqueue_enqueue(adapter->tq, &adapter->rx_task); - /* Reenable this interrupt */ - E1000_WRITE_REG(&adapter->hw, E1000_IMS, EM_MSIX_RX); + ++rxr->rx_irq; + more = em_rxeof(rxr, adapter->rx_process_limit); + if (more) + taskqueue_enqueue(rxr->tq, &rxr->rx_task); + else + /* Reenable this interrupt */ + E1000_WRITE_REG(&adapter->hw, E1000_IMS, rxr->ims); return; } @@ -1888,7 +1490,6 @@ em_msix_rx(void *arg) * MSIX Link Fast Interrupt Service routine * **********************************************************************/ - static void em_msix_link(void *arg) { @@ -1901,45 +1502,71 @@ em_msix_link(void *arg) if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { adapter->hw.mac.get_link_status = 1; taskqueue_enqueue(taskqueue_fast, &adapter->link_task); - } - E1000_WRITE_REG(&adapter->hw, E1000_IMS, - EM_MSIX_LINK | E1000_IMS_LSC); + } else + E1000_WRITE_REG(&adapter->hw, E1000_IMS, + EM_MSIX_LINK | E1000_IMS_LSC); return; } static void em_handle_rx(void *context, int pending) { - struct adapter *adapter = context; - struct ifnet *ifp = adapter->ifp; - - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && - (em_rxeof(adapter, adapter->rx_process_limit) != 0)) - taskqueue_enqueue(adapter->tq, &adapter->rx_task); + struct rx_ring *rxr = context; + struct adapter *adapter = rxr->adapter; + u32 loop = EM_MAX_LOOP; + bool more; + do { + more = em_rxeof(rxr, adapter->rx_process_limit); + } while (loop-- && more); + /* Reenable this interrupt */ + E1000_WRITE_REG(&adapter->hw, E1000_IMS, rxr->ims); } static void em_handle_tx(void *context, int pending) { - struct adapter *adapter = context; + struct tx_ring *txr = context; + struct adapter *adapter = txr->adapter; struct ifnet *ifp = adapter->ifp; + u32 loop = EM_MAX_LOOP; + bool more; + + if (!EM_TX_TRYLOCK(txr)) + return; + do { + more = em_txeof(txr); + } while (loop-- && more); - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - if (!EM_TX_TRYLOCK(adapter)) - return; - em_txeof(adapter); #if __FreeBSD_version >= 800000 - if (!drbr_empty(ifp, adapter->br)) - em_mq_start_locked(ifp, NULL); + if (!drbr_empty(ifp, txr->br)) + em_mq_start_locked(ifp, txr, NULL); #else - if (!IFQ_DRV_IS_EMPTY(&ifp->snd)) - em_start_locked(ifp); + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + em_start_locked(ifp, txr); #endif - EM_TX_UNLOCK(adapter); - } + E1000_WRITE_REG(&adapter->hw, E1000_IMS, txr->ims); + EM_TX_UNLOCK(txr); } -#endif /* EM_FAST_IRQ */ + +static void +em_handle_link(void *context, int pending) +{ + struct adapter *adapter = context; + struct ifnet *ifp = adapter->ifp; + + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) + return; + + EM_CORE_LOCK(adapter); + callout_stop(&adapter->timer); + em_update_link_status(adapter); + callout_reset(&adapter->timer, hz, em_local_timer, adapter); + E1000_WRITE_REG(&adapter->hw, E1000_IMS, + EM_MSIX_LINK | E1000_IMS_LSC); + EM_CORE_UNLOCK(adapter); +} + /********************************************************************* * @@ -1972,8 +1599,6 @@ em_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) if ((adapter->hw.phy.media_type == e1000_media_type_fiber) || (adapter->hw.phy.media_type == e1000_media_type_internal_serdes)) { - if (adapter->hw.mac.type == e1000_82545) - fiber_type = IFM_1000_LX; ifmr->ifm_active |= fiber_type | IFM_FDX; } else { switch (adapter->link_speed) { @@ -2065,8 +1690,9 @@ em_media_change(struct ifnet *ifp) **********************************************************************/ static int -em_xmit(struct adapter *adapter, struct mbuf **m_headp) +em_xmit(struct tx_ring *txr, struct mbuf **m_headp) { + struct adapter *adapter = txr->adapter; bus_dma_segment_t segs[EM_MAX_SCATTER]; bus_dmamap_t map; struct em_buffer *tx_buffer, *tx_buffer_mapped; @@ -2075,31 +1701,17 @@ em_xmit(struct adapter *adapter, struct mbuf **m_headp) u32 txd_upper, txd_lower, txd_used, txd_saved; int nsegs, i, j, first, last = 0; int error, do_tso, tso_desc = 0; -#if __FreeBSD_version < 700000 - struct m_tag *mtag; -#endif + m_head = *m_headp; txd_upper = txd_lower = txd_used = txd_saved = 0; - -#if __FreeBSD_version >= 700000 do_tso = ((m_head->m_pkthdr.csum_flags & CSUM_TSO) != 0); -#else - do_tso = 0; -#endif /* * Force a cleanup if number of TX descriptors * available hits the threshold */ - if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) { - em_txeof(adapter); - /* Now do we at least have a minimal? */ - if (adapter->num_tx_desc_avail <= EM_TX_OP_THRESHOLD) { - adapter->no_tx_desc_avail1++; - return (ENOBUFS); - } - } - + if (txr->tx_avail <= EM_TX_CLEANUP_THRESHOLD) + em_txeof(txr); /* * TSO workaround: @@ -2121,12 +1733,12 @@ em_xmit(struct adapter *adapter, struct mbuf **m_headp) * of the EOP which is the only one that * now gets a DONE bit writeback. */ - first = adapter->next_avail_tx_desc; - tx_buffer = &adapter->tx_buffer_area[first]; + first = txr->next_avail_desc; + tx_buffer = &txr->tx_buffers[first]; tx_buffer_mapped = tx_buffer; map = tx_buffer->map; - error = bus_dmamap_load_mbuf_sg(adapter->txtag, map, + error = bus_dmamap_load_mbuf_sg(txr->txtag, map, *m_headp, segs, &nsegs, BUS_DMA_NOWAIT); /* @@ -2151,7 +1763,7 @@ em_xmit(struct adapter *adapter, struct mbuf **m_headp) *m_headp = m; /* Try it again */ - error = bus_dmamap_load_mbuf_sg(adapter->txtag, map, + error = bus_dmamap_load_mbuf_sg(txr->txtag, map, *m_headp, segs, &nsegs, BUS_DMA_NOWAIT); if (error) { @@ -2171,15 +1783,15 @@ em_xmit(struct adapter *adapter, struct mbuf **m_headp) * it follows a TSO burst, then we need to add a * sentinel descriptor to prevent premature writeback. */ - if ((do_tso == 0) && (adapter->tx_tso == TRUE)) { + if ((do_tso == 0) && (txr->tx_tso == TRUE)) { if (nsegs == 1) tso_desc = TRUE; - adapter->tx_tso = FALSE; + txr->tx_tso = FALSE; } - if (nsegs > (adapter->num_tx_desc_avail - 2)) { - adapter->no_tx_desc_avail2++; - bus_dmamap_unload(adapter->txtag, map); + if (nsegs > (txr->tx_avail - 2)) { + txr->no_desc_avail++; + bus_dmamap_unload(txr->txtag, map); return (ENOBUFS); } m_head = *m_headp; @@ -2187,7 +1799,7 @@ em_xmit(struct adapter *adapter, struct mbuf **m_headp) /* Do hardware assists */ #if __FreeBSD_version >= 700000 if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { - error = em_tso_setup(adapter, m_head, &txd_upper, &txd_lower); + error = em_tso_setup(txr, m_head, &txd_upper, &txd_lower); if (error != TRUE) return (ENXIO); /* something foobar */ /* we need to make a final sentinel transmit desc */ @@ -2195,123 +1807,70 @@ em_xmit(struct adapter *adapter, struct mbuf **m_headp) } else #endif if (m_head->m_pkthdr.csum_flags & CSUM_OFFLOAD) - em_transmit_checksum_setup(adapter, m_head, + em_transmit_checksum_setup(txr, m_head, &txd_upper, &txd_lower); - i = adapter->next_avail_tx_desc; - if (adapter->pcix_82544) - txd_saved = i; + i = txr->next_avail_desc; /* Set up our transmit descriptors */ for (j = 0; j < nsegs; j++) { bus_size_t seg_len; bus_addr_t seg_addr; - /* If adapter is 82544 and on PCIX bus */ - if(adapter->pcix_82544) { - DESC_ARRAY desc_array; - u32 array_elements, counter; - /* - * Check the Address and Length combination and - * split the data accordingly - */ - array_elements = em_fill_descriptors(segs[j].ds_addr, - segs[j].ds_len, &desc_array); - for (counter = 0; counter < array_elements; counter++) { - if (txd_used == adapter->num_tx_desc_avail) { - adapter->next_avail_tx_desc = txd_saved; - adapter->no_tx_desc_avail2++; - bus_dmamap_unload(adapter->txtag, map); - return (ENOBUFS); - } - tx_buffer = &adapter->tx_buffer_area[i]; - ctxd = &adapter->tx_desc_base[i]; - ctxd->buffer_addr = htole64( - desc_array.descriptor[counter].address); - ctxd->lower.data = htole32( - (adapter->txd_cmd | txd_lower | (u16) - desc_array.descriptor[counter].length)); - ctxd->upper.data = - htole32((txd_upper)); - last = i; - if (++i == adapter->num_tx_desc) - i = 0; - tx_buffer->m_head = NULL; - tx_buffer->next_eop = -1; - txd_used++; - } + + tx_buffer = &txr->tx_buffers[i]; + ctxd = &txr->tx_base[i]; + seg_addr = segs[j].ds_addr; + seg_len = segs[j].ds_len; + /* + ** TSO Workaround: + ** If this is the last descriptor, we want to + ** split it so we have a small final sentinel + */ + if (tso_desc && (j == (nsegs -1)) && (seg_len > 8)) { + seg_len -= 4; + ctxd->buffer_addr = htole64(seg_addr); + ctxd->lower.data = htole32( + adapter->txd_cmd | txd_lower | seg_len); + ctxd->upper.data = + htole32(txd_upper); + if (++i == adapter->num_tx_desc) + i = 0; + /* Now make the sentinel */ + ++txd_used; /* using an extra txd */ + ctxd = &txr->tx_base[i]; + tx_buffer = &txr->tx_buffers[i]; + ctxd->buffer_addr = + htole64(seg_addr + seg_len); + ctxd->lower.data = htole32( + adapter->txd_cmd | txd_lower | 4); + ctxd->upper.data = + htole32(txd_upper); + last = i; + if (++i == adapter->num_tx_desc) + i = 0; } else { - tx_buffer = &adapter->tx_buffer_area[i]; - ctxd = &adapter->tx_desc_base[i]; - seg_addr = segs[j].ds_addr; - seg_len = segs[j].ds_len; - /* - ** TSO Workaround: - ** If this is the last descriptor, we want to - ** split it so we have a small final sentinel - */ - if (tso_desc && (j == (nsegs -1)) && (seg_len > 8)) { - seg_len -= 4; - ctxd->buffer_addr = htole64(seg_addr); - ctxd->lower.data = htole32( - adapter->txd_cmd | txd_lower | seg_len); - ctxd->upper.data = - htole32(txd_upper); - if (++i == adapter->num_tx_desc) - i = 0; - /* Now make the sentinel */ - ++txd_used; /* using an extra txd */ - ctxd = &adapter->tx_desc_base[i]; - tx_buffer = &adapter->tx_buffer_area[i]; - ctxd->buffer_addr = - htole64(seg_addr + seg_len); - ctxd->lower.data = htole32( - adapter->txd_cmd | txd_lower | 4); - ctxd->upper.data = - htole32(txd_upper); - last = i; - if (++i == adapter->num_tx_desc) - i = 0; - } else { - ctxd->buffer_addr = htole64(seg_addr); - ctxd->lower.data = htole32( - adapter->txd_cmd | txd_lower | seg_len); - ctxd->upper.data = - htole32(txd_upper); - last = i; - if (++i == adapter->num_tx_desc) - i = 0; - } - tx_buffer->m_head = NULL; - tx_buffer->next_eop = -1; + ctxd->buffer_addr = htole64(seg_addr); + ctxd->lower.data = htole32( + adapter->txd_cmd | txd_lower | seg_len); + ctxd->upper.data = + htole32(txd_upper); + last = i; + if (++i == adapter->num_tx_desc) + i = 0; } + tx_buffer->m_head = NULL; + tx_buffer->next_eop = -1; } - adapter->next_avail_tx_desc = i; - if (adapter->pcix_82544) - adapter->num_tx_desc_avail -= txd_used; - else { - adapter->num_tx_desc_avail -= nsegs; - if (tso_desc) /* TSO used an extra for sentinel */ - adapter->num_tx_desc_avail -= txd_used; - } + txr->next_avail_desc = i; + txr->tx_avail -= nsegs; + if (tso_desc) /* TSO used an extra for sentinel */ + txr->tx_avail -= txd_used; - /* - ** Handle VLAN tag, this is the - ** biggest difference between - ** 6.x and 7 - */ -#if __FreeBSD_version < 700000 - /* Find out if we are in vlan mode. */ - mtag = VLAN_OUTPUT_TAG(ifp, m_head); - if (mtag != NULL) { - ctxd->upper.fields.special = - htole16(VLAN_TAG_VALUE(mtag)); -#else /* FreeBSD 7 */ if (m_head->m_flags & M_VLANTAG) { /* Set the vlan id. */ ctxd->upper.fields.special = htole16(m_head->m_pkthdr.ether_vtag); -#endif /* Tell hardware to add tag */ ctxd->lower.data |= htole32(E1000_TXD_CMD_VLE); } @@ -2319,7 +1878,7 @@ em_xmit(struct adapter *adapter, struct mbuf **m_headp) tx_buffer->m_head = m_head; tx_buffer_mapped->map = tx_buffer->map; tx_buffer->map = map; - bus_dmamap_sync(adapter->txtag, map, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(txr->txtag, map, BUS_DMASYNC_PREWRITE); /* * Last Descriptor of Packet @@ -2332,145 +1891,20 @@ em_xmit(struct adapter *adapter, struct mbuf **m_headp) * Keep track in the first buffer which * descriptor will be written back */ - tx_buffer = &adapter->tx_buffer_area[first]; + tx_buffer = &txr->tx_buffers[first]; tx_buffer->next_eop = last; /* * Advance the Transmit Descriptor Tail (TDT), this tells the E1000 * that this frame is available to transmit. */ - bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map, + bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - if (adapter->hw.mac.type == e1000_82547 && - adapter->link_duplex == HALF_DUPLEX) - em_82547_move_tail(adapter); - else { - E1000_WRITE_REG(&adapter->hw, E1000_TDT(0), i); - if (adapter->hw.mac.type == e1000_82547) - em_82547_update_fifo_head(adapter, - m_head->m_pkthdr.len); - } + E1000_WRITE_REG(&adapter->hw, E1000_TDT(txr->me), i); return (0); } -/********************************************************************* - * - * 82547 workaround to avoid controller hang in half-duplex environment. - * The workaround is to avoid queuing a large packet that would span - * the internal Tx FIFO ring boundary. We need to reset the FIFO pointers - * in this case. We do that only when FIFO is quiescent. - * - **********************************************************************/ -static void -em_82547_move_tail(void *arg) -{ - struct adapter *adapter = arg; - struct e1000_tx_desc *tx_desc; - u16 hw_tdt, sw_tdt, length = 0; - bool eop = 0; - - EM_TX_LOCK_ASSERT(adapter); - - hw_tdt = E1000_READ_REG(&adapter->hw, E1000_TDT(0)); - sw_tdt = adapter->next_avail_tx_desc; - - while (hw_tdt != sw_tdt) { - tx_desc = &adapter->tx_desc_base[hw_tdt]; - length += tx_desc->lower.flags.length; - eop = tx_desc->lower.data & E1000_TXD_CMD_EOP; - if (++hw_tdt == adapter->num_tx_desc) - hw_tdt = 0; - - if (eop) { - if (em_82547_fifo_workaround(adapter, length)) { - adapter->tx_fifo_wrk_cnt++; - callout_reset(&adapter->tx_fifo_timer, 1, - em_82547_move_tail, adapter); - break; - } - E1000_WRITE_REG(&adapter->hw, E1000_TDT(0), hw_tdt); - em_82547_update_fifo_head(adapter, length); - length = 0; - } - } -} - -static int -em_82547_fifo_workaround(struct adapter *adapter, int len) -{ - int fifo_space, fifo_pkt_len; - - fifo_pkt_len = roundup2(len + EM_FIFO_HDR, EM_FIFO_HDR); - - if (adapter->link_duplex == HALF_DUPLEX) { - fifo_space = adapter->tx_fifo_size - adapter->tx_fifo_head; - - if (fifo_pkt_len >= (EM_82547_PKT_THRESH + fifo_space)) { - if (em_82547_tx_fifo_reset(adapter)) - return (0); - else - return (1); - } - } - - return (0); -} - -static void -em_82547_update_fifo_head(struct adapter *adapter, int len) -{ - int fifo_pkt_len = roundup2(len + EM_FIFO_HDR, EM_FIFO_HDR); - - /* tx_fifo_head is always 16 byte aligned */ - adapter->tx_fifo_head += fifo_pkt_len; - if (adapter->tx_fifo_head >= adapter->tx_fifo_size) { - adapter->tx_fifo_head -= adapter->tx_fifo_size; - } -} - - -static int -em_82547_tx_fifo_reset(struct adapter *adapter) -{ - u32 tctl; - - if ((E1000_READ_REG(&adapter->hw, E1000_TDT(0)) == - E1000_READ_REG(&adapter->hw, E1000_TDH(0))) && - (E1000_READ_REG(&adapter->hw, E1000_TDFT) == - E1000_READ_REG(&adapter->hw, E1000_TDFH)) && - (E1000_READ_REG(&adapter->hw, E1000_TDFTS) == - E1000_READ_REG(&adapter->hw, E1000_TDFHS)) && - (E1000_READ_REG(&adapter->hw, E1000_TDFPC) == 0)) { - /* Disable TX unit */ - tctl = E1000_READ_REG(&adapter->hw, E1000_TCTL); - E1000_WRITE_REG(&adapter->hw, E1000_TCTL, - tctl & ~E1000_TCTL_EN); - - /* Reset FIFO pointers */ - E1000_WRITE_REG(&adapter->hw, E1000_TDFT, - adapter->tx_head_addr); - E1000_WRITE_REG(&adapter->hw, E1000_TDFH, - adapter->tx_head_addr); - E1000_WRITE_REG(&adapter->hw, E1000_TDFTS, - adapter->tx_head_addr); - E1000_WRITE_REG(&adapter->hw, E1000_TDFHS, - adapter->tx_head_addr); - - /* Re-enable TX unit */ - E1000_WRITE_REG(&adapter->hw, E1000_TCTL, tctl); - E1000_WRITE_FLUSH(&adapter->hw); - - adapter->tx_fifo_head = 0; - adapter->tx_fifo_reset_cnt++; - - return (TRUE); - } - else { - return (FALSE); - } -} - static void em_set_promisc(struct adapter *adapter) { @@ -2541,7 +1975,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 +1991,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; @@ -2587,11 +2028,10 @@ em_local_timer(void *arg) { struct adapter *adapter = arg; struct ifnet *ifp = adapter->ifp; + struct tx_ring *txr = adapter->tx_rings; EM_CORE_LOCK_ASSERT(adapter); - taskqueue_enqueue(adapter->tq, - &adapter->rxtx_task); em_update_link_status(adapter); em_update_stats_counters(adapter); @@ -2602,18 +2042,31 @@ em_local_timer(void *arg) if (em_display_debug_stats && ifp->if_drv_flags & IFF_DRV_RUNNING) em_print_hw_stats(adapter); - em_smartspeed(adapter); - /* - * Each second we check the watchdog to - * protect against hardware hangs. - */ - em_watchdog(adapter); + ** Check for time since any descriptor was cleaned + */ + for (int i = 0; i < adapter->num_queues; i++, txr++) { + EM_TX_LOCK(txr); + if (txr->watchdog_check == FALSE) { + EM_TX_UNLOCK(txr); + continue; + } + if ((ticks - txr->watchdog_time) > EM_WATCHDOG) + goto hung; + EM_TX_UNLOCK(txr); + } callout_reset(&adapter->timer, hz, em_local_timer, adapter); - + return; +hung: + device_printf(adapter->dev, "Watchdog timeout -- resetting\n"); + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + adapter->watchdog_events++; + EM_TX_UNLOCK(txr); + em_init_locked(adapter); } + static void em_update_link_status(struct adapter *adapter) { @@ -2677,7 +2130,8 @@ 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; + // JFV change later + //adapter->watchdog_check = FALSE; if_link_state_change(ifp, LINK_STATE_DOWN); } } @@ -2696,22 +2150,30 @@ em_stop(void *arg) { struct adapter *adapter = arg; struct ifnet *ifp = adapter->ifp; + struct tx_ring *txr = adapter->tx_rings; EM_CORE_LOCK_ASSERT(adapter); - EM_TX_LOCK_ASSERT(adapter); INIT_DEBUGOUT("em_stop: begin"); em_disable_intr(adapter); callout_stop(&adapter->timer); - callout_stop(&adapter->tx_fifo_timer); /* Tell the stack that the interface is no longer active */ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + /* Unarm watchdog timer. */ + for (int i = 0; i < adapter->num_queues; i++, txr++) { + EM_TX_LOCK(txr); + txr->watchdog_check = FALSE; + EM_TX_UNLOCK(txr); + } + e1000_reset_hw(&adapter->hw); - if (adapter->hw.mac.type >= e1000_82544) - E1000_WRITE_REG(&adapter->hw, E1000_WUC, 0); + E1000_WRITE_REG(&adapter->hw, E1000_WUC, 0); + + e1000_led_off(&adapter->hw); + e1000_cleanup_led(&adapter->hw); } @@ -2757,7 +2219,7 @@ static int em_allocate_pci_resources(struct adapter *adapter) { device_t dev = adapter->dev; - int val, rid, error = E1000_SUCCESS; + int rid; rid = PCIR_BAR(0); adapter->memory = bus_alloc_resource_any(dev, SYS_RES_MEMORY, @@ -2772,58 +2234,17 @@ em_allocate_pci_resources(struct adapter *adapter) rman_get_bushandle(adapter->memory); adapter->hw.hw_addr = (u8 *)&adapter->osdep.mem_bus_space_handle; - /* Only older adapters use IO mapping */ - if ((adapter->hw.mac.type > e1000_82543) && - (adapter->hw.mac.type < e1000_82571)) { - /* Figure our where our IO BAR is ? */ - for (rid = PCIR_BAR(0); rid < PCIR_CIS;) { - val = pci_read_config(dev, rid, 4); - if (EM_BAR_TYPE(val) == EM_BAR_TYPE_IO) { - adapter->io_rid = rid; - break; - } - rid += 4; - /* check for 64bit BAR */ - if (EM_BAR_MEM_TYPE(val) == EM_BAR_MEM_TYPE_64BIT) - rid += 4; - } - if (rid >= PCIR_CIS) { - device_printf(dev, "Unable to locate IO BAR\n"); - return (ENXIO); - } - adapter->ioport = bus_alloc_resource_any(dev, - SYS_RES_IOPORT, &adapter->io_rid, RF_ACTIVE); - if (adapter->ioport == NULL) { - device_printf(dev, "Unable to allocate bus resource: " - "ioport\n"); - return (ENXIO); - } - adapter->hw.io_base = 0; - adapter->osdep.io_bus_space_tag = - rman_get_bustag(adapter->ioport); - adapter->osdep.io_bus_space_handle = - rman_get_bushandle(adapter->ioport); - } - - /* - ** Init the resource arrays - ** used by MSIX setup - */ - for (int i = 0; i < 3; i++) { - adapter->rid[i] = i + 1; /* MSI/X RID starts at 1 */ - adapter->tag[i] = NULL; - adapter->res[i] = NULL; - } + /* Default to a single queue */ + adapter->num_queues = 1; /* * Setup MSI/X or MSI if PCI Express */ - if (em_enable_msi) - adapter->msi = em_setup_msix(adapter); + adapter->msix = em_setup_msix(adapter); adapter->hw.back = &adapter->osdep; - return (error); + return (0); } /********************************************************************* @@ -2835,63 +2256,40 @@ int em_allocate_legacy(struct adapter *adapter) { device_t dev = adapter->dev; - int error; + int error, rid = 0; /* Manually turn off all interrupts */ E1000_WRITE_REG(&adapter->hw, E1000_IMC, 0xffffffff); - /* Legacy RID is 0 */ - if (adapter->msi == 0) - adapter->rid[0] = 0; - + if (adapter->msix == 1) /* using MSI */ + rid = 1; /* We allocate a single interrupt resource */ - adapter->res[0] = bus_alloc_resource_any(dev, - SYS_RES_IRQ, &adapter->rid[0], RF_SHAREABLE | RF_ACTIVE); - if (adapter->res[0] == NULL) { + adapter->res = bus_alloc_resource_any(dev, + SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); + if (adapter->res == NULL) { device_printf(dev, "Unable to allocate bus resource: " "interrupt\n"); return (ENXIO); } -#ifdef EM_LEGACY_IRQ - /* We do Legacy setup */ - if ((error = bus_setup_intr(dev, adapter->res[0], -#if __FreeBSD_version > 700000 - INTR_TYPE_NET | INTR_MPSAFE, NULL, em_intr, adapter, -#else /* 6.X */ - INTR_TYPE_NET | INTR_MPSAFE, em_intr, adapter, -#endif - &adapter->tag[0])) != 0) { - device_printf(dev, "Failed to register interrupt handler"); - return (error); - } - -#else /* FAST_IRQ */ /* - * Try allocating a fast interrupt and the associated deferred - * processing contexts. + * Allocate a fast interrupt and the associated + * deferred processing contexts. */ - TASK_INIT(&adapter->rxtx_task, 0, em_handle_rxtx, adapter); + TASK_INIT(&adapter->que_task, 0, em_handle_que, adapter); TASK_INIT(&adapter->link_task, 0, em_handle_link, adapter); adapter->tq = taskqueue_create_fast("em_taskq", M_NOWAIT, taskqueue_thread_enqueue, &adapter->tq); taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s taskq", device_get_nameunit(adapter->dev)); -#if __FreeBSD_version < 700000 - if ((error = bus_setup_intr(dev, adapter->res[0], - INTR_TYPE_NET | INTR_FAST, em_irq_fast, adapter, -#else - if ((error = bus_setup_intr(dev, adapter->res[0], - INTR_TYPE_NET, em_irq_fast, NULL, adapter, -#endif - &adapter->tag[0])) != 0) { + if ((error = bus_setup_intr(dev, adapter->res, INTR_TYPE_NET, + em_irq_fast, NULL, adapter, &adapter->tag)) != 0) { device_printf(dev, "Failed to register fast interrupt " "handler: %d\n", error); taskqueue_free(adapter->tq); adapter->tq = NULL; return (error); } -#endif /* EM_LEGACY_IRQ */ return (0); } @@ -2906,80 +2304,109 @@ em_allocate_legacy(struct adapter *adapter) int em_allocate_msix(struct adapter *adapter) { - device_t dev = adapter->dev; - int error; + device_t dev = adapter->dev; + struct tx_ring *txr = adapter->tx_rings; + struct rx_ring *rxr = adapter->rx_rings; + int error, rid, vector = 0; + /* Make sure all interrupts are disabled */ E1000_WRITE_REG(&adapter->hw, E1000_IMC, 0xffffffff); - /* First get the resources */ - for (int i = 0; i < adapter->msi; i++) { - adapter->res[i] = bus_alloc_resource_any(dev, - SYS_RES_IRQ, &adapter->rid[i], RF_ACTIVE); - if (adapter->res[i] == NULL) { + /* First set up ring resources */ + for (int i = 0; i < adapter->num_queues; i++, txr++, rxr++) { + + /* RX ring */ + rid = vector + 1; + + rxr->res = bus_alloc_resource_any(dev, + SYS_RES_IRQ, &rid, RF_ACTIVE); + if (rxr->res == NULL) { device_printf(dev, "Unable to allocate bus resource: " - "MSIX Interrupt\n"); + "RX MSIX Interrupt %d\n", i); return (ENXIO); } + if ((error = bus_setup_intr(dev, rxr->res, + INTR_TYPE_NET | INTR_MPSAFE, NULL, em_msix_rx, + rxr, &rxr->tag)) != 0) { + device_printf(dev, "Failed to register RX handler"); + return (error); + } + rxr->msix = vector++; /* NOTE increment vector for TX */ + TASK_INIT(&rxr->rx_task, 0, em_handle_rx, rxr); + rxr->tq = taskqueue_create_fast("em_rxq", M_NOWAIT, + taskqueue_thread_enqueue, &rxr->tq); + taskqueue_start_threads(&rxr->tq, 1, PI_NET, "%s rxq", + device_get_nameunit(adapter->dev)); + /* + ** Set the bit to enable interrupt + ** in E1000_IMS -- bits 20 and 21 + ** are for RX0 and RX1, note this has + ** NOTHING to do with the MSIX vector + */ + rxr->ims = 1 << (20 + i); + adapter->ivars |= (8 | rxr->msix) << (i * 4); + + /* TX ring */ + rid = vector + 1; + txr->res = bus_alloc_resource_any(dev, + SYS_RES_IRQ, &rid, RF_ACTIVE); + if (txr->res == NULL) { + device_printf(dev, + "Unable to allocate bus resource: " + "TX MSIX Interrupt %d\n", i); + return (ENXIO); + } + if ((error = bus_setup_intr(dev, txr->res, + INTR_TYPE_NET | INTR_MPSAFE, NULL, em_msix_tx, + txr, &txr->tag)) != 0) { + device_printf(dev, "Failed to register TX handler"); + return (error); + } + txr->msix = vector++; /* Increment vector for next pass */ + TASK_INIT(&txr->tx_task, 0, em_handle_tx, txr); + txr->tq = taskqueue_create_fast("em_txq", M_NOWAIT, + taskqueue_thread_enqueue, &txr->tq); + taskqueue_start_threads(&txr->tq, 1, PI_NET, "%s txq", + device_get_nameunit(adapter->dev)); + /* + ** Set the bit to enable interrupt + ** in E1000_IMS -- bits 22 and 23 + ** are for TX0 and TX1, note this has + ** NOTHING to do with the MSIX vector + */ + txr->ims = 1 << (22 + i); + adapter->ivars |= (8 | txr->msix) << (8 + (i * 4)); } - /* - * Now allocate deferred processing contexts. - */ - TASK_INIT(&adapter->rx_task, 0, em_handle_rx, adapter); - TASK_INIT(&adapter->tx_task, 0, em_handle_tx, adapter); - /* - * Handle compatibility for msi case for deferral due to - * trylock failure - */ - TASK_INIT(&adapter->rxtx_task, 0, em_handle_tx, adapter); + /* Link interrupt */ + ++rid; + adapter->res = bus_alloc_resource_any(dev, + SYS_RES_IRQ, &rid, RF_ACTIVE); + if (!adapter->res) { + device_printf(dev,"Unable to allocate " + "bus resource: Link interrupt [%d]\n", rid); + return (ENXIO); + } + /* Set the link handler function */ + error = bus_setup_intr(dev, adapter->res, + INTR_TYPE_NET | INTR_MPSAFE, NULL, + em_msix_link, adapter, &adapter->tag); + if (error) { + adapter->res = NULL; + device_printf(dev, "Failed to register LINK handler"); + return (error); + } + adapter->linkvec = vector; + adapter->ivars |= (8 | vector) << 16; + adapter->ivars |= 0x80000000; TASK_INIT(&adapter->link_task, 0, em_handle_link, adapter); - adapter->tq = taskqueue_create_fast("em_taskq", M_NOWAIT, + adapter->tq = taskqueue_create_fast("em_link", M_NOWAIT, taskqueue_thread_enqueue, &adapter->tq); - taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s taskq", + taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq", device_get_nameunit(adapter->dev)); - /* - * And setup the interrupt handlers - */ - - /* First slot to RX */ - if ((error = bus_setup_intr(dev, adapter->res[0], -#if __FreeBSD_version > 700000 - INTR_TYPE_NET | INTR_MPSAFE, NULL, em_msix_rx, adapter, -#else /* 6.X */ - INTR_TYPE_NET | INTR_MPSAFE, em_msix_rx, adapter, -#endif - &adapter->tag[0])) != 0) { - device_printf(dev, "Failed to register RX handler"); - return (error); - } - - /* Next TX */ - if ((error = bus_setup_intr(dev, adapter->res[1], -#if __FreeBSD_version > 700000 - INTR_TYPE_NET | INTR_MPSAFE, NULL, em_msix_tx, adapter, -#else /* 6.X */ - INTR_TYPE_NET | INTR_MPSAFE, em_msix_tx, adapter, -#endif - &adapter->tag[1])) != 0) { - device_printf(dev, "Failed to register TX handler"); - return (error); - } - - /* And Link */ - if ((error = bus_setup_intr(dev, adapter->res[2], -#if __FreeBSD_version > 700000 - INTR_TYPE_NET | INTR_MPSAFE, NULL, em_msix_link, adapter, -#else /* 6.X */ - INTR_TYPE_NET | INTR_MPSAFE, em_msix_link, adapter, -#endif - &adapter->tag[2])) != 0) { - device_printf(dev, "Failed to register TX handler"); - return (error); - } - return (0); } @@ -2987,36 +2414,56 @@ em_allocate_msix(struct adapter *adapter) static void em_free_pci_resources(struct adapter *adapter) { - device_t dev = adapter->dev; + device_t dev = adapter->dev; + struct tx_ring *txr; + struct rx_ring *rxr; + int rid; - /* Make sure the for loop below runs once */ - if (adapter->msi == 0) - adapter->msi = 1; /* - * First release all the interrupt resources: - * notice that since these are just kept - * in an array we can do the same logic - * whether its MSIX or just legacy. - */ - for (int i = 0; i < adapter->msi; i++) { - if (adapter->tag[i] != NULL) { - bus_teardown_intr(dev, adapter->res[i], - adapter->tag[i]); - adapter->tag[i] = NULL; + ** Release all the queue interrupt resources: + */ + for (int i = 0; i < adapter->num_queues; i++) { + txr = &adapter->tx_rings[i]; + rxr = &adapter->rx_rings[i]; + rid = txr->msix +1; + if (txr->tag != NULL) { + bus_teardown_intr(dev, txr->res, txr->tag); + txr->tag = NULL; } - if (adapter->res[i] != NULL) { + if (txr->res != NULL) bus_release_resource(dev, SYS_RES_IRQ, - adapter->rid[i], adapter->res[i]); + rid, txr->res); + rid = rxr->msix +1; + if (rxr->tag != NULL) { + bus_teardown_intr(dev, rxr->res, rxr->tag); + rxr->tag = NULL; } + if (rxr->res != NULL) + bus_release_resource(dev, SYS_RES_IRQ, + rid, rxr->res); } - if (adapter->msi) + if (adapter->linkvec) /* we are doing MSIX */ + rid = adapter->linkvec + 1; + else + (adapter->msix != 0) ? (rid = 1):(rid = 0); + + if (adapter->tag != NULL) { + bus_teardown_intr(dev, adapter->res, adapter->tag); + adapter->tag = NULL; + } + + if (adapter->res != NULL) + bus_release_resource(dev, SYS_RES_IRQ, rid, adapter->res); + + + if (adapter->msix) pci_release_msi(dev); - if (adapter->msix != NULL) + if (adapter->msix_mem != NULL) bus_release_resource(dev, SYS_RES_MEMORY, - PCIR_BAR(EM_MSIX_BAR), adapter->msix); + PCIR_BAR(EM_MSIX_BAR), adapter->msix_mem); if (adapter->memory != NULL) bus_release_resource(dev, SYS_RES_MEMORY, @@ -3025,10 +2472,6 @@ em_free_pci_resources(struct adapter *adapter) if (adapter->flash != NULL) bus_release_resource(dev, SYS_RES_MEMORY, EM_FLASH, adapter->flash); - - if (adapter->ioport != NULL) - bus_release_resource(dev, SYS_RES_IOPORT, - adapter->io_rid, adapter->ioport); } /* @@ -3040,82 +2483,81 @@ em_setup_msix(struct adapter *adapter) device_t dev = adapter->dev; int val = 0; - if (adapter->hw.mac.type < e1000_82571) - return (0); /* Setup MSI/X for Hartwell */ - if (adapter->hw.mac.type == e1000_82574) { + if ((adapter->hw.mac.type == e1000_82574) && + (em_enable_msix == TRUE)) { /* Map the MSIX BAR */ int rid = PCIR_BAR(EM_MSIX_BAR); - adapter->msix = bus_alloc_resource_any(dev, + adapter->msix_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); - if (!adapter->msix) { + if (!adapter->msix_mem) { /* May not be enabled */ device_printf(adapter->dev, "Unable to map MSIX table \n"); goto msi; } val = pci_msix_count(dev); - /* - ** 82574 can be configured for 5 but - ** we limit use to 3. - */ - if (val > 3) val = 3; - if ((val) && pci_alloc_msix(dev, &val) == 0) { - device_printf(adapter->dev,"Using MSIX interrupts\n"); - return (val); + if (val != 5) { + bus_release_resource(dev, SYS_RES_MEMORY, + PCIR_BAR(EM_MSIX_BAR), adapter->msix_mem); + adapter->msix_mem = NULL; + device_printf(adapter->dev, + "MSIX vectors wrong, using MSI \n"); + goto msi; } + if (em_msix_queues == 2) { + val = 5; + adapter->num_queues = 2; + } else { + val = 3; + adapter->num_queues = 1; + } + if (pci_alloc_msix(dev, &val) == 0) { + device_printf(adapter->dev, + "Using MSIX interrupts " + "with %d vectors\n", val); + } + + return (val); } msi: val = pci_msi_count(dev); if (val == 1 && pci_alloc_msi(dev, &val) == 0) { - adapter->msi = 1; + adapter->msix = 1; device_printf(adapter->dev,"Using MSI interrupt\n"); return (val); } + /* Should only happen due to manual invention */ + device_printf(adapter->dev,"Setup MSIX failure\n"); return (0); } + /********************************************************************* * * Initialize the hardware to a configuration * as specified by the adapter structure. * **********************************************************************/ -static int -em_hardware_init(struct adapter *adapter) +static void +em_reset(struct adapter *adapter) { - device_t dev = adapter->dev; - u16 rx_buffer_size; + device_t dev = adapter->dev; + struct e1000_hw *hw = &adapter->hw; + u16 rx_buffer_size; - INIT_DEBUGOUT("em_hardware_init: begin"); - - /* 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; + INIT_DEBUGOUT("em_reset: begin"); /* Set up smart power down as default off on newer adapters. */ - if (!em_smart_pwr_down && (adapter->hw.mac.type == e1000_82571 || - adapter->hw.mac.type == e1000_82572)) { + if (!em_smart_pwr_down && (hw->mac.type == e1000_82571 || + hw->mac.type == e1000_82572)) { u16 phy_tmp = 0; /* Speed up time to link by disabling smart power down. */ - e1000_read_phy_reg(&adapter->hw, - IGP02E1000_PHY_POWER_MGMT, &phy_tmp); + e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_tmp); phy_tmp &= ~IGP02E1000_PM_SPD; - e1000_write_phy_reg(&adapter->hw, - IGP02E1000_PHY_POWER_MGMT, phy_tmp); + e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_tmp); } /* @@ -3132,34 +2574,42 @@ em_hardware_init(struct adapter *adapter) * by 1500. * - The pause time is fairly large at 1000 x 512ns = 512 usec. */ - rx_buffer_size = ((E1000_READ_REG(&adapter->hw, E1000_PBA) & - 0xffff) << 10 ); + rx_buffer_size = ((E1000_READ_REG(hw, E1000_PBA) & 0xffff) << 10 ); - adapter->hw.fc.high_water = rx_buffer_size - + hw->fc.high_water = rx_buffer_size - roundup2(adapter->max_frame_size, 1024); - adapter->hw.fc.low_water = adapter->hw.fc.high_water - 1500; + hw->fc.low_water = hw->fc.high_water - 1500; - if (adapter->hw.mac.type == e1000_80003es2lan) - adapter->hw.fc.pause_time = 0xFFFF; + if (hw->mac.type == e1000_80003es2lan) + hw->fc.pause_time = 0xFFFF; else - adapter->hw.fc.pause_time = EM_FC_PAUSE_TIME; - adapter->hw.fc.send_xon = TRUE; + hw->fc.pause_time = EM_FC_PAUSE_TIME; + + hw->fc.send_xon = TRUE; /* Set Flow control, use the tunable location if sane */ if ((em_fc_setting >= 0) || (em_fc_setting < 4)) - adapter->hw.fc.requested_mode = em_fc_setting; - else - adapter->hw.fc.requested_mode = e1000_fc_none; + hw->fc.requested_mode = em_fc_setting; + else + hw->fc.requested_mode = e1000_fc_none; + /* Override - workaround for PCHLAN issue */ + if (hw->mac.type == e1000_pchlan) + hw->fc.requested_mode = e1000_fc_rx_pause; - if (e1000_init_hw(&adapter->hw) < 0) { + /* Issue a global reset */ + e1000_reset_hw(hw); + E1000_WRITE_REG(hw, E1000_WUC, 0); + + if (e1000_init_hw(hw) < 0) { device_printf(dev, "Hardware Initialization Failed\n"); - return (EIO); + return; } - e1000_check_for_link(&adapter->hw); - - return (0); + E1000_WRITE_REG(hw, E1000_VET, ETHERTYPE_VLAN); + e1000_get_phy_info(hw); + e1000_check_for_link(hw); + return; } /********************************************************************* @@ -3196,31 +2646,14 @@ em_setup_interface(device_t dev, struct adapter *adapter) /* Multiqueue tx functions */ ifp->if_transmit = em_mq_start; ifp->if_qflush = em_qflush; - adapter->br = buf_ring_alloc(4096, M_DEVBUF, M_WAITOK, &adapter->tx_mtx); #endif - if (adapter->hw.mac.type >= e1000_82543) { - int version_cap; -#if __FreeBSD_version < 700000 - version_cap = IFCAP_HWCSUM; -#else - version_cap = IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM; -#endif - ifp->if_capabilities |= version_cap; - ifp->if_capenable |= version_cap; - } -#if __FreeBSD_version >= 700000 - /* Identify TSO capable adapters */ - if ((adapter->hw.mac.type > e1000_82544) && - (adapter->hw.mac.type != e1000_82547)) - ifp->if_capabilities |= IFCAP_TSO4; - /* - * By default only enable on PCI-E, this - * can be overriden by ifconfig. - */ - if (adapter->hw.mac.type >= e1000_82571) - ifp->if_capenable |= IFCAP_TSO4; -#endif + ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM; + ifp->if_capenable |= IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM; + + /* Enable TSO by default, can disable with ifconfig */ + ifp->if_capabilities |= IFCAP_TSO4; + ifp->if_capenable |= IFCAP_TSO4; /* * Tell the upper layer(s) we support long frames. @@ -3233,6 +2666,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 @@ -3243,8 +2682,6 @@ em_setup_interface(device_t dev, struct adapter *adapter) (adapter->hw.phy.media_type == e1000_media_type_internal_serdes)) { u_char fiber_type = IFM_1000_SX; /* default type */ - if (adapter->hw.mac.type == e1000_82545) - fiber_type = IFM_1000_LX; ifmedia_add(&adapter->media, IFM_ETHER | fiber_type | IFM_FDX, 0, NULL); ifmedia_add(&adapter->media, IFM_ETHER | fiber_type, 0, NULL); @@ -3268,67 +2705,6 @@ em_setup_interface(device_t dev, struct adapter *adapter) } -/********************************************************************* - * - * Workaround for SmartSpeed on 82541 and 82547 controllers - * - **********************************************************************/ -static void -em_smartspeed(struct adapter *adapter) -{ - u16 phy_tmp; - - if (adapter->link_active || (adapter->hw.phy.type != e1000_phy_igp) || - adapter->hw.mac.autoneg == 0 || - (adapter->hw.phy.autoneg_advertised & ADVERTISE_1000_FULL) == 0) - return; - - if (adapter->smartspeed == 0) { - /* If Master/Slave config fault is asserted twice, - * we assume back-to-back */ - e1000_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_tmp); - if (!(phy_tmp & SR_1000T_MS_CONFIG_FAULT)) - return; - e1000_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_tmp); - if (phy_tmp & SR_1000T_MS_CONFIG_FAULT) { - e1000_read_phy_reg(&adapter->hw, - PHY_1000T_CTRL, &phy_tmp); - if(phy_tmp & CR_1000T_MS_ENABLE) { - phy_tmp &= ~CR_1000T_MS_ENABLE; - e1000_write_phy_reg(&adapter->hw, - PHY_1000T_CTRL, phy_tmp); - adapter->smartspeed++; - if(adapter->hw.mac.autoneg && - !e1000_phy_setup_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); - e1000_write_phy_reg(&adapter->hw, - PHY_CONTROL, phy_tmp); - } - } - } - return; - } else if(adapter->smartspeed == EM_SMARTSPEED_DOWNSHIFT) { - /* If still no link, perhaps using 2/3 pair cable */ - e1000_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, &phy_tmp); - 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_read_phy_reg(&adapter->hw, PHY_CONTROL, &phy_tmp)) { - phy_tmp |= (MII_CR_AUTO_NEG_EN | - MII_CR_RESTART_AUTO_NEG); - e1000_write_phy_reg(&adapter->hw, PHY_CONTROL, phy_tmp); - } - } - /* Restart process after EM_SMARTSPEED_MAX iterations */ - if(adapter->smartspeed++ == EM_SMARTSPEED_MAX) - adapter->smartspeed = 0; -} - - /* * Manage DMA'able memory. */ @@ -3346,11 +2722,7 @@ em_dma_malloc(struct adapter *adapter, bus_size_t size, { int error; -#if __FreeBSD_version >= 700000 error = bus_dma_tag_create(bus_get_dma_tag(adapter->dev), /* parent */ -#else - error = bus_dma_tag_create(NULL, /* parent */ -#endif EM_DBA_ALIGN, 0, /* alignment, bounds */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ @@ -3421,97 +2793,243 @@ em_dma_free(struct adapter *adapter, struct em_dma_alloc *dma) /********************************************************************* * - * Allocate memory for tx_buffer structures. The tx_buffer stores all - * the information needed to transmit a packet on the wire. + * Allocate memory for the transmit and receive rings, and then + * the descriptors associated with each, called only once at attach. * **********************************************************************/ static int -em_allocate_transmit_structures(struct adapter *adapter) +em_allocate_queues(struct adapter *adapter) { - device_t dev = adapter->dev; - struct em_buffer *tx_buffer; - int error; + device_t dev = adapter->dev; + struct tx_ring *txr = NULL; + struct rx_ring *rxr = NULL; + int rsize, tsize, error = E1000_SUCCESS; + int txconf = 0, rxconf = 0; - /* - * Create DMA tags for tx descriptors - */ -#if __FreeBSD_version >= 700000 - if ((error = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ -#else - if ((error = bus_dma_tag_create(NULL, /* parent */ -#endif - 1, 0, /* alignment, bounds */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - EM_TSO_SIZE, /* maxsize */ - EM_MAX_SCATTER, /* nsegments */ - EM_TSO_SEG_SIZE, /* maxsegsize */ - 0, /* flags */ - NULL, /* lockfunc */ - NULL, /* lockarg */ - &adapter->txtag)) != 0) { - device_printf(dev, "Unable to allocate TX DMA tag\n"); + + /* Allocate the TX ring struct memory */ + if (!(adapter->tx_rings = + (struct tx_ring *) malloc(sizeof(struct tx_ring) * + adapter->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { + device_printf(dev, "Unable to allocate TX ring memory\n"); + error = ENOMEM; goto fail; } - adapter->tx_buffer_area = malloc(sizeof(struct em_buffer) * - adapter->num_tx_desc, M_DEVBUF, M_NOWAIT | M_ZERO); - if (adapter->tx_buffer_area == NULL) { + /* Now allocate the RX */ + if (!(adapter->rx_rings = + (struct rx_ring *) malloc(sizeof(struct rx_ring) * + adapter->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { + device_printf(dev, "Unable to allocate RX ring memory\n"); + error = ENOMEM; + goto rx_fail; + } + + tsize = roundup2(adapter->num_tx_desc * + sizeof(struct e1000_tx_desc), EM_DBA_ALIGN); + /* + * Now set up the TX queues, txconf is needed to handle the + * possibility that things fail midcourse and we need to + * undo memory gracefully + */ + for (int i = 0; i < adapter->num_queues; i++, txconf++) { + /* Set up some basics */ + txr = &adapter->tx_rings[i]; + txr->adapter = adapter; + txr->me = i; + + /* Initialize the TX lock */ + snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)", + device_get_nameunit(dev), txr->me); + mtx_init(&txr->tx_mtx, txr->mtx_name, NULL, MTX_DEF); + + if (em_dma_malloc(adapter, tsize, + &txr->txdma, BUS_DMA_NOWAIT)) { + device_printf(dev, + "Unable to allocate TX Descriptor memory\n"); + error = ENOMEM; + goto err_tx_desc; + } + txr->tx_base = (struct e1000_tx_desc *)txr->txdma.dma_vaddr; + bzero((void *)txr->tx_base, tsize); + + if (em_allocate_transmit_buffers(txr)) { + device_printf(dev, + "Critical Failure setting up transmit buffers\n"); + error = ENOMEM; + goto err_tx_desc; + } +#if __FreeBSD_version >= 800000 + /* Allocate a buf ring */ + txr->br = buf_ring_alloc(4096, M_DEVBUF, + M_WAITOK, &txr->tx_mtx); +#endif + } + + /* + * Next the RX queues... + */ + rsize = roundup2(adapter->num_rx_desc * + sizeof(struct e1000_rx_desc), EM_DBA_ALIGN); + for (int i = 0; i < adapter->num_queues; i++, rxconf++) { + rxr = &adapter->rx_rings[i]; + rxr->adapter = adapter; + rxr->me = i; + + /* Initialize the RX lock */ + snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)", + device_get_nameunit(dev), txr->me); + mtx_init(&rxr->rx_mtx, rxr->mtx_name, NULL, MTX_DEF); + + if (em_dma_malloc(adapter, rsize, + &rxr->rxdma, BUS_DMA_NOWAIT)) { + device_printf(dev, + "Unable to allocate RxDescriptor memory\n"); + error = ENOMEM; + goto err_rx_desc; + } + rxr->rx_base = (struct e1000_rx_desc *)rxr->rxdma.dma_vaddr; + bzero((void *)rxr->rx_base, rsize); + + /* Allocate receive buffers for the ring*/ + if (em_allocate_receive_buffers(rxr)) { + device_printf(dev, + "Critical Failure setting up receive buffers\n"); + error = ENOMEM; + goto err_rx_desc; + } + } + + return (0); + +err_rx_desc: + for (rxr = adapter->rx_rings; rxconf > 0; rxr++, rxconf--) + em_dma_free(adapter, &rxr->rxdma); +err_tx_desc: + for (txr = adapter->tx_rings; txconf > 0; txr++, txconf--) + em_dma_free(adapter, &txr->txdma); + free(adapter->rx_rings, M_DEVBUF); +rx_fail: + buf_ring_free(txr->br, M_DEVBUF); + free(adapter->tx_rings, M_DEVBUF); +fail: + return (error); +} + + +/********************************************************************* + * + * Allocate memory for tx_buffer structures. The tx_buffer stores all + * the information needed to transmit a packet on the wire. This is + * called only once at attach, setup is done every reset. + * + **********************************************************************/ +static int +em_allocate_transmit_buffers(struct tx_ring *txr) +{ + struct adapter *adapter = txr->adapter; + device_t dev = adapter->dev; + struct em_buffer *txbuf; + int error, i; + + /* + * Setup DMA descriptor areas. + */ + if ((error = bus_dma_tag_create(bus_get_dma_tag(dev), + 1, 0, /* alignment, bounds */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + EM_TSO_SIZE, /* maxsize */ + EM_MAX_SCATTER, /* nsegments */ + PAGE_SIZE, /* maxsegsize */ + 0, /* flags */ + NULL, /* lockfunc */ + NULL, /* lockfuncarg */ + &txr->txtag))) { + device_printf(dev,"Unable to allocate TX DMA tag\n"); + goto fail; + } + + if (!(txr->tx_buffers = + (struct em_buffer *) malloc(sizeof(struct em_buffer) * + adapter->num_tx_desc, M_DEVBUF, M_NOWAIT | M_ZERO))) { device_printf(dev, "Unable to allocate tx_buffer memory\n"); error = ENOMEM; goto fail; } - /* Create the descriptor buffer dma maps */ - for (int i = 0; i < adapter->num_tx_desc; i++) { - tx_buffer = &adapter->tx_buffer_area[i]; - error = bus_dmamap_create(adapter->txtag, 0, &tx_buffer->map); + /* Create the descriptor buffer dma maps */ + txbuf = txr->tx_buffers; + for (i = 0; i < adapter->num_tx_desc; i++, txbuf++) { + error = bus_dmamap_create(txr->txtag, 0, &txbuf->map); if (error != 0) { device_printf(dev, "Unable to create TX DMA map\n"); goto fail; } - tx_buffer->next_eop = -1; } - return (0); + return 0; fail: + /* We free all, it handles case where we are in the middle */ em_free_transmit_structures(adapter); return (error); } /********************************************************************* * - * (Re)Initialize transmit structures. + * Initialize a transmit ring. + * + **********************************************************************/ +static void +em_setup_transmit_ring(struct tx_ring *txr) +{ + struct adapter *adapter = txr->adapter; + struct em_buffer *txbuf; + int i; + + /* Clear the old descriptor contents */ + EM_TX_LOCK(txr); + bzero((void *)txr->tx_base, + (sizeof(struct e1000_tx_desc)) * adapter->num_tx_desc); + /* Reset indices */ + txr->next_avail_desc = 0; + txr->next_to_clean = 0; + + /* Free any existing tx buffers. */ + txbuf = txr->tx_buffers; + for (i = 0; i < adapter->num_tx_desc; i++, txbuf++) { + if (txbuf->m_head != NULL) { + bus_dmamap_sync(txr->txtag, txbuf->map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(txr->txtag, txbuf->map); + m_freem(txbuf->m_head); + txbuf->m_head = NULL; + } + /* clear the watch index */ + txbuf->next_eop = -1; + } + + /* Set number of descriptors available */ + txr->tx_avail = adapter->num_tx_desc; + + bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + EM_TX_UNLOCK(txr); +} + +/********************************************************************* + * + * Initialize all transmit rings. * **********************************************************************/ static void em_setup_transmit_structures(struct adapter *adapter) { - struct em_buffer *tx_buffer; + struct tx_ring *txr = adapter->tx_rings; - /* Clear the old ring contents */ - bzero(adapter->tx_desc_base, - (sizeof(struct e1000_tx_desc)) * adapter->num_tx_desc); - - /* Free any existing TX buffers */ - for (int i = 0; i < adapter->num_tx_desc; i++, tx_buffer++) { - tx_buffer = &adapter->tx_buffer_area[i]; - bus_dmamap_sync(adapter->txtag, tx_buffer->map, - BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(adapter->txtag, tx_buffer->map); - m_freem(tx_buffer->m_head); - tx_buffer->m_head = NULL; - tx_buffer->next_eop = -1; - } - - /* Reset state */ - adapter->next_avail_tx_desc = 0; - adapter->next_tx_to_clean = 0; - adapter->num_tx_desc_avail = adapter->num_tx_desc; - - bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + for (int i = 0; i < adapter->num_queues; i++, txr++) + em_setup_transmit_ring(txr); return; } @@ -3524,25 +3042,31 @@ em_setup_transmit_structures(struct adapter *adapter) static void em_initialize_transmit_unit(struct adapter *adapter) { + struct tx_ring *txr = adapter->tx_rings; + struct e1000_hw *hw = &adapter->hw; u32 tctl, tarc, tipg = 0; - u64 bus_addr; INIT_DEBUGOUT("em_initialize_transmit_unit: begin"); - /* Setup the Base and Length of the Tx Descriptor Ring */ - bus_addr = adapter->txdma.dma_paddr; - E1000_WRITE_REG(&adapter->hw, E1000_TDLEN(0), - adapter->num_tx_desc * sizeof(struct e1000_tx_desc)); - E1000_WRITE_REG(&adapter->hw, E1000_TDBAH(0), - (u32)(bus_addr >> 32)); - E1000_WRITE_REG(&adapter->hw, E1000_TDBAL(0), - (u32)bus_addr); - /* Setup the HW Tx Head and Tail descriptor pointers */ - E1000_WRITE_REG(&adapter->hw, E1000_TDT(0), 0); - E1000_WRITE_REG(&adapter->hw, E1000_TDH(0), 0); - HW_DEBUGOUT2("Base = %x, Length = %x\n", - E1000_READ_REG(&adapter->hw, E1000_TDBAL(0)), - E1000_READ_REG(&adapter->hw, E1000_TDLEN(0))); + for (int i = 0; i < adapter->num_queues; i++, txr++) { + u64 bus_addr = txr->txdma.dma_paddr; + /* Base and Len of TX Ring */ + E1000_WRITE_REG(hw, E1000_TDLEN(i), + adapter->num_tx_desc * sizeof(struct e1000_tx_desc)); + E1000_WRITE_REG(hw, E1000_TDBAH(i), + (u32)(bus_addr >> 32)); + E1000_WRITE_REG(hw, E1000_TDBAL(i), + (u32)bus_addr); + /* Init the HEAD/TAIL indices */ + E1000_WRITE_REG(hw, E1000_TDT(i), 0); + E1000_WRITE_REG(hw, E1000_TDH(i), 0); + + HW_DEBUGOUT2("Base = %x, Length = %x\n", + E1000_READ_REG(&adapter->hw, E1000_TDBAL(i)), + E1000_READ_REG(&adapter->hw, E1000_TDLEN(i))); + + txr->watchdog_check = FALSE; + } /* Set the default values for the Tx Inter Packet Gap timer */ switch (adapter->hw.mac.type) { @@ -3569,6 +3093,7 @@ em_initialize_transmit_unit(struct adapter *adapter) E1000_WRITE_REG(&adapter->hw, E1000_TIPG, tipg); E1000_WRITE_REG(&adapter->hw, E1000_TIDV, adapter->tx_int_delay.value); + if(adapter->hw.mac.type >= e1000_82540) E1000_WRITE_REG(&adapter->hw, E1000_TADV, adapter->tx_abs_int_delay.value); @@ -3587,6 +3112,10 @@ em_initialize_transmit_unit(struct adapter *adapter) E1000_WRITE_REG(&adapter->hw, E1000_TARC(1), tarc); } + adapter->txd_cmd = E1000_TXD_CMD_IFCS; + if (adapter->tx_int_delay.value > 0) + adapter->txd_cmd |= E1000_TXD_CMD_IDE; + /* Program the Transmit Control Register */ tctl = E1000_READ_REG(&adapter->hw, E1000_TCTL); tctl &= ~E1000_TCTL_CT; @@ -3599,59 +3128,84 @@ em_initialize_transmit_unit(struct adapter *adapter) /* This write will effectively turn on the transmit unit. */ E1000_WRITE_REG(&adapter->hw, E1000_TCTL, tctl); - /* Setup Transmit Descriptor Base Settings */ - adapter->txd_cmd = E1000_TXD_CMD_IFCS; - - if (adapter->tx_int_delay.value > 0) - adapter->txd_cmd |= E1000_TXD_CMD_IDE; } + /********************************************************************* * - * Free all transmit related data structures. + * Free all transmit rings. * **********************************************************************/ static void em_free_transmit_structures(struct adapter *adapter) { - struct em_buffer *tx_buffer; + struct tx_ring *txr = adapter->tx_rings; - INIT_DEBUGOUT("free_transmit_structures: begin"); + for (int i = 0; i < adapter->num_queues; i++, txr++) { + EM_TX_LOCK(txr); + em_free_transmit_buffers(txr); + em_dma_free(adapter, &txr->txdma); + EM_TX_UNLOCK(txr); + EM_TX_LOCK_DESTROY(txr); + } - if (adapter->tx_buffer_area != NULL) { - for (int i = 0; i < adapter->num_tx_desc; i++) { - tx_buffer = &adapter->tx_buffer_area[i]; - if (tx_buffer->m_head != NULL) { - bus_dmamap_sync(adapter->txtag, tx_buffer->map, - BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(adapter->txtag, - tx_buffer->map); - m_freem(tx_buffer->m_head); - tx_buffer->m_head = NULL; - } else if (tx_buffer->map != NULL) - bus_dmamap_unload(adapter->txtag, - tx_buffer->map); - if (tx_buffer->map != NULL) { - bus_dmamap_destroy(adapter->txtag, - tx_buffer->map); - tx_buffer->map = NULL; + free(adapter->tx_rings, M_DEVBUF); +} + +/********************************************************************* + * + * Free transmit ring related data structures. + * + **********************************************************************/ +static void +em_free_transmit_buffers(struct tx_ring *txr) +{ + struct adapter *adapter = txr->adapter; + struct em_buffer *txbuf; + + INIT_DEBUGOUT("free_transmit_ring: begin"); + + if (txr->tx_buffers == NULL) + return; + + for (int i = 0; i < adapter->num_tx_desc; i++) { + txbuf = &txr->tx_buffers[i]; + if (txbuf->m_head != NULL) { + bus_dmamap_sync(txr->txtag, txbuf->map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(txr->txtag, + txbuf->map); + m_freem(txbuf->m_head); + txbuf->m_head = NULL; + if (txbuf->map != NULL) { + bus_dmamap_destroy(txr->txtag, + txbuf->map); + txbuf->map = NULL; } + } else if (txbuf->map != NULL) { + bus_dmamap_unload(txr->txtag, + txbuf->map); + bus_dmamap_destroy(txr->txtag, + txbuf->map); + txbuf->map = NULL; } } - if (adapter->tx_buffer_area != NULL) { - free(adapter->tx_buffer_area, M_DEVBUF); - adapter->tx_buffer_area = NULL; - } - if (adapter->txtag != NULL) { - bus_dma_tag_destroy(adapter->txtag); - adapter->txtag = NULL; - } #if __FreeBSD_version >= 800000 - if (adapter->br != NULL) - buf_ring_free(adapter->br, M_DEVBUF); + if (txr->br != NULL) + buf_ring_free(txr->br, M_DEVBUF); #endif + if (txr->tx_buffers != NULL) { + free(txr->tx_buffers, M_DEVBUF); + txr->tx_buffers = NULL; + } + if (txr->txtag != NULL) { + bus_dma_tag_destroy(txr->txtag); + txr->txtag = NULL; + } + return; } + /********************************************************************* * * The offload context needs to be set when we transfer the first @@ -3663,22 +3217,23 @@ em_free_transmit_structures(struct adapter *adapter) * big performance win. -jfv **********************************************************************/ static void -em_transmit_checksum_setup(struct adapter *adapter, struct mbuf *mp, +em_transmit_checksum_setup(struct tx_ring *txr, struct mbuf *mp, u32 *txd_upper, u32 *txd_lower) { - struct e1000_context_desc *TXD = NULL; + struct adapter *adapter = txr->adapter; + struct e1000_context_desc *TXD = NULL; struct em_buffer *tx_buffer; struct ether_vlan_header *eh; struct ip *ip = NULL; struct ip6_hdr *ip6; - int curr_txd, ehdrlen; + int cur, ehdrlen; u32 cmd, hdr_len, ip_hlen; u16 etype; u8 ipproto; cmd = hdr_len = ipproto = 0; - curr_txd = adapter->next_avail_tx_desc; + cur = txr->next_avail_desc; /* * Determine where frame payload starts. @@ -3711,7 +3266,7 @@ em_transmit_checksum_setup(struct adapter *adapter, struct mbuf *mp, * Offset of place to put the checksum. */ TXD = (struct e1000_context_desc *) - &adapter->tx_desc_base[curr_txd]; + &txr->tx_base[cur]; TXD->lower_setup.ip_fields.ipcss = ehdrlen; TXD->lower_setup.ip_fields.ipcse = htole16(ehdrlen + ip_hlen); @@ -3753,16 +3308,16 @@ em_transmit_checksum_setup(struct adapter *adapter, struct mbuf *mp, *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; *txd_upper |= E1000_TXD_POPTS_TXSM << 8; /* no need for context if already set */ - if (adapter->last_hw_offload == CSUM_TCP) + if (txr->last_hw_offload == CSUM_TCP) return; - adapter->last_hw_offload = CSUM_TCP; + txr->last_hw_offload = CSUM_TCP; /* * Start offset for payload checksum calculation. * End offset for payload checksum calculation. * Offset of place to put the checksum. */ TXD = (struct e1000_context_desc *) - &adapter->tx_desc_base[curr_txd]; + &txr->tx_base[cur]; TXD->upper_setup.tcp_fields.tucss = hdr_len; TXD->upper_setup.tcp_fields.tucse = htole16(0); TXD->upper_setup.tcp_fields.tucso = @@ -3776,16 +3331,16 @@ em_transmit_checksum_setup(struct adapter *adapter, struct mbuf *mp, *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; *txd_upper |= E1000_TXD_POPTS_TXSM << 8; /* no need for context if already set */ - if (adapter->last_hw_offload == CSUM_UDP) + if (txr->last_hw_offload == CSUM_UDP) return; - adapter->last_hw_offload = CSUM_UDP; + txr->last_hw_offload = CSUM_UDP; /* * Start offset for header checksum calculation. * End offset for header checksum calculation. * Offset of place to put the checksum. */ TXD = (struct e1000_context_desc *) - &adapter->tx_desc_base[curr_txd]; + &txr->tx_base[cur]; TXD->upper_setup.tcp_fields.tucss = hdr_len; TXD->upper_setup.tcp_fields.tucse = htole16(0); TXD->upper_setup.tcp_fields.tucso = @@ -3800,35 +3355,35 @@ em_transmit_checksum_setup(struct adapter *adapter, struct mbuf *mp, TXD->tcp_seg_setup.data = htole32(0); TXD->cmd_and_length = htole32(adapter->txd_cmd | E1000_TXD_CMD_DEXT | cmd); - tx_buffer = &adapter->tx_buffer_area[curr_txd]; + tx_buffer = &txr->tx_buffers[cur]; tx_buffer->m_head = NULL; tx_buffer->next_eop = -1; - if (++curr_txd == adapter->num_tx_desc) - curr_txd = 0; + if (++cur == adapter->num_tx_desc) + cur = 0; - adapter->num_tx_desc_avail--; - adapter->next_avail_tx_desc = curr_txd; + txr->tx_avail--; + txr->next_avail_desc = cur; } -#if __FreeBSD_version >= 700000 /********************************************************************** * * Setup work for hardware segmentation offload (TSO) * **********************************************************************/ static bool -em_tso_setup(struct adapter *adapter, struct mbuf *mp, u32 *txd_upper, +em_tso_setup(struct tx_ring *txr, struct mbuf *mp, u32 *txd_upper, u32 *txd_lower) { - struct e1000_context_desc *TXD; - struct em_buffer *tx_buffer; - struct ether_vlan_header *eh; - struct ip *ip; - struct ip6_hdr *ip6; - struct tcphdr *th; - int curr_txd, ehdrlen, hdr_len, ip_hlen, isip6; + struct adapter *adapter = txr->adapter; + struct e1000_context_desc *TXD; + struct em_buffer *tx_buffer; + struct ether_vlan_header *eh; + struct ip *ip; + struct ip6_hdr *ip6; + struct tcphdr *th; + int cur, ehdrlen, hdr_len, ip_hlen, isip6; u16 etype; /* @@ -3908,9 +3463,9 @@ em_tso_setup(struct adapter *adapter, struct mbuf *mp, u32 *txd_upper, *txd_upper = ((isip6 ? 0 : E1000_TXD_POPTS_IXSM) | E1000_TXD_POPTS_TXSM) << 8; - curr_txd = adapter->next_avail_tx_desc; - tx_buffer = &adapter->tx_buffer_area[curr_txd]; - TXD = (struct e1000_context_desc *) &adapter->tx_desc_base[curr_txd]; + cur = txr->next_avail_desc; + tx_buffer = &txr->tx_buffers[cur]; + TXD = (struct e1000_context_desc *) &txr->tx_base[cur]; /* IPv6 doesn't have a header checksum. */ if (!isip6) { @@ -3945,24 +3500,23 @@ em_tso_setup(struct adapter *adapter, struct mbuf *mp, u32 *txd_upper, TXD->cmd_and_length = htole32(adapter->txd_cmd | E1000_TXD_CMD_DEXT | /* Extended descr */ E1000_TXD_CMD_TSE | /* TSE context */ - (isip6 ? 0 : E1000_TXD_CMD_IP) | /* Do IP csum */ + (isip6 ? 0 : E1000_TXD_CMD_IP) | E1000_TXD_CMD_TCP | /* Do TCP checksum */ (mp->m_pkthdr.len - (hdr_len))); /* Total len */ tx_buffer->m_head = NULL; tx_buffer->next_eop = -1; - if (++curr_txd == adapter->num_tx_desc) - curr_txd = 0; + if (++cur == adapter->num_tx_desc) + cur = 0; - adapter->num_tx_desc_avail--; - adapter->next_avail_tx_desc = curr_txd; - adapter->tx_tso = TRUE; + txr->tx_avail--; + txr->next_avail_desc = cur; + txr->tx_tso = TRUE; return TRUE; } -#endif /* __FreeBSD_version >= 700000 */ /********************************************************************** * @@ -3971,26 +3525,26 @@ em_tso_setup(struct adapter *adapter, struct mbuf *mp, u32 *txd_upper, * tx_buffer is put back on the free queue. * **********************************************************************/ -static void -em_txeof(struct adapter *adapter) +static bool +em_txeof(struct tx_ring *txr) { + struct adapter *adapter = txr->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; - EM_TX_LOCK_ASSERT(adapter); + EM_TX_LOCK_ASSERT(txr); - if (adapter->num_tx_desc_avail == adapter->num_tx_desc) - return; + if (txr->tx_avail == adapter->num_tx_desc) + return (FALSE); - num_avail = adapter->num_tx_desc_avail; - first = adapter->next_tx_to_clean; - tx_desc = &adapter->tx_desc_base[first]; - tx_buffer = &adapter->tx_buffer_area[first]; + num_avail = txr->tx_avail; + first = txr->next_to_clean; + tx_desc = &txr->tx_base[first]; + tx_buffer = &txr->tx_buffers[first]; last = tx_buffer->next_eop; - eop_desc = &adapter->tx_desc_base[last]; + eop_desc = &txr->tx_base[last]; /* * What this does is get the index of the @@ -4002,7 +3556,7 @@ em_txeof(struct adapter *adapter) last = 0; done = last; - bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map, + bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, BUS_DMASYNC_POSTREAD); while (eop_desc->upper.fields.status & E1000_TXD_STAT_DD) { @@ -4011,137 +3565,130 @@ 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++; - bus_dmamap_sync(adapter->txtag, + bus_dmamap_sync(txr->txtag, tx_buffer->map, BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(adapter->txtag, + bus_dmamap_unload(txr->txtag, tx_buffer->map); m_freem(tx_buffer->m_head); tx_buffer->m_head = NULL; } tx_buffer->next_eop = -1; + txr->watchdog_time = ticks; if (++first == adapter->num_tx_desc) first = 0; - tx_buffer = &adapter->tx_buffer_area[first]; - tx_desc = &adapter->tx_desc_base[first]; + tx_buffer = &txr->tx_buffers[first]; + tx_desc = &txr->tx_base[first]; } /* See if we can continue to the next packet */ last = tx_buffer->next_eop; if (last != -1) { - eop_desc = &adapter->tx_desc_base[last]; + eop_desc = &txr->tx_base[last]; /* Get new done point */ if (++last == adapter->num_tx_desc) last = 0; done = last; } else break; } - bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map, + bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - adapter->next_tx_to_clean = first; + 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. + * 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->num_tx_desc_avail = num_avail; - return; + txr->watchdog_check = FALSE; + txr->tx_avail = num_avail; + return (FALSE); } } - /* If any descriptors cleaned, reset the watchdog */ - if (cleaned) - adapter->watchdog_timer = EM_TX_TIMEOUT; - adapter->num_tx_desc_avail = num_avail; - return; + txr->tx_avail = num_avail; + return (TRUE); } + /********************************************************************* * - * 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 - * attempted cleanup and then reinit here. Note that this has been - * seens mostly with fiber adapters. + * Refresh RX descriptor mbufs from system mbuf buffer pool. * **********************************************************************/ static void -em_tx_purge(struct adapter *adapter) -{ - if ((!adapter->link_active) && (adapter->watchdog_timer)) { - EM_TX_LOCK(adapter); - em_txeof(adapter); - EM_TX_UNLOCK(adapter); - if (adapter->watchdog_timer) { /* Still not clean? */ - adapter->watchdog_timer = 0; - em_init_locked(adapter); - } - } -} - -/********************************************************************* - * - * Get a buffer from system mbuf buffer pool. - * - **********************************************************************/ -static int -em_get_buf(struct adapter *adapter, int i) +em_refresh_mbufs(struct rx_ring *rxr, int limit) { + struct adapter *adapter = rxr->adapter; struct mbuf *m; bus_dma_segment_t segs[1]; bus_dmamap_t map; - struct em_buffer *rx_buffer; - int error, nsegs; + struct em_buffer *rxbuf; + int i, error, nsegs, cleaned; - m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); - if (m == NULL) { - adapter->mbuf_cluster_failed++; - return (ENOBUFS); + i = rxr->next_to_refresh; + cleaned = -1; + while (i != limit) { + m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); + if (m == NULL) + goto update; + m->m_len = m->m_pkthdr.len = MCLBYTES; + + if (adapter->max_frame_size <= (MCLBYTES - ETHER_ALIGN)) + m_adj(m, ETHER_ALIGN); + + /* + * Using memory from the mbuf cluster pool, invoke the + * bus_dma machinery to arrange the memory mapping. + */ + error = bus_dmamap_load_mbuf_sg(rxr->rxtag, rxr->rx_sparemap, + m, segs, &nsegs, BUS_DMA_NOWAIT); + if (error != 0) { + m_free(m); + goto update; + } + + /* If nsegs is wrong then the stack is corrupt. */ + KASSERT(nsegs == 1, ("Too many segments returned!")); + + rxbuf = &rxr->rx_buffers[i]; + if (rxbuf->m_head != NULL) + bus_dmamap_unload(rxr->rxtag, rxbuf->map); + + map = rxbuf->map; + rxbuf->map = rxr->rx_sparemap; + rxr->rx_sparemap = map; + bus_dmamap_sync(rxr->rxtag, + rxbuf->map, BUS_DMASYNC_PREREAD); + rxbuf->m_head = m; + rxr->rx_base[i].buffer_addr = htole64(segs[0].ds_addr); + + cleaned = i; + /* Calculate next index */ + if (++i == adapter->num_rx_desc) + i = 0; + /* This is the work marker for refresh */ + rxr->next_to_refresh = i; } - m->m_len = m->m_pkthdr.len = MCLBYTES; +update: + if (cleaned != -1) /* Update tail index */ + E1000_WRITE_REG(&adapter->hw, + E1000_RDT(rxr->me), cleaned); - if (adapter->max_frame_size <= (MCLBYTES - ETHER_ALIGN)) - m_adj(m, ETHER_ALIGN); - - /* - * Using memory from the mbuf cluster pool, invoke the - * bus_dma machinery to arrange the memory mapping. - */ - error = bus_dmamap_load_mbuf_sg(adapter->rxtag, - adapter->rx_sparemap, m, segs, &nsegs, BUS_DMA_NOWAIT); - if (error != 0) { - m_free(m); - return (error); - } - - /* If nsegs is wrong then the stack is corrupt. */ - KASSERT(nsegs == 1, ("Too many segments returned!")); - - rx_buffer = &adapter->rx_buffer_area[i]; - if (rx_buffer->m_head != NULL) - bus_dmamap_unload(adapter->rxtag, rx_buffer->map); - - map = rx_buffer->map; - rx_buffer->map = adapter->rx_sparemap; - adapter->rx_sparemap = map; - bus_dmamap_sync(adapter->rxtag, rx_buffer->map, BUS_DMASYNC_PREREAD); - rx_buffer->m_head = m; - - adapter->rx_desc_base[i].buffer_addr = htole64(segs[0].ds_addr); - return (0); + return; } + /********************************************************************* * * Allocate memory for rx_buffer structures. Since we use one @@ -4151,24 +3698,21 @@ em_get_buf(struct adapter *adapter, int i) * **********************************************************************/ static int -em_allocate_receive_structures(struct adapter *adapter) +em_allocate_receive_buffers(struct rx_ring *rxr) { - device_t dev = adapter->dev; - struct em_buffer *rx_buffer; - int i, error; + struct adapter *adapter = rxr->adapter; + device_t dev = adapter->dev; + struct em_buffer *rxbuf; + int error; - adapter->rx_buffer_area = malloc(sizeof(struct em_buffer) * + rxr->rx_buffers = malloc(sizeof(struct em_buffer) * adapter->num_rx_desc, M_DEVBUF, M_NOWAIT | M_ZERO); - if (adapter->rx_buffer_area == NULL) { + if (rxr->rx_buffers == NULL) { device_printf(dev, "Unable to allocate rx_buffer memory\n"); return (ENOMEM); } -#if __FreeBSD_version >= 700000 error = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ -#else - error = bus_dma_tag_create(NULL, /* parent */ -#endif 1, 0, /* alignment, bounds */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ @@ -4179,7 +3723,7 @@ em_allocate_receive_structures(struct adapter *adapter) 0, /* flags */ NULL, /* lockfunc */ NULL, /* lockarg */ - &adapter->rxtag); + &rxr->rxtag); if (error) { device_printf(dev, "%s: bus_dma_tag_create failed %d\n", __func__, error); @@ -4187,18 +3731,19 @@ em_allocate_receive_structures(struct adapter *adapter) } /* Create the spare map (used by getbuf) */ - error = bus_dmamap_create(adapter->rxtag, BUS_DMA_NOWAIT, - &adapter->rx_sparemap); + error = bus_dmamap_create(rxr->rxtag, BUS_DMA_NOWAIT, + &rxr->rx_sparemap); if (error) { device_printf(dev, "%s: bus_dmamap_create failed: %d\n", __func__, error); goto fail; } - rx_buffer = adapter->rx_buffer_area; - for (i = 0; i < adapter->num_rx_desc; i++, rx_buffer++) { - error = bus_dmamap_create(adapter->rxtag, BUS_DMA_NOWAIT, - &rx_buffer->map); + rxbuf = rxr->rx_buffers; + for (int i = 0; i < adapter->num_rx_desc; i++, rxbuf++) { + rxbuf = &rxr->rx_buffers[i]; + error = bus_dmamap_create(rxr->rxtag, BUS_DMA_NOWAIT, + &rxbuf->map); if (error) { device_printf(dev, "%s: bus_dmamap_create failed: %d\n", __func__, error); @@ -4213,48 +3758,182 @@ em_allocate_receive_structures(struct adapter *adapter) return (error); } + /********************************************************************* * - * (Re)initialize receive structures. + * Initialize a receive ring and its buffers. + * + **********************************************************************/ +static int +em_setup_receive_ring(struct rx_ring *rxr) +{ + struct adapter *adapter = rxr->adapter; + struct em_buffer *rxbuf; + bus_dma_segment_t seg[1]; + int rsize, nsegs, error; + + + /* Clear the ring contents */ + EM_RX_LOCK(rxr); + rsize = roundup2(adapter->num_rx_desc * + sizeof(struct e1000_rx_desc), EM_DBA_ALIGN); + bzero((void *)rxr->rx_base, rsize); + + /* + ** Free current RX buffer structs and their mbufs + */ + for (int i = 0; i < adapter->num_rx_desc; i++) { + rxbuf = &rxr->rx_buffers[i]; + if (rxbuf->m_head != NULL) { + bus_dmamap_sync(rxr->rxtag, rxbuf->map, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(rxr->rxtag, rxbuf->map); + m_freem(rxbuf->m_head); + } + } + + /* Now replenish the mbufs */ + for (int j = 0; j != adapter->num_rx_desc; ++j) { + + rxbuf = &rxr->rx_buffers[j]; + rxbuf->m_head = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); + if (rxbuf->m_head == NULL) + panic("RX ring hdr initialization failed!\n"); + rxbuf->m_head->m_len = MCLBYTES; + rxbuf->m_head->m_flags &= ~M_HASFCS; /* we strip it */ + rxbuf->m_head->m_pkthdr.len = MCLBYTES; + + /* 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].buffer_addr = htole64(seg[0].ds_addr); + } + + + /* Setup our descriptor indices */ + rxr->next_to_check = 0; + rxr->next_to_refresh = 0; + + bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + EM_RX_UNLOCK(rxr); + return (0); +} + +/********************************************************************* + * + * Initialize all receive rings. * **********************************************************************/ static int em_setup_receive_structures(struct adapter *adapter) { - struct em_buffer *rx_buffer; - int i, error; + struct rx_ring *rxr = adapter->rx_rings; + int j; - /* Reset descriptor ring */ - bzero(adapter->rx_desc_base, - (sizeof(struct e1000_rx_desc)) * adapter->num_rx_desc); - - /* Free current RX buffers. */ - rx_buffer = adapter->rx_buffer_area; - for (i = 0; i < adapter->num_rx_desc; i++, rx_buffer++) { - if (rx_buffer->m_head != NULL) { - bus_dmamap_sync(adapter->rxtag, rx_buffer->map, - BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(adapter->rxtag, rx_buffer->map); - m_freem(rx_buffer->m_head); - rx_buffer->m_head = NULL; - } - } - - /* Allocate new ones. */ - for (i = 0; i < adapter->num_rx_desc; i++) { - error = em_get_buf(adapter, i); - if (error) - return (error); - } - - /* Setup our descriptor pointers */ - adapter->next_rx_desc_to_check = 0; - bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + for (j = 0; j < adapter->num_queues; j++, rxr++) + if (em_setup_receive_ring(rxr)) + goto fail; return (0); +fail: + /* + * Free RX buffers allocated so far, we will only handle + * the rings that completed, the failing case will have + * cleaned up for itself. 'j' failed, so its the terminus. + */ + for (int i = 0; i < j; ++i) { + rxr = &adapter->rx_rings[i]; + for (int n = 0; n < adapter->num_rx_desc; n++) { + struct em_buffer *rxbuf; + rxbuf = &rxr->rx_buffers[n]; + if (rxbuf->m_head != NULL) { + bus_dmamap_sync(rxr->rxtag, rxbuf->map, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(rxr->rxtag, rxbuf->map); + m_freem(rxbuf->m_head); + rxbuf->m_head = NULL; + } + } + } + + return (ENOBUFS); } +/********************************************************************* + * + * Free all receive rings. + * + **********************************************************************/ +static void +em_free_receive_structures(struct adapter *adapter) +{ + struct rx_ring *rxr = adapter->rx_rings; + + for (int i = 0; i < adapter->num_queues; i++, rxr++) { + em_free_receive_buffers(rxr); + /* Free the ring memory as well */ + em_dma_free(adapter, &rxr->rxdma); + EM_RX_LOCK_DESTROY(rxr); + } + + free(adapter->rx_rings, M_DEVBUF); +} + + +/********************************************************************* + * + * Free receive ring data structures + * + **********************************************************************/ +static void +em_free_receive_buffers(struct rx_ring *rxr) +{ + struct adapter *adapter = rxr->adapter; + struct em_buffer *rxbuf = NULL; + + INIT_DEBUGOUT("free_receive_buffers: begin"); + + if (rxr->rx_sparemap) { + bus_dmamap_destroy(rxr->rxtag, rxr->rx_sparemap); + rxr->rx_sparemap = NULL; + } + + if (rxr->rx_buffers != NULL) { + for (int i = 0; i < adapter->num_rx_desc; i++) { + rxbuf = &rxr->rx_buffers[i]; + if (rxbuf->map != NULL) { + bus_dmamap_sync(rxr->rxtag, rxbuf->map, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(rxr->rxtag, rxbuf->map); + bus_dmamap_destroy(rxr->rxtag, rxbuf->map); + } + if (rxbuf->m_head != NULL) { + m_freem(rxbuf->m_head); + rxbuf->m_head = NULL; + } + } + free(rxr->rx_buffers, M_DEVBUF); + rxr->rx_buffers = NULL; + } + + if (rxr->rxtag != NULL) { + bus_dma_tag_destroy(rxr->rxtag); + rxr->rxtag = NULL; + } + + return; +} + + /********************************************************************* * * Enable receive unit. @@ -4266,28 +3945,28 @@ em_setup_receive_structures(struct adapter *adapter) static void em_initialize_receive_unit(struct adapter *adapter) { + struct rx_ring *rxr = adapter->rx_rings; struct ifnet *ifp = adapter->ifp; + struct e1000_hw *hw = &adapter->hw; u64 bus_addr; u32 rctl, rxcsum; - INIT_DEBUGOUT("em_initialize_receive_unit: begin"); + INIT_DEBUGOUT("em_initialize_receive_units: begin"); /* * Make sure receives are disabled while setting * up the descriptor ring */ - rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL); - E1000_WRITE_REG(&adapter->hw, E1000_RCTL, rctl & ~E1000_RCTL_EN); + rctl = E1000_READ_REG(hw, E1000_RCTL); + E1000_WRITE_REG(hw, E1000_RCTL, rctl & ~E1000_RCTL_EN); - if (adapter->hw.mac.type >= e1000_82540) { - E1000_WRITE_REG(&adapter->hw, E1000_RADV, - adapter->rx_abs_int_delay.value); - /* - * Set the interrupt throttling rate. Value is calculated - * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) - */ - E1000_WRITE_REG(&adapter->hw, E1000_ITR, DEFAULT_ITR); - } + E1000_WRITE_REG(&adapter->hw, E1000_RADV, + adapter->rx_abs_int_delay.value); + /* + * Set the interrupt throttling rate. Value is calculated + * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) + */ + E1000_WRITE_REG(hw, E1000_ITR, DEFAULT_ITR); /* ** When using MSIX interrupts we need to throttle @@ -4295,67 +3974,17 @@ em_initialize_receive_unit(struct adapter *adapter) */ if (adapter->msix) for (int i = 0; i < 4; i++) - E1000_WRITE_REG(&adapter->hw, - E1000_EITR_82574(i), DEFAULT_ITR); + E1000_WRITE_REG(hw, E1000_EITR_82574(i), + DEFAULT_ITR); /* Disable accelerated ackknowledge */ if (adapter->hw.mac.type == e1000_82574) - E1000_WRITE_REG(&adapter->hw, - E1000_RFCTL, E1000_RFCTL_ACK_DIS); + E1000_WRITE_REG(hw, E1000_RFCTL, E1000_RFCTL_ACK_DIS); - /* Setup the Base and Length of the Rx Descriptor Ring */ - bus_addr = adapter->rxdma.dma_paddr; - E1000_WRITE_REG(&adapter->hw, E1000_RDLEN(0), - adapter->num_rx_desc * sizeof(struct e1000_rx_desc)); - E1000_WRITE_REG(&adapter->hw, E1000_RDBAH(0), - (u32)(bus_addr >> 32)); - E1000_WRITE_REG(&adapter->hw, E1000_RDBAL(0), - (u32)bus_addr); - - /* Setup the Receive Control Register */ - rctl &= ~(3 << E1000_RCTL_MO_SHIFT); - rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO | - E1000_RCTL_RDMTS_HALF | - (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT); - - /* Make sure VLAN Filters are off */ - rctl &= ~E1000_RCTL_VFE; - - if (e1000_tbi_sbp_enabled_82543(&adapter->hw)) - rctl |= E1000_RCTL_SBP; - else - rctl &= ~E1000_RCTL_SBP; - - switch (adapter->rx_buffer_len) { - default: - case 2048: - rctl |= E1000_RCTL_SZ_2048; - break; - case 4096: - rctl |= E1000_RCTL_SZ_4096 | - E1000_RCTL_BSEX | E1000_RCTL_LPE; - break; - case 8192: - rctl |= E1000_RCTL_SZ_8192 | - E1000_RCTL_BSEX | E1000_RCTL_LPE; - break; - case 16384: - rctl |= E1000_RCTL_SZ_16384 | - E1000_RCTL_BSEX | E1000_RCTL_LPE; - break; - } - - if (ifp->if_mtu > ETHERMTU) - rctl |= E1000_RCTL_LPE; - else - rctl &= ~E1000_RCTL_LPE; - - /* Enable 82543 Receive Checksum Offload for TCP and UDP */ - if ((adapter->hw.mac.type >= e1000_82543) && - (ifp->if_capenable & IFCAP_RXCSUM)) { - rxcsum = E1000_READ_REG(&adapter->hw, E1000_RXCSUM); + if (ifp->if_capenable & IFCAP_RXCSUM) { + rxcsum = E1000_READ_REG(hw, E1000_RXCSUM); rxcsum |= (E1000_RXCSUM_IPOFL | E1000_RXCSUM_TUOFL); - E1000_WRITE_REG(&adapter->hw, E1000_RXCSUM, rxcsum); + E1000_WRITE_REG(hw, E1000_RXCSUM, rxcsum); } /* @@ -4365,72 +3994,42 @@ em_initialize_receive_unit(struct adapter *adapter) ** values in RDTR is a known source of problems on other ** platforms another solution is being sought. */ - if (adapter->hw.mac.type == e1000_82573) - E1000_WRITE_REG(&adapter->hw, E1000_RDTR, 0x20); + if (hw->mac.type == e1000_82573) + E1000_WRITE_REG(hw, E1000_RDTR, 0x20); - /* Enable Receives */ - E1000_WRITE_REG(&adapter->hw, E1000_RCTL, rctl); + for (int i = 0; i < adapter->num_queues; i++, rxr++) { + /* Setup the Base and Length of the Rx Descriptor Ring */ + bus_addr = rxr->rxdma.dma_paddr; + E1000_WRITE_REG(hw, E1000_RDLEN(i), + adapter->num_rx_desc * sizeof(struct e1000_rx_desc)); + E1000_WRITE_REG(hw, E1000_RDBAH(i), (u32)(bus_addr >> 32)); + E1000_WRITE_REG(hw, E1000_RDBAL(i), (u32)bus_addr); + /* Setup the Head and Tail Descriptor Pointers */ + E1000_WRITE_REG(hw, E1000_RDH(i), 0); + E1000_WRITE_REG(hw, E1000_RDT(i), adapter->num_rx_desc - 1); + } - /* - * Setup the HW Rx Head and - * Tail Descriptor Pointers - */ - E1000_WRITE_REG(&adapter->hw, E1000_RDH(0), 0); - E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), adapter->num_rx_desc - 1); + /* Setup the Receive Control Register */ + rctl &= ~(3 << E1000_RCTL_MO_SHIFT); + rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | + E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | + (hw->mac.mc_filter_type << E1000_RCTL_MO_SHIFT); + + /* Make sure VLAN Filters are off */ + rctl &= ~E1000_RCTL_VFE; + rctl &= ~E1000_RCTL_SBP; + rctl |= E1000_RCTL_SZ_2048; + if (ifp->if_mtu > ETHERMTU) + rctl |= E1000_RCTL_LPE; + else + rctl &= ~E1000_RCTL_LPE; + + /* Write out the settings */ + E1000_WRITE_REG(hw, E1000_RCTL, rctl); return; } -/********************************************************************* - * - * Free receive related data structures. - * - **********************************************************************/ -static void -em_free_receive_structures(struct adapter *adapter) -{ - struct em_buffer *rx_buffer; - int i; - - INIT_DEBUGOUT("free_receive_structures: begin"); - - if (adapter->rx_sparemap) { - bus_dmamap_destroy(adapter->rxtag, adapter->rx_sparemap); - adapter->rx_sparemap = NULL; - } - - /* Cleanup any existing buffers */ - if (adapter->rx_buffer_area != NULL) { - rx_buffer = adapter->rx_buffer_area; - for (i = 0; i < adapter->num_rx_desc; i++, rx_buffer++) { - if (rx_buffer->m_head != NULL) { - bus_dmamap_sync(adapter->rxtag, rx_buffer->map, - BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(adapter->rxtag, - rx_buffer->map); - m_freem(rx_buffer->m_head); - rx_buffer->m_head = NULL; - } else if (rx_buffer->map != NULL) - bus_dmamap_unload(adapter->rxtag, - rx_buffer->map); - if (rx_buffer->map != NULL) { - bus_dmamap_destroy(adapter->rxtag, - rx_buffer->map); - rx_buffer->map = NULL; - } - } - } - - if (adapter->rx_buffer_area != NULL) { - free(adapter->rx_buffer_area, M_DEVBUF); - adapter->rx_buffer_area = NULL; - } - - if (adapter->rxtag != NULL) { - bus_dma_tag_destroy(adapter->rxtag); - adapter->rxtag = NULL; - } -} /********************************************************************* * @@ -4444,184 +4043,127 @@ em_free_receive_structures(struct adapter *adapter) * For polling we also now return the number of cleaned packets *********************************************************************/ static int -em_rxeof(struct adapter *adapter, int count) +em_rxeof(struct rx_ring *rxr, int count) { - struct ifnet *ifp = adapter->ifp; - struct mbuf *mp; - u8 status, accept_frame = 0, eop = 0; - u16 len, desc_len, prev_len_adj; - int i, rx_sent = 0; - struct e1000_rx_desc *current_desc; + struct adapter *adapter = rxr->adapter; + struct ifnet *ifp = adapter->ifp;; + struct mbuf *mp, *sendmp; + u8 status; + u16 len; + int i, processed, rxdone = 0; + bool eop; + struct e1000_rx_desc *cur; - EM_RX_LOCK(adapter); - i = adapter->next_rx_desc_to_check; - current_desc = &adapter->rx_desc_base[i]; - bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map, - BUS_DMASYNC_POSTREAD); + EM_RX_LOCK(rxr); - if (!((current_desc->status) & E1000_RXD_STAT_DD)) { - EM_RX_UNLOCK(adapter); - return (rx_sent); - } + for (i = rxr->next_to_check, processed = 0; count != 0;) { - while ((current_desc->status & E1000_RXD_STAT_DD) && - (count != 0) && - (ifp->if_drv_flags & IFF_DRV_RUNNING)) { - struct mbuf *m = NULL; + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + break; - mp = adapter->rx_buffer_area[i].m_head; - /* - * Can't defer bus_dmamap_sync(9) because TBI_ACCEPT - * needs to access the last received byte in the mbuf. - */ - bus_dmamap_sync(adapter->rxtag, adapter->rx_buffer_area[i].map, - BUS_DMASYNC_POSTREAD); + bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); - accept_frame = 1; - prev_len_adj = 0; - desc_len = le16toh(current_desc->length); - status = current_desc->status; - if (status & E1000_RXD_STAT_EOP) { - count--; - eop = 1; - if (desc_len < ETHER_CRC_LEN) { - len = 0; - prev_len_adj = ETHER_CRC_LEN - desc_len; - } else - len = desc_len - ETHER_CRC_LEN; - } else { - eop = 0; - len = desc_len; - } + cur = &rxr->rx_base[i]; + status = cur->status; + mp = sendmp = NULL; - if (current_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) { - u8 last_byte; - u32 pkt_len = desc_len; + if ((status & E1000_RXD_STAT_DD) == 0) + break; - if (adapter->fmp != NULL) - pkt_len += adapter->fmp->m_pkthdr.len; + len = le16toh(cur->length); + eop = (status & E1000_RXD_STAT_EOP) != 0; + count--; - last_byte = *(mtod(mp, caddr_t) + desc_len - 1); - if (TBI_ACCEPT(&adapter->hw, status, - current_desc->errors, pkt_len, last_byte, - adapter->min_frame_size, adapter->max_frame_size)) { - e1000_tbi_adjust_stats_82543(&adapter->hw, - &adapter->stats, pkt_len, - adapter->hw.mac.addr, - adapter->max_frame_size); - if (len > 0) - len--; - } else - accept_frame = 0; - } - - if (accept_frame) { - if (em_get_buf(adapter, i) != 0) { - ifp->if_iqdrops++; - goto discard; - } + if ((cur->errors & E1000_RXD_ERR_FRAME_ERR_MASK) == 0) { /* Assign correct length to the current fragment */ + mp = rxr->rx_buffers[i].m_head; mp->m_len = len; - if (adapter->fmp == NULL) { + if (rxr->fmp == NULL) { mp->m_pkthdr.len = len; - adapter->fmp = mp; /* Store the first mbuf */ - adapter->lmp = mp; + rxr->fmp = mp; /* Store the first mbuf */ + rxr->lmp = mp; } else { /* Chain mbuf's together */ mp->m_flags &= ~M_PKTHDR; - /* - * Adjust length of previous mbuf in chain if - * we received less than 4 bytes in the last - * descriptor. - */ - if (prev_len_adj > 0) { - adapter->lmp->m_len -= prev_len_adj; - adapter->fmp->m_pkthdr.len -= - prev_len_adj; - } - adapter->lmp->m_next = mp; - adapter->lmp = adapter->lmp->m_next; - adapter->fmp->m_pkthdr.len += len; + rxr->lmp->m_next = mp; + rxr->lmp = rxr->lmp->m_next; + rxr->fmp->m_pkthdr.len += len; } if (eop) { - adapter->fmp->m_pkthdr.rcvif = ifp; + rxr->fmp->m_pkthdr.rcvif = ifp; ifp->if_ipackets++; - em_receive_checksum(adapter, current_desc, - adapter->fmp); + em_receive_checksum(cur, rxr->fmp); #ifndef __NO_STRICT_ALIGNMENT if (adapter->max_frame_size > (MCLBYTES - ETHER_ALIGN) && - em_fixup_rx(adapter) != 0) + em_fixup_rx(rxr) != 0) goto skip; #endif if (status & E1000_RXD_STAT_VP) { -#if __FreeBSD_version < 700000 - VLAN_INPUT_TAG_NEW(ifp, adapter->fmp, - (le16toh(current_desc->special) & - E1000_RXD_SPC_VLAN_MASK)); -#else - adapter->fmp->m_pkthdr.ether_vtag = - (le16toh(current_desc->special) & + rxr->fmp->m_pkthdr.ether_vtag = + (le16toh(cur->special) & E1000_RXD_SPC_VLAN_MASK); - adapter->fmp->m_flags |= M_VLANTAG; -#endif + rxr->fmp->m_flags |= M_VLANTAG; } #ifndef __NO_STRICT_ALIGNMENT skip: #endif - m = adapter->fmp; - adapter->fmp = NULL; - adapter->lmp = NULL; + sendmp = rxr->fmp; + rxr->fmp = NULL; + rxr->lmp = NULL; } } else { ifp->if_ierrors++; -discard: /* Reuse loaded DMA map and just update mbuf chain */ - mp = adapter->rx_buffer_area[i].m_head; + mp = rxr->rx_buffers[i].m_head; mp->m_len = mp->m_pkthdr.len = MCLBYTES; mp->m_data = mp->m_ext.ext_buf; mp->m_next = NULL; if (adapter->max_frame_size <= (MCLBYTES - ETHER_ALIGN)) m_adj(mp, ETHER_ALIGN); - if (adapter->fmp != NULL) { - m_freem(adapter->fmp); - adapter->fmp = NULL; - adapter->lmp = NULL; + if (rxr->fmp != NULL) { + m_freem(rxr->fmp); + rxr->fmp = NULL; + rxr->lmp = NULL; } - m = NULL; + sendmp = NULL; } /* Zero out the receive descriptors status. */ - current_desc->status = 0; - bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + cur->status = 0; + ++rxdone; /* cumulative for POLL */ + ++processed; /* Advance our pointers to the next descriptor. */ if (++i == adapter->num_rx_desc) i = 0; - /* Call into the stack */ - if (m != NULL) { - adapter->next_rx_desc_to_check = i; - EM_RX_UNLOCK(adapter); - (*ifp->if_input)(ifp, m); - EM_RX_LOCK(adapter); - rx_sent++; - i = adapter->next_rx_desc_to_check; - } - current_desc = &adapter->rx_desc_base[i]; - } - adapter->next_rx_desc_to_check = i; - /* Advance the E1000's Receive Queue #0 "Tail Pointer". */ - if (--i < 0) - i = adapter->num_rx_desc - 1; - E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), i); - EM_RX_UNLOCK(adapter); - return (rx_sent); + /* Send to the stack */ + if (sendmp != NULL) + (*ifp->if_input)(ifp, sendmp); + + /* Only refresh mbufs every 8 descriptors */ + if (processed == 8) { + em_refresh_mbufs(rxr, i); + processed = 0; + } + } + + /* Catch any remaining refresh work */ + if (processed != 0) { + em_refresh_mbufs(rxr, i); + processed = 0; + } + + rxr->next_to_check = i; + + EM_RX_UNLOCK(rxr); + return (rxdone); } #ifndef __NO_STRICT_ALIGNMENT @@ -4640,13 +4182,14 @@ em_rxeof(struct adapter *adapter, int count) * not used at all on architectures with strict alignment. */ static int -em_fixup_rx(struct adapter *adapter) +em_fixup_rx(struct rx_ring *rxr) { + struct adapter *adapter = rxr->adapter; struct mbuf *m, *n; int error; error = 0; - m = adapter->fmp; + m = rxr->fmp; if (m->m_len <= (MCLBYTES - ETHER_HDR_LEN)) { bcopy(m->m_data, m->m_data + ETHER_HDR_LEN, m->m_len); m->m_data += ETHER_HDR_LEN; @@ -4659,11 +4202,11 @@ em_fixup_rx(struct adapter *adapter) n->m_len = ETHER_HDR_LEN; M_MOVE_PKTHDR(n, m); n->m_next = m; - adapter->fmp = n; + rxr->fmp = n; } else { adapter->dropped_pkts++; - m_freem(adapter->fmp); - adapter->fmp = NULL; + m_freem(rxr->fmp); + rxr->fmp = NULL; error = ENOMEM; } } @@ -4680,13 +4223,10 @@ em_fixup_rx(struct adapter *adapter) * *********************************************************************/ static void -em_receive_checksum(struct adapter *adapter, - struct e1000_rx_desc *rx_desc, struct mbuf *mp) +em_receive_checksum(struct e1000_rx_desc *rx_desc, struct mbuf *mp) { - /* 82543 or newer only */ - if ((adapter->hw.mac.type < e1000_82543) || - /* Ignore Checksum bit is set */ - (rx_desc->status & E1000_RXD_STAT_IXSM)) { + /* Ignore Checksum bit is set */ + if (rx_desc->status & E1000_RXD_STAT_IXSM) { mp->m_pkthdr.csum_flags = 0; return; } @@ -4713,7 +4253,6 @@ em_receive_checksum(struct adapter *adapter, } } -#if __FreeBSD_version >= 700029 /* * This routine is run via an vlan * config EVENT @@ -4800,7 +4339,6 @@ em_setup_vlan_hw_support(struct adapter *adapter) E1000_WRITE_REG(&adapter->hw, E1000_RLPML, adapter->max_frame_size + VLAN_TAG_SIZE); } -#endif static void em_enable_intr(struct adapter *adapter) @@ -4843,15 +4381,12 @@ em_init_manageability(struct adapter *adapter) manc &= ~(E1000_MANC_ARP_EN); /* enable receiving management packets to the host */ - if (adapter->hw.mac.type >= e1000_82571) { - manc |= E1000_MANC_EN_MNG2HOST; + manc |= E1000_MANC_EN_MNG2HOST; #define E1000_MNG2HOST_PORT_623 (1 << 5) #define E1000_MNG2HOST_PORT_664 (1 << 6) - manc2h |= E1000_MNG2HOST_PORT_623; - manc2h |= E1000_MNG2HOST_PORT_664; - E1000_WRITE_REG(&adapter->hw, E1000_MANC2H, manc2h); - } - + manc2h |= E1000_MNG2HOST_PORT_623; + manc2h |= E1000_MNG2HOST_PORT_664; + E1000_WRITE_REG(&adapter->hw, E1000_MANC2H, manc2h); E1000_WRITE_REG(&adapter->hw, E1000_MANC, manc); } } @@ -4868,81 +4403,61 @@ em_release_manageability(struct adapter *adapter) /* re-enable hardware interception of ARP */ manc |= E1000_MANC_ARP_EN; - - if (adapter->hw.mac.type >= e1000_82571) - manc &= ~E1000_MANC_EN_MNG2HOST; + manc &= ~E1000_MANC_EN_MNG2HOST; E1000_WRITE_REG(&adapter->hw, E1000_MANC, manc); } } /* - * 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,83 +4473,248 @@ em_is_valid_ether_addr(u8 *addr) } /* - * Enable PCI Wake On Lan capability - */ -void -em_enable_wakeup(device_t dev) +** 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) { - u16 cap, status; - u8 id; + struct adapter *adapter = device_get_softc(dev); + u16 eeprom_data = 0, device_id, apme_mask; - /* 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 */ - 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); + adapter->has_manage = e1000_enable_mng_pass_thru(&adapter->hw); + apme_mask = EM_EEPROM_APME; + + switch (adapter->hw.mac.type) { + case e1000_82573: + case e1000_82583: + adapter->has_amt = TRUE; + /* Falls thru */ + 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_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_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; } -/********************************************************************* -* 82544 Coexistence issue workaround. -* There are 2 issues. -* 1. Transmit Hang issue. -* To detect this issue, following equation can be used... -* SIZE[3:0] + ADDR[2:0] = SUM[3:0]. -* If SUM[3:0] is in between 1 to 4, we will have this issue. -* -* 2. DAC issue. -* To detect this issue, following equation can be used... -* SIZE[3:0] + ADDR[2:0] = SUM[3:0]. -* If SUM[3:0] is in between 9 to c, we will have this issue. -* -* -* WORKAROUND: -* Make sure we do not have ending address -* as 1,2,3,4(Hang) or 9,a,b,c (DAC) -* -*************************************************************************/ -static u32 -em_fill_descriptors (bus_addr_t address, u32 length, - PDESC_ARRAY desc_array) +/* + * Enable PCI Wake On Lan capability + */ +static void +em_enable_wakeup(device_t dev) { - u32 safe_terminator; + struct adapter *adapter = device_get_softc(dev); + struct ifnet *ifp = adapter->ifp; + u32 pmc, ctrl, ctrl_ext, rctl; + u16 status; - /* Since issue is sensitive to length and address.*/ - /* Let us first check the address...*/ - if (length <= 4) { - desc_array->descriptor[0].address = address; - desc_array->descriptor[0].length = length; - desc_array->elements = 1; - return (desc_array->elements); - } - safe_terminator = (u32)((((u32)address & 0x7) + - (length & 0xF)) & 0xF); - /* if it does not fall between 0x1 to 0x4 and 0x9 to 0xC then return */ - if (safe_terminator == 0 || - (safe_terminator > 4 && - safe_terminator < 9) || - (safe_terminator > 0xC && - safe_terminator <= 0xF)) { - desc_array->descriptor[0].address = address; - desc_array->descriptor[0].length = length; - desc_array->elements = 1; - return (desc_array->elements); + if ((pci_find_extcap(dev, PCIY_PMG, &pmc) != 0)) + return; + + /* 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); + + 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); } - desc_array->descriptor[0].address = address; - desc_array->descriptor[0].length = length - 4; - desc_array->descriptor[1].address = address + (length - 4); - desc_array->descriptor[1].length = 4; - desc_array->elements = 2; - return (desc_array->elements); + /* 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; +} + +static void +em_led_func(void *arg, int onoff) +{ + struct adapter *adapter = arg; + + EM_CORE_LOCK(adapter); + if (onoff) { + e1000_setup_led(&adapter->hw); + e1000_led_on(&adapter->hw); + } else { + e1000_led_off(&adapter->hw); + e1000_cleanup_led(&adapter->hw); + } + EM_CORE_UNLOCK(adapter); } /********************************************************************** @@ -5146,6 +4826,8 @@ em_print_debug_info(struct adapter *adapter) { device_t dev = adapter->dev; u8 *hw_addr = adapter->hw.hw_addr; + struct rx_ring *rxr = adapter->rx_rings; + struct tx_ring *txr = adapter->tx_rings; device_printf(dev, "Adapter hardware address = %p \n", hw_addr); device_printf(dev, "CTRL = 0x%x RCTL = 0x%x \n", @@ -5163,29 +4845,33 @@ em_print_debug_info(struct adapter *adapter) device_printf(dev, "rx_int_delay = %d, rx_abs_int_delay = %d\n", E1000_READ_REG(&adapter->hw, E1000_RDTR), E1000_READ_REG(&adapter->hw, E1000_RADV)); - device_printf(dev, "fifo workaround = %lld, fifo_reset_count = %lld\n", - (long long)adapter->tx_fifo_wrk_cnt, - (long long)adapter->tx_fifo_reset_cnt); - device_printf(dev, "hw tdh = %d, hw tdt = %d\n", - E1000_READ_REG(&adapter->hw, E1000_TDH(0)), - E1000_READ_REG(&adapter->hw, E1000_TDT(0))); - device_printf(dev, "hw rdh = %d, hw rdt = %d\n", - E1000_READ_REG(&adapter->hw, E1000_RDH(0)), - E1000_READ_REG(&adapter->hw, E1000_RDT(0))); - device_printf(dev, "Num Tx descriptors avail = %d\n", - adapter->num_tx_desc_avail); - device_printf(dev, "Tx Descriptors not avail1 = %ld\n", - adapter->no_tx_desc_avail1); - device_printf(dev, "Tx Descriptors not avail2 = %ld\n", - adapter->no_tx_desc_avail2); + + for (int i = 0; i < adapter->num_queues; i++, txr++) { + device_printf(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(dev, "TX(%d) no descriptors avail event = %ld\n", + txr->me, txr->no_desc_avail); + device_printf(dev, "TX(%d) MSIX IRQ Handled = %ld\n", + txr->me, txr->tx_irq); + device_printf(dev, "Num Tx descriptors avail = %d\n", + txr->tx_avail); + device_printf(dev, "Tx Descriptors not avail1 = %ld\n", + txr->no_desc_avail); + } + for (int i = 0; i < adapter->num_queues; i++, rxr++) { + device_printf(dev, "RX(%d) MSIX IRQ Handled = %ld\n", + rxr->me, rxr->rx_irq); + device_printf(dev, "hw rdh = %d, hw rdt = %d\n", + E1000_READ_REG(&adapter->hw, E1000_RDH(i)), + E1000_READ_REG(&adapter->hw, E1000_RDT(i))); + } device_printf(dev, "Std mbuf failed = %ld\n", adapter->mbuf_alloc_failed); device_printf(dev, "Std mbuf cluster failed = %ld\n", adapter->mbuf_cluster_failed); device_printf(dev, "Driver dropped packets = %ld\n", adapter->dropped_pkts); - device_printf(dev, "Driver tx dma failure in encap = %ld\n", - adapter->no_tx_dma_setup); } static void @@ -5218,12 +4904,8 @@ em_print_hw_stats(struct adapter *adapter) (long long)adapter->stats.algnerrc); device_printf(dev, "Collision/Carrier extension errors = %lld\n", (long long)adapter->stats.cexterr); - device_printf(dev, "RX overruns = %ld\n", adapter->rx_overruns); device_printf(dev, "watchdog timeouts = %ld\n", adapter->watchdog_events); - device_printf(dev, "RX MSIX IRQ = %ld TX MSIX IRQ = %ld" - " LINK MSIX IRQ = %ld\n", adapter->rx_irq, - adapter->tx_irq , adapter->link_irq); device_printf(dev, "XON Rcvd = %lld\n", (long long)adapter->stats.xonrxc); device_printf(dev, "XON Xmtd = %lld\n", @@ -5327,9 +5009,7 @@ em_sysctl_int_delay(SYSCTL_HANDLER_ARGS) struct em_int_delay_info *info; struct adapter *adapter; u32 regval; - int error; - int usecs; - int ticks; + int error, usecs, ticks; info = (struct em_int_delay_info *)arg1; usecs = info->value; @@ -5378,7 +5058,6 @@ em_add_int_delay_sysctl(struct adapter *adapter, const char *name, info, 0, em_sysctl_int_delay, "I", description); } -#ifndef EM_LEGACY_IRQ static void em_add_rx_process_limit(struct adapter *adapter, const char *name, const char *description, int *limit, int value) @@ -5388,6 +5067,5 @@ em_add_rx_process_limit(struct adapter *adapter, const char *name, SYSCTL_CHILDREN(device_get_sysctl_tree(adapter->dev)), OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW, limit, value, description); } -#endif diff --git a/sys/dev/e1000/if_em.h b/sys/dev/e1000/if_em.h index 7487a89e0d0b..96d217b420d3 100644 --- a/sys/dev/e1000/if_em.h +++ b/sys/dev/e1000/if_em.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -52,9 +52,8 @@ * (num_tx_desc * sizeof(struct e1000_tx_desc)) % 128 == 0 */ #define EM_MIN_TXD 80 -#define EM_MAX_TXD_82543 256 #define EM_MAX_TXD 4096 -#define EM_DEFAULT_TXD EM_MAX_TXD_82543 +#define EM_DEFAULT_TXD 1024 /* * EM_RXD - Maximum number of receive Descriptors @@ -70,9 +69,8 @@ * (num_tx_desc * sizeof(struct e1000_tx_desc)) % 128 == 0 */ #define EM_MIN_RXD 80 -#define EM_MAX_RXD_82543 256 #define EM_MAX_RXD 4096 -#define EM_DEFAULT_RXD EM_MAX_RXD_82543 +#define EM_DEFAULT_RXD 1024 /* * EM_TIDV - Transmit Interrupt Delay Value @@ -135,16 +133,15 @@ #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 (10 * hz) /* * This parameter controls when the driver calls the routine to reclaim * transmit descriptors. */ #define EM_TX_CLEANUP_THRESHOLD (adapter->num_tx_desc / 8) -#define EM_TX_OP_THRESHOLD (adapter->num_tx_desc / 32) /* * This parameter controls whether or not autonegotation is enabled. @@ -182,18 +179,14 @@ #define EM_DEFAULT_PBA 0x00000030 #define EM_SMARTSPEED_DOWNSHIFT 3 #define EM_SMARTSPEED_MAX 15 -#define EM_MAX_INTR 10 +#define EM_MAX_LOOP 10 #define MAX_NUM_MULTICAST_ADDRESSES 128 #define PCI_ANY_ID (~0U) #define ETHER_ALIGN 2 #define EM_FC_PAUSE_TIME 0x0680 #define EM_EEPROM_APME 0x400; - -/* Code compatilbility between 6 and 7 */ -#ifndef ETHER_BPF_MTAP -#define ETHER_BPF_MTAP BPF_MTAP -#endif +#define EM_82544_APME 0x0004; /* * TDBA/RDBA should be aligned on 16 byte boundary. But TDLEN/RDLEN should be @@ -208,7 +201,6 @@ #define EM_BAR_TYPE(v) ((v) & EM_BAR_TYPE_MASK) #define EM_BAR_TYPE_MASK 0x00000001 #define EM_BAR_TYPE_MMEM 0x00000000 -#define EM_BAR_TYPE_IO 0x00000001 #define EM_BAR_TYPE_FLASH 0x0014 #define EM_BAR_MEM_TYPE(v) ((v) & EM_BAR_MEM_TYPE_MASK) #define EM_BAR_MEM_TYPE_MASK 0x00000006 @@ -236,6 +228,7 @@ #define EM_TSO_SIZE (65535 + sizeof(struct ether_vlan_header)) #define EM_TSO_SEG_SIZE 4096 /* Max dma segment size */ #define EM_MSIX_MASK 0x01F00000 /* For 82574 use */ +#define EM_MSIX_LINK 0x01000000 /* For 82574 use */ #define ETH_ZLEN 60 #define ETH_ADDR_LEN 6 #define CSUM_OFFLOAD 7 /* Offload bits in mbuf flag */ @@ -248,18 +241,6 @@ */ #define EM_EIAC 0x000DC -/* Used in for 82547 10Mb Half workaround */ -#define EM_PBA_BYTES_SHIFT 0xA -#define EM_TX_HEAD_ADDR_SHIFT 7 -#define EM_PBA_TX_MASK 0xFFFF0000 -#define EM_FIFO_HDR 0x10 -#define EM_82547_PKT_THRESH 0x3e0 - -/* Precision Time Sync (IEEE 1588) defines */ -#define ETHERTYPE_IEEE1588 0x88F7 -#define PICOSECS_PER_TICK 20833 -#define TSYNC_PORT 319 /* UDP port for the protocol */ - /* * Bus dma allocation structure used by * e1000_dma_malloc and e1000_dma_free. @@ -281,59 +262,134 @@ struct em_int_delay_info { int value; /* Current value in usecs */ }; +/* + * The transmit ring, one per tx queue + */ +struct tx_ring { + struct adapter *adapter; + struct mtx tx_mtx; + char mtx_name[16]; + u32 me; + u32 msix; + u32 ims; + bool watchdog_check; + int watchdog_time; + struct em_dma_alloc txdma; + struct e1000_tx_desc *tx_base; + struct task tx_task; + struct taskqueue *tq; + u32 next_avail_desc; + u32 next_to_clean; + struct em_buffer *tx_buffers; + volatile u16 tx_avail; + u32 tx_tso; /* last tx was tso */ + u16 last_hw_offload; +#if __FreeBSD_version >= 800000 + struct buf_ring *br; +#endif + /* Interrupt resources */ + bus_dma_tag_t txtag; + void *tag; + struct resource *res; + unsigned long tx_irq; + unsigned long no_desc_avail; +}; + +/* + * The Receive ring, one per rx queue + */ +struct rx_ring { + struct adapter *adapter; + u32 me; + u32 msix; + u32 ims; + struct mtx rx_mtx; + char mtx_name[16]; + u32 payload; + struct task rx_task; + struct taskqueue *tq; + struct e1000_rx_desc *rx_base; + struct em_dma_alloc rxdma; + u32 next_to_refresh; + u32 next_to_check; + struct em_buffer *rx_buffers; + struct mbuf *fmp; + struct mbuf *lmp; + + /* Interrupt resources */ + void *tag; + struct resource *res; + bus_dma_tag_t rxtag; + bus_dmamap_t rx_sparemap; + + /* Soft stats */ + unsigned long rx_irq; + unsigned long rx_packets; + unsigned long rx_bytes; +}; + + /* Our adapter structure */ struct adapter { struct ifnet *ifp; -#if __FreeBSD_version >= 800000 - struct buf_ring *br; -#endif struct e1000_hw hw; /* FreeBSD operating-system-specific structures. */ struct e1000_osdep osdep; struct device *dev; + struct cdev *led_dev; struct resource *memory; struct resource *flash; - struct resource *msix; + struct resource *msix_mem; - struct resource *ioport; - int io_rid; - - /* 82574 may use 3 int vectors */ - struct resource *res[3]; - void *tag[3]; - int rid[3]; + struct resource *res; + void *tag; + u32 linkvec; + u32 ivars; struct ifmedia media; struct callout timer; - struct callout tx_fifo_timer; - int watchdog_timer; - int msi; + int msix; int if_flags; int max_frame_size; int min_frame_size; struct mtx core_mtx; - struct mtx tx_mtx; - struct mtx rx_mtx; int em_insert_vlan_header; + u32 ims; + bool in_detach; /* Task for FAST handling */ struct task link_task; - struct task rxtx_task; - struct task rx_task; - struct task tx_task; + struct task que_task; struct taskqueue *tq; /* private task queue */ -#if __FreeBSD_version >= 700029 eventhandler_tag vlan_attach; eventhandler_tag vlan_detach; - u32 num_vlans; -#endif + + u16 num_vlans; + u16 num_queues; + + /* + * Transmit rings: + * Allocated at run time, an array of rings. + */ + struct tx_ring *tx_rings; + int num_tx_desc; + u32 txd_cmd; + + /* + * Receive rings: + * Allocated at run time, an array of rings. + */ + struct rx_ring *rx_rings; + int num_rx_desc; + u32 rx_process_limit; /* 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; @@ -345,89 +401,26 @@ struct adapter { struct em_int_delay_info rx_int_delay; struct em_int_delay_info rx_abs_int_delay; - /* - * Transmit definitions - * - * We have an array of num_tx_desc descriptors (handled - * by the controller) paired with an array of tx_buffers - * (at tx_buffer_area). - * The index of the next available descriptor is next_avail_tx_desc. - * The number of remaining tx_desc is num_tx_desc_avail. - */ - struct em_dma_alloc txdma; /* bus_dma glue for tx desc */ - struct e1000_tx_desc *tx_desc_base; - uint32_t next_avail_tx_desc; - uint32_t next_tx_to_clean; - volatile uint16_t num_tx_desc_avail; - uint16_t num_tx_desc; - uint16_t last_hw_offload; - uint32_t txd_cmd; - struct em_buffer *tx_buffer_area; - bus_dma_tag_t txtag; /* dma tag for tx */ - uint32_t tx_tso; /* last tx was tso */ - - /* - * Receive definitions - * - * we have an array of num_rx_desc rx_desc (handled by the - * controller), and paired with an array of rx_buffers - * (at rx_buffer_area). - * The next pair to check on receive is at offset next_rx_desc_to_check - */ - struct em_dma_alloc rxdma; /* bus_dma glue for rx desc */ - struct e1000_rx_desc *rx_desc_base; - uint32_t next_rx_desc_to_check; - uint32_t rx_buffer_len; - uint16_t num_rx_desc; - int rx_process_limit; - struct em_buffer *rx_buffer_area; - bus_dma_tag_t rxtag; - bus_dmamap_t rx_sparemap; - - /* - * First/last mbuf pointers, for - * collecting multisegment RX packets. - */ - struct mbuf *fmp; - struct mbuf *lmp; - /* Misc stats maintained by the driver */ unsigned long dropped_pkts; unsigned long mbuf_alloc_failed; unsigned long mbuf_cluster_failed; - unsigned long no_tx_desc_avail1; - unsigned long no_tx_desc_avail2; unsigned long no_tx_map_avail; unsigned long no_tx_dma_setup; - unsigned long watchdog_events; unsigned long rx_overruns; - unsigned long rx_irq; - unsigned long tx_irq; + unsigned long watchdog_events; unsigned long link_irq; - /* 82547 workaround */ - uint32_t tx_fifo_size; - uint32_t tx_fifo_head; - uint32_t tx_fifo_head_addr; - uint64_t tx_fifo_reset_cnt; - uint64_t tx_fifo_wrk_cnt; - uint32_t tx_head_addr; - - /* For 82544 PCIX Workaround */ - boolean_t pcix_82544; - boolean_t in_detach; - - struct e1000_hw_stats stats; }; -/* ****************************************************************************** +/******************************************************************************** * vendor_info_array * * This array contains the list of Subvendor/Subdevice IDs on which the driver * should load. * - * ******************************************************************************/ + ********************************************************************************/ typedef struct _em_vendor_info_t { unsigned int vendor_id; unsigned int device_id; @@ -442,19 +435,6 @@ struct em_buffer { bus_dmamap_t map; /* bus_dma map for packet */ }; -/* For 82544 PCIX Workaround */ -typedef struct _ADDRESS_LENGTH_PAIR -{ - uint64_t address; - uint32_t length; -} ADDRESS_LENGTH_PAIR, *PADDRESS_LENGTH_PAIR; - -typedef struct _DESCRIPTOR_PAIR -{ - ADDRESS_LENGTH_PAIR descriptor[4]; - uint32_t elements; -} DESC_ARRAY, *PDESC_ARRAY; - #define EM_CORE_LOCK_INIT(_sc, _name) \ mtx_init(&(_sc)->core_mtx, _name, "EM Core Lock", MTX_DEF) #define EM_TX_LOCK_INIT(_sc, _name) \ diff --git a/sys/dev/e1000/if_igb.c b/sys/dev/e1000/if_igb.c index 8b3290a3f77d..5fdd52c163b6 100644 --- a/sys/dev/e1000/if_igb.c +++ b/sys/dev/e1000/if_igb.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -36,6 +36,7 @@ #ifdef HAVE_KERNEL_OPTION_HEADERS #include "opt_device_polling.h" #include "opt_inet.h" +#include "opt_altq.h" #endif #include @@ -62,10 +63,6 @@ #include #include -#ifdef IGB_IEEE1588 -#include -#endif - #include #include #include @@ -86,6 +83,7 @@ #include #include +#include #include #include @@ -101,7 +99,7 @@ int igb_display_debug_stats = 0; /********************************************************************* * Driver version: *********************************************************************/ -char igb_driver_version[] = "version - 1.7.3"; +char igb_driver_version[] = "version - 1.9.3"; /********************************************************************* @@ -123,12 +121,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 +164,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 +176,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 *); @@ -190,13 +194,19 @@ static int igb_setup_receive_ring(struct rx_ring *); static void igb_initialize_receive_units(struct adapter *); static void igb_free_receive_structures(struct adapter *); static void igb_free_receive_buffers(struct rx_ring *); +static void igb_free_receive_ring(struct rx_ring *); static void igb_enable_intr(struct adapter *); static void igb_disable_intr(struct adapter *); static void igb_update_stats_counters(struct adapter *); static bool igb_txeof(struct tx_ring *); -static bool igb_rxeof(struct rx_ring *, int); -static void igb_rx_checksum(u32, struct mbuf *, bool); + +static __inline void igb_rx_discard(struct rx_ring *, int); +static __inline void igb_rx_input(struct rx_ring *, + struct ifnet *, struct mbuf *, u32); + +static bool igb_rxeof(struct igb_queue *, int); +static void igb_rx_checksum(u32, struct mbuf *, u32); static int igb_tx_ctx_setup(struct tx_ring *, struct mbuf *); static bool igb_tso_setup(struct tx_ring *, struct mbuf *, u32 *); static void igb_set_promisc(struct adapter *); @@ -204,7 +214,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 void igb_refresh_mbufs(struct rx_ring *, int); static void igb_register_vlan(void *, struct ifnet *, u16); static void igb_unregister_vlan(void *, struct ifnet *, u16); @@ -225,21 +235,22 @@ static void igb_release_manageability(struct adapter *); static void igb_get_hw_control(struct adapter *); static void igb_release_hw_control(struct adapter *); static void igb_enable_wakeup(device_t); +static void igb_led_func(void *, int); static int igb_irq_fast(void *); static void igb_add_rx_process_limit(struct adapter *, const char *, const char *, int *, int); static void igb_handle_rxtx(void *context, int pending); -static void igb_handle_tx(void *context, int pending); -static void igb_handle_rx(void *context, int pending); +static void igb_handle_que(void *context, int pending); +static void igb_handle_link(void *context, int pending); /* These are MSIX only irq handlers */ -static void igb_msix_rx(void *); -static void igb_msix_tx(void *); +static void igb_msix_que(void *); static void igb_msix_link(void *); -/* Adaptive Interrupt Moderation */ -static void igb_update_aim(struct rx_ring *); +#ifdef DEVICE_POLLING +static poll_handler_t igb_poll; +#endif /* POLLING */ /********************************************************************* * FreeBSD Device Interface Entry Points @@ -276,31 +287,35 @@ TUNABLE_INT("hw.igb.rxd", &igb_rxd); TUNABLE_INT("hw.igb.txd", &igb_txd); /* -** These parameters are used in Adaptive -** Interrupt Moderation. The value is set -** into EITR and controls the interrupt -** frequency. A variable static scheme can -** be created by changing the assigned value -** of igb_ave_latency to the desired value, -** and then set igb_enable_aim to FALSE. -** This will result in all EITR registers -** getting set to that value statically. +** AIM: Adaptive Interrupt Moderation +** which means that the interrupt rate +** is varied over time based on the +** traffic for that interrupt vector */ static int igb_enable_aim = TRUE; TUNABLE_INT("hw.igb.enable_aim", &igb_enable_aim); -static int igb_low_latency = IGB_LOW_LATENCY; -TUNABLE_INT("hw.igb.low_latency", &igb_low_latency); -static int igb_ave_latency = IGB_AVE_LATENCY; -TUNABLE_INT("hw.igb.ave_latency", &igb_ave_latency); -static int igb_bulk_latency = IGB_BULK_LATENCY; -TUNABLE_INT("hw.igb.bulk_latency", &igb_bulk_latency); - + /* -** This will autoconfigure based on the number -** of CPUs if set to 0. Only a matched pair of -** TX and RX rings are allowed. + * 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 + * many circumstances tested, however there have + * been some stability issues, so the default is + * off. + */ +static bool igb_header_split = FALSE; +TUNABLE_INT("hw.igb.hdr_split", &igb_header_split); + +/* +** This will autoconfigure based on +** the number of CPUs if left at 0. */ -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 */ @@ -415,21 +430,6 @@ igb_attach(device_t dev) OID_AUTO, "enable_aim", CTLTYPE_INT|CTLFLAG_RW, &igb_enable_aim, 1, "Interrupt Moderation"); - SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), - SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "low_latency", CTLTYPE_INT|CTLFLAG_RW, - &igb_low_latency, 1, "Low Latency"); - - SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), - SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "ave_latency", CTLTYPE_INT|CTLFLAG_RW, - &igb_ave_latency, 1, "Average Latency"); - - SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), - SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "bulk_latency", CTLTYPE_INT|CTLFLAG_RW, - &igb_bulk_latency, 1, "Bulk Latency"); - callout_init_mtx(&adapter->timer, &adapter->core_mtx, 0); /* Determine hardware and mac info */ @@ -540,17 +540,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,21 +553,8 @@ igb_attach(device_t dev) /* Setup OS specific network interface */ igb_setup_interface(dev, adapter); -#ifdef IGB_IEEE1588 - /* - ** Setup the timer: IEEE 1588 support - */ - adapter->cycles.read = igb_read_clock; - adapter->cycles.mask = (u64)-1; - adapter->cycles.mult = 1; - adapter->cycles.shift = IGB_TSYNC_SHIFT; - E1000_WRITE_REG(&adapter->hw, E1000_TIMINCA, (1<<24) | - IGB_TSYNC_CYCLE_TIME * IGB_TSYNC_SHIFT); - E1000_WRITE_REG(&adapter->hw, E1000_SYSTIML, 0x00000000); - E1000_WRITE_REG(&adapter->hw, E1000_SYSTIMH, 0xFF800000); - - // JFV - this is not complete yet -#endif + /* Now get a good starting state */ + igb_reset(adapter); /* Initialize statistics */ igb_update_stats_counters(adapter); @@ -607,6 +587,9 @@ igb_attach(device_t dev) /* Tell the stack that the interface is not active */ adapter->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + adapter->led_dev = led_create(igb_led_func, adapter, + device_get_nameunit(dev)); + INIT_DEBUGOUT("igb_attach: end"); return (0); @@ -646,6 +629,14 @@ igb_detach(device_t dev) return (EBUSY); } + if (adapter->led_dev != NULL) + led_destroy(adapter->led_dev); + +#ifdef DEVICE_POLLING + if (ifp->if_capenable & IFCAP_POLLING) + ether_poll_deregister(ifp); +#endif + IGB_CORE_LOCK(adapter); adapter->in_detach = 1; igb_stop(adapter); @@ -787,8 +778,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; } } @@ -826,6 +817,9 @@ igb_mq_start(struct ifnet *ifp, struct mbuf *m) /* Which queue to use */ if ((m->m_flags & M_FLOWID) != 0) i = m->m_pkthdr.flowid % adapter->num_queues; + else + i = curcpu % adapter->num_queues; + txr = &adapter->tx_rings[i]; if (IGB_TX_TRYLOCK(txr)) { @@ -842,59 +836,48 @@ igb_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr, struct mbuf *m) { struct adapter *adapter = txr->adapter; struct mbuf *next; - int err = 0; + int err = 0, enq; - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { - err = drbr_enqueue(ifp, txr->br, m); + IGB_TX_LOCK_ASSERT(txr); + + if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != + IFF_DRV_RUNNING || adapter->link_active == 0) { + if (m != NULL) + err = drbr_enqueue(ifp, txr->br, m); return (err); } - if (m == NULL) /* Called by tasklet */ - goto process; - - /* If nothing queued go right to xmit */ - if (!drbr_needs_enqueue(ifp, txr->br)) { - if ((err = igb_xmit(txr, &m)) != 0) { - if (m != NULL) - err = drbr_enqueue(ifp, txr->br, m); - 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; - } - - } else if ((err = drbr_enqueue(ifp, txr->br, m)) != 0) - return (err); - -process: - if (drbr_empty(ifp, txr->br)) - return (err); - - /* Process the queue */ - while (TRUE) { - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) - break; + enq = 0; + if (m == NULL) { next = drbr_dequeue(ifp, txr->br); - if (next == NULL) - break; + } else if (drbr_needs_enqueue(ifp, txr->br)) { + if ((err = drbr_enqueue(ifp, txr->br, m)) != 0) + return (err); + next = drbr_dequeue(ifp, txr->br); + } else + next = m; + /* Process the queue */ + while (next != NULL) { if ((err = igb_xmit(txr, &next)) != 0) { if (next != NULL) err = drbr_enqueue(ifp, txr->br, next); break; } + enq++; 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; + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + break; + if (txr->tx_avail <= IGB_TX_OP_THRESHOLD) { + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + break; + } + next = drbr_dequeue(ifp, txr->br); + } + if (enq > 0) { + /* Set the watchdog */ + txr->watchdog_check = TRUE; } - - if (txr->tx_avail <= IGB_TX_OP_THRESHOLD) - ifp->if_drv_flags |= IFF_DRV_OACTIVE; - return (err); } @@ -1011,6 +994,9 @@ igb_ioctl(struct ifnet *ifp, u_long command, caddr_t data) IGB_CORE_LOCK(adapter); igb_disable_intr(adapter); igb_set_multi(adapter); +#ifdef DEVICE_POLLING + if (!(ifp->if_capenable & IFCAP_POLLING)) +#endif igb_enable_intr(adapter); IGB_CORE_UNLOCK(adapter); } @@ -1037,6 +1023,26 @@ igb_ioctl(struct ifnet *ifp, u_long command, caddr_t data) IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFCAP (Set Capabilities)"); reinit = 0; mask = ifr->ifr_reqcap ^ ifp->if_capenable; +#ifdef DEVICE_POLLING + if (mask & IFCAP_POLLING) { + if (ifr->ifr_reqcap & IFCAP_POLLING) { + error = ether_poll_register(igb_poll, ifp); + if (error) + return (error); + IGB_CORE_LOCK(adapter); + igb_disable_intr(adapter); + ifp->if_capenable |= IFCAP_POLLING; + IGB_CORE_UNLOCK(adapter); + } else { + error = ether_poll_deregister(ifp); + /* Enable interrupt even in error case */ + IGB_CORE_LOCK(adapter); + igb_enable_intr(adapter); + ifp->if_capenable &= ~IFCAP_POLLING; + IGB_CORE_UNLOCK(adapter); + } + } +#endif if (mask & IFCAP_HWCSUM) { ifp->if_capenable ^= IFCAP_HWCSUM; reinit = 1; @@ -1059,15 +1065,6 @@ igb_ioctl(struct ifnet *ifp, u_long command, caddr_t data) break; } -#ifdef IGB_IEEE1588 - /* - ** IOCTL support for Precision Time (IEEE 1588) Support - */ - case SIOCSHWTSTAMP: - error = igb_hwtstamp_ioctl(adapter, ifp); - break; -#endif - default: error = ether_ioctl(ifp, command, data); break; @@ -1076,80 +1073,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 +1088,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,11 +1105,7 @@ 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); @@ -1239,7 +1145,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,25 +1164,20 @@ 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); +#ifdef DEVICE_POLLING + /* + * Only enable interrupts if we are not polling, make sure + * they are off otherwise. + */ + if (ifp->if_capenable & IFCAP_POLLING) + igb_disable_intr(adapter); + else +#endif /* DEVICE_POLLING */ { - /* 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); + igb_enable_intr(adapter); + E1000_WRITE_REG(&adapter->hw, E1000_ICS, E1000_ICS_LSC); } /* Don't reset the phy next time init gets called */ @@ -1298,15 +1198,15 @@ igb_init(void *arg) static void igb_handle_rxtx(void *context, int pending) { - struct adapter *adapter = context; - struct tx_ring *txr = adapter->tx_rings; - struct rx_ring *rxr = adapter->rx_rings; - struct ifnet *ifp; + struct igb_queue *que = context; + struct adapter *adapter = que->adapter; + struct tx_ring *txr = adapter->tx_rings; + struct ifnet *ifp; ifp = adapter->ifp; if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - if (igb_rxeof(rxr, adapter->rx_process_limit)) + if (igb_rxeof(que, adapter->rx_process_limit)) taskqueue_enqueue(adapter->tq, &adapter->rxtx_task); IGB_TX_LOCK(txr); igb_txeof(txr); @@ -1325,40 +1225,50 @@ igb_handle_rxtx(void *context, int pending) } static void -igb_handle_rx(void *context, int pending) +igb_handle_que(void *context, int pending) { - struct rx_ring *rxr = context; - struct adapter *adapter = rxr->adapter; - struct ifnet *ifp = adapter->ifp; - - 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); - -} + struct igb_queue *que = context; + struct adapter *adapter = que->adapter; + struct tx_ring *txr = que->txr; + struct ifnet *ifp = adapter->ifp; + u32 loop = IGB_MAX_LOOP; + bool more; -static void -igb_handle_tx(void *context, int pending) -{ - struct tx_ring *txr = context; - struct adapter *adapter = txr->adapter; - struct ifnet *ifp = adapter->ifp; + /* RX first */ + do { + more = igb_rxeof(que, -1); + } while (loop-- && more); - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - IGB_TX_LOCK(txr); - igb_txeof(txr); + if (IGB_TX_TRYLOCK(txr)) { + loop = IGB_MAX_LOOP; + 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); + igb_mq_start_locked(ifp, txr, NULL); #else if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) igb_start_locked(txr, ifp); #endif IGB_TX_UNLOCK(txr); } + + /* Reenable this interrupt */ +#ifdef DEVICE_POLLING + if (!(ifp->if_capenable & IFCAP_POLLING)) +#endif + E1000_WRITE_REG(&adapter->hw, E1000_EIMS, que->eims); } +/* Deal with link in a sleepable context */ +static void +igb_handle_link(void *context, int pending) +{ + struct adapter *adapter = context; + + adapter->hw.mac.get_link_status = 1; + igb_update_link_status(adapter); +} /********************************************************************* * @@ -1395,16 +1305,72 @@ igb_irq_fast(void *arg) taskqueue_enqueue(adapter->tq, &adapter->rxtx_task); /* Link status change */ - if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { - adapter->hw.mac.get_link_status = 1; - igb_update_link_status(adapter); - } + if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) + taskqueue_enqueue(adapter->tq, &adapter->link_task); if (reg_icr & E1000_ICR_RXO) adapter->rx_overruns++; return FILTER_HANDLED; } +#ifdef DEVICE_POLLING +/********************************************************************* + * + * Legacy polling routine : if using this code you MUST be sure that + * multiqueue is not defined, ie, set igb_num_queues to 1. + * + *********************************************************************/ +#if __FreeBSD_version >= 800000 +#define POLL_RETURN_COUNT(a) (a) +static int +#else +#define POLL_RETURN_COUNT(a) +static void +#endif +igb_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) +{ + struct adapter *adapter = ifp->if_softc; + struct igb_queue *que = adapter->queues; + struct tx_ring *txr = adapter->tx_rings; + u32 reg_icr, rx_done = 0; + u32 loop = IGB_MAX_LOOP; + bool more; + + IGB_CORE_LOCK(adapter); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + IGB_CORE_UNLOCK(adapter); + return POLL_RETURN_COUNT(rx_done); + } + + if (cmd == POLL_AND_CHECK_STATUS) { + reg_icr = E1000_READ_REG(&adapter->hw, E1000_ICR); + /* Link status change */ + if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) + taskqueue_enqueue(adapter->tq, &adapter->link_task); + + if (reg_icr & E1000_ICR_RXO) + adapter->rx_overruns++; + } + IGB_CORE_UNLOCK(adapter); + + /* TODO: rx_count */ + rx_done = igb_rxeof(que, count) ? 1 : 0; + + 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); +#else + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + igb_start_locked(txr, ifp); +#endif + IGB_TX_UNLOCK(txr); + return POLL_RETURN_COUNT(rx_done); +} +#endif /* DEVICE_POLLING */ /********************************************************************* * @@ -1412,58 +1378,82 @@ igb_irq_fast(void *arg) * **********************************************************************/ static void -igb_msix_tx(void *arg) +igb_msix_que(void *arg) { - struct tx_ring *txr = arg; - struct adapter *adapter = txr->adapter; - u32 loop = IGB_MAX_LOOP; - bool more; + struct igb_queue *que = arg; + struct adapter *adapter = que->adapter; + struct tx_ring *txr = que->txr; + struct rx_ring *rxr = que->rxr; + u32 newitr = 0; + bool more_tx, more_rx; + + E1000_WRITE_REG(&adapter->hw, E1000_EIMC, que->eims); + ++que->irqs; - ++txr->tx_irq; IGB_TX_LOCK(txr); - - do { - more = igb_txeof(txr); - } while (loop-- && more); - + more_tx = igb_txeof(txr); IGB_TX_UNLOCK(txr); - /* Schedule a clean task */ - taskqueue_enqueue(adapter->tq, &txr->tx_task); + more_rx = igb_rxeof(que, adapter->rx_process_limit); - /* Reenable this interrupt */ - E1000_WRITE_REG(&adapter->hw, E1000_EIMS, txr->eims); - return; -} + if (igb_enable_aim == FALSE) + goto no_calc; + /* + ** Do Adaptive Interrupt Moderation: + ** - Write out last calculated setting + ** - Calculate based on average size over + ** the last interval. + */ + if (que->eitr_setting) + E1000_WRITE_REG(&adapter->hw, + E1000_EITR(que->msix), que->eitr_setting); + + que->eitr_setting = 0; -/********************************************************************* - * - * MSIX RX Interrupt Service routine - * - **********************************************************************/ + /* Idle, do nothing */ + if ((txr->bytes == 0) && (rxr->bytes == 0)) + goto no_calc; + + /* Used half Default if sub-gig */ + if (adapter->link_speed != 1000) + newitr = IGB_DEFAULT_ITR / 2; + else { + if ((txr->bytes) && (txr->packets)) + newitr = txr->bytes/txr->packets; + if ((rxr->bytes) && (rxr->packets)) + newitr = max(newitr, + (rxr->bytes / rxr->packets)); + newitr += 24; /* account for hardware frame, crc */ + /* set an upper boundary */ + newitr = min(newitr, 3000); + /* Be nice to the mid range */ + if ((newitr > 300) && (newitr < 1200)) + newitr = (newitr / 3); + else + newitr = (newitr / 2); + } + newitr &= 0x7FFC; /* Mask invalid bits */ + if (adapter->hw.mac.type == e1000_82575) + newitr |= newitr << 16; + else + newitr |= 0x8000000; + + /* save for next interrupt */ + que->eitr_setting = newitr; -static void -igb_msix_rx(void *arg) -{ - struct rx_ring *rxr = arg; - struct adapter *adapter = rxr->adapter; - u32 loop = IGB_MAX_LOOP; - bool more; + /* Reset state */ + txr->bytes = 0; + txr->packets = 0; + rxr->bytes = 0; + rxr->packets = 0; - ++rxr->rx_irq; - do { - more = igb_rxeof(rxr, adapter->rx_process_limit); - } while (loop-- && more); - - /* 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); +no_calc: + /* Schedule a clean task if needed*/ + if (more_tx || more_rx) + taskqueue_enqueue(que->tq, &que->que_task); + else + /* Reenable this interrupt */ + E1000_WRITE_REG(&adapter->hw, E1000_EIMS, que->eims); return; } @@ -1484,8 +1474,7 @@ igb_msix_link(void *arg) icr = E1000_READ_REG(&adapter->hw, E1000_ICR); if (!(icr & E1000_ICR_LSC)) goto spurious; - adapter->hw.mac.get_link_status = 1; - igb_update_link_status(adapter); + taskqueue_enqueue(adapter->tq, &adapter->link_task); spurious: /* Rearm */ @@ -1495,59 +1484,6 @@ igb_msix_link(void *arg) } -/* -** Routine to adjust the RX EITR value based on traffic, -** its a simple three state model, but seems to help. -** -** Note that the three EITR values are tuneable using -** sysctl in real time. The feature can be effectively -** nullified by setting them equal. -*/ -#define BULK_THRESHOLD 10000 -#define AVE_THRESHOLD 1600 - -static void -igb_update_aim(struct rx_ring *rxr) -{ - struct adapter *adapter = rxr->adapter; - u32 olditr, newitr; - - /* Update interrupt moderation based on traffic */ - olditr = rxr->eitr_setting; - newitr = olditr; - - /* Idle, don't change setting */ - if (rxr->bytes == 0) - return; - - if (olditr == igb_low_latency) { - if (rxr->bytes > AVE_THRESHOLD) - newitr = igb_ave_latency; - } else if (olditr == igb_ave_latency) { - if (rxr->bytes < AVE_THRESHOLD) - newitr = igb_low_latency; - else if (rxr->bytes > BULK_THRESHOLD) - newitr = igb_bulk_latency; - } else if (olditr == igb_bulk_latency) { - if (rxr->bytes < BULK_THRESHOLD) - newitr = igb_ave_latency; - } - - 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); - } - - rxr->bytes = 0; - return; -} - - /********************************************************************* * * Media Ioctl callback @@ -1780,15 +1716,14 @@ igb_xmit(struct tx_ring *txr, struct mbuf **m_headp) } else if (igb_tx_ctx_setup(txr, m_head)) olinfo_status |= E1000_TXD_POPTS_TXSM << 8; -#ifdef IGB_IEEE1588 - /* This is changing soon to an mtag detection */ - if (we detect this mbuf has a TSTAMP mtag) - cmd_type_len |= E1000_ADVTXD_MAC_TSTAMP; -#endif /* Calculate payload length */ 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++) { @@ -1801,8 +1736,7 @@ igb_xmit(struct tx_ring *txr, struct mbuf **m_headp) seg_len = segs[j].ds_len; txd->read.buffer_addr = htole64(seg_addr); - txd->read.cmd_type_len = htole32( - adapter->txd_cmd | cmd_type_len | seg_len); + txd->read.cmd_type_len = htole32(cmd_type_len | seg_len); txd->read.olinfo_status = htole32(olinfo_status); last = i; if (++i == adapter->num_tx_desc) @@ -1825,13 +1759,14 @@ igb_xmit(struct tx_ring *txr, struct mbuf **m_headp) * and Report Status (RS) */ txd->read.cmd_type_len |= - htole32(E1000_TXD_CMD_EOP | E1000_TXD_CMD_RS); + htole32(E1000_ADVTXD_DCMD_EOP | E1000_ADVTXD_DCMD_RS); /* * Keep track in the first buffer which * descriptor will be written back */ tx_buffer = &txr->tx_buffers[first]; tx_buffer->next_eop = last; + txr->watchdog_time = ticks; /* * Advance the Transmit Descriptor Tail (TDT), this tells the E1000 @@ -1896,7 +1831,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,7 +1847,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); @@ -1920,17 +1863,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 +1886,35 @@ 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 */ +#ifdef DEVICE_POLLING + if (!(ifp->if_capenable & IFCAP_POLLING)) +#endif 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 @@ -1997,6 +1961,7 @@ igb_update_link_status(struct adapter *adapter) "Full Duplex" : "Half Duplex")); adapter->link_active = 1; ifp->if_baudrate = adapter->link_speed * 1000000; + /* This can sleep */ if_link_state_change(ifp, LINK_STATE_UP); } else if (!link_check && (adapter->link_active == 1)) { ifp->if_baudrate = adapter->link_speed = 0; @@ -2004,10 +1969,11 @@ igb_update_link_status(struct adapter *adapter) if (bootverbose) device_printf(dev, "Link is Down\n"); adapter->link_active = 0; + /* This can sleep */ 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; } } @@ -2023,6 +1989,7 @@ igb_stop(void *arg) { struct adapter *adapter = arg; struct ifnet *ifp = adapter->ifp; + struct tx_ring *txr = adapter->tx_rings; IGB_CORE_LOCK_ASSERT(adapter); @@ -2035,8 +2002,18 @@ igb_stop(void *arg) /* Tell the stack that the interface is no longer active */ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + /* Unarm watchdog timer. */ + for (int i = 0; i < adapter->num_queues; i++, txr++) { + IGB_TX_LOCK(txr); + txr->watchdog_check = FALSE; + IGB_TX_UNLOCK(txr); + } + e1000_reset_hw(&adapter->hw); E1000_WRITE_REG(&adapter->hw, E1000_WUC, 0); + + e1000_led_off(&adapter->hw); + e1000_cleanup_led(&adapter->hw); } @@ -2114,8 +2091,9 @@ igb_allocate_pci_resources(struct adapter *adapter) static int igb_allocate_legacy(struct adapter *adapter) { - device_t dev = adapter->dev; - int error, rid = 0; + device_t dev = adapter->dev; + struct igb_queue *que = adapter->queues; + int error, rid = 0; /* Turn off all interrupts */ E1000_WRITE_REG(&adapter->hw, E1000_IMC, 0xffffffff); @@ -2137,7 +2115,9 @@ igb_allocate_legacy(struct adapter *adapter) * Try allocating a fast interrupt and the associated deferred * processing contexts. */ - TASK_INIT(&adapter->rxtx_task, 0, igb_handle_rxtx, adapter); + TASK_INIT(&adapter->rxtx_task, 0, igb_handle_rxtx, que); + /* Make tasklet for deferred link handling */ + TASK_INIT(&adapter->link_task, 0, igb_handle_link, adapter); adapter->tq = taskqueue_create_fast("igb_taskq", M_NOWAIT, taskqueue_thread_enqueue, &adapter->tq); taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s taskq", @@ -2158,96 +2138,56 @@ igb_allocate_legacy(struct adapter *adapter) /********************************************************************* * - * Setup the MSIX Interrupt handlers: + * Setup the MSIX Queue Interrupt handlers: * **********************************************************************/ static int igb_allocate_msix(struct adapter *adapter) { - device_t dev = adapter->dev; - struct tx_ring *txr = adapter->tx_rings; - struct rx_ring *rxr = adapter->rx_rings; - int error, rid, vector = 0; + device_t dev = adapter->dev; + struct igb_queue *que = adapter->queues; + int error, rid, vector = 0; - /* - * Setup the interrupt handlers - */ - /* TX Setup */ - for (int i = 0; i < adapter->num_queues; i++, vector++, txr++) { + for (int i = 0; i < adapter->num_queues; i++, vector++, que++) { rid = vector +1; - txr->res = bus_alloc_resource_any(dev, + que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); - if (txr->res == NULL) { + if (que->res == NULL) { device_printf(dev, "Unable to allocate bus resource: " - "MSIX TX Interrupt\n"); + "MSIX Queue Interrupt\n"); return (ENXIO); } - error = bus_setup_intr(dev, txr->res, + error = bus_setup_intr(dev, que->res, INTR_TYPE_NET | INTR_MPSAFE, NULL, - igb_msix_tx, txr, &txr->tag); + igb_msix_que, que, &que->tag); if (error) { - txr->res = NULL; - device_printf(dev, "Failed to register TX handler"); + que->res = NULL; + device_printf(dev, "Failed to register Queue handler"); return (error); } - /* Make tasklet for deferred handling - one per queue */ - TASK_INIT(&txr->tx_task, 0, igb_handle_tx, txr); - txr->msix = vector; + que->msix = vector; if (adapter->hw.mac.type == e1000_82575) - txr->eims = E1000_EICR_TX_QUEUE0 << i; + que->eims = E1000_EICR_TX_QUEUE0 << i; else - txr->eims = 1 << vector; + que->eims = 1 << vector; /* ** Bind the msix vector, and thus the - ** ring to the corresponding cpu. + ** rings to the corresponding cpu. */ if (adapter->num_queues > 1) - bus_bind_intr(dev, txr->res, i); - } - - /* RX Setup */ - for (int i = 0; i < adapter->num_queues; i++, vector++, rxr++) { - rid = vector +1; - rxr->res = bus_alloc_resource_any(dev, - SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); - if (rxr->res == NULL) { - device_printf(dev, - "Unable to allocate bus resource: " - "MSIX RX Interrupt\n"); - return (ENXIO); - } - error = bus_setup_intr(dev, rxr->res, - INTR_TYPE_NET | INTR_MPSAFE, NULL, - igb_msix_rx, rxr, &rxr->tag); - if (error) { - rxr->res = NULL; - 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; - else - rxr->eims = 1 << vector; - /* Get a mask for local timer */ - adapter->rx_mask |= rxr->eims; - /* - ** Bind the msix vector, and thus the - ** ring to the corresponding cpu. - ** Notice that this makes an RX/TX pair - ** bound to each CPU, limited by the MSIX - ** vectors. - */ - if (adapter->num_queues > 1) - bus_bind_intr(dev, rxr->res, i); + bus_bind_intr(dev, que->res, i); + /* Make tasklet for deferred handling */ + TASK_INIT(&que->que_task, 0, igb_handle_que, que); + que->tq = taskqueue_create_fast("igb_que", M_NOWAIT, + taskqueue_thread_enqueue, &que->tq); + taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que", + device_get_nameunit(adapter->dev)); } /* And Link */ - rid = vector +1; + rid = vector + 1; adapter->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); if (adapter->res == NULL) { @@ -2263,9 +2203,12 @@ igb_allocate_msix(struct adapter *adapter) return (error); } adapter->linkvec = vector; - adapter->tq = taskqueue_create_fast("igb_taskq", M_NOWAIT, + + /* Make tasklet for deferred handling */ + TASK_INIT(&adapter->link_task, 0, igb_handle_link, adapter); + adapter->tq = taskqueue_create_fast("igb_link", M_NOWAIT, taskqueue_thread_enqueue, &adapter->tq); - taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s taskq", + taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s link", device_get_nameunit(adapter->dev)); return (0); @@ -2275,52 +2218,48 @@ igb_allocate_msix(struct adapter *adapter) static void igb_configure_queues(struct adapter *adapter) { - struct e1000_hw *hw = &adapter->hw; - struct tx_ring *txr; - struct rx_ring *rxr; + struct e1000_hw *hw = &adapter->hw; + struct igb_queue *que; + u32 tmp, ivar = 0; + u32 newitr = IGB_DEFAULT_ITR; + + /* 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_PBA | E1000_GPIE_NSICR); /* 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 */ - E1000_WRITE_REG(hw, E1000_GPIE, - E1000_GPIE_MSIX_MODE | - E1000_GPIE_EIAME | - E1000_GPIE_PBA | E1000_GPIE_NSICR); - /* RX */ + switch (adapter->hw.mac.type) { + case e1000_82580: + /* RX entries */ for (int i = 0; i < adapter->num_queues; i++) { - u32 index = i & 0x7; /* Each IVAR has two entries */ + u32 index = i >> 1; ivar = E1000_READ_REG_ARRAY(hw, E1000_IVAR0, index); - rxr = &adapter->rx_rings[i]; - if (i < 8) { - ivar &= 0xFFFFFF00; - ivar |= rxr->msix | E1000_IVAR_VALID; - } else { + que = &adapter->queues[i]; + if (i & 1) { ivar &= 0xFF00FFFF; - ivar |= (rxr->msix | E1000_IVAR_VALID) << 16; - } - 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 & 0x7; /* Each IVAR has two entries */ - ivar = E1000_READ_REG_ARRAY(hw, E1000_IVAR0, index); - txr = &adapter->tx_rings[i]; - if (i < 8) { - ivar &= 0xFFFF00FF; - ivar |= (txr->msix | E1000_IVAR_VALID) << 8; + ivar |= (que->msix | E1000_IVAR_VALID) << 16; } else { - ivar &= 0x00FFFFFF; - ivar |= (txr->msix | E1000_IVAR_VALID) << 24; + ivar &= 0xFFFFFF00; + ivar |= que->msix | E1000_IVAR_VALID; } E1000_WRITE_REG_ARRAY(hw, E1000_IVAR0, index, ivar); - adapter->eims_mask |= txr->eims; + } + /* TX entries */ + for (int i = 0; i < adapter->num_queues; i++) { + u32 index = i >> 1; + ivar = E1000_READ_REG_ARRAY(hw, E1000_IVAR0, index); + que = &adapter->queues[i]; + if (i & 1) { + ivar &= 0x00FFFFFF; + ivar |= (que->msix | E1000_IVAR_VALID) << 24; + } else { + ivar &= 0xFFFF00FF; + ivar |= (que->msix | E1000_IVAR_VALID) << 8; + } + E1000_WRITE_REG_ARRAY(hw, E1000_IVAR0, index, ivar); + adapter->eims_mask |= que->eims; } /* And for the link interrupt */ @@ -2328,11 +2267,48 @@ 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; + case e1000_82576: + /* RX entries */ + for (int i = 0; i < adapter->num_queues; i++) { + u32 index = i & 0x7; /* Each IVAR has two entries */ + ivar = E1000_READ_REG_ARRAY(hw, E1000_IVAR0, index); + que = &adapter->queues[i]; + if (i < 8) { + ivar &= 0xFFFFFF00; + ivar |= que->msix | E1000_IVAR_VALID; + } else { + ivar &= 0xFF00FFFF; + ivar |= (que->msix | E1000_IVAR_VALID) << 16; + } + E1000_WRITE_REG_ARRAY(hw, E1000_IVAR0, index, ivar); + adapter->eims_mask |= que->eims; + } + /* TX entries */ + for (int i = 0; i < adapter->num_queues; i++) { + u32 index = i & 0x7; /* Each IVAR has two entries */ + ivar = E1000_READ_REG_ARRAY(hw, E1000_IVAR0, index); + que = &adapter->queues[i]; + if (i < 8) { + ivar &= 0xFFFF00FF; + ivar |= (que->msix | E1000_IVAR_VALID) << 8; + } else { + ivar &= 0x00FFFFFF; + ivar |= (que->msix | E1000_IVAR_VALID) << 24; + } + E1000_WRITE_REG_ARRAY(hw, E1000_IVAR0, index, ivar); + adapter->eims_mask |= que->eims; + } - /* enable MSI-X PBA support*/ + /* 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_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. */ @@ -2340,20 +2316,15 @@ igb_configure_queues(struct adapter *adapter) tmp |= E1000_CTRL_EXT_IRCA; E1000_WRITE_REG(hw, E1000_CTRL_EXT, tmp); - /* TX */ + /* Queues */ for (int i = 0; i < adapter->num_queues; i++) { - txr = &adapter->tx_rings[i]; - E1000_WRITE_REG(hw, E1000_MSIXBM(txr->msix), - txr->eims); - adapter->eims_mask |= txr->eims; - } - - /* RX */ - for (int i = 0; i < adapter->num_queues; i++) { - rxr = &adapter->rx_rings[i]; - E1000_WRITE_REG(hw, E1000_MSIXBM(rxr->msix), - rxr->eims); - adapter->eims_mask |= rxr->eims; + que = &adapter->queues[i]; + tmp = E1000_EICR_RX_QUEUE0 << i; + tmp |= E1000_EICR_TX_QUEUE0 << i; + que->eims = tmp; + E1000_WRITE_REG_ARRAY(hw, E1000_MSIXBM(0), + i, que->eims); + adapter->eims_mask |= que->eims; } /* Link */ @@ -2361,7 +2332,21 @@ igb_configure_queues(struct adapter *adapter) E1000_EIMS_OTHER); adapter->link_mask |= E1000_EIMS_OTHER; adapter->eims_mask |= adapter->link_mask; + default: + break; } + + /* Set the starting interrupt rate */ + if (hw->mac.type == e1000_82575) + newitr |= newitr << 16; + else + newitr |= 0x8000000; + + for (int i = 0; i < adapter->num_queues; i++) { + que = &adapter->queues[i]; + E1000_WRITE_REG(hw, E1000_EITR(que->msix), newitr); + } + return; } @@ -2369,8 +2354,7 @@ igb_configure_queues(struct adapter *adapter) static void igb_free_pci_resources(struct adapter *adapter) { - struct tx_ring *txr = adapter->tx_rings; - struct rx_ring *rxr = adapter->rx_rings; + struct igb_queue *que = adapter->queues; device_t dev = adapter->dev; int rid; @@ -2386,26 +2370,17 @@ igb_free_pci_resources(struct adapter *adapter) goto mem; /* - * First release all the TX/RX interrupt resources: + * First release all the interrupt resources: */ - for (int i = 0; i < adapter->num_queues; i++, txr++) { - rid = txr->msix + 1; - if (txr->tag != NULL) { - bus_teardown_intr(dev, txr->res, txr->tag); - txr->tag = NULL; + for (int i = 0; i < adapter->num_queues; i++, que++) { + rid = que->msix + 1; + if (que->tag != NULL) { + bus_teardown_intr(dev, que->res, que->tag); + que->tag = NULL; } - if (txr->res != NULL) - bus_release_resource(dev, SYS_RES_IRQ, rid, txr->res); - } - - for (int i = 0; i < adapter->num_queues; i++, rxr++) { - rid = rxr->msix + 1; - if (rxr->tag != NULL) { - bus_teardown_intr(dev, rxr->res, rxr->tag); - rxr->tag = NULL; - } - if (rxr->res != NULL) - bus_release_resource(dev, SYS_RES_IRQ, rid, rxr->res); + if (que->res != NULL) + bus_release_resource(dev, + SYS_RES_IRQ, rid, que->res); } /* Clean the Legacy or Link interrupt last */ @@ -2444,6 +2419,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, @@ -2464,15 +2443,21 @@ igb_setup_msix(struct adapter *adapter) } /* Figure out a reasonable auto config value */ - queues = (mp_ncpus > ((msgs-1)/2)) ? (msgs-1)/2 : mp_ncpus; + queues = (mp_ncpus > (msgs-1)) ? (msgs-1) : mp_ncpus; + + /* Manual override */ + if (igb_num_queues != 0) + queues = igb_num_queues; + + /* Can have max of 4 queues on 82575 */ + if ((adapter->hw.mac.type == e1000_82575) && (queues > 4)) + queues = 4; - if (igb_num_queues == 0) - igb_num_queues = queues; /* - ** Two vectors (RX/TX pair) per queue + ** One vector (RX/TX pair) per queue ** plus an additional for Link interrupt */ - want = (igb_num_queues * 2) + 1; + want = queues + 1; if (msgs >= want) msgs = want; else { @@ -2485,7 +2470,7 @@ igb_setup_msix(struct adapter *adapter) if ((msgs) && pci_alloc_msix(dev, &msgs) == 0) { device_printf(adapter->dev, "Using MSIX interrupts with %d vectors\n", msgs); - adapter->num_queues = igb_num_queues; + adapter->num_queues = queues; return (msgs); } msi: @@ -2497,24 +2482,70 @@ igb_setup_msix(struct adapter *adapter) /********************************************************************* * - * 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; + struct e1000_hw *hw = &adapter->hw; + struct e1000_fc_info *fc = &hw->fc; + struct ifnet *ifp = adapter->ifp; + u32 pba = 0; + u16 hwm; - INIT_DEBUGOUT("igb_hardware_init: begin"); - - /* 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. @@ -2522,41 +2553,74 @@ igb_hardware_init(struct adapter *adapter) * 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; - if (e1000_init_hw(&adapter->hw) < 0) { + 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(hw) < 0) device_printf(dev, "Hardware Initialization Failed\n"); - return (EIO); + + if (hw->mac.type == e1000_82580) { + u32 reg; + + 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_check_for_link(&adapter->hw); - - return (0); + E1000_WRITE_REG(&adapter->hw, E1000_VET, ETHERTYPE_VLAN); + e1000_get_phy_info(hw); + e1000_check_for_link(hw); + return; } /********************************************************************* @@ -2596,7 +2660,13 @@ 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; +#ifdef DEVICE_POLLING + ifp->if_capabilities |= IFCAP_POLLING; +#endif /* * Tell the upper layer(s) we support long frames. @@ -2654,7 +2724,7 @@ igb_dma_malloc(struct adapter *adapter, bus_size_t size, int error; error = bus_dma_tag_create(bus_get_dma_tag(adapter->dev), /* parent */ - 1, 0, /* alignment, bounds */ + IGB_DBA_ALIGN, 0, /* alignment, bounds */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ @@ -2732,22 +2802,31 @@ static int igb_allocate_queues(struct adapter *adapter) { device_t dev = adapter->dev; - struct tx_ring *txr; - struct rx_ring *rxr; + struct igb_queue *que = NULL; + struct tx_ring *txr = NULL; + struct rx_ring *rxr = NULL; int rsize, tsize, error = E1000_SUCCESS; int txconf = 0, rxconf = 0; - /* First allocate the TX ring struct memory */ + /* First allocate the top level queue structs */ + if (!(adapter->queues = + (struct igb_queue *) malloc(sizeof(struct igb_queue) * + adapter->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { + device_printf(dev, "Unable to allocate queue memory\n"); + error = ENOMEM; + goto fail; + } + + /* Next allocate the TX ring struct memory */ if (!(adapter->tx_rings = (struct tx_ring *) malloc(sizeof(struct tx_ring) * adapter->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { device_printf(dev, "Unable to allocate TX ring memory\n"); error = ENOMEM; - goto fail; + goto tx_fail; } - txr = adapter->tx_rings; - /* Next allocate the RX */ + /* Now allocate the RX */ if (!(adapter->rx_rings = (struct rx_ring *) malloc(sizeof(struct rx_ring) * adapter->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { @@ -2755,7 +2834,6 @@ igb_allocate_queues(struct adapter *adapter) error = ENOMEM; goto rx_fail; } - rxr = adapter->rx_rings; tsize = roundup2(adapter->num_tx_desc * sizeof(union e1000_adv_tx_desc), IGB_DBA_ALIGN); @@ -2833,6 +2911,16 @@ igb_allocate_queues(struct adapter *adapter) } } + /* + ** Finally set up the queue holding structs + */ + for (int i = 0; i < adapter->num_queues; i++) { + que = &adapter->queues[i]; + que->adapter = adapter; + que->txr = &adapter->tx_rings[i]; + que->rxr = &adapter->rx_rings[i]; + } + return (0); err_rx_desc: @@ -2843,7 +2931,10 @@ igb_allocate_queues(struct adapter *adapter) igb_dma_free(adapter, &txr->txdma); free(adapter->rx_rings, M_DEVBUF); rx_fail: + buf_ring_free(txr->br, M_DEVBUF); free(adapter->tx_rings, M_DEVBUF); +tx_fail: + free(adapter->queues, M_DEVBUF); fail: return (error); } @@ -2866,7 +2957,7 @@ 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(dev), 1, 0, /* alignment, bounds */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ @@ -2920,6 +3011,7 @@ igb_setup_transmit_ring(struct tx_ring *txr) int i; /* Clear the old descriptor contents */ + IGB_TX_LOCK(txr); bzero((void *)txr->tx_base, (sizeof(union e1000_adv_tx_desc)) * adapter->num_tx_desc); /* Reset indices */ @@ -2945,7 +3037,7 @@ igb_setup_transmit_ring(struct tx_ring *txr) bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - + IGB_TX_UNLOCK(txr); } /********************************************************************* @@ -2973,48 +3065,50 @@ static void igb_initialize_transmit_units(struct adapter *adapter) { struct tx_ring *txr = adapter->tx_rings; + struct e1000_hw *hw = &adapter->hw; u32 tctl, txdctl; INIT_DEBUGOUT("igb_initialize_transmit_units: begin"); - /* Setup the Base and Length of the Tx Descriptor Rings */ + /* Setup the Tx Descriptor Rings */ for (int i = 0; i < adapter->num_queues; i++, txr++) { u64 bus_addr = txr->txdma.dma_paddr; - E1000_WRITE_REG(&adapter->hw, E1000_TDLEN(i), + E1000_WRITE_REG(hw, E1000_TDLEN(i), adapter->num_tx_desc * sizeof(struct e1000_tx_desc)); - E1000_WRITE_REG(&adapter->hw, E1000_TDBAH(i), + E1000_WRITE_REG(hw, E1000_TDBAH(i), (uint32_t)(bus_addr >> 32)); - E1000_WRITE_REG(&adapter->hw, E1000_TDBAL(i), + E1000_WRITE_REG(hw, E1000_TDBAL(i), (uint32_t)bus_addr); /* Setup the HW Tx Head and Tail descriptor pointers */ - E1000_WRITE_REG(&adapter->hw, E1000_TDT(i), 0); - E1000_WRITE_REG(&adapter->hw, E1000_TDH(i), 0); + E1000_WRITE_REG(hw, E1000_TDT(i), 0); + E1000_WRITE_REG(hw, E1000_TDH(i), 0); HW_DEBUGOUT2("Base = %x, Length = %x\n", - E1000_READ_REG(&adapter->hw, E1000_TDBAL(i)), - E1000_READ_REG(&adapter->hw, E1000_TDLEN(i))); + E1000_READ_REG(hw, E1000_TDBAL(i)), + E1000_READ_REG(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_READ_REG(hw, E1000_TXDCTL(i)); + txdctl |= IGB_TX_PTHRESH; + txdctl |= IGB_TX_HTHRESH << 8; + txdctl |= IGB_TX_WTHRESH << 16; txdctl |= E1000_TXDCTL_QUEUE_ENABLE; - E1000_WRITE_REG(&adapter->hw, E1000_TXDCTL(i), txdctl); + E1000_WRITE_REG(hw, E1000_TXDCTL(i), txdctl); } /* Program the Transmit Control Register */ - tctl = E1000_READ_REG(&adapter->hw, E1000_TCTL); + tctl = E1000_READ_REG(hw, E1000_TCTL); tctl &= ~E1000_TCTL_CT; tctl |= (E1000_TCTL_PSP | E1000_TCTL_RTLC | E1000_TCTL_EN | (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT)); - e1000_config_collision_dist(&adapter->hw); + e1000_config_collision_dist(hw); /* This write will effectively turn on the transmit unit. */ - E1000_WRITE_REG(&adapter->hw, E1000_TCTL, tctl); - + E1000_WRITE_REG(hw, E1000_TCTL, tctl); } /********************************************************************* @@ -3093,8 +3187,7 @@ igb_free_transmit_buffers(struct tx_ring *txr) /********************************************************************** * - * Setup work for hardware segmentation offload (TSO) on - * adapters using advanced tx descriptors (82575) + * Setup work for hardware segmentation offload (TSO) * **********************************************************************/ static boolean_t @@ -3165,6 +3258,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 +3288,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 +3300,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 +3380,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 +3415,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 +3425,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 +3442,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,10 +3450,11 @@ 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++; + txr->bytes += + tx_buffer->m_head->m_pkthdr.len; bus_dmamap_sync(txr->txtag, tx_buffer->map, BUS_DMASYNC_POSTWRITE); @@ -3365,6 +3465,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; @@ -3372,6 +3473,8 @@ igb_txeof(struct tx_ring *txr) tx_buffer = &txr->tx_buffers[first]; tx_desc = &txr->tx_base[first]; } + ++txr->packets; + ++ifp->if_opackets; /* See if we can continue to the next packet */ last = tx_buffer->next_eop; if (last != -1) { @@ -3388,138 +3491,103 @@ 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; + 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 RX descriptor rings + * - now keeps its own state so discards due to resource + * exhaustion are unnecessary, if an mbuf cannot be obtained + * it just returns, keeping its placeholder, thus it can simply + * be recalled to try again. * **********************************************************************/ -static int -igb_get_buf(struct rx_ring *rxr, int i, u8 clean) +static void +igb_refresh_mbufs(struct rx_ring *rxr, int limit) { struct adapter *adapter = rxr->adapter; + bus_dma_segment_t hseg[1]; + bus_dma_segment_t pseg[1]; + struct igb_rx_buf *rxbuf; struct mbuf *mh, *mp; - bus_dma_segment_t seg[2]; - bus_dmamap_t map; - struct igb_rx_buffer *rx_buffer; - int error, nsegs; - int merr = 0; + int i, nsegs, error, cleaned; + i = rxr->next_to_refresh; + cleaned = -1; /* Signify no completions */ + while (i != limit) { + rxbuf = &rxr->rx_buffers[i]; + if (rxbuf->m_head == NULL) { + mh = m_gethdr(M_DONTWAIT, MT_DATA); + if (mh == NULL) + goto update; + mh->m_pkthdr.len = mh->m_len = MHLEN; + mh->m_len = MHLEN; + mh->m_flags |= M_PKTHDR; + m_adj(mh, ETHER_ALIGN); + /* Get the memory mapping */ + error = bus_dmamap_load_mbuf_sg(rxr->htag, + rxbuf->hmap, mh, hseg, &nsegs, BUS_DMA_NOWAIT); + if (error != 0) { + printf("GET BUF: dmamap load" + " failure - %d\n", error); + m_free(mh); + goto update; + } + rxbuf->m_head = mh; + bus_dmamap_sync(rxr->htag, rxbuf->hmap, + BUS_DMASYNC_PREREAD); + rxr->rx_base[i].read.hdr_addr = + htole64(hseg[0].ds_addr); + } - rx_buffer = &rxr->rx_buffers[i]; + if (rxbuf->m_pack == NULL) { + mp = m_getjcl(M_DONTWAIT, MT_DATA, + M_PKTHDR, adapter->rx_mbuf_sz); + if (mp == NULL) + goto update; + mp->m_pkthdr.len = mp->m_len = adapter->rx_mbuf_sz; + /* Get the memory mapping */ + error = bus_dmamap_load_mbuf_sg(rxr->ptag, + rxbuf->pmap, mp, pseg, &nsegs, BUS_DMA_NOWAIT); + if (error != 0) { + printf("GET BUF: dmamap load" + " failure - %d\n", error); + m_free(mp); + goto update; + } + rxbuf->m_pack = mp; + bus_dmamap_sync(rxr->ptag, rxbuf->pmap, + BUS_DMASYNC_PREREAD); + rxr->rx_base[i].read.pkt_addr = + htole64(pseg[0].ds_addr); + } - /* 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; - - mh->m_len = MHLEN; - mh->m_flags |= M_PKTHDR; - - 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; + cleaned = i; + /* Calculate next index */ + if (++i == adapter->num_rx_desc) + i = 0; + /* This is the work marker for refresh */ + rxr->next_to_refresh = i; } - /* - ** 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 (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); - - /* - ** 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. - */ -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); +update: + if (cleaned != -1) /* If we refreshed some, bump tail */ + E1000_WRITE_REG(&adapter->hw, + E1000_RDT(rxr->me), cleaned); + return; } @@ -3536,55 +3604,64 @@ 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; goto fail; } - /* - ** The tag is made to accomodate the largest buffer size - ** 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(dev), 1, 0, /* alignment, bounds */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ - MJUM16BYTES, /* maxsize */ - 2, /* nsegments */ - MJUMPAGESIZE, /* maxsegsize */ + MSIZE, /* maxsize */ + 1, /* nsegments */ + MSIZE, /* maxsegsize */ 0, /* flags */ NULL, /* lockfunc */ NULL, /* lockfuncarg */ - &rxr->rxtag))) { + &rxr->htag))) { device_printf(dev, "Unable to create RX DMA tag\n"); goto fail; } - /* Create the spare map (used by getbuf) */ - error = bus_dmamap_create(rxr->rxtag, BUS_DMA_NOWAIT, - &rxr->rx_spare_map); - if (error) { - device_printf(dev, - "%s: bus_dmamap_create header spare failed: %d\n", - __func__, error); + if ((error = bus_dma_tag_create(bus_get_dma_tag(dev), + 1, 0, /* alignment, bounds */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + MJUMPAGESIZE, /* maxsize */ + 1, /* nsegments */ + MJUMPAGESIZE, /* maxsegsize */ + 0, /* flags */ + NULL, /* lockfunc */ + NULL, /* lockfuncarg */ + &rxr->ptag))) { + device_printf(dev, "Unable to create RX payload DMA tag\n"); goto fail; } - for (i = 0; i < adapter->num_rx_desc; i++, rxbuf++) { + for (i = 0; i < adapter->num_rx_desc; i++) { rxbuf = &rxr->rx_buffers[i]; - error = bus_dmamap_create(rxr->rxtag, - BUS_DMA_NOWAIT, &rxbuf->map); + error = bus_dmamap_create(rxr->htag, + BUS_DMA_NOWAIT, &rxbuf->hmap); if (error) { - device_printf(dev, "Unable to create RX DMA maps\n"); + device_printf(dev, + "Unable to create RX head DMA maps\n"); + goto fail; + } + error = bus_dmamap_create(rxr->ptag, + BUS_DMA_NOWAIT, &rxbuf->pmap); + if (error) { + device_printf(dev, + "Unable to create RX packet DMA maps\n"); goto fail; } } @@ -3597,6 +3674,37 @@ igb_allocate_receive_buffers(struct rx_ring *rxr) return (error); } + +static void +igb_free_receive_ring(struct rx_ring *rxr) +{ + struct adapter *adapter; + struct igb_rx_buf *rxbuf; + int i; + + adapter = rxr->adapter; + for (i = 0; i < adapter->num_rx_desc; i++) { + rxbuf = &rxr->rx_buffers[i]; + if (rxbuf->m_head != NULL) { + bus_dmamap_sync(rxr->htag, rxbuf->hmap, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(rxr->htag, rxbuf->hmap); + rxbuf->m_head->m_flags |= M_PKTHDR; + m_freem(rxbuf->m_head); + } + if (rxbuf->m_pack != NULL) { + bus_dmamap_sync(rxr->ptag, rxbuf->pmap, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(rxr->ptag, rxbuf->pmap); + rxbuf->m_pack->m_flags |= M_PKTHDR; + m_freem(rxbuf->m_pack); + } + rxbuf->m_head = NULL; + rxbuf->m_pack = NULL; + } +} + + /********************************************************************* * * Initialize a receive ring and its buffers. @@ -3608,17 +3716,17 @@ 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 pseg[1], hseg[1]; 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 */ + IGB_RX_LOCK(rxr); rsize = roundup2(adapter->num_rx_desc * sizeof(union e1000_adv_rx_desc), IGB_DBA_ALIGN); bzero((void *)rxr->rx_base, rsize); @@ -3626,33 +3734,62 @@ igb_setup_receive_ring(struct rx_ring *rxr) /* ** Free current RX buffer structures and their mbufs */ - for (int i = 0; i < adapter->num_rx_desc; i++) { - rxbuf = &rxr->rx_buffers[i]; - bus_dmamap_sync(rxr->rxtag, rxbuf->map, - BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(rxr->rxtag, rxbuf->map); - if (rxbuf->m_head) { - rxbuf->m_head->m_next = rxbuf->m_pack; - m_freem(rxbuf->m_head); - } - rxbuf->m_head = NULL; - rxbuf->m_pack = NULL; - } + igb_free_receive_ring(rxr); - /* 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 ring mbufs */ + for (int j = 0; j != adapter->num_rx_desc; ++j) { + struct mbuf *mh, *mp; - /* Setup our descriptor indices */ - rxr->next_to_check = 0; - rxr->last_cleaned = 0; + rxbuf = &rxr->rx_buffers[j]; + + /* First the header */ + rxbuf->m_head = m_gethdr(M_DONTWAIT, MT_DATA); + if (rxbuf->m_head == NULL) + goto fail; + m_adj(rxbuf->m_head, ETHER_ALIGN); + mh = rxbuf->m_head; + mh->m_len = mh->m_pkthdr.len = MHLEN; + mh->m_flags |= M_PKTHDR; + /* Get the memory mapping */ + error = bus_dmamap_load_mbuf_sg(rxr->htag, + rxbuf->hmap, rxbuf->m_head, hseg, + &nsegs, BUS_DMA_NOWAIT); + if (error != 0) /* Nothing elegant to do here */ + goto fail; + bus_dmamap_sync(rxr->htag, + rxbuf->hmap, BUS_DMASYNC_PREREAD); + /* Update descriptor */ + rxr->rx_base[j].read.hdr_addr = htole64(hseg[0].ds_addr); + + /* Now the payload cluster */ + rxbuf->m_pack = m_getjcl(M_DONTWAIT, MT_DATA, + M_PKTHDR, adapter->rx_mbuf_sz); + if (rxbuf->m_pack == NULL) + goto fail; + mp = rxbuf->m_pack; + mp->m_pkthdr.len = mp->m_len = adapter->rx_mbuf_sz; + /* Get the memory mapping */ + error = bus_dmamap_load_mbuf_sg(rxr->ptag, + rxbuf->pmap, mp, pseg, + &nsegs, BUS_DMA_NOWAIT); + if (error != 0) + goto fail; + bus_dmamap_sync(rxr->ptag, + rxbuf->pmap, BUS_DMASYNC_PREREAD); + /* Update descriptor */ + rxr->rx_base[j].read.pkt_addr = htole64(pseg[0].ds_addr); + } + rxr->next_to_refresh = 0; + rxr->lro_enabled = FALSE; + + if (igb_header_split) + rxr->hdr_split = TRUE; + else + ifp->if_capabilities &= ~IFCAP_LRO; + + rxr->fmp = NULL; + rxr->lmp = NULL; + rxr->discard = FALSE; bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); @@ -3666,32 +3803,21 @@ igb_setup_receive_ring(struct rx_ring *rxr) if (ifp->if_capenable & IFCAP_LRO) { int err = tcp_lro_init(lro); if (err) { - device_printf(dev,"LRO Initialization failed!\n"); + device_printf(dev, "LRO Initialization failed!\n"); goto fail; } INIT_DEBUGOUT("RX LRO Initialized\n"); rxr->lro_enabled = TRUE; - rxr->hdr_split = TRUE; lro->ifp = adapter->ifp; } + IGB_RX_UNLOCK(rxr); return (0); + fail: - /* - * We need to clean up any buffers allocated - * so far, 'j' is the failing index. - */ - for (int i = 0; i < j; i++) { - rxbuf = &rxr->rx_buffers[i]; - if (rxbuf->m_head != NULL) { - bus_dmamap_sync(rxr->rxtag, rxbuf->map, - BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(rxr->rxtag, rxbuf->map); - m_freem(rxbuf->m_head); - rxbuf->m_head = NULL; - } - } - return (ENOBUFS); + igb_free_receive_ring(rxr); + IGB_RX_UNLOCK(rxr); + return (error); } /********************************************************************* @@ -3719,17 +3845,8 @@ igb_setup_receive_structures(struct adapter *adapter) */ rxr = adapter->rx_rings; for (--i; i > 0; i--, rxr++) { - for (j = 0; j < adapter->num_rx_desc; j++) { - struct igb_rx_buffer *rxbuf; - rxbuf = &rxr->rx_buffers[j]; - if (rxbuf->m_head != NULL) { - bus_dmamap_sync(rxr->rxtag, rxbuf->map, - BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(rxr->rxtag, rxbuf->map); - m_freem(rxbuf->m_head); - rxbuf->m_head = NULL; - } - } + for (j = 0; j < adapter->num_rx_desc; j++) + igb_free_receive_ring(rxr); } return (ENOBUFS); @@ -3745,6 +3862,7 @@ igb_initialize_receive_units(struct adapter *adapter) { struct rx_ring *rxr = adapter->rx_rings; struct ifnet *ifp = adapter->ifp; + struct e1000_hw *hw = &adapter->hw; u32 rctl, rxcsum, psize, srrctl = 0; INIT_DEBUGOUT("igb_initialize_receive_unit: begin"); @@ -3753,8 +3871,8 @@ igb_initialize_receive_units(struct adapter *adapter) * Make sure receives are disabled while setting * up the descriptor ring */ - rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL); - E1000_WRITE_REG(&adapter->hw, E1000_RCTL, rctl & ~E1000_RCTL_EN); + rctl = E1000_READ_REG(hw, E1000_RCTL); + E1000_WRITE_REG(hw, E1000_RCTL, rctl & ~E1000_RCTL_EN); /* ** Set up for header split @@ -3791,27 +3909,27 @@ igb_initialize_receive_units(struct adapter *adapter) u64 bus_addr = rxr->rxdma.dma_paddr; u32 rxdctl; - E1000_WRITE_REG(&adapter->hw, E1000_RDLEN(i), + E1000_WRITE_REG(hw, E1000_RDLEN(i), adapter->num_rx_desc * sizeof(struct e1000_rx_desc)); - E1000_WRITE_REG(&adapter->hw, E1000_RDBAH(i), + E1000_WRITE_REG(hw, E1000_RDBAH(i), (uint32_t)(bus_addr >> 32)); - E1000_WRITE_REG(&adapter->hw, E1000_RDBAL(i), + E1000_WRITE_REG(hw, E1000_RDBAL(i), (uint32_t)bus_addr); - E1000_WRITE_REG(&adapter->hw, E1000_SRRCTL(i), srrctl); + E1000_WRITE_REG(hw, E1000_SRRCTL(i), srrctl); /* Enable this Queue */ - rxdctl = E1000_READ_REG(&adapter->hw, E1000_RXDCTL(i)); + rxdctl = E1000_READ_REG(hw, E1000_RXDCTL(i)); rxdctl |= E1000_RXDCTL_QUEUE_ENABLE; rxdctl &= 0xFFF00000; rxdctl |= IGB_RX_PTHRESH; rxdctl |= IGB_RX_HTHRESH << 8; rxdctl |= IGB_RX_WTHRESH << 16; - E1000_WRITE_REG(&adapter->hw, E1000_RXDCTL(i), rxdctl); + E1000_WRITE_REG(hw, E1000_RXDCTL(i), rxdctl); } /* ** Setup for RX MultiQueue */ - rxcsum = E1000_READ_REG(&adapter->hw, E1000_RXCSUM); + rxcsum = E1000_READ_REG(hw, E1000_RXCSUM); if (adapter->num_queues >1) { u32 random[10], mrqc, shift = 0; union igb_reta { @@ -3827,13 +3945,13 @@ igb_initialize_receive_units(struct adapter *adapter) reta.bytes[i & 3] = (i % adapter->num_queues) << shift; if ((i & 3) == 3) - E1000_WRITE_REG(&adapter->hw, + E1000_WRITE_REG(hw, E1000_RETA(i >> 2), reta.dword); } /* Now fill in hash table */ mrqc = E1000_MRQC_ENABLE_RSS_4Q; for (int i = 0; i < 10; i++) - E1000_WRITE_REG_ARRAY(&adapter->hw, + E1000_WRITE_REG_ARRAY(hw, E1000_RSSRK(0), i, random[i]); mrqc |= (E1000_MRQC_RSS_FIELD_IPV4 | @@ -3845,7 +3963,7 @@ igb_initialize_receive_units(struct adapter *adapter) mrqc |=( E1000_MRQC_RSS_FIELD_IPV6_UDP_EX | E1000_MRQC_RSS_FIELD_IPV6_TCP_EX); - E1000_WRITE_REG(&adapter->hw, E1000_MRQC, mrqc); + E1000_WRITE_REG(hw, E1000_MRQC, mrqc); /* ** NOTE: Receive Full-Packet Checksum Offload @@ -3856,7 +3974,7 @@ igb_initialize_receive_units(struct adapter *adapter) rxcsum |= E1000_RXCSUM_PCSD; #if __FreeBSD_version >= 800000 /* For SCTP Offload */ - if ((adapter->hw.mac.type == e1000_82576) + if ((hw->mac.type == e1000_82576) && (ifp->if_capenable & IFCAP_RXCSUM)) rxcsum |= E1000_RXCSUM_CRCOFL; #endif @@ -3871,29 +3989,30 @@ igb_initialize_receive_units(struct adapter *adapter) } else rxcsum &= ~E1000_RXCSUM_TUOFL; } - E1000_WRITE_REG(&adapter->hw, E1000_RXCSUM, rxcsum); + E1000_WRITE_REG(hw, E1000_RXCSUM, rxcsum); /* Setup the Receive Control Register */ rctl &= ~(3 << E1000_RCTL_MO_SHIFT); rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | - (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT); - + (hw->mac.mc_filter_type << E1000_RCTL_MO_SHIFT); + /* Strip CRC bytes. */ + rctl |= E1000_RCTL_SECRC; /* Make sure VLAN Filters are off */ rctl &= ~E1000_RCTL_VFE; /* Don't store bad packets */ rctl &= ~E1000_RCTL_SBP; /* Enable Receives */ - E1000_WRITE_REG(&adapter->hw, E1000_RCTL, rctl); + E1000_WRITE_REG(hw, E1000_RCTL, rctl); /* * Setup the HW Rx Head and Tail Descriptor Pointers * - needs to be after enable */ for (int i = 0; i < adapter->num_queues; i++) { - E1000_WRITE_REG(&adapter->hw, E1000_RDH(i), 0); - E1000_WRITE_REG(&adapter->hw, E1000_RDT(i), + E1000_WRITE_REG(hw, E1000_RDH(i), 0); + E1000_WRITE_REG(hw, E1000_RDT(i), adapter->num_rx_desc - 1); } return; @@ -3927,48 +4046,115 @@ 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 *rxbuf; + int i; 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; - } - /* Cleanup any existing buffers */ if (rxr->rx_buffers != NULL) { - rx_buffer = &rxr->rx_buffers[0]; - for (int i = 0; i < adapter->num_rx_desc; i++, rx_buffer++) { - if (rx_buffer->m_head != NULL) { - bus_dmamap_sync(rxr->rxtag, rx_buffer->map, + for (i = 0; i < adapter->num_rx_desc; i++) { + rxbuf = &rxr->rx_buffers[i]; + if (rxbuf->m_head != NULL) { + bus_dmamap_sync(rxr->htag, rxbuf->hmap, BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(rxr->rxtag, - rx_buffer->map); - m_freem(rx_buffer->m_head); - rx_buffer->m_head = NULL; - } else if (rx_buffer->map != NULL) - bus_dmamap_unload(rxr->rxtag, - rx_buffer->map); - if (rx_buffer->map != NULL) { - bus_dmamap_destroy(rxr->rxtag, - rx_buffer->map); - rx_buffer->map = NULL; + bus_dmamap_unload(rxr->htag, rxbuf->hmap); + rxbuf->m_head->m_flags |= M_PKTHDR; + m_freem(rxbuf->m_head); } + if (rxbuf->m_pack != NULL) { + bus_dmamap_sync(rxr->ptag, rxbuf->pmap, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(rxr->ptag, rxbuf->pmap); + rxbuf->m_pack->m_flags |= M_PKTHDR; + m_freem(rxbuf->m_pack); + } + rxbuf->m_head = NULL; + rxbuf->m_pack = NULL; + if (rxbuf->hmap != NULL) { + bus_dmamap_destroy(rxr->htag, rxbuf->hmap); + rxbuf->hmap = NULL; + } + if (rxbuf->pmap != NULL) { + bus_dmamap_destroy(rxr->ptag, rxbuf->pmap); + rxbuf->pmap = NULL; + } + } + if (rxr->rx_buffers != NULL) { + free(rxr->rx_buffers, M_DEVBUF); + rxr->rx_buffers = NULL; } } - if (rxr->rx_buffers != NULL) { - free(rxr->rx_buffers, M_DEVBUF); - rxr->rx_buffers = NULL; + if (rxr->htag != NULL) { + bus_dma_tag_destroy(rxr->htag); + rxr->htag = NULL; } - - if (rxr->rxtag != NULL) { - bus_dma_tag_destroy(rxr->rxtag); - rxr->rxtag = NULL; + if (rxr->ptag != NULL) { + bus_dma_tag_destroy(rxr->ptag); + rxr->ptag = NULL; } } + +static __inline void +igb_rx_discard(struct rx_ring *rxr, int i) +{ + struct adapter *adapter = rxr->adapter; + struct igb_rx_buf *rbuf; + struct mbuf *mh, *mp; + + rbuf = &rxr->rx_buffers[i]; + if (rxr->fmp != NULL) { + rxr->fmp->m_flags |= M_PKTHDR; + m_freem(rxr->fmp); + rxr->fmp = NULL; + rxr->lmp = NULL; + } + + mh = rbuf->m_head; + mp = rbuf->m_pack; + + /* Reuse loaded DMA map and just update mbuf chain */ + 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; + mp->m_next = NULL; + return; +} + +static __inline void +igb_rx_input(struct rx_ring *rxr, struct ifnet *ifp, struct mbuf *m, u32 ptype) +{ + + /* + * ATM LRO is only for IPv4/TCP packets and TCP checksum of the packet + * should be computed by hardware. Also it should not have VLAN tag in + * ethernet header. + */ + if (rxr->lro_enabled && + (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0 && + (ptype & E1000_RXDADV_PKTTYPE_ETQF) == 0 && + (ptype & (E1000_RXDADV_PKTTYPE_IPV4 | E1000_RXDADV_PKTTYPE_TCP)) == + (E1000_RXDADV_PKTTYPE_IPV4 | E1000_RXDADV_PKTTYPE_TCP) && + (m->m_pkthdr.csum_flags & (CSUM_DATA_VALID | CSUM_PSEUDO_HDR)) == + (CSUM_DATA_VALID | CSUM_PSEUDO_HDR)) { + /* + * Send to the stack if: + ** - LRO not enabled, or + ** - no LRO resources, or + ** - lro enqueue fails + */ + if (rxr->lro.lro_cnt != 0) + if (tcp_lro_rx(&rxr->lro, m, 0) == 0) + return; + } + (*ifp->if_input)(ifp, m); +} + /********************************************************************* * * This routine executes in interrupt context. It replenishes @@ -3981,48 +4167,57 @@ 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) +igb_rxeof(struct igb_queue *que, int count) { - struct adapter *adapter = rxr->adapter; - struct ifnet *ifp; + struct adapter *adapter = que->adapter; + struct rx_ring *rxr = que->rxr; + struct ifnet *ifp = adapter->ifp; struct lro_ctrl *lro = &rxr->lro; struct lro_entry *queued; - int i; - u32 staterr; + int i, processed = 0; + u32 ptype, staterr = 0; 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; - - if (!(staterr & E1000_RXD_STAT_DD)) { - IGB_RX_UNLOCK(rxr); - return FALSE; - } - - /* Sync the ring */ + /* Sync the ring. */ bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, - BUS_DMASYNC_POSTREAD); + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); /* Main clean loop */ - 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; + for (i = rxr->next_to_check; count != 0;) { + struct mbuf *sendmp, *mh, *mp; + struct igb_rx_buf *rxbuf; + u16 hlen, plen, hdr, vtag; + bool eop = FALSE; - accept_frame = 1; - hlen = plen = len_adj = vtag = 0; + cur = &rxr->rx_base[i]; + staterr = le32toh(cur->wb.upper.status_error); + if ((staterr & E1000_RXD_STAT_DD) == 0) + break; + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + break; + count--; sendmp = mh = mp = NULL; - ptype = (u16)(cur->wb.lower.lo_dword.data >> 4); + cur->wb.upper.status_error = 0; + rxbuf = &rxr->rx_buffers[i]; + plen = le16toh(cur->wb.upper.length); + ptype = le32toh(cur->wb.lower.lo_dword.data) & IGB_PKTTYPE_MASK; + vtag = le16toh(cur->wb.upper.vlan); + hdr = le16toh(cur->wb.lower.lo_dword.hs_rss.hdr_info); + eop = ((staterr & E1000_RXD_STAT_EOP) == E1000_RXD_STAT_EOP); - /* Sync the buffers */ - bus_dmamap_sync(rxr->rxtag, rxr->rx_buffers[i].map, - BUS_DMASYNC_POSTREAD); + /* Make sure all segments of a bad packet are discarded */ + if (((staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) != 0) || + (rxr->discard)) { + ifp->if_ierrors++; + ++rxr->rx_discarded; + if (!eop) /* Catch subsequent segs */ + rxr->discard = TRUE; + else + rxr->discard = FALSE; + igb_rx_discard(rxr, i); + goto next_desc; + } /* ** The way the hardware is configured to @@ -4035,35 +4230,28 @@ igb_rxeof(struct rx_ring *rxr, int count) ** packet spans multiple descriptors, in that ** case only the first header is valid. */ - if ((rxr->hdr_split) && (rxr->fmp == NULL)){ - hdr = le16toh(cur-> - wb.lower.lo_dword.hs_rss.hdr_info); + if (rxr->hdr_split && rxr->fmp == NULL) { hlen = (hdr & E1000_RXDADV_HDRBUFLEN_MASK) >> E1000_RXDADV_HDRBUFLEN_SHIFT; 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; + /* clear buf info for refresh */ + rxbuf->m_head = NULL; /* ** Get the payload length, this ** could be zero if its a small ** packet. */ - if (plen) { + if (plen > 0) { 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; + /* clear buf info for refresh */ + rxbuf->m_pack = NULL; rxr->rx_split_packets++; - } else { /* small packets */ - mh->m_flags &= ~M_PKTHDR; - mh->m_next = NULL; } } else { /* @@ -4072,179 +4260,91 @@ igb_rxeof(struct rx_ring *rxr, int count) ** 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; + mh->m_len = plen; + /* clear buf info for refresh */ + rxbuf->m_pack = NULL; } - if (staterr & E1000_RXD_STAT_EOP) { - count--; - eop = 1; - /* - ** Strip CRC and account for frag - */ - 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; - } - } else - eop = 0; + ++processed; /* So we know when to refresh */ - 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; - } - } - - if (eop) { - bool sctp = ((ptype & 0x40) != 0); - rxr->fmp->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; - } -#if __FreeBSD_version >= 800000 - rxr->fmp->m_pkthdr.flowid = curcpu; - rxr->fmp->m_flags |= M_FLOWID; -#endif - sendmp = rxr->fmp; - rxr->fmp = NULL; - rxr->lmp = NULL; + /* Initial frame - setup */ + if (rxr->fmp == NULL) { + mh->m_pkthdr.len = mh->m_len; + /* Store the first mbuf */ + rxr->fmp = mh; + rxr->lmp = mh; + if (mp != NULL) { + /* Add payload if split */ + mh->m_pkthdr.len += mp->m_len; + rxr->lmp = mh->m_next; } } 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; - mp->m_len = mp->m_pkthdr.len = adapter->rx_mbuf_sz; - mp->m_data = mp->m_ext.ext_buf; - 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; + /* Chain mbuf's together */ + rxr->lmp->m_next = mh; + rxr->lmp = rxr->lmp->m_next; + rxr->fmp->m_pkthdr.len += mh->m_len; } + if (eop) { + rxr->fmp->m_pkthdr.rcvif = ifp; + ifp->if_ipackets++; + rxr->rx_packets++; + /* capture data for AIM */ + rxr->packets++; + rxr->bytes += rxr->fmp->m_pkthdr.len; + rxr->rx_bytes += rxr->fmp->m_pkthdr.len; + + if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) + igb_rx_checksum(staterr, rxr->fmp, ptype); + + if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0 && + (staterr & E1000_RXD_STAT_VP) != 0) { + rxr->fmp->m_pkthdr.ether_vtag = vtag; + rxr->fmp->m_flags |= M_VLANTAG; + } +#if __FreeBSD_version >= 800000 + rxr->fmp->m_pkthdr.flowid = que->msix; + rxr->fmp->m_flags |= M_FLOWID; +#endif + sendmp = rxr->fmp; + /* Make sure to set M_PKTHDR. */ + sendmp->m_flags |= M_PKTHDR; + rxr->fmp = NULL; + rxr->lmp = NULL; + } + +next_desc: 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. */ if (++i == adapter->num_rx_desc) i = 0; - /* - ** Note that we hold the RX lock thru - ** the following call so this ring's - ** next_to_check is not gonna change. + ** Send to the stack or LRO */ - if (sendmp != NULL) { - /* - ** Send to the stack if: - ** - LRO not enabled, or - ** - no LRO resources, or - ** - lro enqueue fails - */ - if ((!rxr->lro_enabled) || - ((!lro->lro_cnt) || (tcp_lro_rx(lro, sendmp, 0)))) - (*ifp->if_input)(ifp, sendmp); - } + if (sendmp != NULL) + igb_rx_input(rxr, ifp, sendmp, ptype); - /* Get the next descriptor */ - cur = &rxr->rx_base[i]; - staterr = cur->wb.upper.status_error; + /* Every 8 descriptors we go to refresh mbufs */ + if (processed == 8) { + igb_refresh_mbufs(rxr, i); + processed = 0; + } } - 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); + /* Catch any remainders */ + if (processed != 0) { + igb_refresh_mbufs(rxr, i); + processed = 0; + } + + rxr->next_to_check = i; /* * Flush any outstanding LRO work */ - while (!SLIST_EMPTY(&lro->lro_active)) { - queued = SLIST_FIRST(&lro->lro_active); + while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) { SLIST_REMOVE_HEAD(&lro->lro_active, next); tcp_lro_flush(lro, queued); } @@ -4255,15 +4355,12 @@ igb_rxeof(struct rx_ring *rxr, int count) ** We still have cleaning to do? ** Schedule another interrupt if so. */ - if (staterr & E1000_RXD_STAT_DD) { - E1000_WRITE_REG(&adapter->hw, E1000_EICS, rxr->eims); - return TRUE; - } + if ((staterr & E1000_RXD_STAT_DD) != 0) + return (TRUE); - return FALSE; + return (FALSE); } - /********************************************************************* * * Verify that the hardware indicated that the checksum is valid. @@ -4272,10 +4369,11 @@ igb_rxeof(struct rx_ring *rxr, int count) * *********************************************************************/ static void -igb_rx_checksum(u32 staterr, struct mbuf *mp, bool sctp) +igb_rx_checksum(u32 staterr, struct mbuf *mp, u32 ptype) { u16 status = (u16)staterr; u8 errors = (u8) (staterr >> 24); + int sctp; /* Ignore Checksum bit is set */ if (status & E1000_RXD_STAT_IXSM) { @@ -4283,6 +4381,11 @@ igb_rx_checksum(u32 staterr, struct mbuf *mp, bool sctp) return; } + if ((ptype & E1000_RXDADV_PKTTYPE_ETQF) == 0 && + (ptype & E1000_RXDADV_PKTTYPE_SCTP) != 0) + sctp = 1; + else + sctp = 0; if (status & E1000_RXD_STAT_IPCS) { /* Did it pass? */ if (!(errors & E1000_RXD_ERR_IPE)) { @@ -4302,7 +4405,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 == 0) mp->m_pkthdr.csum_data = htons(0xffff); } } @@ -4522,7 +4625,7 @@ igb_is_valid_ether_addr(uint8_t *addr) /* * Enable PCI Wake On Lan capability */ -void +static void igb_enable_wakeup(device_t dev) { u16 cap, status; @@ -4543,6 +4646,21 @@ igb_enable_wakeup(device_t dev) return; } +static void +igb_led_func(void *arg, int onoff) +{ + struct adapter *adapter = arg; + + IGB_CORE_LOCK(adapter); + if (onoff) { + e1000_setup_led(&adapter->hw); + e1000_led_on(&adapter->hw); + } else { + e1000_led_off(&adapter->hw); + e1000_cleanup_led(&adapter->hw); + } + IGB_CORE_UNLOCK(adapter); +} /********************************************************************** * @@ -4650,6 +4768,7 @@ static void igb_print_debug_info(struct adapter *adapter) { device_t dev = adapter->dev; + struct igb_queue *que = adapter->queues; struct rx_ring *rxr = adapter->rx_rings; struct tx_ring *txr = adapter->tx_rings; uint8_t *hw_addr = adapter->hw.hw_addr; @@ -4672,16 +4791,19 @@ igb_print_debug_info(struct adapter *adapter) adapter->hw.fc.high_water, adapter->hw.fc.low_water); - for (int i = 0; i < adapter->num_queues; i++, txr++) { - device_printf(dev, "Queue(%d) tdh = %d, tdt = %d\n", i, + for (int i = 0; i < adapter->num_queues; i++, rxr++, txr++) { + device_printf(dev, "Queue(%d) tdh = %d, tdt = %d ", i, E1000_READ_REG(&adapter->hw, E1000_TDH(i)), E1000_READ_REG(&adapter->hw, E1000_TDT(i))); + device_printf(dev, "rdh = %d, rdt = %d\n", + E1000_READ_REG(&adapter->hw, E1000_RDH(i)), + E1000_READ_REG(&adapter->hw, E1000_RDT(i))); device_printf(dev, "TX(%d) no descriptors avail event = %lld\n", txr->me, (long long)txr->no_desc_avail); - device_printf(dev, "TX(%d) MSIX IRQ Handled = %lld\n", txr->me, - (long long)txr->tx_irq); - device_printf(dev, "TX(%d) Packets sent = %lld\n", txr->me, - (long long)txr->tx_packets); + device_printf(dev, "TX(%d) Packets sent = %lld\n", + txr->me, (long long)txr->tx_packets); + device_printf(dev, "RX(%d) Packets received = %lld ", + rxr->me, (long long)rxr->rx_packets); } for (int i = 0; i < adapter->num_queues; i++, rxr++) { @@ -4691,20 +4813,20 @@ igb_print_debug_info(struct adapter *adapter) E1000_READ_REG(&adapter->hw, E1000_RDT(i))); device_printf(dev, "RX(%d) Packets received = %lld\n", rxr->me, (long long)rxr->rx_packets); - device_printf(dev, "RX(%d) Split Packets = %lld\n", rxr->me, + device_printf(dev, " Split Packets = %lld ", (long long)rxr->rx_split_packets); - device_printf(dev, "RX(%d) Byte count = %lld\n", rxr->me, + device_printf(dev, " Byte count = %lld\n", (long long)rxr->rx_bytes); - device_printf(dev, "RX(%d) MSIX IRQ Handled = %lld\n", rxr->me, - (long long)rxr->rx_irq); - device_printf(dev,"RX(%d) LRO Queued= %d\n", - rxr->me, lro->lro_queued); - device_printf(dev,"RX(%d) LRO Flushed= %d\n", - rxr->me, lro->lro_flushed); + device_printf(dev,"RX(%d) LRO Queued= %d ", + i, lro->lro_queued); + device_printf(dev,"LRO Flushed= %d\n",lro->lro_flushed); } - device_printf(dev, "LINK MSIX IRQ Handled = %u\n", adapter->link_irq); + for (int i = 0; i < adapter->num_queues; i++, que++) + device_printf(dev,"QUE(%d) IRQs = %llx\n", + i, (long long)que->irqs); + device_printf(dev, "LINK MSIX IRQ Handled = %u\n", adapter->link_irq); device_printf(dev, "Mbuf defrag failed = %ld\n", adapter->mbuf_defrag_failed); device_printf(dev, "Std mbuf header failed = %ld\n", @@ -4857,173 +4979,3 @@ igb_add_rx_process_limit(struct adapter *adapter, const char *name, SYSCTL_CHILDREN(device_get_sysctl_tree(adapter->dev)), OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW, limit, value, description); } - -#ifdef IGB_IEEE1588 -/* -** igb_hwtstamp_ioctl - control hardware time stamping -** -** Outgoing time stamping can be enabled and disabled. Play nice and -** disable it when requested, although it shouldn't case any overhead -** when no packet needs it. At most one packet in the queue may be -** marked for time stamping, otherwise it would be impossible to tell -** for sure to which packet the hardware time stamp belongs. -** -** Incoming time stamping has to be configured via the hardware -** filters. Not all combinations are supported, in particular event -** type has to be specified. Matching the kind of event packet is -** not supported, with the exception of "all V2 events regardless of -** level 2 or 4". -** -*/ -static int -igb_hwtstamp_ioctl(struct adapter *adapter, struct ifreq *ifr) -{ - struct e1000_hw *hw = &adapter->hw; - struct hwtstamp_ctrl *config; - u32 tsync_tx_ctl_bit = E1000_TSYNCTXCTL_ENABLED; - u32 tsync_rx_ctl_bit = E1000_TSYNCRXCTL_ENABLED; - u32 tsync_rx_ctl_type = 0; - u32 tsync_rx_cfg = 0; - int is_l4 = 0; - int is_l2 = 0; - u16 port = 319; /* PTP */ - u32 regval; - - config = (struct hwtstamp_ctrl *) ifr->ifr_data; - - /* reserved for future extensions */ - if (config->flags) - return (EINVAL); - - switch (config->tx_type) { - case HWTSTAMP_TX_OFF: - tsync_tx_ctl_bit = 0; - break; - case HWTSTAMP_TX_ON: - tsync_tx_ctl_bit = E1000_TSYNCTXCTL_ENABLED; - break; - default: - return (ERANGE); - } - - switch (config->rx_filter) { - case HWTSTAMP_FILTER_NONE: - tsync_rx_ctl_bit = 0; - break; - case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: - case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: - case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: - case HWTSTAMP_FILTER_ALL: - /* - * register TSYNCRXCFG must be set, therefore it is not - * possible to time stamp both Sync and Delay_Req messages - * => fall back to time stamping all packets - */ - tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_ALL; - config->rx_filter = HWTSTAMP_FILTER_ALL; - break; - case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: - tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_L4_V1; - tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE; - is_l4 = 1; - break; - case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: - tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_L4_V1; - tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE; - is_l4 = 1; - break; - case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: - case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: - tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_L2_L4_V2; - tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V2_SYNC_MESSAGE; - is_l2 = 1; - is_l4 = 1; - config->rx_filter = HWTSTAMP_FILTER_SOME; - break; - case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: - case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: - tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_L2_L4_V2; - tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V2_DELAY_REQ_MESSAGE; - is_l2 = 1; - is_l4 = 1; - config->rx_filter = HWTSTAMP_FILTER_SOME; - break; - case HWTSTAMP_FILTER_PTP_V2_EVENT: - case HWTSTAMP_FILTER_PTP_V2_SYNC: - case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: - tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_EVENT_V2; - config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; - is_l2 = 1; - break; - default: - return -ERANGE; - } - - /* enable/disable TX */ - regval = E1000_READ_REG(hw, E1000_TSYNCTXCTL); - regval = (regval & ~E1000_TSYNCTXCTL_ENABLED) | tsync_tx_ctl_bit; - E1000_WRITE_REG(hw, E1000_TSYNCTXCTL, regval); - - /* enable/disable RX, define which PTP packets are time stamped */ - regval = E1000_READ_REG(hw, E1000_TSYNCRXCTL); - regval = (regval & ~E1000_TSYNCRXCTL_ENABLED) | tsync_rx_ctl_bit; - regval = (regval & ~0xE) | tsync_rx_ctl_type; - E1000_WRITE_REG(hw, E1000_TSYNCRXCTL, regval); - E1000_WRITE_REG(hw, E1000_TSYNCRXCFG, tsync_rx_cfg); - - /* - * Ethertype Filter Queue Filter[0][15:0] = 0x88F7 - * (Ethertype to filter on) - * Ethertype Filter Queue Filter[0][26] = 0x1 (Enable filter) - * Ethertype Filter Queue Filter[0][30] = 0x1 (Enable Timestamping) - */ - E1000_WRITE_REG(hw, E1000_ETQF0, is_l2 ? 0x440088f7 : 0); - - /* L4 Queue Filter[0]: only filter by source and destination port */ - E1000_WRITE_REG(hw, E1000_SPQF0, htons(port)); - E1000_WRITE_REG(hw, E1000_IMIREXT(0), is_l4 ? - ((1<<12) | (1<<19) /* bypass size and control flags */) : 0); - E1000_WRITE_REG(hw, E1000_IMIR(0), is_l4 ? - (htons(port) - | (0<<16) /* immediate interrupt disabled */ - | 0 /* (1<<17) bit cleared: do not bypass - destination port check */) - : 0); - E1000_WRITE_REG(hw, E1000_FTQF0, is_l4 ? - (0x11 /* UDP */ - | (1<<15) /* VF not compared */ - | (1<<27) /* Enable Timestamping */ - | (7<<28) /* only source port filter enabled, - source/target address and protocol - masked */) - : ((1<<15) | (15<<28) /* all mask bits set = filter not - enabled */)); - - wrfl(); - - adapter->hwtstamp_ctrl = config; - - /* clear TX/RX time stamp registers, just to be sure */ - regval = E1000_READ_REG(hw, E1000_TXSTMPH); - regval = E1000_READ_REG(hw, E1000_RXSTMPH); - - return (error); -} - -/* -** igb_read_clock - read raw cycle counter (to be used by time counter) -*/ -static cycle_t igb_read_clock(const struct cyclecounter *tc) -{ - struct igb_adapter *adapter = - container_of(tc, struct igb_adapter, cycles); - struct e1000_hw *hw = &adapter->hw; - u64 stamp; - - stamp = E1000_READ_REG(hw, E1000_SYSTIML); - stamp |= (u64)E1000_READ_REG(hw, E1000_SYSTIMH) << 32ULL; - - return (stamp); -} - -#endif /* IGB_IEEE1588 */ diff --git a/sys/dev/e1000/if_igb.h b/sys/dev/e1000/if_igb.h index ddc4d8ae9e6a..28bcc91caa0c 100644 --- a/sys/dev/e1000/if_igb.h +++ b/sys/dev/e1000/if_igb.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -47,8 +47,8 @@ * desscriptors should meet the following condition. * (num_tx_desc * sizeof(struct e1000_tx_desc)) % 128 == 0 */ -#define IGB_MIN_TXD 80 -#define IGB_DEFAULT_TXD 256 +#define IGB_MIN_TXD 256 +#define IGB_DEFAULT_TXD 1024 #define IGB_MAX_TXD 4096 /* @@ -62,8 +62,8 @@ * desscriptors should meet the following condition. * (num_tx_desc * sizeof(struct e1000_tx_desc)) % 128 == 0 */ -#define IGB_MIN_RXD 80 -#define IGB_DEFAULT_RXD 256 +#define IGB_MIN_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 @@ -173,10 +173,16 @@ #define IGB_SMARTSPEED_DOWNSHIFT 3 #define IGB_SMARTSPEED_MAX 15 #define IGB_MAX_LOOP 10 -#define IGB_RX_PTHRESH 16 + +#define IGB_RX_PTHRESH (hw->mac.type <= e1000_82576 ? 16 : 8) #define IGB_RX_HTHRESH 8 #define IGB_RX_WTHRESH 1 +#define IGB_TX_PTHRESH 8 +#define IGB_TX_HTHRESH 1 +#define IGB_TX_WTHRESH ((hw->mac.type == e1000_82576 && \ + adapter->msix_mem) ? 1 : 16) + #define MAX_NUM_MULTICAST_ADDRESSES 128 #define PCI_ANY_ID (~0U) #define ETHER_ALIGN 2 @@ -225,6 +231,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,17 +242,16 @@ #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 +/* Define the starting Interrupt rate per Queue */ +#define IGB_INTS_PER_SEC 8000 +#define IGB_DEFAULT_ITR 1000000000/(IGB_INTS_PER_SEC * 256) + + +/* Header split codes for get_buf */ +#define IGB_CLEAN_HEADER 0x01 +#define IGB_CLEAN_PAYLOAD 0x02 +#define IGB_CLEAN_BOTH (IGB_CLEAN_HEADER | IGB_CLEAN_PAYLOAD) -/* - * Interrupt Moderation parameters - */ -#define IGB_LOW_LATENCY 128 -#define IGB_AVE_LATENCY 450 -#define IGB_BULK_LATENCY 1200 #define IGB_LINK_ITR 2000 /* Precision Time Sync (IEEE 1588) defines */ @@ -268,18 +274,33 @@ struct igb_dma_alloc { /* - * Transmit ring: one per tx queue +** Driver queue struct: this is the interrupt container +** for the associated tx and rx ring. +*/ +struct igb_queue { + struct adapter *adapter; + u32 msix; /* This queue's MSIX vector */ + u32 eims; /* This queue's EIMS bit */ + u32 eitr_setting; + struct resource *res; + void *tag; + struct tx_ring *txr; + struct rx_ring *rxr; + struct task que_task; + struct taskqueue *tq; + u64 irqs; +}; + +/* + * Transmit ring: one per queue */ struct tx_ring { struct adapter *adapter; u32 me; - u32 msix; /* This ring's MSIX vector */ - u32 eims; /* This ring's EIMS bit */ struct mtx tx_mtx; char mtx_name[16]; - struct igb_dma_alloc txdma; /* bus_dma glue for tx desc */ + struct igb_dma_alloc txdma; struct e1000_tx_desc *tx_base; - struct task tx_task; /* cleanup tasklet */ u32 next_avail_desc; u32 next_to_clean; volatile u16 tx_avail; @@ -287,37 +308,36 @@ struct tx_ring { #if __FreeBSD_version >= 800000 struct buf_ring *br; #endif - bus_dma_tag_t txtag; /* dma tag for tx */ - struct resource *res; - void *tag; + bus_dma_tag_t txtag; - u32 watchdog_timer; + u32 bytes; + u32 packets; + + bool watchdog_check; + int watchdog_time; u64 no_desc_avail; - u64 tx_irq; u64 tx_packets; }; /* - * Receive ring: one per rx queue + * Receive ring: one per queue */ struct rx_ring { struct adapter *adapter; u32 me; - u32 msix; /* This ring's MSIX vector */ - u32 eims; /* This ring's EIMS bit */ - struct igb_dma_alloc rxdma; /* bus_dma glue for tx desc */ + struct igb_dma_alloc rxdma; union e1000_adv_rx_desc *rx_base; struct lro_ctrl lro; bool lro_enabled; bool hdr_split; - struct task rx_task; /* cleanup tasklet */ + bool discard; struct mtx rx_mtx; char mtx_name[16]; - u32 last_cleaned; + u32 next_to_refresh; u32 next_to_check; - struct igb_rx_buffer *rx_buffers; - bus_dma_tag_t rxtag; /* dma tag for tx */ - bus_dmamap_t rx_spare_map; + struct igb_rx_buf *rx_buffers; + bus_dma_tag_t htag; /* dma tag for rx head */ + bus_dma_tag_t ptag; /* dma tag for rx packet */ /* * First/last mbuf pointers, for * collecting multisegment RX packets. @@ -326,14 +346,11 @@ struct rx_ring { struct mbuf *lmp; u32 bytes; - u32 eitr_setting; - - struct resource *res; - void *tag; + u32 packets; /* Soft stats */ - u64 rx_irq; u64 rx_split_packets; + u64 rx_discarded; u64 rx_packets; u64 rx_bytes; }; @@ -342,9 +359,9 @@ struct adapter { struct ifnet *ifp; struct e1000_hw hw; - /* FreeBSD operating-system-specific structures. */ struct e1000_osdep osdep; struct device *dev; + struct cdev *led_dev; struct resource *pci_mem; struct resource *msix_mem; @@ -354,6 +371,7 @@ struct adapter { int linkvec; int link_mask; + struct task link_task; int link_irq; struct ifmedia media; @@ -364,9 +382,8 @@ 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 */ + struct taskqueue *tq; /* adapter task queue */ u16 num_queues; eventhandler_tag vlan_attach; @@ -383,12 +400,14 @@ struct adapter { u16 link_duplex; u32 smartspeed; + /* Interface queues */ + struct igb_queue *queues; + /* * Transmit rings */ struct tx_ring *tx_rings; u16 num_tx_desc; - u32 txd_cmd; /* * Receive rings @@ -445,25 +464,29 @@ 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 */ + bus_dmamap_t hmap; /* bus_dma map for header */ + bus_dmamap_t pmap; /* bus_dma map for packet */ }; #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_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_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) #define IGB_CORE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->core_mtx, MA_OWNED) + +#define IGB_TX_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->tx_mtx) +#define IGB_TX_LOCK(_sc) mtx_lock(&(_sc)->tx_mtx) +#define IGB_TX_UNLOCK(_sc) mtx_unlock(&(_sc)->tx_mtx) +#define IGB_TX_TRYLOCK(_sc) mtx_trylock(&(_sc)->tx_mtx) +#define IGB_TX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->tx_mtx, MA_OWNED) + +#define IGB_RX_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->rx_mtx) +#define IGB_RX_LOCK(_sc) mtx_lock(&(_sc)->rx_mtx) +#define IGB_RX_UNLOCK(_sc) mtx_unlock(&(_sc)->rx_mtx) #define IGB_TX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->tx_mtx, MA_OWNED) #endif /* _IGB_H_DEFINED_ */ diff --git a/sys/dev/e1000/if_lem.c b/sys/dev/e1000/if_lem.c new file mode 100644 index 000000000000..cf71f2bb74bf --- /dev/null +++ b/sys/dev/e1000/if_lem.c @@ -0,0 +1,4706 @@ +/****************************************************************************** + + Copyright (c) 2001-2010, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ +/*$FreeBSD$*/ + +#ifdef HAVE_KERNEL_OPTION_HEADERS +#include "opt_device_polling.h" +#include "opt_inet.h" +#endif + +#include +#include +#if __FreeBSD_version >= 800000 +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if __FreeBSD_version >= 700029 +#include +#endif +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "e1000_api.h" +#include "if_lem.h" + +/********************************************************************* + * Set this to one to display debug statistics + *********************************************************************/ +int lem_display_debug_stats = 0; + +/********************************************************************* + * Legacy Em Driver version: + *********************************************************************/ +char lem_driver_version[] = "1.0.0"; + + +/********************************************************************* + * PCI Device ID Table + * + * Used by probe to select devices to load on + * Last field stores an index into e1000_strings + * Last entry must be all 0s + * + * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } + *********************************************************************/ + +static em_vendor_info_t lem_vendor_info_array[] = +{ + /* Intel(R) PRO/1000 Network Connection */ + { 0x8086, E1000_DEV_ID_82540EM, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82540EM_LOM, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82540EP, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82540EP_LOM, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82540EP_LP, PCI_ANY_ID, PCI_ANY_ID, 0}, + + { 0x8086, E1000_DEV_ID_82541EI, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82541ER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82541ER_LOM, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82541EI_MOBILE, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82541GI, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82541GI_LF, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82541GI_MOBILE, PCI_ANY_ID, PCI_ANY_ID, 0}, + + { 0x8086, E1000_DEV_ID_82542, PCI_ANY_ID, PCI_ANY_ID, 0}, + + { 0x8086, E1000_DEV_ID_82543GC_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82543GC_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, + + { 0x8086, E1000_DEV_ID_82544EI_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82544EI_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82544GC_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82544GC_LOM, PCI_ANY_ID, PCI_ANY_ID, 0}, + + { 0x8086, E1000_DEV_ID_82545EM_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82545EM_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82545GM_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82545GM_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82545GM_SERDES, PCI_ANY_ID, PCI_ANY_ID, 0}, + + { 0x8086, E1000_DEV_ID_82546EB_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82546EB_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82546EB_QUAD_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82546GB_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82546GB_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82546GB_SERDES, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82546GB_PCIE, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82546GB_QUAD_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3, + PCI_ANY_ID, PCI_ANY_ID, 0}, + + { 0x8086, E1000_DEV_ID_82547EI, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82547EI_MOBILE, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82547GI, PCI_ANY_ID, PCI_ANY_ID, 0}, + /* required last entry */ + { 0, 0, 0, 0, 0} +}; + +/********************************************************************* + * Table of branding strings for all supported NICs. + *********************************************************************/ + +static char *lem_strings[] = { + "Intel(R) PRO/1000 Legacy Network Connection" +}; + +/********************************************************************* + * Function prototypes + *********************************************************************/ +static int lem_probe(device_t); +static int lem_attach(device_t); +static int lem_detach(device_t); +static int lem_shutdown(device_t); +static int lem_suspend(device_t); +static int lem_resume(device_t); +static void lem_start(struct ifnet *); +static void lem_start_locked(struct ifnet *ifp); +#if __FreeBSD_version >= 800000 +static int lem_mq_start(struct ifnet *, struct mbuf *); +static int lem_mq_start_locked(struct ifnet *, struct mbuf *); +static void lem_qflush(struct ifnet *); +#endif +static int lem_ioctl(struct ifnet *, u_long, caddr_t); +static void lem_init(void *); +static void lem_init_locked(struct adapter *); +static void lem_stop(void *); +static void lem_media_status(struct ifnet *, struct ifmediareq *); +static int lem_media_change(struct ifnet *); +static void lem_identify_hardware(struct adapter *); +static int lem_allocate_pci_resources(struct adapter *); +static int lem_allocate_irq(struct adapter *adapter); +static void lem_free_pci_resources(struct adapter *); +static void lem_local_timer(void *); +static int lem_hardware_init(struct adapter *); +static void lem_setup_interface(device_t, struct adapter *); +static void lem_setup_transmit_structures(struct adapter *); +static void lem_initialize_transmit_unit(struct adapter *); +static int lem_setup_receive_structures(struct adapter *); +static void lem_initialize_receive_unit(struct adapter *); +static void lem_enable_intr(struct adapter *); +static void lem_disable_intr(struct adapter *); +static void lem_free_transmit_structures(struct adapter *); +static void lem_free_receive_structures(struct adapter *); +static void lem_update_stats_counters(struct adapter *); +static void lem_txeof(struct adapter *); +static void lem_tx_purge(struct adapter *); +static int lem_allocate_receive_structures(struct adapter *); +static int lem_allocate_transmit_structures(struct adapter *); +static int lem_rxeof(struct adapter *, int); +#ifndef __NO_STRICT_ALIGNMENT +static int lem_fixup_rx(struct adapter *); +#endif +static void lem_receive_checksum(struct adapter *, struct e1000_rx_desc *, + struct mbuf *); +static void lem_transmit_checksum_setup(struct adapter *, struct mbuf *, + u32 *, u32 *); +static void lem_set_promisc(struct adapter *); +static void lem_disable_promisc(struct adapter *); +static void lem_set_multi(struct adapter *); +static void lem_print_hw_stats(struct adapter *); +static void lem_update_link_status(struct adapter *); +static int lem_get_buf(struct adapter *, int); +#if __FreeBSD_version >= 700029 +static void lem_register_vlan(void *, struct ifnet *, u16); +static void lem_unregister_vlan(void *, struct ifnet *, u16); +static void lem_setup_vlan_hw_support(struct adapter *); +#endif +static int lem_xmit(struct adapter *, struct mbuf **); +static void lem_smartspeed(struct adapter *); +static int lem_82547_fifo_workaround(struct adapter *, int); +static void lem_82547_update_fifo_head(struct adapter *, int); +static int lem_82547_tx_fifo_reset(struct adapter *); +static void lem_82547_move_tail(void *); +static int lem_dma_malloc(struct adapter *, bus_size_t, + struct em_dma_alloc *, int); +static void lem_dma_free(struct adapter *, struct em_dma_alloc *); +static void lem_print_debug_info(struct adapter *); +static void lem_print_nvm_info(struct adapter *); +static int lem_is_valid_ether_addr(u8 *); +static int lem_sysctl_stats(SYSCTL_HANDLER_ARGS); +static int lem_sysctl_debug_info(SYSCTL_HANDLER_ARGS); +static u32 lem_fill_descriptors (bus_addr_t address, u32 length, + PDESC_ARRAY desc_array); +static int lem_sysctl_int_delay(SYSCTL_HANDLER_ARGS); +static void lem_add_int_delay_sysctl(struct adapter *, const char *, + const char *, struct em_int_delay_info *, int, int); +/* Management and WOL Support */ +static void lem_init_manageability(struct adapter *); +static void lem_release_manageability(struct adapter *); +static void lem_get_hw_control(struct adapter *); +static void lem_release_hw_control(struct adapter *); +static void lem_get_wakeup(device_t); +static void lem_enable_wakeup(device_t); +static int lem_enable_phy_wakeup(struct adapter *); +static void lem_led_func(void *, int); + +#ifdef EM_LEGACY_IRQ +static void lem_intr(void *); +#else /* FAST IRQ */ +#if __FreeBSD_version < 700000 +static void lem_irq_fast(void *); +#else +static int lem_irq_fast(void *); +#endif +static void lem_handle_rxtx(void *context, int pending); +static void lem_handle_link(void *context, int pending); +static void lem_add_rx_process_limit(struct adapter *, const char *, + const char *, int *, int); +#endif /* ~EM_LEGACY_IRQ */ + +#ifdef DEVICE_POLLING +static poll_handler_t lem_poll; +#endif /* POLLING */ + +/********************************************************************* + * FreeBSD Device Interface Entry Points + *********************************************************************/ + +static device_method_t lem_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, lem_probe), + DEVMETHOD(device_attach, lem_attach), + DEVMETHOD(device_detach, lem_detach), + DEVMETHOD(device_shutdown, lem_shutdown), + DEVMETHOD(device_suspend, lem_suspend), + DEVMETHOD(device_resume, lem_resume), + {0, 0} +}; + +static driver_t lem_driver = { + "em", lem_methods, sizeof(struct adapter), +}; + +extern devclass_t em_devclass; +DRIVER_MODULE(lem, pci, lem_driver, em_devclass, 0, 0); +MODULE_DEPEND(lem, pci, 1, 1, 1); +MODULE_DEPEND(lem, ether, 1, 1, 1); + +/********************************************************************* + * Tunable default values. + *********************************************************************/ + +#define EM_TICKS_TO_USECS(ticks) ((1024 * (ticks) + 500) / 1000) +#define EM_USECS_TO_TICKS(usecs) ((1000 * (usecs) + 512) / 1024) +#define M_TSO_LEN 66 + +/* Allow common code without TSO */ +#ifndef CSUM_TSO +#define CSUM_TSO 0 +#endif + +static int lem_tx_int_delay_dflt = EM_TICKS_TO_USECS(EM_TIDV); +static int lem_rx_int_delay_dflt = EM_TICKS_TO_USECS(EM_RDTR); +static int lem_tx_abs_int_delay_dflt = EM_TICKS_TO_USECS(EM_TADV); +static int lem_rx_abs_int_delay_dflt = EM_TICKS_TO_USECS(EM_RADV); +static int lem_rxd = EM_DEFAULT_RXD; +static int lem_txd = EM_DEFAULT_TXD; +static int lem_smart_pwr_down = FALSE; + +/* Controls whether promiscuous also shows bad packets */ +static int lem_debug_sbp = FALSE; + +TUNABLE_INT("hw.em.tx_int_delay", &lem_tx_int_delay_dflt); +TUNABLE_INT("hw.em.rx_int_delay", &lem_rx_int_delay_dflt); +TUNABLE_INT("hw.em.tx_abs_int_delay", &lem_tx_abs_int_delay_dflt); +TUNABLE_INT("hw.em.rx_abs_int_delay", &lem_rx_abs_int_delay_dflt); +TUNABLE_INT("hw.em.rxd", &lem_rxd); +TUNABLE_INT("hw.em.txd", &lem_txd); +TUNABLE_INT("hw.em.smart_pwr_down", &lem_smart_pwr_down); +TUNABLE_INT("hw.em.sbp", &lem_debug_sbp); + +#ifndef EM_LEGACY_IRQ +/* How many packets rxeof tries to clean at a time */ +static int lem_rx_process_limit = 100; +TUNABLE_INT("hw.em.rx_process_limit", &lem_rx_process_limit); +#endif + +/* Flow control setting - default to FULL */ +static int lem_fc_setting = e1000_fc_full; +TUNABLE_INT("hw.em.fc_setting", &lem_fc_setting); + +/* +** Shadow VFTA table, this is needed because +** the real vlan filter table gets cleared during +** a soft reset and the driver needs to be able +** to repopulate it. +*/ +static u32 lem_shadow_vfta[EM_VFTA_SIZE]; + +/* Global used in WOL setup with multiport cards */ +static int global_quad_port_a = 0; + +/********************************************************************* + * Device identification routine + * + * em_probe determines if the driver should be loaded on + * adapter based on PCI vendor/device id of the adapter. + * + * return BUS_PROBE_DEFAULT on success, positive on failure + *********************************************************************/ + +static int +lem_probe(device_t dev) +{ + char adapter_name[60]; + u16 pci_vendor_id = 0; + u16 pci_device_id = 0; + u16 pci_subvendor_id = 0; + u16 pci_subdevice_id = 0; + em_vendor_info_t *ent; + + INIT_DEBUGOUT("em_probe: begin"); + + pci_vendor_id = pci_get_vendor(dev); + if (pci_vendor_id != EM_VENDOR_ID) + return (ENXIO); + + pci_device_id = pci_get_device(dev); + pci_subvendor_id = pci_get_subvendor(dev); + pci_subdevice_id = pci_get_subdevice(dev); + + ent = lem_vendor_info_array; + while (ent->vendor_id != 0) { + if ((pci_vendor_id == ent->vendor_id) && + (pci_device_id == ent->device_id) && + + ((pci_subvendor_id == ent->subvendor_id) || + (ent->subvendor_id == PCI_ANY_ID)) && + + ((pci_subdevice_id == ent->subdevice_id) || + (ent->subdevice_id == PCI_ANY_ID))) { + sprintf(adapter_name, "%s %s", + lem_strings[ent->index], + lem_driver_version); + device_set_desc_copy(dev, adapter_name); + return (BUS_PROBE_DEFAULT); + } + ent++; + } + + return (ENXIO); +} + +/********************************************************************* + * Device initialization routine + * + * The attach entry point is called when the driver is being loaded. + * This routine identifies the type of hardware, allocates all resources + * and initializes the hardware. + * + * return 0 on success, positive on failure + *********************************************************************/ + +static int +lem_attach(device_t dev) +{ + struct adapter *adapter; + int tsize, rsize; + int error = 0; + + INIT_DEBUGOUT("lem_attach: begin"); + + adapter = device_get_softc(dev); + adapter->dev = adapter->osdep.dev = dev; + EM_CORE_LOCK_INIT(adapter, device_get_nameunit(dev)); + EM_TX_LOCK_INIT(adapter, device_get_nameunit(dev)); + EM_RX_LOCK_INIT(adapter, device_get_nameunit(dev)); + + /* SYSCTL stuff */ + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, adapter, 0, + lem_sysctl_debug_info, "I", "Debug Information"); + + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "stats", CTLTYPE_INT|CTLFLAG_RW, adapter, 0, + lem_sysctl_stats, "I", "Statistics"); + + callout_init_mtx(&adapter->timer, &adapter->core_mtx, 0); + callout_init_mtx(&adapter->tx_fifo_timer, &adapter->tx_mtx, 0); + + /* Determine hardware and mac info */ + lem_identify_hardware(adapter); + + /* Setup PCI resources */ + if (lem_allocate_pci_resources(adapter)) { + device_printf(dev, "Allocation of PCI resources failed\n"); + error = ENXIO; + goto err_pci; + } + + /* Do Shared Code initialization */ + if (e1000_setup_init_funcs(&adapter->hw, TRUE)) { + device_printf(dev, "Setup of Shared code failed\n"); + error = ENXIO; + goto err_pci; + } + + e1000_get_bus_info(&adapter->hw); + + /* Set up some sysctls for the tunable interrupt delays */ + lem_add_int_delay_sysctl(adapter, "rx_int_delay", + "receive interrupt delay in usecs", &adapter->rx_int_delay, + E1000_REGISTER(&adapter->hw, E1000_RDTR), lem_rx_int_delay_dflt); + lem_add_int_delay_sysctl(adapter, "tx_int_delay", + "transmit interrupt delay in usecs", &adapter->tx_int_delay, + E1000_REGISTER(&adapter->hw, E1000_TIDV), lem_tx_int_delay_dflt); + if (adapter->hw.mac.type >= e1000_82540) { + lem_add_int_delay_sysctl(adapter, "rx_abs_int_delay", + "receive interrupt delay limit in usecs", + &adapter->rx_abs_int_delay, + E1000_REGISTER(&adapter->hw, E1000_RADV), + lem_rx_abs_int_delay_dflt); + lem_add_int_delay_sysctl(adapter, "tx_abs_int_delay", + "transmit interrupt delay limit in usecs", + &adapter->tx_abs_int_delay, + E1000_REGISTER(&adapter->hw, E1000_TADV), + lem_tx_abs_int_delay_dflt); + } + +#ifndef EM_LEGACY_IRQ + /* Sysctls for limiting the amount of work done in the taskqueue */ + lem_add_rx_process_limit(adapter, "rx_processing_limit", + "max number of rx packets to process", &adapter->rx_process_limit, + lem_rx_process_limit); +#endif + + /* + * Validate number of transmit and receive descriptors. It + * must not exceed hardware maximum, and must be multiple + * of E1000_DBA_ALIGN. + */ + if (((lem_txd * sizeof(struct e1000_tx_desc)) % EM_DBA_ALIGN) != 0 || + (adapter->hw.mac.type >= e1000_82544 && lem_txd > EM_MAX_TXD) || + (adapter->hw.mac.type < e1000_82544 && lem_txd > EM_MAX_TXD_82543) || + (lem_txd < EM_MIN_TXD)) { + device_printf(dev, "Using %d TX descriptors instead of %d!\n", + EM_DEFAULT_TXD, lem_txd); + adapter->num_tx_desc = EM_DEFAULT_TXD; + } else + adapter->num_tx_desc = lem_txd; + if (((lem_rxd * sizeof(struct e1000_rx_desc)) % EM_DBA_ALIGN) != 0 || + (adapter->hw.mac.type >= e1000_82544 && lem_rxd > EM_MAX_RXD) || + (adapter->hw.mac.type < e1000_82544 && lem_rxd > EM_MAX_RXD_82543) || + (lem_rxd < EM_MIN_RXD)) { + device_printf(dev, "Using %d RX descriptors instead of %d!\n", + EM_DEFAULT_RXD, lem_rxd); + adapter->num_rx_desc = EM_DEFAULT_RXD; + } else + adapter->num_rx_desc = lem_rxd; + + adapter->hw.mac.autoneg = DO_AUTO_NEG; + adapter->hw.phy.autoneg_wait_to_complete = FALSE; + adapter->hw.phy.autoneg_advertised = AUTONEG_ADV_DEFAULT; + adapter->rx_buffer_len = 2048; + + e1000_init_script_state_82541(&adapter->hw, TRUE); + e1000_set_tbi_compatibility_82543(&adapter->hw, TRUE); + + /* Copper options */ + if (adapter->hw.phy.media_type == e1000_media_type_copper) { + adapter->hw.phy.mdix = AUTO_ALL_MODES; + adapter->hw.phy.disable_polarity_correction = FALSE; + adapter->hw.phy.ms_type = EM_MASTER_SLAVE; + } + + /* + * Set the frame limits assuming + * standard ethernet sized frames. + */ + adapter->max_frame_size = ETHERMTU + ETHER_HDR_LEN + ETHERNET_FCS_SIZE; + adapter->min_frame_size = ETH_ZLEN + ETHERNET_FCS_SIZE; + + /* + * This controls when hardware reports transmit completion + * status. + */ + adapter->hw.mac.report_tx_early = 1; + + tsize = roundup2(adapter->num_tx_desc * sizeof(struct e1000_tx_desc), + EM_DBA_ALIGN); + + /* Allocate Transmit Descriptor ring */ + if (lem_dma_malloc(adapter, tsize, &adapter->txdma, BUS_DMA_NOWAIT)) { + device_printf(dev, "Unable to allocate tx_desc memory\n"); + error = ENOMEM; + goto err_tx_desc; + } + adapter->tx_desc_base = + (struct e1000_tx_desc *)adapter->txdma.dma_vaddr; + + rsize = roundup2(adapter->num_rx_desc * sizeof(struct e1000_rx_desc), + EM_DBA_ALIGN); + + /* Allocate Receive Descriptor ring */ + if (lem_dma_malloc(adapter, rsize, &adapter->rxdma, BUS_DMA_NOWAIT)) { + device_printf(dev, "Unable to allocate rx_desc memory\n"); + error = ENOMEM; + goto err_rx_desc; + } + adapter->rx_desc_base = + (struct e1000_rx_desc *)adapter->rxdma.dma_vaddr; + + /* + ** Start from a known state, this is + ** important in reading the nvm and + ** mac from that. + */ + e1000_reset_hw(&adapter->hw); + + /* Make sure we have a good EEPROM before we read from it */ + if (e1000_validate_nvm_checksum(&adapter->hw) < 0) { + /* + ** Some PCI-E parts fail the first check due to + ** the link being in sleep state, call it again, + ** if it fails a second time its a real issue. + */ + if (e1000_validate_nvm_checksum(&adapter->hw) < 0) { + device_printf(dev, + "The EEPROM Checksum Is Not Valid\n"); + error = EIO; + goto err_hw_init; + } + } + + /* Copy the permanent MAC address out of the EEPROM */ + if (e1000_read_mac_addr(&adapter->hw) < 0) { + device_printf(dev, "EEPROM read error while reading MAC" + " address\n"); + error = EIO; + goto err_hw_init; + } + + if (!lem_is_valid_ether_addr(adapter->hw.mac.addr)) { + device_printf(dev, "Invalid MAC address\n"); + error = EIO; + goto err_hw_init; + } + + /* Initialize the hardware */ + if (lem_hardware_init(adapter)) { + device_printf(dev, "Unable to initialize the hardware\n"); + error = EIO; + goto err_hw_init; + } + + /* Allocate transmit descriptors and buffers */ + if (lem_allocate_transmit_structures(adapter)) { + device_printf(dev, "Could not setup transmit structures\n"); + error = ENOMEM; + goto err_tx_struct; + } + + /* Allocate receive descriptors and buffers */ + if (lem_allocate_receive_structures(adapter)) { + device_printf(dev, "Could not setup receive structures\n"); + error = ENOMEM; + goto err_rx_struct; + } + + /* + ** Do interrupt configuration + */ + error = lem_allocate_irq(adapter); + if (error) + goto err_rx_struct; + + /* + * Get Wake-on-Lan and Management info for later use + */ + lem_get_wakeup(dev); + + /* Setup OS specific network interface */ + lem_setup_interface(dev, adapter); + + /* Initialize statistics */ + lem_update_stats_counters(adapter); + + adapter->hw.mac.get_link_status = 1; + lem_update_link_status(adapter); + + /* Indicate SOL/IDER usage */ + if (e1000_check_reset_block(&adapter->hw)) + device_printf(dev, + "PHY reset is blocked due to SOL/IDER session.\n"); + + /* Do we need workaround for 82544 PCI-X adapter? */ + if (adapter->hw.bus.type == e1000_bus_type_pcix && + adapter->hw.mac.type == e1000_82544) + adapter->pcix_82544 = TRUE; + else + adapter->pcix_82544 = FALSE; + +#if __FreeBSD_version >= 700029 + /* Register for VLAN events */ + adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, + lem_register_vlan, adapter, EVENTHANDLER_PRI_FIRST); + adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, + lem_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST); +#endif + + /* Non-AMT based hardware can now take control from firmware */ + if (adapter->has_manage && !adapter->has_amt) + lem_get_hw_control(adapter); + + /* Tell the stack that the interface is not active */ + adapter->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + + adapter->led_dev = led_create(lem_led_func, adapter, + device_get_nameunit(dev)); + + INIT_DEBUGOUT("lem_attach: end"); + + return (0); + +err_rx_struct: + lem_free_transmit_structures(adapter); +err_tx_struct: +err_hw_init: + lem_release_hw_control(adapter); + lem_dma_free(adapter, &adapter->rxdma); +err_rx_desc: + lem_dma_free(adapter, &adapter->txdma); +err_tx_desc: +err_pci: + lem_free_pci_resources(adapter); + EM_TX_LOCK_DESTROY(adapter); + EM_RX_LOCK_DESTROY(adapter); + EM_CORE_LOCK_DESTROY(adapter); + + return (error); +} + +/********************************************************************* + * Device removal routine + * + * The detach entry point is called when the driver is being removed. + * This routine stops the adapter and deallocates all the resources + * that were allocated for driver operation. + * + * return 0 on success, positive on failure + *********************************************************************/ + +static int +lem_detach(device_t dev) +{ + struct adapter *adapter = device_get_softc(dev); + struct ifnet *ifp = adapter->ifp; + + INIT_DEBUGOUT("em_detach: begin"); + + /* Make sure VLANS are not using driver */ +#if __FreeBSD_version >= 700000 + if (adapter->ifp->if_vlantrunk != NULL) { +#else + if (adapter->ifp->if_nvlans != 0) { +#endif + device_printf(dev,"Vlan in use, detach first\n"); + return (EBUSY); + } + +#ifdef DEVICE_POLLING + if (ifp->if_capenable & IFCAP_POLLING) + ether_poll_deregister(ifp); +#endif + + if (adapter->led_dev != NULL) + led_destroy(adapter->led_dev); + + EM_CORE_LOCK(adapter); + EM_TX_LOCK(adapter); + adapter->in_detach = 1; + lem_stop(adapter); + e1000_phy_hw_reset(&adapter->hw); + + lem_release_manageability(adapter); + + EM_TX_UNLOCK(adapter); + EM_CORE_UNLOCK(adapter); + +#if __FreeBSD_version >= 700029 + /* Unregister VLAN events */ + if (adapter->vlan_attach != NULL) + EVENTHANDLER_DEREGISTER(vlan_config, adapter->vlan_attach); + if (adapter->vlan_detach != NULL) + EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach); +#endif + + ether_ifdetach(adapter->ifp); + callout_drain(&adapter->timer); + callout_drain(&adapter->tx_fifo_timer); + + lem_free_pci_resources(adapter); + bus_generic_detach(dev); + if_free(ifp); + + lem_free_transmit_structures(adapter); + lem_free_receive_structures(adapter); + + /* Free Transmit Descriptor ring */ + if (adapter->tx_desc_base) { + lem_dma_free(adapter, &adapter->txdma); + adapter->tx_desc_base = NULL; + } + + /* Free Receive Descriptor ring */ + if (adapter->rx_desc_base) { + lem_dma_free(adapter, &adapter->rxdma); + adapter->rx_desc_base = NULL; + } + + lem_release_hw_control(adapter); + EM_TX_LOCK_DESTROY(adapter); + EM_RX_LOCK_DESTROY(adapter); + EM_CORE_LOCK_DESTROY(adapter); + + return (0); +} + +/********************************************************************* + * + * Shutdown entry point + * + **********************************************************************/ + +static int +lem_shutdown(device_t dev) +{ + return lem_suspend(dev); +} + +/* + * Suspend/resume device methods. + */ +static int +lem_suspend(device_t dev) +{ + struct adapter *adapter = device_get_softc(dev); + + EM_CORE_LOCK(adapter); + + lem_release_manageability(adapter); + lem_release_hw_control(adapter); + lem_enable_wakeup(dev); + + EM_CORE_UNLOCK(adapter); + + return bus_generic_suspend(dev); +} + +static int +lem_resume(device_t dev) +{ + struct adapter *adapter = device_get_softc(dev); + struct ifnet *ifp = adapter->ifp; + + EM_CORE_LOCK(adapter); + lem_init_locked(adapter); + lem_init_manageability(adapter); + EM_CORE_UNLOCK(adapter); + lem_start(ifp); + + return bus_generic_resume(dev); +} + + +/********************************************************************* + * Transmit entry point + * + * em_start is called by the stack to initiate a transmit. + * The driver will remain in this routine as long as there are + * packets to transmit and transmit resources are available. + * In case resources are not available stack is notified and + * the packet is requeued. + **********************************************************************/ + +#if __FreeBSD_version >= 800000 +static int +lem_mq_start_locked(struct ifnet *ifp, struct mbuf *m) +{ + struct adapter *adapter = ifp->if_softc; + struct mbuf *next; + int error = E1000_SUCCESS; + + EM_TX_LOCK_ASSERT(adapter); + /* To allow being called from a tasklet */ + if (m == NULL) + goto process; + + if (((ifp->if_drv_flags & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) != + IFF_DRV_RUNNING) + || (!adapter->link_active)) { + error = drbr_enqueue(ifp, adapter->br, m); + return (error); + } else if (drbr_empty(ifp, adapter->br) && + (adapter->num_tx_desc_avail > EM_TX_OP_THRESHOLD)) { + if ((error = lem_xmit(adapter, &m)) != 0) { + if (m) + error = drbr_enqueue(ifp, adapter->br, m); + return (error); + } else { + /* + * We've bypassed the buf ring so we need to update + * ifp directly + */ + drbr_stats_update(ifp, m->m_pkthdr.len, m->m_flags); + /* + ** Send a copy of the frame to the BPF + ** listener and set the watchdog on. + */ + ETHER_BPF_MTAP(ifp, m); + adapter->watchdog_check = TRUE; + } + } else if ((error = drbr_enqueue(ifp, adapter->br, m)) != 0) + return (error); + +process: + if (drbr_empty(ifp, adapter->br)) + return(error); + /* Process the queue */ + while (TRUE) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + break; + next = drbr_dequeue(ifp, adapter->br); + if (next == NULL) + break; + if ((error = lem_xmit(adapter, &next)) != 0) { + if (next != NULL) + error = drbr_enqueue(ifp, adapter->br, next); + break; + } + drbr_stats_update(ifp, next->m_pkthdr.len, next->m_flags); + ETHER_BPF_MTAP(ifp, next); + /* Set the watchdog */ + adapter->watchdog_check = TRUE; + } + + if (adapter->num_tx_desc_avail <= EM_TX_OP_THRESHOLD) + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + + return (error); +} + +/* +** Multiqueue capable stack interface, this is not +** yet truely multiqueue, but that is coming... +*/ +static int +lem_mq_start(struct ifnet *ifp, struct mbuf *m) +{ + + struct adapter *adapter = ifp->if_softc; + int error = 0; + + if (EM_TX_TRYLOCK(adapter)) { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + error = lem_mq_start_locked(ifp, m); + EM_TX_UNLOCK(adapter); + } else + error = drbr_enqueue(ifp, adapter->br, m); + + return (error); +} + +static void +lem_qflush(struct ifnet *ifp) +{ + struct mbuf *m; + struct adapter *adapter = (struct adapter *)ifp->if_softc; + + EM_TX_LOCK(adapter); + while ((m = buf_ring_dequeue_sc(adapter->br)) != NULL) + m_freem(m); + if_qflush(ifp); + EM_TX_UNLOCK(adapter); +} +#endif /* FreeBSD_version */ + +static void +lem_start_locked(struct ifnet *ifp) +{ + struct adapter *adapter = ifp->if_softc; + struct mbuf *m_head; + + EM_TX_LOCK_ASSERT(adapter); + + if ((ifp->if_drv_flags & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) != + IFF_DRV_RUNNING) + return; + if (!adapter->link_active) + return; + + while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { + + IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); + if (m_head == NULL) + break; + /* + * Encapsulation can modify our pointer, and or make it + * NULL on failure. In that event, we can't requeue. + */ + if (lem_xmit(adapter, &m_head)) { + if (m_head == NULL) + break; + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + IFQ_DRV_PREPEND(&ifp->if_snd, m_head); + break; + } + + /* Send a copy of the frame to the BPF listener */ + ETHER_BPF_MTAP(ifp, m_head); + + /* Set timeout in case hardware has problems transmitting. */ + adapter->watchdog_check = TRUE; + } + if (adapter->num_tx_desc_avail <= EM_TX_OP_THRESHOLD) + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + + return; +} + +static void +lem_start(struct ifnet *ifp) +{ + struct adapter *adapter = ifp->if_softc; + + EM_TX_LOCK(adapter); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + lem_start_locked(ifp); + EM_TX_UNLOCK(adapter); +} + +/********************************************************************* + * Ioctl entry point + * + * em_ioctl is called when the user wants to configure the + * interface. + * + * return 0 on success, positive on failure + **********************************************************************/ + +static int +lem_ioctl(struct ifnet *ifp, u_long command, caddr_t data) +{ + struct adapter *adapter = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *)data; +#ifdef INET + struct ifaddr *ifa = (struct ifaddr *)data; +#endif + int error = 0; + + if (adapter->in_detach) + return (error); + + switch (command) { + case SIOCSIFADDR: +#ifdef INET + if (ifa->ifa_addr->sa_family == AF_INET) { + /* + * XXX + * Since resetting hardware takes a very long time + * and results in link renegotiation we only + * initialize the hardware only when it is absolutely + * required. + */ + ifp->if_flags |= IFF_UP; + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { + EM_CORE_LOCK(adapter); + lem_init_locked(adapter); + EM_CORE_UNLOCK(adapter); + } + arp_ifinit(ifp, ifa); + } else +#endif + error = ether_ioctl(ifp, command, data); + break; + case SIOCSIFMTU: + { + int max_frame_size; + + IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFMTU (Set Interface MTU)"); + + EM_CORE_LOCK(adapter); + switch (adapter->hw.mac.type) { + case e1000_82542: + max_frame_size = ETHER_MAX_LEN; + break; + default: + max_frame_size = MAX_JUMBO_FRAME_SIZE; + } + if (ifr->ifr_mtu > max_frame_size - ETHER_HDR_LEN - + ETHER_CRC_LEN) { + EM_CORE_UNLOCK(adapter); + error = EINVAL; + break; + } + + ifp->if_mtu = ifr->ifr_mtu; + adapter->max_frame_size = + ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; + lem_init_locked(adapter); + EM_CORE_UNLOCK(adapter); + break; + } + case SIOCSIFFLAGS: + IOCTL_DEBUGOUT("ioctl rcv'd:\ + SIOCSIFFLAGS (Set Interface Flags)"); + EM_CORE_LOCK(adapter); + if (ifp->if_flags & IFF_UP) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { + if ((ifp->if_flags ^ adapter->if_flags) & + (IFF_PROMISC | IFF_ALLMULTI)) { + lem_disable_promisc(adapter); + lem_set_promisc(adapter); + } + } else + lem_init_locked(adapter); + } else + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + EM_TX_LOCK(adapter); + lem_stop(adapter); + EM_TX_UNLOCK(adapter); + } + adapter->if_flags = ifp->if_flags; + EM_CORE_UNLOCK(adapter); + break; + case SIOCADDMULTI: + case SIOCDELMULTI: + IOCTL_DEBUGOUT("ioctl rcv'd: SIOC(ADD|DEL)MULTI"); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + EM_CORE_LOCK(adapter); + lem_disable_intr(adapter); + lem_set_multi(adapter); + if (adapter->hw.mac.type == e1000_82542 && + adapter->hw.revision_id == E1000_REVISION_2) { + lem_initialize_receive_unit(adapter); + } +#ifdef DEVICE_POLLING + if (!(ifp->if_capenable & IFCAP_POLLING)) +#endif + lem_enable_intr(adapter); + EM_CORE_UNLOCK(adapter); + } + break; + case SIOCSIFMEDIA: + /* Check SOL/IDER usage */ + EM_CORE_LOCK(adapter); + if (e1000_check_reset_block(&adapter->hw)) { + EM_CORE_UNLOCK(adapter); + device_printf(adapter->dev, "Media change is" + " blocked due to SOL/IDER session.\n"); + break; + } + EM_CORE_UNLOCK(adapter); + case SIOCGIFMEDIA: + IOCTL_DEBUGOUT("ioctl rcv'd: \ + SIOCxIFMEDIA (Get/Set Interface Media)"); + error = ifmedia_ioctl(ifp, ifr, &adapter->media, command); + break; + case SIOCSIFCAP: + { + int mask, reinit; + + IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFCAP (Set Capabilities)"); + reinit = 0; + mask = ifr->ifr_reqcap ^ ifp->if_capenable; +#ifdef DEVICE_POLLING + if (mask & IFCAP_POLLING) { + if (ifr->ifr_reqcap & IFCAP_POLLING) { + error = ether_poll_register(lem_poll, ifp); + if (error) + return (error); + EM_CORE_LOCK(adapter); + lem_disable_intr(adapter); + ifp->if_capenable |= IFCAP_POLLING; + EM_CORE_UNLOCK(adapter); + } else { + error = ether_poll_deregister(ifp); + /* Enable interrupt even in error case */ + EM_CORE_LOCK(adapter); + lem_enable_intr(adapter); + ifp->if_capenable &= ~IFCAP_POLLING; + EM_CORE_UNLOCK(adapter); + } + } +#endif + if (mask & IFCAP_HWCSUM) { + ifp->if_capenable ^= IFCAP_HWCSUM; + reinit = 1; + } +#if __FreeBSD_version >= 700000 + if (mask & IFCAP_TSO4) { + ifp->if_capenable ^= IFCAP_TSO4; + 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)) + lem_init(adapter); +#if __FreeBSD_version >= 700000 + VLAN_CAPABILITIES(ifp); +#endif + break; + } + + default: + error = ether_ioctl(ifp, command, data); + break; + } + + return (error); +} + + +/********************************************************************* + * Init entry point + * + * This routine is used in two ways. It is used by the stack as + * init entry point in network interface structure. It is also used + * by the driver as a hw/sw initialization routine to get to a + * consistent state. + * + * return 0 on success, positive on failure + **********************************************************************/ + +static void +lem_init_locked(struct adapter *adapter) +{ + struct ifnet *ifp = adapter->ifp; + device_t dev = adapter->dev; + u32 pba; + + INIT_DEBUGOUT("lem_init: begin"); + + EM_CORE_LOCK_ASSERT(adapter); + + EM_TX_LOCK(adapter); + lem_stop(adapter); + EM_TX_UNLOCK(adapter); + + /* + * Packet Buffer Allocation (PBA) + * Writing PBA sets the receive portion of the buffer + * the remainder is used for the transmit buffer. + * + * Devices before the 82547 had a Packet Buffer of 64K. + * Default allocation: PBA=48K for Rx, leaving 16K for Tx. + * After the 82547 the buffer was reduced to 40K. + * Default allocation: PBA=30K for Rx, leaving 10K for Tx. + * Note: default does not leave enough room for Jumbo Frame >10k. + */ + switch (adapter->hw.mac.type) { + case e1000_82547: + case e1000_82547_rev_2: /* 82547: Total Packet Buffer is 40K */ + if (adapter->max_frame_size > 8192) + pba = E1000_PBA_22K; /* 22K for Rx, 18K for Tx */ + else + pba = E1000_PBA_30K; /* 30K for Rx, 10K for Tx */ + adapter->tx_fifo_head = 0; + adapter->tx_head_addr = pba << EM_TX_HEAD_ADDR_SHIFT; + adapter->tx_fifo_size = + (E1000_PBA_40K - pba) << EM_PBA_BYTES_SHIFT; + break; + default: + /* Devices before 82547 had a Packet Buffer of 64K. */ + if (adapter->max_frame_size > 8192) + pba = E1000_PBA_40K; /* 40K for Rx, 24K for Tx */ + else + pba = E1000_PBA_48K; /* 48K for Rx, 16K for Tx */ + } + + INIT_DEBUGOUT1("lem_init: pba=%dK",pba); + 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); + + /* Put the address into the Receive Address Array */ + e1000_rar_set(&adapter->hw, adapter->hw.mac.addr, 0); + + /* Initialize the hardware */ + if (lem_hardware_init(adapter)) { + device_printf(dev, "Unable to initialize the hardware\n"); + return; + } + lem_update_link_status(adapter); + + /* Setup VLAN support, basic and offload if available */ + E1000_WRITE_REG(&adapter->hw, E1000_VET, ETHERTYPE_VLAN); + +#if __FreeBSD_version < 700029 + if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) { + u32 ctrl; + ctrl = E1000_READ_REG(&adapter->hw, E1000_CTRL); + ctrl |= E1000_CTRL_VME; + E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl); + } +#else + /* Use real VLAN Filter support */ + lem_setup_vlan_hw_support(adapter); +#endif + + /* Set hardware offload abilities */ + ifp->if_hwassist = 0; + if (adapter->hw.mac.type >= e1000_82543) { + if (ifp->if_capenable & IFCAP_TXCSUM) + ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); +#if __FreeBSD_version >= 700000 + if (ifp->if_capenable & IFCAP_TSO4) + ifp->if_hwassist |= CSUM_TSO; +#endif + } + + /* Configure for OS presence */ + lem_init_manageability(adapter); + + /* Prepare transmit descriptors and buffers */ + lem_setup_transmit_structures(adapter); + lem_initialize_transmit_unit(adapter); + + /* Setup Multicast table */ + lem_set_multi(adapter); + + /* Prepare receive descriptors and buffers */ + if (lem_setup_receive_structures(adapter)) { + device_printf(dev, "Could not setup receive structures\n"); + EM_TX_LOCK(adapter); + lem_stop(adapter); + EM_TX_UNLOCK(adapter); + return; + } + lem_initialize_receive_unit(adapter); + + /* Don't lose promiscuous settings */ + lem_set_promisc(adapter); + + ifp->if_drv_flags |= IFF_DRV_RUNNING; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + + callout_reset(&adapter->timer, hz, lem_local_timer, adapter); + e1000_clear_hw_cntrs_base_generic(&adapter->hw); + + /* MSI/X configuration for 82574 */ + if (adapter->hw.mac.type == e1000_82574) { + int tmp; + tmp = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT); + tmp |= E1000_CTRL_EXT_PBA_CLR; + E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT, tmp); + /* + ** Set the IVAR - interrupt vector routing. + ** Each nibble represents a vector, high bit + ** is enable, other 3 bits are the MSIX table + ** entry, we map RXQ0 to 0, TXQ0 to 1, and + ** Link (other) to 2, hence the magic number. + */ + E1000_WRITE_REG(&adapter->hw, E1000_IVAR, 0x800A0908); + } + +#ifdef DEVICE_POLLING + /* + * Only enable interrupts if we are not polling, make sure + * they are off otherwise. + */ + if (ifp->if_capenable & IFCAP_POLLING) + lem_disable_intr(adapter); + else +#endif /* DEVICE_POLLING */ + lem_enable_intr(adapter); + + /* AMT based hardware can now take control from firmware */ + if (adapter->has_manage && adapter->has_amt) + lem_get_hw_control(adapter); + + /* Don't reset the phy next time init gets called */ + adapter->hw.phy.reset_disable = TRUE; +} + +static void +lem_init(void *arg) +{ + struct adapter *adapter = arg; + + EM_CORE_LOCK(adapter); + lem_init_locked(adapter); + EM_CORE_UNLOCK(adapter); +} + + +#ifdef DEVICE_POLLING +/********************************************************************* + * + * Legacy polling routine + * + *********************************************************************/ +static int +lem_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) +{ + struct adapter *adapter = ifp->if_softc; + u32 reg_icr, rx_done = 0; + + EM_CORE_LOCK(adapter); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + EM_CORE_UNLOCK(adapter); + return (rx_done); + } + + if (cmd == POLL_AND_CHECK_STATUS) { + reg_icr = E1000_READ_REG(&adapter->hw, E1000_ICR); + if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + callout_stop(&adapter->timer); + adapter->hw.mac.get_link_status = 1; + lem_update_link_status(adapter); + callout_reset(&adapter->timer, hz, + lem_local_timer, adapter); + } + } + EM_CORE_UNLOCK(adapter); + + rx_done = lem_rxeof(adapter, count); + + EM_TX_LOCK(adapter); + lem_txeof(adapter); +#if __FreeBSD_version >= 800000 + if (!drbr_empty(ifp, adapter->br)) + lem_mq_start_locked(ifp, NULL); +#else + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + lem_start_locked(ifp); +#endif + EM_TX_UNLOCK(adapter); + return (rx_done); +} +#endif /* DEVICE_POLLING */ + +#ifdef EM_LEGACY_IRQ +/********************************************************************* + * + * Legacy Interrupt Service routine + * + *********************************************************************/ + +static void +lem_intr(void *arg) +{ + struct adapter *adapter = arg; + struct ifnet *ifp = adapter->ifp; + u32 reg_icr; + + + if (ifp->if_capenable & IFCAP_POLLING) + return; + + EM_CORE_LOCK(adapter); + reg_icr = E1000_READ_REG(&adapter->hw, E1000_ICR); + if (reg_icr & E1000_ICR_RXO) + adapter->rx_overruns++; + + if ((reg_icr == 0xffffffff) || (reg_icr == 0)) + goto out; + + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + goto out; + + if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + callout_stop(&adapter->timer); + adapter->hw.mac.get_link_status = 1; + lem_update_link_status(adapter); + /* Deal with TX cruft when link lost */ + lem_tx_purge(adapter); + callout_reset(&adapter->timer, hz, + lem_local_timer, adapter); + goto out; + } + + EM_TX_LOCK(adapter); + lem_txeof(adapter); + lem_rxeof(adapter, -1); + lem_txeof(adapter); + if (ifp->if_drv_flags & IFF_DRV_RUNNING && + !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + lem_start_locked(ifp); + EM_TX_UNLOCK(adapter); + +out: + EM_CORE_UNLOCK(adapter); + return; +} + +#else /* EM_FAST_IRQ, then fast interrupt routines only */ + +static void +lem_handle_link(void *context, int pending) +{ + struct adapter *adapter = context; + struct ifnet *ifp = adapter->ifp; + + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) + return; + + EM_CORE_LOCK(adapter); + callout_stop(&adapter->timer); + lem_update_link_status(adapter); + /* Deal with TX cruft when link lost */ + lem_tx_purge(adapter); + callout_reset(&adapter->timer, hz, lem_local_timer, adapter); + EM_CORE_UNLOCK(adapter); +} + + +/* Combined RX/TX handler, used by Legacy and MSI */ +static void +lem_handle_rxtx(void *context, int pending) +{ + struct adapter *adapter = context; + struct ifnet *ifp = adapter->ifp; + + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + if (lem_rxeof(adapter, adapter->rx_process_limit) != 0) + taskqueue_enqueue(adapter->tq, &adapter->rxtx_task); + EM_TX_LOCK(adapter); + lem_txeof(adapter); + +#if __FreeBSD_version >= 800000 + if (!drbr_empty(ifp, adapter->br)) + lem_mq_start_locked(ifp, NULL); +#else + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + lem_start_locked(ifp); +#endif + EM_TX_UNLOCK(adapter); + } + + lem_enable_intr(adapter); +} + +/********************************************************************* + * + * Fast Legacy/MSI Combined Interrupt Service routine + * + *********************************************************************/ +#if __FreeBSD_version < 700000 +#define FILTER_STRAY +#define FILTER_HANDLED +static void +#else +static int +#endif +lem_irq_fast(void *arg) +{ + struct adapter *adapter = arg; + struct ifnet *ifp; + u32 reg_icr; + + ifp = adapter->ifp; + + reg_icr = E1000_READ_REG(&adapter->hw, E1000_ICR); + + /* Hot eject? */ + if (reg_icr == 0xffffffff) + return FILTER_STRAY; + + /* Definitely not our interrupt. */ + if (reg_icr == 0x0) + return FILTER_STRAY; + + /* + * Mask interrupts until the taskqueue is finished running. This is + * cheap, just assume that it is needed. This also works around the + * MSI message reordering errata on certain systems. + */ + lem_disable_intr(adapter); + taskqueue_enqueue(adapter->tq, &adapter->rxtx_task); + + /* Link status change */ + if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + adapter->hw.mac.get_link_status = 1; + taskqueue_enqueue(taskqueue_fast, &adapter->link_task); + } + + if (reg_icr & E1000_ICR_RXO) + adapter->rx_overruns++; + return FILTER_HANDLED; +} +#endif /* ~EM_LEGACY_IRQ */ + + +/********************************************************************* + * + * Media Ioctl callback + * + * This routine is called whenever the user queries the status of + * the interface using ifconfig. + * + **********************************************************************/ +static void +lem_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) +{ + struct adapter *adapter = ifp->if_softc; + u_char fiber_type = IFM_1000_SX; + + INIT_DEBUGOUT("lem_media_status: begin"); + + EM_CORE_LOCK(adapter); + lem_update_link_status(adapter); + + ifmr->ifm_status = IFM_AVALID; + ifmr->ifm_active = IFM_ETHER; + + if (!adapter->link_active) { + EM_CORE_UNLOCK(adapter); + return; + } + + ifmr->ifm_status |= IFM_ACTIVE; + + if ((adapter->hw.phy.media_type == e1000_media_type_fiber) || + (adapter->hw.phy.media_type == e1000_media_type_internal_serdes)) { + if (adapter->hw.mac.type == e1000_82545) + fiber_type = IFM_1000_LX; + ifmr->ifm_active |= fiber_type | IFM_FDX; + } else { + switch (adapter->link_speed) { + case 10: + ifmr->ifm_active |= IFM_10_T; + break; + case 100: + ifmr->ifm_active |= IFM_100_TX; + break; + case 1000: + ifmr->ifm_active |= IFM_1000_T; + break; + } + if (adapter->link_duplex == FULL_DUPLEX) + ifmr->ifm_active |= IFM_FDX; + else + ifmr->ifm_active |= IFM_HDX; + } + EM_CORE_UNLOCK(adapter); +} + +/********************************************************************* + * + * Media Ioctl callback + * + * This routine is called when the user changes speed/duplex using + * media/mediopt option with ifconfig. + * + **********************************************************************/ +static int +lem_media_change(struct ifnet *ifp) +{ + struct adapter *adapter = ifp->if_softc; + struct ifmedia *ifm = &adapter->media; + + INIT_DEBUGOUT("lem_media_change: begin"); + + if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) + return (EINVAL); + + EM_CORE_LOCK(adapter); + switch (IFM_SUBTYPE(ifm->ifm_media)) { + case IFM_AUTO: + adapter->hw.mac.autoneg = DO_AUTO_NEG; + adapter->hw.phy.autoneg_advertised = AUTONEG_ADV_DEFAULT; + break; + case IFM_1000_LX: + case IFM_1000_SX: + case IFM_1000_T: + adapter->hw.mac.autoneg = DO_AUTO_NEG; + adapter->hw.phy.autoneg_advertised = ADVERTISE_1000_FULL; + break; + case IFM_100_TX: + adapter->hw.mac.autoneg = FALSE; + adapter->hw.phy.autoneg_advertised = 0; + if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) + adapter->hw.mac.forced_speed_duplex = ADVERTISE_100_FULL; + else + adapter->hw.mac.forced_speed_duplex = ADVERTISE_100_HALF; + break; + case IFM_10_T: + adapter->hw.mac.autoneg = FALSE; + adapter->hw.phy.autoneg_advertised = 0; + if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) + adapter->hw.mac.forced_speed_duplex = ADVERTISE_10_FULL; + else + adapter->hw.mac.forced_speed_duplex = ADVERTISE_10_HALF; + break; + default: + device_printf(adapter->dev, "Unsupported media type\n"); + } + + /* As the speed/duplex settings my have changed we need to + * reset the PHY. + */ + adapter->hw.phy.reset_disable = FALSE; + + lem_init_locked(adapter); + EM_CORE_UNLOCK(adapter); + + return (0); +} + +/********************************************************************* + * + * This routine maps the mbufs to tx descriptors. + * + * return 0 on success, positive on failure + **********************************************************************/ + +static int +lem_xmit(struct adapter *adapter, struct mbuf **m_headp) +{ + bus_dma_segment_t segs[EM_MAX_SCATTER]; + bus_dmamap_t map; + struct em_buffer *tx_buffer, *tx_buffer_mapped; + struct e1000_tx_desc *ctxd = NULL; + struct mbuf *m_head; + u32 txd_upper, txd_lower, txd_used, txd_saved; + int error, nsegs, i, j, first, last = 0; +#if __FreeBSD_version < 700000 + struct m_tag *mtag; +#endif + m_head = *m_headp; + txd_upper = txd_lower = txd_used = txd_saved = 0; + + /* + * Force a cleanup if number of TX descriptors + * available hits the threshold + */ + if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) { + lem_txeof(adapter); + /* Now do we at least have a minimal? */ + if (adapter->num_tx_desc_avail <= EM_TX_OP_THRESHOLD) { + adapter->no_tx_desc_avail1++; + return (ENOBUFS); + } + } + + /* + * Map the packet for DMA + * + * Capture the first descriptor index, + * this descriptor will have the index + * of the EOP which is the only one that + * now gets a DONE bit writeback. + */ + first = adapter->next_avail_tx_desc; + tx_buffer = &adapter->tx_buffer_area[first]; + tx_buffer_mapped = tx_buffer; + map = tx_buffer->map; + + error = bus_dmamap_load_mbuf_sg(adapter->txtag, map, + *m_headp, segs, &nsegs, BUS_DMA_NOWAIT); + + /* + * There are two types of errors we can (try) to handle: + * - EFBIG means the mbuf chain was too long and bus_dma ran + * out of segments. Defragment the mbuf chain and try again. + * - ENOMEM means bus_dma could not obtain enough bounce buffers + * at this point in time. Defer sending and try again later. + * All other errors, in particular EINVAL, are fatal and prevent the + * mbuf chain from ever going through. Drop it and report error. + */ + if (error == EFBIG) { + struct mbuf *m; + + m = m_defrag(*m_headp, M_DONTWAIT); + if (m == NULL) { + adapter->mbuf_alloc_failed++; + m_freem(*m_headp); + *m_headp = NULL; + return (ENOBUFS); + } + *m_headp = m; + + /* Try it again */ + error = bus_dmamap_load_mbuf_sg(adapter->txtag, map, + *m_headp, segs, &nsegs, BUS_DMA_NOWAIT); + + if (error) { + adapter->no_tx_dma_setup++; + m_freem(*m_headp); + *m_headp = NULL; + return (error); + } + } else if (error != 0) { + adapter->no_tx_dma_setup++; + return (error); + } + + if (nsegs > (adapter->num_tx_desc_avail - 2)) { + adapter->no_tx_desc_avail2++; + bus_dmamap_unload(adapter->txtag, map); + return (ENOBUFS); + } + m_head = *m_headp; + + /* Do hardware assists */ + if (m_head->m_pkthdr.csum_flags & CSUM_OFFLOAD) + lem_transmit_checksum_setup(adapter, m_head, + &txd_upper, &txd_lower); + + i = adapter->next_avail_tx_desc; + if (adapter->pcix_82544) + txd_saved = i; + + /* Set up our transmit descriptors */ + for (j = 0; j < nsegs; j++) { + bus_size_t seg_len; + bus_addr_t seg_addr; + /* If adapter is 82544 and on PCIX bus */ + if(adapter->pcix_82544) { + DESC_ARRAY desc_array; + u32 array_elements, counter; + /* + * Check the Address and Length combination and + * split the data accordingly + */ + array_elements = lem_fill_descriptors(segs[j].ds_addr, + segs[j].ds_len, &desc_array); + for (counter = 0; counter < array_elements; counter++) { + if (txd_used == adapter->num_tx_desc_avail) { + adapter->next_avail_tx_desc = txd_saved; + adapter->no_tx_desc_avail2++; + bus_dmamap_unload(adapter->txtag, map); + return (ENOBUFS); + } + tx_buffer = &adapter->tx_buffer_area[i]; + ctxd = &adapter->tx_desc_base[i]; + ctxd->buffer_addr = htole64( + desc_array.descriptor[counter].address); + ctxd->lower.data = htole32( + (adapter->txd_cmd | txd_lower | (u16) + desc_array.descriptor[counter].length)); + ctxd->upper.data = + htole32((txd_upper)); + last = i; + if (++i == adapter->num_tx_desc) + i = 0; + tx_buffer->m_head = NULL; + tx_buffer->next_eop = -1; + txd_used++; + } + } else { + tx_buffer = &adapter->tx_buffer_area[i]; + ctxd = &adapter->tx_desc_base[i]; + seg_addr = segs[j].ds_addr; + seg_len = segs[j].ds_len; + ctxd->buffer_addr = htole64(seg_addr); + ctxd->lower.data = htole32( + adapter->txd_cmd | txd_lower | seg_len); + ctxd->upper.data = + htole32(txd_upper); + last = i; + if (++i == adapter->num_tx_desc) + i = 0; + tx_buffer->m_head = NULL; + tx_buffer->next_eop = -1; + } + } + + adapter->next_avail_tx_desc = i; + + if (adapter->pcix_82544) + adapter->num_tx_desc_avail -= txd_used; + else + adapter->num_tx_desc_avail -= nsegs; + + /* + ** Handle VLAN tag, this is the + ** biggest difference between + ** 6.x and 7 + */ +#if __FreeBSD_version < 700000 + /* Find out if we are in vlan mode. */ + mtag = VLAN_OUTPUT_TAG(ifp, m_head); + if (mtag != NULL) { + ctxd->upper.fields.special = + htole16(VLAN_TAG_VALUE(mtag)); +#else /* FreeBSD 7 */ + if (m_head->m_flags & M_VLANTAG) { + /* Set the vlan id. */ + ctxd->upper.fields.special = + htole16(m_head->m_pkthdr.ether_vtag); +#endif + /* Tell hardware to add tag */ + ctxd->lower.data |= htole32(E1000_TXD_CMD_VLE); + } + + tx_buffer->m_head = m_head; + tx_buffer_mapped->map = tx_buffer->map; + tx_buffer->map = map; + bus_dmamap_sync(adapter->txtag, map, BUS_DMASYNC_PREWRITE); + + /* + * Last Descriptor of Packet + * needs End Of Packet (EOP) + * and Report Status (RS) + */ + ctxd->lower.data |= + htole32(E1000_TXD_CMD_EOP | E1000_TXD_CMD_RS); + /* + * Keep track in the first buffer which + * descriptor will be written back + */ + tx_buffer = &adapter->tx_buffer_area[first]; + tx_buffer->next_eop = last; + + /* + * Advance the Transmit Descriptor Tail (TDT), this tells the E1000 + * that this frame is available to transmit. + */ + bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + if (adapter->hw.mac.type == e1000_82547 && + adapter->link_duplex == HALF_DUPLEX) + lem_82547_move_tail(adapter); + else { + E1000_WRITE_REG(&adapter->hw, E1000_TDT(0), i); + if (adapter->hw.mac.type == e1000_82547) + lem_82547_update_fifo_head(adapter, + m_head->m_pkthdr.len); + } + + return (0); +} + +/********************************************************************* + * + * 82547 workaround to avoid controller hang in half-duplex environment. + * The workaround is to avoid queuing a large packet that would span + * the internal Tx FIFO ring boundary. We need to reset the FIFO pointers + * in this case. We do that only when FIFO is quiescent. + * + **********************************************************************/ +static void +lem_82547_move_tail(void *arg) +{ + struct adapter *adapter = arg; + struct e1000_tx_desc *tx_desc; + u16 hw_tdt, sw_tdt, length = 0; + bool eop = 0; + + EM_TX_LOCK_ASSERT(adapter); + + hw_tdt = E1000_READ_REG(&adapter->hw, E1000_TDT(0)); + sw_tdt = adapter->next_avail_tx_desc; + + while (hw_tdt != sw_tdt) { + tx_desc = &adapter->tx_desc_base[hw_tdt]; + length += tx_desc->lower.flags.length; + eop = tx_desc->lower.data & E1000_TXD_CMD_EOP; + if (++hw_tdt == adapter->num_tx_desc) + hw_tdt = 0; + + if (eop) { + if (lem_82547_fifo_workaround(adapter, length)) { + adapter->tx_fifo_wrk_cnt++; + callout_reset(&adapter->tx_fifo_timer, 1, + lem_82547_move_tail, adapter); + break; + } + E1000_WRITE_REG(&adapter->hw, E1000_TDT(0), hw_tdt); + lem_82547_update_fifo_head(adapter, length); + length = 0; + } + } +} + +static int +lem_82547_fifo_workaround(struct adapter *adapter, int len) +{ + int fifo_space, fifo_pkt_len; + + fifo_pkt_len = roundup2(len + EM_FIFO_HDR, EM_FIFO_HDR); + + if (adapter->link_duplex == HALF_DUPLEX) { + fifo_space = adapter->tx_fifo_size - adapter->tx_fifo_head; + + if (fifo_pkt_len >= (EM_82547_PKT_THRESH + fifo_space)) { + if (lem_82547_tx_fifo_reset(adapter)) + return (0); + else + return (1); + } + } + + return (0); +} + +static void +lem_82547_update_fifo_head(struct adapter *adapter, int len) +{ + int fifo_pkt_len = roundup2(len + EM_FIFO_HDR, EM_FIFO_HDR); + + /* tx_fifo_head is always 16 byte aligned */ + adapter->tx_fifo_head += fifo_pkt_len; + if (adapter->tx_fifo_head >= adapter->tx_fifo_size) { + adapter->tx_fifo_head -= adapter->tx_fifo_size; + } +} + + +static int +lem_82547_tx_fifo_reset(struct adapter *adapter) +{ + u32 tctl; + + if ((E1000_READ_REG(&adapter->hw, E1000_TDT(0)) == + E1000_READ_REG(&adapter->hw, E1000_TDH(0))) && + (E1000_READ_REG(&adapter->hw, E1000_TDFT) == + E1000_READ_REG(&adapter->hw, E1000_TDFH)) && + (E1000_READ_REG(&adapter->hw, E1000_TDFTS) == + E1000_READ_REG(&adapter->hw, E1000_TDFHS)) && + (E1000_READ_REG(&adapter->hw, E1000_TDFPC) == 0)) { + /* Disable TX unit */ + tctl = E1000_READ_REG(&adapter->hw, E1000_TCTL); + E1000_WRITE_REG(&adapter->hw, E1000_TCTL, + tctl & ~E1000_TCTL_EN); + + /* Reset FIFO pointers */ + E1000_WRITE_REG(&adapter->hw, E1000_TDFT, + adapter->tx_head_addr); + E1000_WRITE_REG(&adapter->hw, E1000_TDFH, + adapter->tx_head_addr); + E1000_WRITE_REG(&adapter->hw, E1000_TDFTS, + adapter->tx_head_addr); + E1000_WRITE_REG(&adapter->hw, E1000_TDFHS, + adapter->tx_head_addr); + + /* Re-enable TX unit */ + E1000_WRITE_REG(&adapter->hw, E1000_TCTL, tctl); + E1000_WRITE_FLUSH(&adapter->hw); + + adapter->tx_fifo_head = 0; + adapter->tx_fifo_reset_cnt++; + + return (TRUE); + } + else { + return (FALSE); + } +} + +static void +lem_set_promisc(struct adapter *adapter) +{ + struct ifnet *ifp = adapter->ifp; + u32 reg_rctl; + + reg_rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL); + + if (ifp->if_flags & IFF_PROMISC) { + reg_rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); + /* Turn this on if you want to see bad packets */ + if (lem_debug_sbp) + reg_rctl |= E1000_RCTL_SBP; + E1000_WRITE_REG(&adapter->hw, E1000_RCTL, reg_rctl); + } else if (ifp->if_flags & IFF_ALLMULTI) { + reg_rctl |= E1000_RCTL_MPE; + reg_rctl &= ~E1000_RCTL_UPE; + E1000_WRITE_REG(&adapter->hw, E1000_RCTL, reg_rctl); + } +} + +static void +lem_disable_promisc(struct adapter *adapter) +{ + u32 reg_rctl; + + reg_rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL); + + reg_rctl &= (~E1000_RCTL_UPE); + reg_rctl &= (~E1000_RCTL_MPE); + reg_rctl &= (~E1000_RCTL_SBP); + E1000_WRITE_REG(&adapter->hw, E1000_RCTL, reg_rctl); +} + + +/********************************************************************* + * Multicast Update + * + * This routine is called whenever multicast address list is updated. + * + **********************************************************************/ + +static void +lem_set_multi(struct adapter *adapter) +{ + struct ifnet *ifp = adapter->ifp; + struct ifmultiaddr *ifma; + u32 reg_rctl = 0; + u8 *mta; /* Multicast array memory */ + int mcnt = 0; + + IOCTL_DEBUGOUT("lem_set_multi: begin"); + + if (adapter->hw.mac.type == e1000_82542 && + adapter->hw.revision_id == E1000_REVISION_2) { + reg_rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL); + if (adapter->hw.bus.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) + e1000_pci_clear_mwi(&adapter->hw); + reg_rctl |= E1000_RCTL_RST; + E1000_WRITE_REG(&adapter->hw, E1000_RCTL, reg_rctl); + msec_delay(5); + } + + /* Allocate temporary memory to setup array */ + mta = malloc(sizeof(u8) * + (ETH_ADDR_LEN * MAX_NUM_MULTICAST_ADDRESSES), + M_DEVBUF, M_NOWAIT | M_ZERO); + if (mta == NULL) + panic("lem_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; + + if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) + break; + + bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), + &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; + E1000_WRITE_REG(&adapter->hw, E1000_RCTL, reg_rctl); + } else + e1000_update_mc_addr_list(&adapter->hw, mta, mcnt); + + if (adapter->hw.mac.type == e1000_82542 && + adapter->hw.revision_id == E1000_REVISION_2) { + reg_rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL); + reg_rctl &= ~E1000_RCTL_RST; + E1000_WRITE_REG(&adapter->hw, E1000_RCTL, reg_rctl); + msec_delay(5); + if (adapter->hw.bus.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) + e1000_pci_set_mwi(&adapter->hw); + } + free(mta, M_DEVBUF); +} + + +/********************************************************************* + * Timer routine + * + * This routine checks for link status and updates statistics. + * + **********************************************************************/ + +static void +lem_local_timer(void *arg) +{ + struct adapter *adapter = arg; + struct ifnet *ifp = adapter->ifp; + + EM_CORE_LOCK_ASSERT(adapter); + + taskqueue_enqueue(adapter->tq, + &adapter->rxtx_task); + lem_update_link_status(adapter); + lem_update_stats_counters(adapter); + + if (lem_display_debug_stats && ifp->if_drv_flags & IFF_DRV_RUNNING) + lem_print_hw_stats(adapter); + + lem_smartspeed(adapter); + + /* + * We check the watchdog: the time since + * the last TX descriptor was cleaned. + * This implies a functional TX engine. + */ + if ((adapter->watchdog_check == TRUE) && + (ticks - adapter->watchdog_time > EM_WATCHDOG)) + goto hung; + + callout_reset(&adapter->timer, hz, lem_local_timer, adapter); + return; +hung: + device_printf(adapter->dev, "Watchdog timeout -- resetting\n"); + adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + adapter->watchdog_events++; + lem_init_locked(adapter); +} + +static void +lem_update_link_status(struct adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct ifnet *ifp = adapter->ifp; + device_t dev = adapter->dev; + u32 link_check = 0; + + /* Get the cached link value or read phy for real */ + switch (hw->phy.media_type) { + case e1000_media_type_copper: + if (hw->mac.get_link_status) { + /* Do the work to read phy */ + e1000_check_for_link(hw); + link_check = !hw->mac.get_link_status; + if (link_check) /* ESB2 fix */ + e1000_cfg_on_link_up(hw); + } else + link_check = TRUE; + break; + case e1000_media_type_fiber: + e1000_check_for_link(hw); + link_check = (E1000_READ_REG(hw, E1000_STATUS) & + E1000_STATUS_LU); + break; + case e1000_media_type_internal_serdes: + e1000_check_for_link(hw); + link_check = adapter->hw.mac.serdes_has_link; + break; + default: + case e1000_media_type_unknown: + break; + } + + /* Now check for a transition */ + if (link_check && (adapter->link_active == 0)) { + e1000_get_speed_and_duplex(hw, &adapter->link_speed, + &adapter->link_duplex); + if (bootverbose) + device_printf(dev, "Link is up %d Mbps %s\n", + adapter->link_speed, + ((adapter->link_duplex == FULL_DUPLEX) ? + "Full Duplex" : "Half Duplex")); + adapter->link_active = 1; + adapter->smartspeed = 0; + ifp->if_baudrate = adapter->link_speed * 1000000; + if_link_state_change(ifp, LINK_STATE_UP); + } else if (!link_check && (adapter->link_active == 1)) { + ifp->if_baudrate = adapter->link_speed = 0; + adapter->link_duplex = 0; + if (bootverbose) + device_printf(dev, "Link is Down\n"); + adapter->link_active = 0; + /* Link down, disable watchdog */ + adapter->watchdog_check = FALSE; + if_link_state_change(ifp, LINK_STATE_DOWN); + } +} + +/********************************************************************* + * + * This routine disables all traffic on the adapter by issuing a + * global reset on the MAC and deallocates TX/RX buffers. + * + * This routine should always be called with BOTH the CORE + * and TX locks. + **********************************************************************/ + +static void +lem_stop(void *arg) +{ + struct adapter *adapter = arg; + struct ifnet *ifp = adapter->ifp; + + EM_CORE_LOCK_ASSERT(adapter); + EM_TX_LOCK_ASSERT(adapter); + + INIT_DEBUGOUT("lem_stop: begin"); + + lem_disable_intr(adapter); + callout_stop(&adapter->timer); + callout_stop(&adapter->tx_fifo_timer); + + /* Tell the stack that the interface is no longer active */ + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + + e1000_reset_hw(&adapter->hw); + if (adapter->hw.mac.type >= e1000_82544) + E1000_WRITE_REG(&adapter->hw, E1000_WUC, 0); + + e1000_led_off(&adapter->hw); + e1000_cleanup_led(&adapter->hw); +} + + +/********************************************************************* + * + * Determine hardware revision. + * + **********************************************************************/ +static void +lem_identify_hardware(struct adapter *adapter) +{ + device_t dev = adapter->dev; + + /* Make sure our PCI config space has the necessary stuff set */ + adapter->hw.bus.pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2); + if (!((adapter->hw.bus.pci_cmd_word & PCIM_CMD_BUSMASTEREN) && + (adapter->hw.bus.pci_cmd_word & PCIM_CMD_MEMEN))) { + device_printf(dev, "Memory Access and/or Bus Master bits " + "were not set!\n"); + adapter->hw.bus.pci_cmd_word |= + (PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN); + pci_write_config(dev, PCIR_COMMAND, + adapter->hw.bus.pci_cmd_word, 2); + } + + /* Save off the information about this board */ + adapter->hw.vendor_id = pci_get_vendor(dev); + adapter->hw.device_id = pci_get_device(dev); + adapter->hw.revision_id = pci_read_config(dev, PCIR_REVID, 1); + adapter->hw.subsystem_vendor_id = + pci_read_config(dev, PCIR_SUBVEND_0, 2); + adapter->hw.subsystem_device_id = + pci_read_config(dev, PCIR_SUBDEV_0, 2); + + /* Do Shared Code Init and Setup */ + if (e1000_set_mac_type(&adapter->hw)) { + device_printf(dev, "Setup init failure\n"); + return; + } +} + +static int +lem_allocate_pci_resources(struct adapter *adapter) +{ + device_t dev = adapter->dev; + int val, rid, error = E1000_SUCCESS; + + rid = PCIR_BAR(0); + adapter->memory = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &rid, RF_ACTIVE); + if (adapter->memory == NULL) { + device_printf(dev, "Unable to allocate bus resource: memory\n"); + return (ENXIO); + } + adapter->osdep.mem_bus_space_tag = + rman_get_bustag(adapter->memory); + adapter->osdep.mem_bus_space_handle = + rman_get_bushandle(adapter->memory); + adapter->hw.hw_addr = (u8 *)&adapter->osdep.mem_bus_space_handle; + + /* Only older adapters use IO mapping */ + if (adapter->hw.mac.type > e1000_82543) { + /* Figure our where our IO BAR is ? */ + for (rid = PCIR_BAR(0); rid < PCIR_CIS;) { + val = pci_read_config(dev, rid, 4); + if (EM_BAR_TYPE(val) == EM_BAR_TYPE_IO) { + adapter->io_rid = rid; + break; + } + rid += 4; + /* check for 64bit BAR */ + if (EM_BAR_MEM_TYPE(val) == EM_BAR_MEM_TYPE_64BIT) + rid += 4; + } + if (rid >= PCIR_CIS) { + device_printf(dev, "Unable to locate IO BAR\n"); + return (ENXIO); + } + adapter->ioport = bus_alloc_resource_any(dev, + SYS_RES_IOPORT, &adapter->io_rid, RF_ACTIVE); + if (adapter->ioport == NULL) { + device_printf(dev, "Unable to allocate bus resource: " + "ioport\n"); + return (ENXIO); + } + adapter->hw.io_base = 0; + adapter->osdep.io_bus_space_tag = + rman_get_bustag(adapter->ioport); + adapter->osdep.io_bus_space_handle = + rman_get_bushandle(adapter->ioport); + } + + adapter->hw.back = &adapter->osdep; + + return (error); +} + +/********************************************************************* + * + * Setup the Legacy or MSI Interrupt handler + * + **********************************************************************/ +int +lem_allocate_irq(struct adapter *adapter) +{ + device_t dev = adapter->dev; + int error, rid = 0; + + /* Manually turn off all interrupts */ + E1000_WRITE_REG(&adapter->hw, E1000_IMC, 0xffffffff); + + /* We allocate a single interrupt resource */ + adapter->res[0] = bus_alloc_resource_any(dev, + SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); + if (adapter->res[0] == NULL) { + device_printf(dev, "Unable to allocate bus resource: " + "interrupt\n"); + return (ENXIO); + } + +#ifdef EM_LEGACY_IRQ + /* We do Legacy setup */ + if ((error = bus_setup_intr(dev, adapter->res[0], +#if __FreeBSD_version > 700000 + INTR_TYPE_NET | INTR_MPSAFE, NULL, lem_intr, adapter, +#else /* 6.X */ + INTR_TYPE_NET | INTR_MPSAFE, lem_intr, adapter, +#endif + &adapter->tag[0])) != 0) { + device_printf(dev, "Failed to register interrupt handler"); + return (error); + } + +#else /* FAST_IRQ */ + /* + * Try allocating a fast interrupt and the associated deferred + * processing contexts. + */ + TASK_INIT(&adapter->rxtx_task, 0, lem_handle_rxtx, adapter); + TASK_INIT(&adapter->link_task, 0, lem_handle_link, adapter); + adapter->tq = taskqueue_create_fast("lem_taskq", M_NOWAIT, + taskqueue_thread_enqueue, &adapter->tq); + taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s taskq", + device_get_nameunit(adapter->dev)); +#if __FreeBSD_version < 700000 + if ((error = bus_setup_intr(dev, adapter->res[0], + INTR_TYPE_NET | INTR_FAST, lem_irq_fast, adapter, +#else + if ((error = bus_setup_intr(dev, adapter->res[0], + INTR_TYPE_NET, lem_irq_fast, NULL, adapter, +#endif + &adapter->tag[0])) != 0) { + device_printf(dev, "Failed to register fast interrupt " + "handler: %d\n", error); + taskqueue_free(adapter->tq); + adapter->tq = NULL; + return (error); + } +#endif /* EM_LEGACY_IRQ */ + + return (0); +} + + +static void +lem_free_pci_resources(struct adapter *adapter) +{ + device_t dev = adapter->dev; + + + if (adapter->tag[0] != NULL) { + bus_teardown_intr(dev, adapter->res[0], + adapter->tag[0]); + adapter->tag[0] = NULL; + } + + if (adapter->res[0] != NULL) { + bus_release_resource(dev, SYS_RES_IRQ, + 0, adapter->res[0]); + } + + if (adapter->memory != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, + PCIR_BAR(0), adapter->memory); + + if (adapter->ioport != NULL) + bus_release_resource(dev, SYS_RES_IOPORT, + adapter->io_rid, adapter->ioport); +} + + +/********************************************************************* + * + * Initialize the hardware to a configuration + * as specified by the adapter structure. + * + **********************************************************************/ +static int +lem_hardware_init(struct adapter *adapter) +{ + device_t dev = adapter->dev; + u16 rx_buffer_size; + + INIT_DEBUGOUT("lem_hardware_init: begin"); + + /* Issue a global reset */ + e1000_reset_hw(&adapter->hw); + + /* When hardware is reset, fifo_head is also reset */ + adapter->tx_fifo_head = 0; + + /* + * 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. + */ + rx_buffer_size = ((E1000_READ_REG(&adapter->hw, E1000_PBA) & + 0xffff) << 10 ); + + 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; + + adapter->hw.fc.pause_time = EM_FC_PAUSE_TIME; + adapter->hw.fc.send_xon = TRUE; + + /* Set Flow control, use the tunable location if sane */ + if ((lem_fc_setting >= 0) || (lem_fc_setting < 4)) + adapter->hw.fc.requested_mode = lem_fc_setting; + else + adapter->hw.fc.requested_mode = e1000_fc_none; + + if (e1000_init_hw(&adapter->hw) < 0) { + device_printf(dev, "Hardware Initialization Failed\n"); + return (EIO); + } + + e1000_check_for_link(&adapter->hw); + + return (0); +} + +/********************************************************************* + * + * Setup networking device structure and register an interface. + * + **********************************************************************/ +static void +lem_setup_interface(device_t dev, struct adapter *adapter) +{ + struct ifnet *ifp; + + INIT_DEBUGOUT("lem_setup_interface: begin"); + + ifp = adapter->ifp = if_alloc(IFT_ETHER); + if (ifp == NULL) + panic("%s: can not if_alloc()", device_get_nameunit(dev)); + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_mtu = ETHERMTU; + ifp->if_init = lem_init; + ifp->if_softc = adapter; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_ioctl = lem_ioctl; + ifp->if_start = lem_start; + IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 1); + ifp->if_snd.ifq_drv_maxlen = adapter->num_tx_desc - 1; + IFQ_SET_READY(&ifp->if_snd); + + ether_ifattach(ifp, adapter->hw.mac.addr); + + ifp->if_capabilities = ifp->if_capenable = 0; + +#if __FreeBSD_version >= 800000 + /* Multiqueue tx functions */ + ifp->if_transmit = lem_mq_start; + ifp->if_qflush = lem_qflush; + adapter->br = buf_ring_alloc(4096, M_DEVBUF, M_WAITOK, &adapter->tx_mtx); +#endif + if (adapter->hw.mac.type >= e1000_82543) { + int version_cap; +#if __FreeBSD_version < 700000 + version_cap = IFCAP_HWCSUM; +#else + version_cap = IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM; +#endif + ifp->if_capabilities |= version_cap; + ifp->if_capenable |= version_cap; + } + + /* + * Tell the upper layer(s) we support long frames. + */ + ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); + ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; + ifp->if_capenable |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; + +#ifdef DEVICE_POLLING + 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 + */ + ifmedia_init(&adapter->media, IFM_IMASK, + lem_media_change, lem_media_status); + if ((adapter->hw.phy.media_type == e1000_media_type_fiber) || + (adapter->hw.phy.media_type == e1000_media_type_internal_serdes)) { + u_char fiber_type = IFM_1000_SX; /* default type */ + + if (adapter->hw.mac.type == e1000_82545) + fiber_type = IFM_1000_LX; + ifmedia_add(&adapter->media, IFM_ETHER | fiber_type | IFM_FDX, + 0, NULL); + ifmedia_add(&adapter->media, IFM_ETHER | fiber_type, 0, NULL); + } else { + ifmedia_add(&adapter->media, IFM_ETHER | IFM_10_T, 0, NULL); + ifmedia_add(&adapter->media, IFM_ETHER | IFM_10_T | IFM_FDX, + 0, NULL); + ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX, + 0, NULL); + ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX | IFM_FDX, + 0, NULL); + if (adapter->hw.phy.type != e1000_phy_ife) { + ifmedia_add(&adapter->media, + IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL); + ifmedia_add(&adapter->media, + IFM_ETHER | IFM_1000_T, 0, NULL); + } + } + ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); + ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); +} + + +/********************************************************************* + * + * Workaround for SmartSpeed on 82541 and 82547 controllers + * + **********************************************************************/ +static void +lem_smartspeed(struct adapter *adapter) +{ + u16 phy_tmp; + + if (adapter->link_active || (adapter->hw.phy.type != e1000_phy_igp) || + adapter->hw.mac.autoneg == 0 || + (adapter->hw.phy.autoneg_advertised & ADVERTISE_1000_FULL) == 0) + return; + + if (adapter->smartspeed == 0) { + /* If Master/Slave config fault is asserted twice, + * we assume back-to-back */ + e1000_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_tmp); + if (!(phy_tmp & SR_1000T_MS_CONFIG_FAULT)) + return; + e1000_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_tmp); + if (phy_tmp & SR_1000T_MS_CONFIG_FAULT) { + e1000_read_phy_reg(&adapter->hw, + PHY_1000T_CTRL, &phy_tmp); + if(phy_tmp & CR_1000T_MS_ENABLE) { + phy_tmp &= ~CR_1000T_MS_ENABLE; + e1000_write_phy_reg(&adapter->hw, + PHY_1000T_CTRL, phy_tmp); + adapter->smartspeed++; + if(adapter->hw.mac.autoneg && + !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); + e1000_write_phy_reg(&adapter->hw, + PHY_CONTROL, phy_tmp); + } + } + } + return; + } else if(adapter->smartspeed == EM_SMARTSPEED_DOWNSHIFT) { + /* If still no link, perhaps using 2/3 pair cable */ + e1000_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, &phy_tmp); + phy_tmp |= CR_1000T_MS_ENABLE; + e1000_write_phy_reg(&adapter->hw, PHY_1000T_CTRL, phy_tmp); + if(adapter->hw.mac.autoneg && + !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); + e1000_write_phy_reg(&adapter->hw, PHY_CONTROL, phy_tmp); + } + } + /* Restart process after EM_SMARTSPEED_MAX iterations */ + if(adapter->smartspeed++ == EM_SMARTSPEED_MAX) + adapter->smartspeed = 0; +} + + +/* + * Manage DMA'able memory. + */ +static void +lem_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + if (error) + return; + *(bus_addr_t *) arg = segs[0].ds_addr; +} + +static int +lem_dma_malloc(struct adapter *adapter, bus_size_t size, + struct em_dma_alloc *dma, int mapflags) +{ + int error; + +#if __FreeBSD_version >= 700000 + error = bus_dma_tag_create(bus_get_dma_tag(adapter->dev), /* parent */ +#else + error = bus_dma_tag_create(NULL, /* parent */ +#endif + EM_DBA_ALIGN, 0, /* alignment, bounds */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + size, /* maxsize */ + 1, /* nsegments */ + size, /* maxsegsize */ + 0, /* flags */ + NULL, /* lockfunc */ + NULL, /* lockarg */ + &dma->dma_tag); + if (error) { + device_printf(adapter->dev, + "%s: bus_dma_tag_create failed: %d\n", + __func__, error); + goto fail_0; + } + + error = bus_dmamem_alloc(dma->dma_tag, (void**) &dma->dma_vaddr, + BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &dma->dma_map); + if (error) { + device_printf(adapter->dev, + "%s: bus_dmamem_alloc(%ju) failed: %d\n", + __func__, (uintmax_t)size, error); + goto fail_2; + } + + dma->dma_paddr = 0; + error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr, + size, lem_dmamap_cb, &dma->dma_paddr, mapflags | BUS_DMA_NOWAIT); + if (error || dma->dma_paddr == 0) { + device_printf(adapter->dev, + "%s: bus_dmamap_load failed: %d\n", + __func__, error); + goto fail_3; + } + + return (0); + +fail_3: + bus_dmamap_unload(dma->dma_tag, dma->dma_map); +fail_2: + bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map); + bus_dma_tag_destroy(dma->dma_tag); +fail_0: + dma->dma_map = NULL; + dma->dma_tag = NULL; + + return (error); +} + +static void +lem_dma_free(struct adapter *adapter, struct em_dma_alloc *dma) +{ + if (dma->dma_tag == NULL) + return; + if (dma->dma_map != NULL) { + bus_dmamap_sync(dma->dma_tag, dma->dma_map, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(dma->dma_tag, dma->dma_map); + bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map); + dma->dma_map = NULL; + } + bus_dma_tag_destroy(dma->dma_tag); + dma->dma_tag = NULL; +} + + +/********************************************************************* + * + * Allocate memory for tx_buffer structures. The tx_buffer stores all + * the information needed to transmit a packet on the wire. + * + **********************************************************************/ +static int +lem_allocate_transmit_structures(struct adapter *adapter) +{ + device_t dev = adapter->dev; + struct em_buffer *tx_buffer; + int error; + + /* + * Create DMA tags for tx descriptors + */ +#if __FreeBSD_version >= 700000 + if ((error = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ +#else + if ((error = bus_dma_tag_create(NULL, /* parent */ +#endif + 1, 0, /* alignment, bounds */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + EM_TSO_SIZE, /* maxsize */ + EM_MAX_SCATTER, /* nsegments */ + EM_TSO_SEG_SIZE, /* maxsegsize */ + 0, /* flags */ + NULL, /* lockfunc */ + NULL, /* lockarg */ + &adapter->txtag)) != 0) { + device_printf(dev, "Unable to allocate TX DMA tag\n"); + goto fail; + } + + adapter->tx_buffer_area = malloc(sizeof(struct em_buffer) * + adapter->num_tx_desc, M_DEVBUF, M_NOWAIT | M_ZERO); + if (adapter->tx_buffer_area == NULL) { + device_printf(dev, "Unable to allocate tx_buffer memory\n"); + error = ENOMEM; + goto fail; + } + + /* Create the descriptor buffer dma maps */ + for (int i = 0; i < adapter->num_tx_desc; i++) { + tx_buffer = &adapter->tx_buffer_area[i]; + error = bus_dmamap_create(adapter->txtag, 0, &tx_buffer->map); + if (error != 0) { + device_printf(dev, "Unable to create TX DMA map\n"); + goto fail; + } + tx_buffer->next_eop = -1; + } + + return (0); +fail: + lem_free_transmit_structures(adapter); + return (error); +} + +/********************************************************************* + * + * (Re)Initialize transmit structures. + * + **********************************************************************/ +static void +lem_setup_transmit_structures(struct adapter *adapter) +{ + struct em_buffer *tx_buffer; + + /* Clear the old ring contents */ + bzero(adapter->tx_desc_base, + (sizeof(struct e1000_tx_desc)) * adapter->num_tx_desc); + + /* Free any existing TX buffers */ + for (int i = 0; i < adapter->num_tx_desc; i++, tx_buffer++) { + tx_buffer = &adapter->tx_buffer_area[i]; + bus_dmamap_sync(adapter->txtag, tx_buffer->map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(adapter->txtag, tx_buffer->map); + m_freem(tx_buffer->m_head); + tx_buffer->m_head = NULL; + tx_buffer->next_eop = -1; + } + + /* Reset state */ + adapter->next_avail_tx_desc = 0; + adapter->next_tx_to_clean = 0; + adapter->num_tx_desc_avail = adapter->num_tx_desc; + + bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + return; +} + +/********************************************************************* + * + * Enable transmit unit. + * + **********************************************************************/ +static void +lem_initialize_transmit_unit(struct adapter *adapter) +{ + u32 tctl, tipg = 0; + u64 bus_addr; + + INIT_DEBUGOUT("lem_initialize_transmit_unit: begin"); + /* Setup the Base and Length of the Tx Descriptor Ring */ + bus_addr = adapter->txdma.dma_paddr; + E1000_WRITE_REG(&adapter->hw, E1000_TDLEN(0), + adapter->num_tx_desc * sizeof(struct e1000_tx_desc)); + E1000_WRITE_REG(&adapter->hw, E1000_TDBAH(0), + (u32)(bus_addr >> 32)); + E1000_WRITE_REG(&adapter->hw, E1000_TDBAL(0), + (u32)bus_addr); + /* Setup the HW Tx Head and Tail descriptor pointers */ + E1000_WRITE_REG(&adapter->hw, E1000_TDT(0), 0); + E1000_WRITE_REG(&adapter->hw, E1000_TDH(0), 0); + + HW_DEBUGOUT2("Base = %x, Length = %x\n", + E1000_READ_REG(&adapter->hw, E1000_TDBAL(0)), + E1000_READ_REG(&adapter->hw, E1000_TDLEN(0))); + + /* Set the default values for the Tx Inter Packet Gap timer */ + switch (adapter->hw.mac.type) { + case e1000_82542: + tipg = DEFAULT_82542_TIPG_IPGT; + tipg |= DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; + tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; + break; + default: + if ((adapter->hw.phy.media_type == e1000_media_type_fiber) || + (adapter->hw.phy.media_type == + e1000_media_type_internal_serdes)) + tipg = DEFAULT_82543_TIPG_IPGT_FIBER; + else + tipg = DEFAULT_82543_TIPG_IPGT_COPPER; + tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; + tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; + } + + E1000_WRITE_REG(&adapter->hw, E1000_TIPG, tipg); + E1000_WRITE_REG(&adapter->hw, E1000_TIDV, adapter->tx_int_delay.value); + if(adapter->hw.mac.type >= e1000_82540) + E1000_WRITE_REG(&adapter->hw, E1000_TADV, + adapter->tx_abs_int_delay.value); + + /* Program the Transmit Control Register */ + tctl = E1000_READ_REG(&adapter->hw, E1000_TCTL); + tctl &= ~E1000_TCTL_CT; + tctl |= (E1000_TCTL_PSP | E1000_TCTL_RTLC | E1000_TCTL_EN | + (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT)); + + /* This write will effectively turn on the transmit unit. */ + E1000_WRITE_REG(&adapter->hw, E1000_TCTL, tctl); + + /* Setup Transmit Descriptor Base Settings */ + adapter->txd_cmd = E1000_TXD_CMD_IFCS; + + if (adapter->tx_int_delay.value > 0) + adapter->txd_cmd |= E1000_TXD_CMD_IDE; +} + +/********************************************************************* + * + * Free all transmit related data structures. + * + **********************************************************************/ +static void +lem_free_transmit_structures(struct adapter *adapter) +{ + struct em_buffer *tx_buffer; + + INIT_DEBUGOUT("free_transmit_structures: begin"); + + if (adapter->tx_buffer_area != NULL) { + for (int i = 0; i < adapter->num_tx_desc; i++) { + tx_buffer = &adapter->tx_buffer_area[i]; + if (tx_buffer->m_head != NULL) { + bus_dmamap_sync(adapter->txtag, tx_buffer->map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(adapter->txtag, + tx_buffer->map); + m_freem(tx_buffer->m_head); + tx_buffer->m_head = NULL; + } else if (tx_buffer->map != NULL) + bus_dmamap_unload(adapter->txtag, + tx_buffer->map); + if (tx_buffer->map != NULL) { + bus_dmamap_destroy(adapter->txtag, + tx_buffer->map); + tx_buffer->map = NULL; + } + } + } + if (adapter->tx_buffer_area != NULL) { + free(adapter->tx_buffer_area, M_DEVBUF); + adapter->tx_buffer_area = NULL; + } + if (adapter->txtag != NULL) { + bus_dma_tag_destroy(adapter->txtag); + adapter->txtag = NULL; + } +#if __FreeBSD_version >= 800000 + if (adapter->br != NULL) + buf_ring_free(adapter->br, M_DEVBUF); +#endif +} + +/********************************************************************* + * + * The offload context needs to be set when we transfer the first + * packet of a particular protocol (TCP/UDP). This routine has been + * enhanced to deal with inserted VLAN headers, and IPV6 (not complete) + * + * Added back the old method of keeping the current context type + * and not setting if unnecessary, as this is reported to be a + * big performance win. -jfv + **********************************************************************/ +static void +lem_transmit_checksum_setup(struct adapter *adapter, struct mbuf *mp, + u32 *txd_upper, u32 *txd_lower) +{ + struct e1000_context_desc *TXD = NULL; + struct em_buffer *tx_buffer; + struct ether_vlan_header *eh; + struct ip *ip = NULL; + struct ip6_hdr *ip6; + int curr_txd, ehdrlen; + u32 cmd, hdr_len, ip_hlen; + u16 etype; + u8 ipproto; + + + cmd = hdr_len = ipproto = 0; + curr_txd = adapter->next_avail_tx_desc; + + /* + * Determine where frame payload starts. + * Jump over vlan headers if already present, + * helpful for QinQ too. + */ + eh = mtod(mp, struct ether_vlan_header *); + if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { + etype = ntohs(eh->evl_proto); + ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; + } else { + etype = ntohs(eh->evl_encap_proto); + ehdrlen = ETHER_HDR_LEN; + } + + /* + * We only support TCP/UDP for IPv4 and IPv6 for the moment. + * TODO: Support SCTP too when it hits the tree. + */ + switch (etype) { + case ETHERTYPE_IP: + ip = (struct ip *)(mp->m_data + ehdrlen); + ip_hlen = ip->ip_hl << 2; + + /* Setup of IP header checksum. */ + if (mp->m_pkthdr.csum_flags & CSUM_IP) { + /* + * Start offset for header checksum calculation. + * End offset for header checksum calculation. + * Offset of place to put the checksum. + */ + TXD = (struct e1000_context_desc *) + &adapter->tx_desc_base[curr_txd]; + TXD->lower_setup.ip_fields.ipcss = ehdrlen; + TXD->lower_setup.ip_fields.ipcse = + htole16(ehdrlen + ip_hlen); + TXD->lower_setup.ip_fields.ipcso = + ehdrlen + offsetof(struct ip, ip_sum); + cmd |= E1000_TXD_CMD_IP; + *txd_upper |= E1000_TXD_POPTS_IXSM << 8; + } + + if (mp->m_len < ehdrlen + ip_hlen) + return; /* failure */ + + hdr_len = ehdrlen + ip_hlen; + ipproto = ip->ip_p; + + break; + case ETHERTYPE_IPV6: + ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen); + ip_hlen = sizeof(struct ip6_hdr); /* XXX: No header stacking. */ + + if (mp->m_len < ehdrlen + ip_hlen) + return; /* failure */ + + /* IPv6 doesn't have a header checksum. */ + + hdr_len = ehdrlen + ip_hlen; + ipproto = ip6->ip6_nxt; + + break; + default: + *txd_upper = 0; + *txd_lower = 0; + return; + } + + switch (ipproto) { + case IPPROTO_TCP: + if (mp->m_pkthdr.csum_flags & CSUM_TCP) { + *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; + *txd_upper |= E1000_TXD_POPTS_TXSM << 8; + /* no need for context if already set */ + if (adapter->last_hw_offload == CSUM_TCP) + return; + adapter->last_hw_offload = CSUM_TCP; + /* + * Start offset for payload checksum calculation. + * End offset for payload checksum calculation. + * Offset of place to put the checksum. + */ + TXD = (struct e1000_context_desc *) + &adapter->tx_desc_base[curr_txd]; + TXD->upper_setup.tcp_fields.tucss = hdr_len; + TXD->upper_setup.tcp_fields.tucse = htole16(0); + TXD->upper_setup.tcp_fields.tucso = + hdr_len + offsetof(struct tcphdr, th_sum); + cmd |= E1000_TXD_CMD_TCP; + } + break; + case IPPROTO_UDP: + { + if (mp->m_pkthdr.csum_flags & CSUM_UDP) { + *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; + *txd_upper |= E1000_TXD_POPTS_TXSM << 8; + /* no need for context if already set */ + if (adapter->last_hw_offload == CSUM_UDP) + return; + adapter->last_hw_offload = CSUM_UDP; + /* + * Start offset for header checksum calculation. + * End offset for header checksum calculation. + * Offset of place to put the checksum. + */ + TXD = (struct e1000_context_desc *) + &adapter->tx_desc_base[curr_txd]; + TXD->upper_setup.tcp_fields.tucss = hdr_len; + TXD->upper_setup.tcp_fields.tucse = htole16(0); + TXD->upper_setup.tcp_fields.tucso = + hdr_len + offsetof(struct udphdr, uh_sum); + } + /* Fall Thru */ + } + default: + break; + } + + TXD->tcp_seg_setup.data = htole32(0); + TXD->cmd_and_length = + htole32(adapter->txd_cmd | E1000_TXD_CMD_DEXT | cmd); + tx_buffer = &adapter->tx_buffer_area[curr_txd]; + tx_buffer->m_head = NULL; + tx_buffer->next_eop = -1; + + if (++curr_txd == adapter->num_tx_desc) + curr_txd = 0; + + adapter->num_tx_desc_avail--; + adapter->next_avail_tx_desc = curr_txd; +} + + +/********************************************************************** + * + * Examine each tx_buffer in the used queue. If the hardware is done + * processing the packet then free associated resources. The + * tx_buffer is put back on the free queue. + * + **********************************************************************/ +static void +lem_txeof(struct adapter *adapter) +{ + int first, last, done, num_avail; + struct em_buffer *tx_buffer; + struct e1000_tx_desc *tx_desc, *eop_desc; + struct ifnet *ifp = adapter->ifp; + + EM_TX_LOCK_ASSERT(adapter); + + if (adapter->num_tx_desc_avail == adapter->num_tx_desc) + return; + + num_avail = adapter->num_tx_desc_avail; + first = adapter->next_tx_to_clean; + tx_desc = &adapter->tx_desc_base[first]; + tx_buffer = &adapter->tx_buffer_area[first]; + last = tx_buffer->next_eop; + eop_desc = &adapter->tx_desc_base[last]; + + /* + * What this does is get the index of the + * first descriptor AFTER the EOP of the + * first packet, that way we can do the + * simple comparison on the inner while loop. + */ + if (++last == adapter->num_tx_desc) + last = 0; + done = last; + + bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map, + BUS_DMASYNC_POSTREAD); + + while (eop_desc->upper.fields.status & E1000_TXD_STAT_DD) { + /* We clean the range of the packet */ + while (first != done) { + tx_desc->upper.data = 0; + tx_desc->lower.data = 0; + tx_desc->buffer_addr = 0; + ++num_avail; + + if (tx_buffer->m_head) { + ifp->if_opackets++; + bus_dmamap_sync(adapter->txtag, + tx_buffer->map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(adapter->txtag, + tx_buffer->map); + + m_freem(tx_buffer->m_head); + tx_buffer->m_head = NULL; + } + tx_buffer->next_eop = -1; + adapter->watchdog_time = ticks; + + if (++first == adapter->num_tx_desc) + first = 0; + + tx_buffer = &adapter->tx_buffer_area[first]; + tx_desc = &adapter->tx_desc_base[first]; + } + /* See if we can continue to the next packet */ + last = tx_buffer->next_eop; + if (last != -1) { + eop_desc = &adapter->tx_desc_base[last]; + /* Get new done point */ + if (++last == adapter->num_tx_desc) last = 0; + done = last; + } else + break; + } + bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + adapter->next_tx_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 watchdog. + */ + if (num_avail > EM_TX_CLEANUP_THRESHOLD) { + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + if (num_avail == adapter->num_tx_desc) { + adapter->watchdog_check = FALSE; + adapter->num_tx_desc_avail = num_avail; + return; + } + } + + adapter->num_tx_desc_avail = num_avail; + return; +} + +/********************************************************************* + * + * When Link is lost sometimes there is work still in the TX ring + * 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. + * + **********************************************************************/ +static void +lem_tx_purge(struct adapter *adapter) +{ + if ((!adapter->link_active) && (adapter->watchdog_check)) { + EM_TX_LOCK(adapter); + lem_txeof(adapter); + EM_TX_UNLOCK(adapter); + if (adapter->watchdog_check) /* Still outstanding? */ + lem_init_locked(adapter); + } +} + +/********************************************************************* + * + * Get a buffer from system mbuf buffer pool. + * + **********************************************************************/ +static int +lem_get_buf(struct adapter *adapter, int i) +{ + struct mbuf *m; + bus_dma_segment_t segs[1]; + bus_dmamap_t map; + struct em_buffer *rx_buffer; + int error, nsegs; + + m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); + if (m == NULL) { + adapter->mbuf_cluster_failed++; + return (ENOBUFS); + } + m->m_len = m->m_pkthdr.len = MCLBYTES; + + if (adapter->max_frame_size <= (MCLBYTES - ETHER_ALIGN)) + m_adj(m, ETHER_ALIGN); + + /* + * Using memory from the mbuf cluster pool, invoke the + * bus_dma machinery to arrange the memory mapping. + */ + error = bus_dmamap_load_mbuf_sg(adapter->rxtag, + adapter->rx_sparemap, m, segs, &nsegs, BUS_DMA_NOWAIT); + if (error != 0) { + m_free(m); + return (error); + } + + /* If nsegs is wrong then the stack is corrupt. */ + KASSERT(nsegs == 1, ("Too many segments returned!")); + + rx_buffer = &adapter->rx_buffer_area[i]; + if (rx_buffer->m_head != NULL) + bus_dmamap_unload(adapter->rxtag, rx_buffer->map); + + map = rx_buffer->map; + rx_buffer->map = adapter->rx_sparemap; + adapter->rx_sparemap = map; + bus_dmamap_sync(adapter->rxtag, rx_buffer->map, BUS_DMASYNC_PREREAD); + rx_buffer->m_head = m; + + adapter->rx_desc_base[i].buffer_addr = htole64(segs[0].ds_addr); + return (0); +} + +/********************************************************************* + * + * Allocate memory for rx_buffer structures. Since we use one + * rx_buffer per received packet, the maximum number of rx_buffer's + * that we'll need is equal to the number of receive descriptors + * that we've allocated. + * + **********************************************************************/ +static int +lem_allocate_receive_structures(struct adapter *adapter) +{ + device_t dev = adapter->dev; + struct em_buffer *rx_buffer; + int i, error; + + adapter->rx_buffer_area = malloc(sizeof(struct em_buffer) * + adapter->num_rx_desc, M_DEVBUF, M_NOWAIT | M_ZERO); + if (adapter->rx_buffer_area == NULL) { + device_printf(dev, "Unable to allocate rx_buffer memory\n"); + return (ENOMEM); + } + +#if __FreeBSD_version >= 700000 + error = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ +#else + error = bus_dma_tag_create(NULL, /* parent */ +#endif + 1, 0, /* alignment, bounds */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + MCLBYTES, /* maxsize */ + 1, /* nsegments */ + MCLBYTES, /* maxsegsize */ + 0, /* flags */ + NULL, /* lockfunc */ + NULL, /* lockarg */ + &adapter->rxtag); + if (error) { + device_printf(dev, "%s: bus_dma_tag_create failed %d\n", + __func__, error); + goto fail; + } + + /* Create the spare map (used by getbuf) */ + error = bus_dmamap_create(adapter->rxtag, BUS_DMA_NOWAIT, + &adapter->rx_sparemap); + if (error) { + device_printf(dev, "%s: bus_dmamap_create failed: %d\n", + __func__, error); + goto fail; + } + + rx_buffer = adapter->rx_buffer_area; + for (i = 0; i < adapter->num_rx_desc; i++, rx_buffer++) { + error = bus_dmamap_create(adapter->rxtag, BUS_DMA_NOWAIT, + &rx_buffer->map); + if (error) { + device_printf(dev, "%s: bus_dmamap_create failed: %d\n", + __func__, error); + goto fail; + } + } + + return (0); + +fail: + lem_free_receive_structures(adapter); + return (error); +} + +/********************************************************************* + * + * (Re)initialize receive structures. + * + **********************************************************************/ +static int +lem_setup_receive_structures(struct adapter *adapter) +{ + struct em_buffer *rx_buffer; + int i, error; + + /* Reset descriptor ring */ + bzero(adapter->rx_desc_base, + (sizeof(struct e1000_rx_desc)) * adapter->num_rx_desc); + + /* Free current RX buffers. */ + rx_buffer = adapter->rx_buffer_area; + for (i = 0; i < adapter->num_rx_desc; i++, rx_buffer++) { + if (rx_buffer->m_head != NULL) { + bus_dmamap_sync(adapter->rxtag, rx_buffer->map, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(adapter->rxtag, rx_buffer->map); + m_freem(rx_buffer->m_head); + rx_buffer->m_head = NULL; + } + } + + /* Allocate new ones. */ + for (i = 0; i < adapter->num_rx_desc; i++) { + error = lem_get_buf(adapter, i); + if (error) + return (error); + } + + /* Setup our descriptor pointers */ + adapter->next_rx_desc_to_check = 0; + bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + return (0); +} + +/********************************************************************* + * + * Enable receive unit. + * + **********************************************************************/ +#define MAX_INTS_PER_SEC 8000 +#define DEFAULT_ITR 1000000000/(MAX_INTS_PER_SEC * 256) + +static void +lem_initialize_receive_unit(struct adapter *adapter) +{ + struct ifnet *ifp = adapter->ifp; + u64 bus_addr; + u32 rctl, rxcsum; + + INIT_DEBUGOUT("lem_initialize_receive_unit: begin"); + + /* + * Make sure receives are disabled while setting + * up the descriptor ring + */ + rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL); + E1000_WRITE_REG(&adapter->hw, E1000_RCTL, rctl & ~E1000_RCTL_EN); + + if (adapter->hw.mac.type >= e1000_82540) { + E1000_WRITE_REG(&adapter->hw, E1000_RADV, + adapter->rx_abs_int_delay.value); + /* + * Set the interrupt throttling rate. Value is calculated + * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) + */ + E1000_WRITE_REG(&adapter->hw, E1000_ITR, DEFAULT_ITR); + } + + /* + ** When using MSIX interrupts we need to throttle + ** using the EITR register (82574 only) + */ + if (adapter->msix) + for (int i = 0; i < 4; i++) + E1000_WRITE_REG(&adapter->hw, + E1000_EITR_82574(i), DEFAULT_ITR); + + /* Disable accelerated ackknowledge */ + if (adapter->hw.mac.type == e1000_82574) + E1000_WRITE_REG(&adapter->hw, + E1000_RFCTL, E1000_RFCTL_ACK_DIS); + + /* Setup the Base and Length of the Rx Descriptor Ring */ + bus_addr = adapter->rxdma.dma_paddr; + E1000_WRITE_REG(&adapter->hw, E1000_RDLEN(0), + adapter->num_rx_desc * sizeof(struct e1000_rx_desc)); + E1000_WRITE_REG(&adapter->hw, E1000_RDBAH(0), + (u32)(bus_addr >> 32)); + E1000_WRITE_REG(&adapter->hw, E1000_RDBAL(0), + (u32)bus_addr); + + /* Setup the Receive Control Register */ + rctl &= ~(3 << E1000_RCTL_MO_SHIFT); + rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO | + E1000_RCTL_RDMTS_HALF | + (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT); + + /* Make sure VLAN Filters are off */ + rctl &= ~E1000_RCTL_VFE; + + if (e1000_tbi_sbp_enabled_82543(&adapter->hw)) + rctl |= E1000_RCTL_SBP; + else + rctl &= ~E1000_RCTL_SBP; + + switch (adapter->rx_buffer_len) { + default: + case 2048: + rctl |= E1000_RCTL_SZ_2048; + break; + case 4096: + rctl |= E1000_RCTL_SZ_4096 | + E1000_RCTL_BSEX | E1000_RCTL_LPE; + break; + case 8192: + rctl |= E1000_RCTL_SZ_8192 | + E1000_RCTL_BSEX | E1000_RCTL_LPE; + break; + case 16384: + rctl |= E1000_RCTL_SZ_16384 | + E1000_RCTL_BSEX | E1000_RCTL_LPE; + break; + } + + if (ifp->if_mtu > ETHERMTU) + rctl |= E1000_RCTL_LPE; + else + rctl &= ~E1000_RCTL_LPE; + + /* Enable 82543 Receive Checksum Offload for TCP and UDP */ + if ((adapter->hw.mac.type >= e1000_82543) && + (ifp->if_capenable & IFCAP_RXCSUM)) { + rxcsum = E1000_READ_REG(&adapter->hw, E1000_RXCSUM); + rxcsum |= (E1000_RXCSUM_IPOFL | E1000_RXCSUM_TUOFL); + E1000_WRITE_REG(&adapter->hw, E1000_RXCSUM, rxcsum); + } + + /* Enable Receives */ + E1000_WRITE_REG(&adapter->hw, E1000_RCTL, rctl); + + /* + * Setup the HW Rx Head and + * Tail Descriptor Pointers + */ + E1000_WRITE_REG(&adapter->hw, E1000_RDH(0), 0); + E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), adapter->num_rx_desc - 1); + + return; +} + +/********************************************************************* + * + * Free receive related data structures. + * + **********************************************************************/ +static void +lem_free_receive_structures(struct adapter *adapter) +{ + struct em_buffer *rx_buffer; + int i; + + INIT_DEBUGOUT("free_receive_structures: begin"); + + if (adapter->rx_sparemap) { + bus_dmamap_destroy(adapter->rxtag, adapter->rx_sparemap); + adapter->rx_sparemap = NULL; + } + + /* Cleanup any existing buffers */ + if (adapter->rx_buffer_area != NULL) { + rx_buffer = adapter->rx_buffer_area; + for (i = 0; i < adapter->num_rx_desc; i++, rx_buffer++) { + if (rx_buffer->m_head != NULL) { + bus_dmamap_sync(adapter->rxtag, rx_buffer->map, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(adapter->rxtag, + rx_buffer->map); + m_freem(rx_buffer->m_head); + rx_buffer->m_head = NULL; + } else if (rx_buffer->map != NULL) + bus_dmamap_unload(adapter->rxtag, + rx_buffer->map); + if (rx_buffer->map != NULL) { + bus_dmamap_destroy(adapter->rxtag, + rx_buffer->map); + rx_buffer->map = NULL; + } + } + } + + if (adapter->rx_buffer_area != NULL) { + free(adapter->rx_buffer_area, M_DEVBUF); + adapter->rx_buffer_area = NULL; + } + + if (adapter->rxtag != NULL) { + bus_dma_tag_destroy(adapter->rxtag); + adapter->rxtag = NULL; + } +} + +/********************************************************************* + * + * This routine executes in interrupt context. It replenishes + * the mbufs in the descriptor and sends data which has been + * dma'ed into host memory to upper layer. + * + * We loop at most count times if count is > 0, or until done if + * count < 0. + * + * For polling we also now return the number of cleaned packets + *********************************************************************/ +static int +lem_rxeof(struct adapter *adapter, int count) +{ + struct ifnet *ifp = adapter->ifp;; + struct mbuf *mp; + u8 status, accept_frame = 0, eop = 0; + u16 len, desc_len, prev_len_adj; + int i, rx_sent = 0; + struct e1000_rx_desc *current_desc; + + EM_RX_LOCK(adapter); + i = adapter->next_rx_desc_to_check; + current_desc = &adapter->rx_desc_base[i]; + bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map, + BUS_DMASYNC_POSTREAD); + + if (!((current_desc->status) & E1000_RXD_STAT_DD)) { + EM_RX_UNLOCK(adapter); + return (rx_sent); + } + + while ((current_desc->status & E1000_RXD_STAT_DD) && + (count != 0) && + (ifp->if_drv_flags & IFF_DRV_RUNNING)) { + struct mbuf *m = NULL; + + mp = adapter->rx_buffer_area[i].m_head; + /* + * Can't defer bus_dmamap_sync(9) because TBI_ACCEPT + * needs to access the last received byte in the mbuf. + */ + bus_dmamap_sync(adapter->rxtag, adapter->rx_buffer_area[i].map, + BUS_DMASYNC_POSTREAD); + + accept_frame = 1; + prev_len_adj = 0; + desc_len = le16toh(current_desc->length); + status = current_desc->status; + if (status & E1000_RXD_STAT_EOP) { + count--; + eop = 1; + if (desc_len < ETHER_CRC_LEN) { + len = 0; + prev_len_adj = ETHER_CRC_LEN - desc_len; + } else + len = desc_len - ETHER_CRC_LEN; + } else { + eop = 0; + len = desc_len; + } + + if (current_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) { + u8 last_byte; + u32 pkt_len = desc_len; + + if (adapter->fmp != NULL) + pkt_len += adapter->fmp->m_pkthdr.len; + + last_byte = *(mtod(mp, caddr_t) + desc_len - 1); + if (TBI_ACCEPT(&adapter->hw, status, + current_desc->errors, pkt_len, last_byte, + adapter->min_frame_size, adapter->max_frame_size)) { + e1000_tbi_adjust_stats_82543(&adapter->hw, + &adapter->stats, pkt_len, + adapter->hw.mac.addr, + adapter->max_frame_size); + if (len > 0) + len--; + } else + accept_frame = 0; + } + + if (accept_frame) { + if (lem_get_buf(adapter, i) != 0) { + ifp->if_iqdrops++; + goto discard; + } + + /* Assign correct length to the current fragment */ + mp->m_len = len; + + if (adapter->fmp == NULL) { + mp->m_pkthdr.len = len; + adapter->fmp = mp; /* Store the first mbuf */ + adapter->lmp = mp; + } else { + /* Chain mbuf's together */ + mp->m_flags &= ~M_PKTHDR; + /* + * Adjust length of previous mbuf in chain if + * we received less than 4 bytes in the last + * descriptor. + */ + if (prev_len_adj > 0) { + adapter->lmp->m_len -= prev_len_adj; + adapter->fmp->m_pkthdr.len -= + prev_len_adj; + } + adapter->lmp->m_next = mp; + adapter->lmp = adapter->lmp->m_next; + adapter->fmp->m_pkthdr.len += len; + } + + if (eop) { + adapter->fmp->m_pkthdr.rcvif = ifp; + ifp->if_ipackets++; + lem_receive_checksum(adapter, current_desc, + adapter->fmp); +#ifndef __NO_STRICT_ALIGNMENT + if (adapter->max_frame_size > + (MCLBYTES - ETHER_ALIGN) && + lem_fixup_rx(adapter) != 0) + goto skip; +#endif + if (status & E1000_RXD_STAT_VP) { +#if __FreeBSD_version < 700000 + VLAN_INPUT_TAG_NEW(ifp, adapter->fmp, + (le16toh(current_desc->special) & + E1000_RXD_SPC_VLAN_MASK)); +#else + adapter->fmp->m_pkthdr.ether_vtag = + (le16toh(current_desc->special) & + E1000_RXD_SPC_VLAN_MASK); + adapter->fmp->m_flags |= M_VLANTAG; +#endif + } +#ifndef __NO_STRICT_ALIGNMENT +skip: +#endif + m = adapter->fmp; + adapter->fmp = NULL; + adapter->lmp = NULL; + } + } else { + ifp->if_ierrors++; +discard: + /* Reuse loaded DMA map and just update mbuf chain */ + mp = adapter->rx_buffer_area[i].m_head; + mp->m_len = mp->m_pkthdr.len = MCLBYTES; + mp->m_data = mp->m_ext.ext_buf; + mp->m_next = NULL; + if (adapter->max_frame_size <= + (MCLBYTES - ETHER_ALIGN)) + m_adj(mp, ETHER_ALIGN); + if (adapter->fmp != NULL) { + m_freem(adapter->fmp); + adapter->fmp = NULL; + adapter->lmp = NULL; + } + m = NULL; + } + + /* Zero out the receive descriptors status. */ + current_desc->status = 0; + bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + /* Advance our pointers to the next descriptor. */ + if (++i == adapter->num_rx_desc) + i = 0; + /* Call into the stack */ + if (m != NULL) { + adapter->next_rx_desc_to_check = i; + EM_RX_UNLOCK(adapter); + (*ifp->if_input)(ifp, m); + EM_RX_LOCK(adapter); + rx_sent++; + i = adapter->next_rx_desc_to_check; + } + current_desc = &adapter->rx_desc_base[i]; + } + adapter->next_rx_desc_to_check = i; + + /* Advance the E1000's Receive Queue #0 "Tail Pointer". */ + if (--i < 0) + i = adapter->num_rx_desc - 1; + E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), i); + EM_RX_UNLOCK(adapter); + return (rx_sent); +} + +#ifndef __NO_STRICT_ALIGNMENT +/* + * When jumbo frames are enabled we should realign entire payload on + * architecures with strict alignment. This is serious design mistake of 8254x + * as it nullifies DMA operations. 8254x just allows RX buffer size to be + * 2048/4096/8192/16384. What we really want is 2048 - ETHER_ALIGN to align its + * payload. On architecures without strict alignment restrictions 8254x still + * performs unaligned memory access which would reduce the performance too. + * To avoid copying over an entire frame to align, we allocate a new mbuf and + * copy ethernet header to the new mbuf. The new mbuf is prepended into the + * existing mbuf chain. + * + * Be aware, best performance of the 8254x is achived only when jumbo frame is + * not used at all on architectures with strict alignment. + */ +static int +lem_fixup_rx(struct adapter *adapter) +{ + struct mbuf *m, *n; + int error; + + error = 0; + m = adapter->fmp; + if (m->m_len <= (MCLBYTES - ETHER_HDR_LEN)) { + bcopy(m->m_data, m->m_data + ETHER_HDR_LEN, m->m_len); + m->m_data += ETHER_HDR_LEN; + } else { + MGETHDR(n, M_DONTWAIT, MT_DATA); + if (n != NULL) { + bcopy(m->m_data, n->m_data, ETHER_HDR_LEN); + m->m_data += ETHER_HDR_LEN; + m->m_len -= ETHER_HDR_LEN; + n->m_len = ETHER_HDR_LEN; + M_MOVE_PKTHDR(n, m); + n->m_next = m; + adapter->fmp = n; + } else { + adapter->dropped_pkts++; + m_freem(adapter->fmp); + adapter->fmp = NULL; + error = ENOMEM; + } + } + + return (error); +} +#endif + +/********************************************************************* + * + * Verify that the hardware indicated that the checksum is valid. + * Inform the stack about the status of checksum so that stack + * doesn't spend time verifying the checksum. + * + *********************************************************************/ +static void +lem_receive_checksum(struct adapter *adapter, + struct e1000_rx_desc *rx_desc, struct mbuf *mp) +{ + /* 82543 or newer only */ + if ((adapter->hw.mac.type < e1000_82543) || + /* Ignore Checksum bit is set */ + (rx_desc->status & E1000_RXD_STAT_IXSM)) { + mp->m_pkthdr.csum_flags = 0; + return; + } + + if (rx_desc->status & E1000_RXD_STAT_IPCS) { + /* Did it pass? */ + if (!(rx_desc->errors & E1000_RXD_ERR_IPE)) { + /* IP Checksum Good */ + mp->m_pkthdr.csum_flags = CSUM_IP_CHECKED; + mp->m_pkthdr.csum_flags |= CSUM_IP_VALID; + + } else { + mp->m_pkthdr.csum_flags = 0; + } + } + + if (rx_desc->status & E1000_RXD_STAT_TCPCS) { + /* Did it pass? */ + if (!(rx_desc->errors & E1000_RXD_ERR_TCPE)) { + mp->m_pkthdr.csum_flags |= + (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); + mp->m_pkthdr.csum_data = htons(0xffff); + } + } +} + +#if __FreeBSD_version >= 700029 +/* + * This routine is run via an vlan + * config EVENT + */ +static void +lem_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 */ + return; + + if ((vtag == 0) || (vtag > 4095)) /* Invalid ID */ + return; + + index = (vtag >> 5) & 0x7F; + bit = vtag & 0x1F; + lem_shadow_vfta[index] |= (1 << bit); + ++adapter->num_vlans; + /* Re-init to load the changes */ + lem_init(adapter); +} + +/* + * This routine is run via an vlan + * unconfig EVENT + */ +static void +lem_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) +{ + struct adapter *adapter = ifp->if_softc; + u32 index, bit; + + if (ifp->if_softc != arg) + return; + + if ((vtag == 0) || (vtag > 4095)) /* Invalid */ + return; + + index = (vtag >> 5) & 0x7F; + bit = vtag & 0x1F; + lem_shadow_vfta[index] &= ~(1 << bit); + --adapter->num_vlans; + /* Re-init to load the changes */ + lem_init(adapter); +} + +static void +lem_setup_vlan_hw_support(struct adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 reg; + + /* + ** We get here thru init_locked, meaning + ** a soft reset, this has already cleared + ** the VFTA and other state, so if there + ** have been no vlan's registered do nothing. + */ + if (adapter->num_vlans == 0) + return; + + /* + ** A soft reset zero's out the VFTA, so + ** we need to repopulate it now. + */ + for (int i = 0; i < EM_VFTA_SIZE; i++) + if (lem_shadow_vfta[i] != 0) + E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, + i, lem_shadow_vfta[i]); + + reg = E1000_READ_REG(hw, E1000_CTRL); + reg |= E1000_CTRL_VME; + E1000_WRITE_REG(hw, E1000_CTRL, reg); + + /* Enable the Filter Table */ + reg = E1000_READ_REG(hw, E1000_RCTL); + reg &= ~E1000_RCTL_CFIEN; + reg |= E1000_RCTL_VFE; + E1000_WRITE_REG(hw, E1000_RCTL, reg); + + /* Update the frame size */ + E1000_WRITE_REG(&adapter->hw, E1000_RLPML, + adapter->max_frame_size + VLAN_TAG_SIZE); +} +#endif + +static void +lem_enable_intr(struct adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ims_mask = IMS_ENABLE_MASK; + + if (adapter->msix) { + E1000_WRITE_REG(hw, EM_EIAC, EM_MSIX_MASK); + ims_mask |= EM_MSIX_MASK; + } + E1000_WRITE_REG(hw, E1000_IMS, ims_mask); +} + +static void +lem_disable_intr(struct adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + + if (adapter->msix) + E1000_WRITE_REG(hw, EM_EIAC, 0); + E1000_WRITE_REG(&adapter->hw, E1000_IMC, 0xffffffff); +} + +/* + * Bit of a misnomer, what this really means is + * to enable OS management of the system... aka + * to disable special hardware management features + */ +static void +lem_init_manageability(struct adapter *adapter) +{ + /* A shared code workaround */ + if (adapter->has_manage) { + int manc = E1000_READ_REG(&adapter->hw, E1000_MANC); + /* disable hardware interception of ARP */ + manc &= ~(E1000_MANC_ARP_EN); + E1000_WRITE_REG(&adapter->hw, E1000_MANC, manc); + } +} + +/* + * Give control back to hardware management + * controller if there is one. + */ +static void +lem_release_manageability(struct adapter *adapter) +{ + if (adapter->has_manage) { + int manc = E1000_READ_REG(&adapter->hw, E1000_MANC); + + /* re-enable hardware interception of ARP */ + manc |= E1000_MANC_ARP_EN; + E1000_WRITE_REG(&adapter->hw, E1000_MANC, manc); + } +} + +/* + * lem_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 +lem_get_hw_control(struct adapter *adapter) +{ + u32 ctrl_ext; + + 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; +} + +/* + * lem_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 versions of the + * f/w this means that the network i/f is closed. + */ +static void +lem_release_hw_control(struct adapter *adapter) +{ + u32 ctrl_ext; + + if (!adapter->has_manage) + return; + + 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 +lem_is_valid_ether_addr(u8 *addr) +{ + char zero_addr[6] = { 0, 0, 0, 0, 0, 0 }; + + if ((addr[0] & 1) || (!bcmp(addr, zero_addr, ETHER_ADDR_LEN))) { + return (FALSE); + } + + return (TRUE); +} + +/* +** Parse the interface capabilities with regard +** to both system management and wake-on-lan for +** later use. +*/ +static void +lem_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_82546: + case e1000_82546_rev_3: + 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; + 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: + /* 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: + /* 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 + */ +static void +lem_enable_wakeup(device_t dev) +{ + 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; + + /* 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); + + /* 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 (lem_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); + } + + + /* 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 +lem_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; +} + +static void +lem_led_func(void *arg, int onoff) +{ + struct adapter *adapter = arg; + + EM_CORE_LOCK(adapter); + if (onoff) { + e1000_setup_led(&adapter->hw); + e1000_led_on(&adapter->hw); + } else { + e1000_led_off(&adapter->hw); + e1000_cleanup_led(&adapter->hw); + } + EM_CORE_UNLOCK(adapter); +} + +/********************************************************************* +* 82544 Coexistence issue workaround. +* There are 2 issues. +* 1. Transmit Hang issue. +* To detect this issue, following equation can be used... +* SIZE[3:0] + ADDR[2:0] = SUM[3:0]. +* If SUM[3:0] is in between 1 to 4, we will have this issue. +* +* 2. DAC issue. +* To detect this issue, following equation can be used... +* SIZE[3:0] + ADDR[2:0] = SUM[3:0]. +* If SUM[3:0] is in between 9 to c, we will have this issue. +* +* +* WORKAROUND: +* Make sure we do not have ending address +* as 1,2,3,4(Hang) or 9,a,b,c (DAC) +* +*************************************************************************/ +static u32 +lem_fill_descriptors (bus_addr_t address, u32 length, + PDESC_ARRAY desc_array) +{ + u32 safe_terminator; + + /* Since issue is sensitive to length and address.*/ + /* Let us first check the address...*/ + if (length <= 4) { + desc_array->descriptor[0].address = address; + desc_array->descriptor[0].length = length; + desc_array->elements = 1; + return (desc_array->elements); + } + safe_terminator = (u32)((((u32)address & 0x7) + + (length & 0xF)) & 0xF); + /* if it does not fall between 0x1 to 0x4 and 0x9 to 0xC then return */ + if (safe_terminator == 0 || + (safe_terminator > 4 && + safe_terminator < 9) || + (safe_terminator > 0xC && + safe_terminator <= 0xF)) { + desc_array->descriptor[0].address = address; + desc_array->descriptor[0].length = length; + desc_array->elements = 1; + return (desc_array->elements); + } + + desc_array->descriptor[0].address = address; + desc_array->descriptor[0].length = length - 4; + desc_array->descriptor[1].address = address + (length - 4); + desc_array->descriptor[1].length = 4; + desc_array->elements = 2; + return (desc_array->elements); +} + +/********************************************************************** + * + * Update the board statistics counters. + * + **********************************************************************/ +static void +lem_update_stats_counters(struct adapter *adapter) +{ + struct ifnet *ifp; + + if(adapter->hw.phy.media_type == e1000_media_type_copper || + (E1000_READ_REG(&adapter->hw, E1000_STATUS) & E1000_STATUS_LU)) { + adapter->stats.symerrs += E1000_READ_REG(&adapter->hw, E1000_SYMERRS); + adapter->stats.sec += E1000_READ_REG(&adapter->hw, E1000_SEC); + } + adapter->stats.crcerrs += E1000_READ_REG(&adapter->hw, E1000_CRCERRS); + adapter->stats.mpc += E1000_READ_REG(&adapter->hw, E1000_MPC); + adapter->stats.scc += E1000_READ_REG(&adapter->hw, E1000_SCC); + adapter->stats.ecol += E1000_READ_REG(&adapter->hw, E1000_ECOL); + + adapter->stats.mcc += E1000_READ_REG(&adapter->hw, E1000_MCC); + adapter->stats.latecol += E1000_READ_REG(&adapter->hw, E1000_LATECOL); + adapter->stats.colc += E1000_READ_REG(&adapter->hw, E1000_COLC); + adapter->stats.dc += E1000_READ_REG(&adapter->hw, E1000_DC); + adapter->stats.rlec += E1000_READ_REG(&adapter->hw, E1000_RLEC); + adapter->stats.xonrxc += E1000_READ_REG(&adapter->hw, E1000_XONRXC); + adapter->stats.xontxc += E1000_READ_REG(&adapter->hw, E1000_XONTXC); + adapter->stats.xoffrxc += E1000_READ_REG(&adapter->hw, E1000_XOFFRXC); + adapter->stats.xofftxc += E1000_READ_REG(&adapter->hw, E1000_XOFFTXC); + adapter->stats.fcruc += E1000_READ_REG(&adapter->hw, E1000_FCRUC); + adapter->stats.prc64 += E1000_READ_REG(&adapter->hw, E1000_PRC64); + adapter->stats.prc127 += E1000_READ_REG(&adapter->hw, E1000_PRC127); + adapter->stats.prc255 += E1000_READ_REG(&adapter->hw, E1000_PRC255); + adapter->stats.prc511 += E1000_READ_REG(&adapter->hw, E1000_PRC511); + adapter->stats.prc1023 += E1000_READ_REG(&adapter->hw, E1000_PRC1023); + adapter->stats.prc1522 += E1000_READ_REG(&adapter->hw, E1000_PRC1522); + adapter->stats.gprc += E1000_READ_REG(&adapter->hw, E1000_GPRC); + adapter->stats.bprc += E1000_READ_REG(&adapter->hw, E1000_BPRC); + adapter->stats.mprc += E1000_READ_REG(&adapter->hw, E1000_MPRC); + adapter->stats.gptc += E1000_READ_REG(&adapter->hw, E1000_GPTC); + + /* For the 64-bit byte counters the low dword must be read first. */ + /* Both registers clear on the read of the high dword */ + + adapter->stats.gorc += E1000_READ_REG(&adapter->hw, E1000_GORCH); + adapter->stats.gotc += E1000_READ_REG(&adapter->hw, E1000_GOTCH); + + adapter->stats.rnbc += E1000_READ_REG(&adapter->hw, E1000_RNBC); + adapter->stats.ruc += E1000_READ_REG(&adapter->hw, E1000_RUC); + adapter->stats.rfc += E1000_READ_REG(&adapter->hw, E1000_RFC); + adapter->stats.roc += E1000_READ_REG(&adapter->hw, E1000_ROC); + adapter->stats.rjc += E1000_READ_REG(&adapter->hw, E1000_RJC); + + adapter->stats.tor += E1000_READ_REG(&adapter->hw, E1000_TORH); + adapter->stats.tot += E1000_READ_REG(&adapter->hw, E1000_TOTH); + + adapter->stats.tpr += E1000_READ_REG(&adapter->hw, E1000_TPR); + adapter->stats.tpt += E1000_READ_REG(&adapter->hw, E1000_TPT); + adapter->stats.ptc64 += E1000_READ_REG(&adapter->hw, E1000_PTC64); + adapter->stats.ptc127 += E1000_READ_REG(&adapter->hw, E1000_PTC127); + adapter->stats.ptc255 += E1000_READ_REG(&adapter->hw, E1000_PTC255); + adapter->stats.ptc511 += E1000_READ_REG(&adapter->hw, E1000_PTC511); + adapter->stats.ptc1023 += E1000_READ_REG(&adapter->hw, E1000_PTC1023); + adapter->stats.ptc1522 += E1000_READ_REG(&adapter->hw, E1000_PTC1522); + adapter->stats.mptc += E1000_READ_REG(&adapter->hw, E1000_MPTC); + adapter->stats.bptc += E1000_READ_REG(&adapter->hw, E1000_BPTC); + + if (adapter->hw.mac.type >= e1000_82543) { + adapter->stats.algnerrc += + E1000_READ_REG(&adapter->hw, E1000_ALGNERRC); + adapter->stats.rxerrc += + E1000_READ_REG(&adapter->hw, E1000_RXERRC); + adapter->stats.tncrs += + E1000_READ_REG(&adapter->hw, E1000_TNCRS); + adapter->stats.cexterr += + E1000_READ_REG(&adapter->hw, E1000_CEXTERR); + adapter->stats.tsctc += + E1000_READ_REG(&adapter->hw, E1000_TSCTC); + adapter->stats.tsctfc += + E1000_READ_REG(&adapter->hw, E1000_TSCTFC); + } + ifp = adapter->ifp; + + ifp->if_collisions = adapter->stats.colc; + + /* Rx Errors */ + ifp->if_ierrors = adapter->dropped_pkts + adapter->stats.rxerrc + + adapter->stats.crcerrs + adapter->stats.algnerrc + + adapter->stats.ruc + adapter->stats.roc + + adapter->stats.mpc + adapter->stats.cexterr; + + /* Tx Errors */ + ifp->if_oerrors = adapter->stats.ecol + + adapter->stats.latecol + adapter->watchdog_events; +} + + +/********************************************************************** + * + * This routine is called only when lem_display_debug_stats is enabled. + * This routine provides a way to take a look at important statistics + * maintained by the driver and hardware. + * + **********************************************************************/ +static void +lem_print_debug_info(struct adapter *adapter) +{ + device_t dev = adapter->dev; + u8 *hw_addr = adapter->hw.hw_addr; + + device_printf(dev, "Adapter hardware address = %p \n", hw_addr); + device_printf(dev, "CTRL = 0x%x RCTL = 0x%x \n", + E1000_READ_REG(&adapter->hw, E1000_CTRL), + E1000_READ_REG(&adapter->hw, E1000_RCTL)); + device_printf(dev, "Packet buffer = Tx=%dk Rx=%dk \n", + ((E1000_READ_REG(&adapter->hw, E1000_PBA) & 0xffff0000) >> 16),\ + (E1000_READ_REG(&adapter->hw, E1000_PBA) & 0xffff) ); + device_printf(dev, "Flow control watermarks high = %d low = %d\n", + adapter->hw.fc.high_water, + adapter->hw.fc.low_water); + device_printf(dev, "tx_int_delay = %d, tx_abs_int_delay = %d\n", + E1000_READ_REG(&adapter->hw, E1000_TIDV), + E1000_READ_REG(&adapter->hw, E1000_TADV)); + device_printf(dev, "rx_int_delay = %d, rx_abs_int_delay = %d\n", + E1000_READ_REG(&adapter->hw, E1000_RDTR), + E1000_READ_REG(&adapter->hw, E1000_RADV)); + device_printf(dev, "fifo workaround = %lld, fifo_reset_count = %lld\n", + (long long)adapter->tx_fifo_wrk_cnt, + (long long)adapter->tx_fifo_reset_cnt); + device_printf(dev, "hw tdh = %d, hw tdt = %d\n", + E1000_READ_REG(&adapter->hw, E1000_TDH(0)), + E1000_READ_REG(&adapter->hw, E1000_TDT(0))); + device_printf(dev, "hw rdh = %d, hw rdt = %d\n", + E1000_READ_REG(&adapter->hw, E1000_RDH(0)), + E1000_READ_REG(&adapter->hw, E1000_RDT(0))); + device_printf(dev, "Num Tx descriptors avail = %d\n", + adapter->num_tx_desc_avail); + device_printf(dev, "Tx Descriptors not avail1 = %ld\n", + adapter->no_tx_desc_avail1); + device_printf(dev, "Tx Descriptors not avail2 = %ld\n", + adapter->no_tx_desc_avail2); + device_printf(dev, "Std mbuf failed = %ld\n", + adapter->mbuf_alloc_failed); + device_printf(dev, "Std mbuf cluster failed = %ld\n", + adapter->mbuf_cluster_failed); + device_printf(dev, "Driver dropped packets = %ld\n", + adapter->dropped_pkts); + device_printf(dev, "Driver tx dma failure in encap = %ld\n", + adapter->no_tx_dma_setup); +} + +static void +lem_print_hw_stats(struct adapter *adapter) +{ + device_t dev = adapter->dev; + + device_printf(dev, "Excessive collisions = %lld\n", + (long long)adapter->stats.ecol); +#if (DEBUG_HW > 0) /* Dont output these errors normally */ + device_printf(dev, "Symbol errors = %lld\n", + (long long)adapter->stats.symerrs); +#endif + device_printf(dev, "Sequence errors = %lld\n", + (long long)adapter->stats.sec); + device_printf(dev, "Defer count = %lld\n", + (long long)adapter->stats.dc); + device_printf(dev, "Missed Packets = %lld\n", + (long long)adapter->stats.mpc); + device_printf(dev, "Receive No Buffers = %lld\n", + (long long)adapter->stats.rnbc); + /* RLEC is inaccurate on some hardware, calculate our own. */ + device_printf(dev, "Receive Length Errors = %lld\n", + ((long long)adapter->stats.roc + (long long)adapter->stats.ruc)); + device_printf(dev, "Receive errors = %lld\n", + (long long)adapter->stats.rxerrc); + device_printf(dev, "Crc errors = %lld\n", + (long long)adapter->stats.crcerrs); + device_printf(dev, "Alignment errors = %lld\n", + (long long)adapter->stats.algnerrc); + device_printf(dev, "Collision/Carrier extension errors = %lld\n", + (long long)adapter->stats.cexterr); + device_printf(dev, "RX overruns = %ld\n", adapter->rx_overruns); + device_printf(dev, "watchdog timeouts = %ld\n", + adapter->watchdog_events); + device_printf(dev, "RX MSIX IRQ = %ld TX MSIX IRQ = %ld" + " LINK MSIX IRQ = %ld\n", adapter->rx_irq, + adapter->tx_irq , adapter->link_irq); + device_printf(dev, "XON Rcvd = %lld\n", + (long long)adapter->stats.xonrxc); + device_printf(dev, "XON Xmtd = %lld\n", + (long long)adapter->stats.xontxc); + device_printf(dev, "XOFF Rcvd = %lld\n", + (long long)adapter->stats.xoffrxc); + device_printf(dev, "XOFF Xmtd = %lld\n", + (long long)adapter->stats.xofftxc); + device_printf(dev, "Good Packets Rcvd = %lld\n", + (long long)adapter->stats.gprc); + device_printf(dev, "Good Packets Xmtd = %lld\n", + (long long)adapter->stats.gptc); + device_printf(dev, "TSO Contexts Xmtd = %lld\n", + (long long)adapter->stats.tsctc); + device_printf(dev, "TSO Contexts Failed = %lld\n", + (long long)adapter->stats.tsctfc); +} + +/********************************************************************** + * + * This routine provides a way to dump out the adapter eeprom, + * often a useful debug/service tool. This only dumps the first + * 32 words, stuff that matters is in that extent. + * + **********************************************************************/ +static void +lem_print_nvm_info(struct adapter *adapter) +{ + u16 eeprom_data; + int i, j, row = 0; + + /* Its a bit crude, but it gets the job done */ + printf("\nInterface EEPROM Dump:\n"); + printf("Offset\n0x0000 "); + for (i = 0, j = 0; i < 32; i++, j++) { + if (j == 8) { /* Make the offset block */ + j = 0; ++row; + printf("\n0x00%x0 ",row); + } + e1000_read_nvm(&adapter->hw, i, 1, &eeprom_data); + printf("%04x ", eeprom_data); + } + printf("\n"); +} + +static int +lem_sysctl_debug_info(SYSCTL_HANDLER_ARGS) +{ + struct adapter *adapter; + int error; + int result; + + result = -1; + error = sysctl_handle_int(oidp, &result, 0, req); + + if (error || !req->newptr) + return (error); + + if (result == 1) { + adapter = (struct adapter *)arg1; + lem_print_debug_info(adapter); + } + /* + * This value will cause a hex dump of the + * first 32 16-bit words of the EEPROM to + * the screen. + */ + if (result == 2) { + adapter = (struct adapter *)arg1; + lem_print_nvm_info(adapter); + } + + return (error); +} + + +static int +lem_sysctl_stats(SYSCTL_HANDLER_ARGS) +{ + struct adapter *adapter; + int error; + int result; + + result = -1; + error = sysctl_handle_int(oidp, &result, 0, req); + + if (error || !req->newptr) + return (error); + + if (result == 1) { + adapter = (struct adapter *)arg1; + lem_print_hw_stats(adapter); + } + + return (error); +} + +static int +lem_sysctl_int_delay(SYSCTL_HANDLER_ARGS) +{ + struct em_int_delay_info *info; + struct adapter *adapter; + u32 regval; + int error; + int usecs; + int ticks; + + info = (struct em_int_delay_info *)arg1; + usecs = info->value; + error = sysctl_handle_int(oidp, &usecs, 0, req); + if (error != 0 || req->newptr == NULL) + return (error); + if (usecs < 0 || usecs > EM_TICKS_TO_USECS(65535)) + return (EINVAL); + info->value = usecs; + ticks = EM_USECS_TO_TICKS(usecs); + + adapter = info->adapter; + + EM_CORE_LOCK(adapter); + regval = E1000_READ_OFFSET(&adapter->hw, info->offset); + regval = (regval & ~0xffff) | (ticks & 0xffff); + /* Handle a few special cases. */ + switch (info->offset) { + case E1000_RDTR: + break; + case E1000_TIDV: + if (ticks == 0) { + adapter->txd_cmd &= ~E1000_TXD_CMD_IDE; + /* Don't write 0 into the TIDV register. */ + regval++; + } else + adapter->txd_cmd |= E1000_TXD_CMD_IDE; + break; + } + E1000_WRITE_OFFSET(&adapter->hw, info->offset, regval); + EM_CORE_UNLOCK(adapter); + return (0); +} + +static void +lem_add_int_delay_sysctl(struct adapter *adapter, const char *name, + const char *description, struct em_int_delay_info *info, + int offset, int value) +{ + info->adapter = adapter; + info->offset = offset; + info->value = value; + SYSCTL_ADD_PROC(device_get_sysctl_ctx(adapter->dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(adapter->dev)), + OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW, + info, 0, lem_sysctl_int_delay, "I", description); +} + +#ifndef EM_LEGACY_IRQ +static void +lem_add_rx_process_limit(struct adapter *adapter, const char *name, + const char *description, int *limit, int value) +{ + *limit = value; + SYSCTL_ADD_INT(device_get_sysctl_ctx(adapter->dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(adapter->dev)), + OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW, limit, value, description); +} +#endif + + diff --git a/sys/dev/e1000/if_lem.h b/sys/dev/e1000/if_lem.h new file mode 100644 index 000000000000..13c2cbc4dd3c --- /dev/null +++ b/sys/dev/e1000/if_lem.h @@ -0,0 +1,481 @@ +/****************************************************************************** + + Copyright (c) 2001-2010, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ +/*$FreeBSD$*/ + + +#ifndef _LEM_H_DEFINED_ +#define _LEM_H_DEFINED_ + + +/* Tunables */ + +/* + * EM_TXD: Maximum number of Transmit Descriptors + * Valid Range: 80-256 for 82542 and 82543-based adapters + * 80-4096 for others + * Default Value: 256 + * This value is the number of transmit descriptors allocated by the driver. + * Increasing this value allows the driver to queue more transmits. Each + * descriptor is 16 bytes. + * Since TDLEN should be multiple of 128bytes, the number of transmit + * desscriptors should meet the following condition. + * (num_tx_desc * sizeof(struct e1000_tx_desc)) % 128 == 0 + */ +#define EM_MIN_TXD 80 +#define EM_MAX_TXD_82543 256 +#define EM_MAX_TXD 4096 +#define EM_DEFAULT_TXD EM_MAX_TXD_82543 + +/* + * EM_RXD - Maximum number of receive Descriptors + * Valid Range: 80-256 for 82542 and 82543-based adapters + * 80-4096 for others + * Default Value: 256 + * This value is the number of receive descriptors allocated by the driver. + * Increasing this value allows the driver to buffer more incoming packets. + * Each descriptor is 16 bytes. A receive buffer is also allocated for each + * descriptor. The maximum MTU size is 16110. + * Since TDLEN should be multiple of 128bytes, the number of transmit + * desscriptors should meet the following condition. + * (num_tx_desc * sizeof(struct e1000_tx_desc)) % 128 == 0 + */ +#define EM_MIN_RXD 80 +#define EM_MAX_RXD_82543 256 +#define EM_MAX_RXD 4096 +#define EM_DEFAULT_RXD EM_MAX_RXD_82543 + +/* + * EM_TIDV - Transmit Interrupt Delay Value + * Valid Range: 0-65535 (0=off) + * Default Value: 64 + * This value delays the generation of transmit interrupts in units of + * 1.024 microseconds. Transmit interrupt reduction can improve CPU + * efficiency if properly tuned for specific network traffic. If the + * system is reporting dropped transmits, this value may be set too high + * causing the driver to run out of available transmit descriptors. + */ +#define EM_TIDV 64 + +/* + * EM_TADV - Transmit Absolute Interrupt Delay Value + * (Not valid for 82542/82543/82544) + * Valid Range: 0-65535 (0=off) + * Default Value: 64 + * This value, in units of 1.024 microseconds, limits the delay in which a + * transmit interrupt is generated. Useful only if EM_TIDV is non-zero, + * this value ensures that an interrupt is generated after the initial + * packet is sent on the wire within the set amount of time. Proper tuning, + * along with EM_TIDV, may improve traffic throughput in specific + * network conditions. + */ +#define EM_TADV 64 + +/* + * EM_RDTR - Receive Interrupt Delay Timer (Packet Timer) + * Valid Range: 0-65535 (0=off) + * Default Value: 0 + * This value delays the generation of receive interrupts in units of 1.024 + * microseconds. Receive interrupt reduction can improve CPU efficiency if + * properly tuned for specific network traffic. Increasing this value adds + * extra latency to frame reception and can end up decreasing the throughput + * of TCP traffic. If the system is reporting dropped receives, this value + * may be set too high, causing the driver to run out of available receive + * descriptors. + * + * CAUTION: When setting EM_RDTR to a value other than 0, adapters + * may hang (stop transmitting) under certain network conditions. + * If this occurs a WATCHDOG message is logged in the system + * event log. In addition, the controller is automatically reset, + * restoring the network connection. To eliminate the potential + * for the hang ensure that EM_RDTR is set to 0. + */ +#define EM_RDTR 0 + +/* + * Receive Interrupt Absolute Delay Timer (Not valid for 82542/82543/82544) + * Valid Range: 0-65535 (0=off) + * Default Value: 64 + * This value, in units of 1.024 microseconds, limits the delay in which a + * receive interrupt is generated. Useful only if EM_RDTR is non-zero, + * this value ensures that an interrupt is generated after the initial + * packet is received within the set amount of time. Proper tuning, + * along with EM_RDTR, may improve traffic throughput in specific network + * conditions. + */ +#define EM_RADV 64 + +/* + * This parameter controls the max duration of transmit watchdog. + */ +#define EM_WATCHDOG (10 * hz) + +/* + * This parameter controls when the driver calls the routine to reclaim + * transmit descriptors. + */ +#define EM_TX_CLEANUP_THRESHOLD (adapter->num_tx_desc / 8) +#define EM_TX_OP_THRESHOLD (adapter->num_tx_desc / 32) + +/* + * This parameter controls whether or not autonegotation is enabled. + * 0 - Disable autonegotiation + * 1 - Enable autonegotiation + */ +#define DO_AUTO_NEG 1 + +/* + * This parameter control whether or not the driver will wait for + * autonegotiation to complete. + * 1 - Wait for autonegotiation to complete + * 0 - Don't wait for autonegotiation to complete + */ +#define WAIT_FOR_AUTO_NEG_DEFAULT 0 + +/* Tunables -- End */ + +#define AUTONEG_ADV_DEFAULT (ADVERTISE_10_HALF | ADVERTISE_10_FULL | \ + ADVERTISE_100_HALF | ADVERTISE_100_FULL | \ + ADVERTISE_1000_FULL) + +#define AUTO_ALL_MODES 0 + +/* PHY master/slave setting */ +#define EM_MASTER_SLAVE e1000_ms_hw_default + +/* + * Micellaneous constants + */ +#define EM_VENDOR_ID 0x8086 +#define EM_FLASH 0x0014 + +#define EM_JUMBO_PBA 0x00000028 +#define EM_DEFAULT_PBA 0x00000030 +#define EM_SMARTSPEED_DOWNSHIFT 3 +#define EM_SMARTSPEED_MAX 15 +#define EM_MAX_LOOP 10 + +#define MAX_NUM_MULTICAST_ADDRESSES 128 +#define PCI_ANY_ID (~0U) +#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 +#define ETHER_BPF_MTAP BPF_MTAP +#endif + +/* + * TDBA/RDBA should be aligned on 16 byte boundary. But TDLEN/RDLEN should be + * multiple of 128 bytes. So we align TDBA/RDBA on 128 byte boundary. This will + * also optimize cache line size effect. H/W supports up to cache line size 128. + */ +#define EM_DBA_ALIGN 128 + +#define SPEED_MODE_BIT (1<<21) /* On PCI-E MACs only */ + +/* PCI Config defines */ +#define EM_BAR_TYPE(v) ((v) & EM_BAR_TYPE_MASK) +#define EM_BAR_TYPE_MASK 0x00000001 +#define EM_BAR_TYPE_MMEM 0x00000000 +#define EM_BAR_TYPE_IO 0x00000001 +#define EM_BAR_TYPE_FLASH 0x0014 +#define EM_BAR_MEM_TYPE(v) ((v) & EM_BAR_MEM_TYPE_MASK) +#define EM_BAR_MEM_TYPE_MASK 0x00000006 +#define EM_BAR_MEM_TYPE_32BIT 0x00000000 +#define EM_BAR_MEM_TYPE_64BIT 0x00000004 +#define EM_MSIX_BAR 3 /* On 82575 */ + +/* Defines for printing debug information */ +#define DEBUG_INIT 0 +#define DEBUG_IOCTL 0 +#define DEBUG_HW 0 + +#define INIT_DEBUGOUT(S) if (DEBUG_INIT) printf(S "\n") +#define INIT_DEBUGOUT1(S, A) if (DEBUG_INIT) printf(S "\n", A) +#define INIT_DEBUGOUT2(S, A, B) if (DEBUG_INIT) printf(S "\n", A, B) +#define IOCTL_DEBUGOUT(S) if (DEBUG_IOCTL) printf(S "\n") +#define IOCTL_DEBUGOUT1(S, A) if (DEBUG_IOCTL) printf(S "\n", A) +#define IOCTL_DEBUGOUT2(S, A, B) if (DEBUG_IOCTL) printf(S "\n", A, B) +#define HW_DEBUGOUT(S) if (DEBUG_HW) printf(S "\n") +#define HW_DEBUGOUT1(S, A) if (DEBUG_HW) printf(S "\n", A) +#define HW_DEBUGOUT2(S, A, B) if (DEBUG_HW) printf(S "\n", A, B) + +#define EM_MAX_SCATTER 64 +#define EM_VFTA_SIZE 128 +#define EM_TSO_SIZE (65535 + sizeof(struct ether_vlan_header)) +#define EM_TSO_SEG_SIZE 4096 /* Max dma segment size */ +#define EM_MSIX_MASK 0x01F00000 /* For 82574 use */ +#define ETH_ZLEN 60 +#define ETH_ADDR_LEN 6 +#define CSUM_OFFLOAD 7 /* Offload bits in mbuf flag */ + +/* + * 82574 has a nonstandard address for EIAC + * and since its only used in MSIX, and in + * the em driver only 82574 uses MSIX we can + * solve it just using this define. + */ +#define EM_EIAC 0x000DC + +/* Used in for 82547 10Mb Half workaround */ +#define EM_PBA_BYTES_SHIFT 0xA +#define EM_TX_HEAD_ADDR_SHIFT 7 +#define EM_PBA_TX_MASK 0xFFFF0000 +#define EM_FIFO_HDR 0x10 +#define EM_82547_PKT_THRESH 0x3e0 + +/* Precision Time Sync (IEEE 1588) defines */ +#define ETHERTYPE_IEEE1588 0x88F7 +#define PICOSECS_PER_TICK 20833 +#define TSYNC_PORT 319 /* UDP port for the protocol */ + +/* + * Bus dma allocation structure used by + * e1000_dma_malloc and e1000_dma_free. + */ +struct em_dma_alloc { + bus_addr_t dma_paddr; + caddr_t dma_vaddr; + bus_dma_tag_t dma_tag; + bus_dmamap_t dma_map; + bus_dma_segment_t dma_seg; + int dma_nseg; +}; + +struct adapter; + +struct em_int_delay_info { + struct adapter *adapter; /* Back-pointer to the adapter struct */ + int offset; /* Register offset to read/write */ + int value; /* Current value in usecs */ +}; + +/* Our adapter structure */ +struct adapter { + struct ifnet *ifp; +#if __FreeBSD_version >= 800000 + struct buf_ring *br; +#endif + struct e1000_hw hw; + + /* FreeBSD operating-system-specific structures. */ + struct e1000_osdep osdep; + struct device *dev; + struct cdev *led_dev; + + struct resource *memory; + struct resource *flash; + struct resource *msix; + + struct resource *ioport; + int io_rid; + + /* 82574 may use 3 int vectors */ + struct resource *res[3]; + void *tag[3]; + int rid[3]; + + struct ifmedia media; + struct callout timer; + struct callout tx_fifo_timer; + bool watchdog_check; + int watchdog_time; + int msi; + int if_flags; + int max_frame_size; + int min_frame_size; + struct mtx core_mtx; + struct mtx tx_mtx; + struct mtx rx_mtx; + int em_insert_vlan_header; + + /* Task for FAST handling */ + struct task link_task; + struct task rxtx_task; + struct task rx_task; + struct task tx_task; + struct taskqueue *tq; /* private task queue */ + +#if __FreeBSD_version >= 700029 + eventhandler_tag vlan_attach; + eventhandler_tag vlan_detach; + u32 num_vlans; +#endif + + /* Management and WOL features */ + u32 wol; + bool has_manage; + bool has_amt; + + /* Info about the board itself */ + uint8_t link_active; + uint16_t link_speed; + uint16_t link_duplex; + uint32_t smartspeed; + struct em_int_delay_info tx_int_delay; + struct em_int_delay_info tx_abs_int_delay; + struct em_int_delay_info rx_int_delay; + struct em_int_delay_info rx_abs_int_delay; + + /* + * Transmit definitions + * + * We have an array of num_tx_desc descriptors (handled + * by the controller) paired with an array of tx_buffers + * (at tx_buffer_area). + * The index of the next available descriptor is next_avail_tx_desc. + * The number of remaining tx_desc is num_tx_desc_avail. + */ + struct em_dma_alloc txdma; /* bus_dma glue for tx desc */ + struct e1000_tx_desc *tx_desc_base; + uint32_t next_avail_tx_desc; + uint32_t next_tx_to_clean; + volatile uint16_t num_tx_desc_avail; + uint16_t num_tx_desc; + uint16_t last_hw_offload; + uint32_t txd_cmd; + struct em_buffer *tx_buffer_area; + bus_dma_tag_t txtag; /* dma tag for tx */ + uint32_t tx_tso; /* last tx was tso */ + + /* + * Receive definitions + * + * we have an array of num_rx_desc rx_desc (handled by the + * controller), and paired with an array of rx_buffers + * (at rx_buffer_area). + * The next pair to check on receive is at offset next_rx_desc_to_check + */ + struct em_dma_alloc rxdma; /* bus_dma glue for rx desc */ + struct e1000_rx_desc *rx_desc_base; + uint32_t next_rx_desc_to_check; + uint32_t rx_buffer_len; + uint16_t num_rx_desc; + int rx_process_limit; + struct em_buffer *rx_buffer_area; + bus_dma_tag_t rxtag; + bus_dmamap_t rx_sparemap; + + /* + * First/last mbuf pointers, for + * collecting multisegment RX packets. + */ + struct mbuf *fmp; + struct mbuf *lmp; + + /* Misc stats maintained by the driver */ + unsigned long dropped_pkts; + unsigned long mbuf_alloc_failed; + unsigned long mbuf_cluster_failed; + unsigned long no_tx_desc_avail1; + unsigned long no_tx_desc_avail2; + unsigned long no_tx_map_avail; + unsigned long no_tx_dma_setup; + unsigned long watchdog_events; + unsigned long rx_overruns; + unsigned long rx_irq; + unsigned long tx_irq; + unsigned long link_irq; + + /* 82547 workaround */ + uint32_t tx_fifo_size; + uint32_t tx_fifo_head; + uint32_t tx_fifo_head_addr; + uint64_t tx_fifo_reset_cnt; + uint64_t tx_fifo_wrk_cnt; + uint32_t tx_head_addr; + + /* For 82544 PCIX Workaround */ + boolean_t pcix_82544; + boolean_t in_detach; + + + struct e1000_hw_stats stats; +}; + +/* ****************************************************************************** + * vendor_info_array + * + * This array contains the list of Subvendor/Subdevice IDs on which the driver + * should load. + * + * ******************************************************************************/ +typedef struct _em_vendor_info_t { + unsigned int vendor_id; + unsigned int device_id; + unsigned int subvendor_id; + unsigned int subdevice_id; + unsigned int index; +} em_vendor_info_t; + +struct em_buffer { + int next_eop; /* Index of the desc to watch */ + struct mbuf *m_head; + bus_dmamap_t map; /* bus_dma map for packet */ +}; + +/* For 82544 PCIX Workaround */ +typedef struct _ADDRESS_LENGTH_PAIR +{ + uint64_t address; + uint32_t length; +} ADDRESS_LENGTH_PAIR, *PADDRESS_LENGTH_PAIR; + +typedef struct _DESCRIPTOR_PAIR +{ + ADDRESS_LENGTH_PAIR descriptor[4]; + uint32_t elements; +} DESC_ARRAY, *PDESC_ARRAY; + +#define EM_CORE_LOCK_INIT(_sc, _name) \ + mtx_init(&(_sc)->core_mtx, _name, "EM Core Lock", MTX_DEF) +#define EM_TX_LOCK_INIT(_sc, _name) \ + mtx_init(&(_sc)->tx_mtx, _name, "EM TX Lock", MTX_DEF) +#define EM_RX_LOCK_INIT(_sc, _name) \ + mtx_init(&(_sc)->rx_mtx, _name, "EM RX Lock", MTX_DEF) +#define EM_CORE_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->core_mtx) +#define EM_TX_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->tx_mtx) +#define EM_RX_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->rx_mtx) +#define EM_CORE_LOCK(_sc) mtx_lock(&(_sc)->core_mtx) +#define EM_TX_LOCK(_sc) mtx_lock(&(_sc)->tx_mtx) +#define EM_TX_TRYLOCK(_sc) mtx_trylock(&(_sc)->tx_mtx) +#define EM_RX_LOCK(_sc) mtx_lock(&(_sc)->rx_mtx) +#define EM_CORE_UNLOCK(_sc) mtx_unlock(&(_sc)->core_mtx) +#define EM_TX_UNLOCK(_sc) mtx_unlock(&(_sc)->tx_mtx) +#define EM_RX_UNLOCK(_sc) mtx_unlock(&(_sc)->rx_mtx) +#define EM_CORE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->core_mtx, MA_OWNED) +#define EM_TX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->tx_mtx, MA_OWNED) + +#endif /* _LEM_H_DEFINED_ */