]> pilppa.com Git - linux-2.6-omap-h63xx.git/commitdiff
igb: PCI-Express 82575 Gigabit Ethernet driver
authorAuke Kok <auke-jan.h.kok@intel.com>
Thu, 24 Jan 2008 10:22:38 +0000 (02:22 -0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 28 Jan 2008 23:10:33 +0000 (15:10 -0800)
We are pleased to announce a new Gigabit Ethernet product and its
driver to the linux community. This product is the Intel(R) 82575
Gigabit Ethernet adapter family. Physical adapters will be available
to the public soon. These adapters come in 2- and 4-port versions
(copper PHY) currently. Other variants will be available later.

The 82575 chipset supports significantly different features that
warrant a new driver. The descriptor format is (just like the
ixgbe driver) different. The device can use multiple MSI-X vectors
and multiple queues for both send and receive. This allows us to
optimize some of the driver code specifically as well compared to
the e1000-supported devices.

This version of the igb driver no lnger uses fake netdevices and
incorporates napi_struct members for each ring to do the multi-
queue polling. multi-queue is enabled by default and the driver
supports NAPI mode only.

All the namespace collisions should be gone in this version too. The
register macro's have been condensed to improve readability.

Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
17 files changed:
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/igb/Makefile [new file with mode: 0644]
drivers/net/igb/e1000_82575.c [new file with mode: 0644]
drivers/net/igb/e1000_82575.h [new file with mode: 0644]
drivers/net/igb/e1000_defines.h [new file with mode: 0644]
drivers/net/igb/e1000_hw.h [new file with mode: 0644]
drivers/net/igb/e1000_mac.c [new file with mode: 0644]
drivers/net/igb/e1000_mac.h [new file with mode: 0644]
drivers/net/igb/e1000_nvm.c [new file with mode: 0644]
drivers/net/igb/e1000_nvm.h [new file with mode: 0644]
drivers/net/igb/e1000_phy.c [new file with mode: 0644]
drivers/net/igb/e1000_phy.h [new file with mode: 0644]
drivers/net/igb/e1000_regs.h [new file with mode: 0644]
drivers/net/igb/igb.h [new file with mode: 0644]
drivers/net/igb/igb_ethtool.c [new file with mode: 0644]
drivers/net/igb/igb_main.c [new file with mode: 0644]

index f87d9ff3311a8fa96667a2ada40030a365d94f94..af40ff434def6cddb55b30711d2627cef3d6affe 100644 (file)
@@ -2019,6 +2019,28 @@ config IP1000
          To compile this driver as a module, choose M here: the module
          will be called ipg.  This is recommended.
 
+config IGB
+       tristate "Intel(R) 82575 PCI-Express Gigabit Ethernet support"
+       depends on PCI
+       ---help---
+         This driver supports Intel(R) 82575 gigabit ethernet family of
+         adapters.  For more information on how to identify your adapter, go
+         to the Adapter & Driver ID Guide at:
+
+         <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+
+         For general information and support, go to the Intel support
+         website at:
+
+         <http://support.intel.com>
+
+         More specific information on configuring the driver is in
+         <file:Documentation/networking/e1000.txt>.
+
+         To compile this driver as a module, choose M here and read
+         <file:Documentation/networking/net-modules.txt>.  The module
+         will be called igb.
+
 source "drivers/net/ixp2000/Kconfig"
 
 config MYRI_SBUS
index 79fe3f158af149d4a915dd92890201b9e4f04766..9fc7794e88ea779eefd212c5c18f219fd85ffbe0 100644 (file)
@@ -6,6 +6,7 @@ obj-$(CONFIG_E1000) += e1000/
 obj-$(CONFIG_E1000E) += e1000e/
 obj-$(CONFIG_IBM_EMAC) += ibm_emac/
 obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac/
+obj-$(CONFIG_IGB) += igb/
 obj-$(CONFIG_IXGBE) += ixgbe/
 obj-$(CONFIG_IXGB) += ixgb/
 obj-$(CONFIG_IP1000) += ipg.o
diff --git a/drivers/net/igb/Makefile b/drivers/net/igb/Makefile
new file mode 100644 (file)
index 0000000..1927b3f
--- /dev/null
@@ -0,0 +1,37 @@
+################################################################################
+#
+# Intel 82575 PCI-Express Ethernet Linux driver
+# Copyright(c) 1999 - 2007 Intel Corporation.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The full GNU General Public License is included in this distribution in
+# the file called "COPYING".
+#
+# Contact Information:
+# Linux NICS <linux.nics@intel.com>
+# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+#
+################################################################################
+
+#
+# Makefile for the Intel(R) 82575 PCI-Express ethernet driver
+#
+
+obj-$(CONFIG_IGB) += igb.o
+
+igb-objs := igb_main.o igb_ethtool.o e1000_82575.o \
+           e1000_mac.o e1000_nvm.o e1000_phy.o
+
diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c
new file mode 100644 (file)
index 0000000..cda3ec8
--- /dev/null
@@ -0,0 +1,1269 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* e1000_82575
+ * e1000_82576
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+
+#include "e1000_mac.h"
+#include "e1000_82575.h"
+
+static s32  igb_get_invariants_82575(struct e1000_hw *);
+static s32  igb_acquire_phy_82575(struct e1000_hw *);
+static void igb_release_phy_82575(struct e1000_hw *);
+static s32  igb_acquire_nvm_82575(struct e1000_hw *);
+static void igb_release_nvm_82575(struct e1000_hw *);
+static s32  igb_check_for_link_82575(struct e1000_hw *);
+static s32  igb_get_cfg_done_82575(struct e1000_hw *);
+static s32  igb_init_hw_82575(struct e1000_hw *);
+static s32  igb_phy_hw_reset_sgmii_82575(struct e1000_hw *);
+static s32  igb_read_phy_reg_sgmii_82575(struct e1000_hw *, u32, u16 *);
+static void igb_rar_set_82575(struct e1000_hw *, u8 *, u32);
+static s32  igb_reset_hw_82575(struct e1000_hw *);
+static s32  igb_set_d0_lplu_state_82575(struct e1000_hw *, bool);
+static s32  igb_setup_copper_link_82575(struct e1000_hw *);
+static s32  igb_setup_fiber_serdes_link_82575(struct e1000_hw *);
+static s32  igb_write_phy_reg_sgmii_82575(struct e1000_hw *, u32, u16);
+static void igb_clear_hw_cntrs_82575(struct e1000_hw *);
+static s32  igb_acquire_swfw_sync_82575(struct e1000_hw *, u16);
+static s32  igb_configure_pcs_link_82575(struct e1000_hw *);
+static s32  igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *, u16 *,
+                                                u16 *);
+static s32  igb_get_phy_id_82575(struct e1000_hw *);
+static void igb_release_swfw_sync_82575(struct e1000_hw *, u16);
+static bool igb_sgmii_active_82575(struct e1000_hw *);
+static s32  igb_reset_init_script_82575(struct e1000_hw *);
+static s32  igb_read_mac_addr_82575(struct e1000_hw *);
+
+
+struct e1000_dev_spec_82575 {
+       bool sgmii_active;
+};
+
+static s32 igb_get_invariants_82575(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       struct e1000_nvm_info *nvm = &hw->nvm;
+       struct e1000_mac_info *mac = &hw->mac;
+       struct e1000_dev_spec_82575 *dev_spec;
+       u32 eecd;
+       s32 ret_val;
+       u16 size;
+       u32 ctrl_ext = 0;
+
+       switch (hw->device_id) {
+       case E1000_DEV_ID_82575EB_COPPER:
+       case E1000_DEV_ID_82575EB_FIBER_SERDES:
+       case E1000_DEV_ID_82575GB_QUAD_COPPER:
+               mac->type = e1000_82575;
+               break;
+       default:
+               return -E1000_ERR_MAC_INIT;
+               break;
+       }
+
+       /* MAC initialization */
+       hw->dev_spec_size = sizeof(struct e1000_dev_spec_82575);
+
+       /* Device-specific structure allocation */
+       hw->dev_spec = kzalloc(hw->dev_spec_size, GFP_KERNEL);
+
+       if (!hw->dev_spec)
+               return -ENOMEM;
+
+       dev_spec = (struct e1000_dev_spec_82575 *)hw->dev_spec;
+
+       /* Set media type */
+       /*
+        * The 82575 uses bits 22:23 for link mode. The mode can be changed
+        * based on the EEPROM. We cannot rely upon device ID. There
+        * is no distinguishable difference between fiber and internal
+        * SerDes mode on the 82575. There can be an external PHY attached
+        * on the SGMII interface. For this, we'll set sgmii_active to true.
+        */
+       phy->media_type = e1000_media_type_copper;
+       dev_spec->sgmii_active = false;
+
+       ctrl_ext = rd32(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) {
+               dev_spec->sgmii_active = true;
+               ctrl_ext |= E1000_CTRL_I2C_ENA;
+       } else {
+               ctrl_ext &= ~E1000_CTRL_I2C_ENA;
+       }
+       wr32(E1000_CTRL_EXT, ctrl_ext);
+
+       /* Set mta register count */
+       mac->mta_reg_count = 128;
+       /* Set rar entry count */
+       mac->rar_entry_count = E1000_RAR_ENTRIES_82575;
+       /* Set if part includes ASF firmware */
+       mac->asf_firmware_present = true;
+       /* Set if manageability features are enabled. */
+       mac->arc_subsystem_valid =
+               (rd32(E1000_FWSM) & E1000_FWSM_MODE_MASK)
+                       ? true : false;
+
+       /* physical interface link setup */
+       mac->ops.setup_physical_interface =
+               (hw->phy.media_type == e1000_media_type_copper)
+                       ? igb_setup_copper_link_82575
+                       : igb_setup_fiber_serdes_link_82575;
+
+       /* NVM initialization */
+       eecd = rd32(E1000_EECD);
+
+       nvm->opcode_bits        = 8;
+       nvm->delay_usec         = 1;
+       switch (nvm->override) {
+       case e1000_nvm_override_spi_large:
+               nvm->page_size    = 32;
+               nvm->address_bits = 16;
+               break;
+       case e1000_nvm_override_spi_small:
+               nvm->page_size    = 8;
+               nvm->address_bits = 8;
+               break;
+       default:
+               nvm->page_size    = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
+               nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
+               break;
+       }
+
+       nvm->type = e1000_nvm_eeprom_spi;
+
+       size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+                    E1000_EECD_SIZE_EX_SHIFT);
+
+       /*
+        * Added to a constant, "size" becomes the left-shift value
+        * for setting word_size.
+        */
+       size += NVM_WORD_SIZE_BASE_SHIFT;
+       nvm->word_size = 1 << size;
+
+       /* setup PHY parameters */
+       if (phy->media_type != e1000_media_type_copper) {
+               phy->type = e1000_phy_none;
+               return 0;
+       }
+
+       phy->autoneg_mask        = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+       phy->reset_delay_us      = 100;
+
+       /* PHY function pointers */
+       if (igb_sgmii_active_82575(hw)) {
+               phy->ops.reset_phy          = igb_phy_hw_reset_sgmii_82575;
+               phy->ops.read_phy_reg       = igb_read_phy_reg_sgmii_82575;
+               phy->ops.write_phy_reg      = igb_write_phy_reg_sgmii_82575;
+       } else {
+               phy->ops.reset_phy          = igb_phy_hw_reset;
+               phy->ops.read_phy_reg       = igb_read_phy_reg_igp;
+               phy->ops.write_phy_reg      = igb_write_phy_reg_igp;
+       }
+
+       /* Set phy->phy_addr and phy->id. */
+       ret_val = igb_get_phy_id_82575(hw);
+       if (ret_val)
+               return ret_val;
+
+       /* Verify phy id and set remaining function pointers */
+       switch (phy->id) {
+       case M88E1111_I_PHY_ID:
+               phy->type                   = e1000_phy_m88;
+               phy->ops.get_phy_info       = igb_get_phy_info_m88;
+               phy->ops.get_cable_length   = igb_get_cable_length_m88;
+               phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88;
+               break;
+       case IGP03E1000_E_PHY_ID:
+               phy->type                   = e1000_phy_igp_3;
+               phy->ops.get_phy_info       = igb_get_phy_info_igp;
+               phy->ops.get_cable_length   = igb_get_cable_length_igp_2;
+               phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_igp;
+               phy->ops.set_d0_lplu_state  = igb_set_d0_lplu_state_82575;
+               phy->ops.set_d3_lplu_state  = igb_set_d3_lplu_state;
+               break;
+       default:
+               return -E1000_ERR_PHY;
+       }
+
+       return 0;
+}
+
+/**
+ *  e1000_acquire_phy_82575 - Acquire rights to access PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire access rights to the correct PHY.  This is a
+ *  function pointer entry point called by the api module.
+ **/
+static s32 igb_acquire_phy_82575(struct e1000_hw *hw)
+{
+       u16 mask;
+
+       mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
+
+       return igb_acquire_swfw_sync_82575(hw, mask);
+}
+
+/**
+ *  e1000_release_phy_82575 - Release rights to access PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  A wrapper to release access rights to the correct PHY.  This is a
+ *  function pointer entry point called by the api module.
+ **/
+static void igb_release_phy_82575(struct e1000_hw *hw)
+{
+       u16 mask;
+
+       mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
+       igb_release_swfw_sync_82575(hw, mask);
+}
+
+/**
+ *  e1000_read_phy_reg_sgmii_82575 - Read PHY register using sgmii
+ *  @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 serial gigabit media independent
+ *  interface and stores the retrieved information in data.
+ **/
+static s32 igb_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset,
+                                         u16 *data)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       u32 i, i2ccmd = 0;
+
+       if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) {
+               hw_dbg(hw, "PHY Address %u is out of range\n", offset);
+               return -E1000_ERR_PARAM;
+       }
+
+       /*
+        * 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));
+
+       wr32(E1000_I2CCMD, i2ccmd);
+
+       /* Poll the ready bit to see if the I2C read completed */
+       for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
+               udelay(50);
+               i2ccmd = rd32(E1000_I2CCMD);
+               if (i2ccmd & E1000_I2CCMD_READY)
+                       break;
+       }
+       if (!(i2ccmd & E1000_I2CCMD_READY)) {
+               hw_dbg(hw, "I2CCMD Read did not complete\n");
+               return -E1000_ERR_PHY;
+       }
+       if (i2ccmd & E1000_I2CCMD_ERROR) {
+               hw_dbg(hw, "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 0;
+}
+
+/**
+ *  e1000_write_phy_reg_sgmii_82575 - Write PHY register using sgmii
+ *  @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 serial gigabit
+ *  media independent interface.
+ **/
+static s32 igb_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;
+
+       if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) {
+               hw_dbg(hw, "PHY Address %d is out of range\n", offset);
+               return -E1000_ERR_PARAM;
+       }
+
+       /* 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);
+
+       wr32(E1000_I2CCMD, i2ccmd);
+
+       /* Poll the ready bit to see if the I2C read completed */
+       for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
+               udelay(50);
+               i2ccmd = rd32(E1000_I2CCMD);
+               if (i2ccmd & E1000_I2CCMD_READY)
+                       break;
+       }
+       if (!(i2ccmd & E1000_I2CCMD_READY)) {
+               hw_dbg(hw, "I2CCMD Write did not complete\n");
+               return -E1000_ERR_PHY;
+       }
+       if (i2ccmd & E1000_I2CCMD_ERROR) {
+               hw_dbg(hw, "I2CCMD Error bit set\n");
+               return -E1000_ERR_PHY;
+       }
+
+       return 0;
+}
+
+/**
+ *  e1000_get_phy_id_82575 - Retreive PHY addr and id
+ *  @hw: pointer to the HW structure
+ *
+ *  Retreives the PHY address and ID for both PHY's which do and do not use
+ *  sgmi interface.
+ **/
+static s32 igb_get_phy_id_82575(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32  ret_val = 0;
+       u16 phy_id;
+
+       /*
+        * For SGMII PHYs, we try the list of possible addresses until
+        * we find one that works.  For non-SGMII PHYs
+        * (e.g. integrated copper PHYs), an address of 1 should
+        * work.  The result of this function should mean phy->phy_addr
+        * and phy->id are set correctly.
+        */
+       if (!(igb_sgmii_active_82575(hw))) {
+               phy->addr = 1;
+               ret_val = igb_get_phy_id(hw);
+               goto out;
+       }
+
+       /*
+        * The address field in the I2CCMD register is 3 bits and 0 is invalid.
+        * Therefore, we need to test 1-7
+        */
+       for (phy->addr = 1; phy->addr < 8; phy->addr++) {
+               ret_val = igb_read_phy_reg_sgmii_82575(hw, PHY_ID1, &phy_id);
+               if (ret_val == 0) {
+                       hw_dbg(hw, "Vendor ID 0x%08X read at address %u\n",
+                                 phy_id,
+                                 phy->addr);
+                       /*
+                        * At the time of this writing, The M88 part is
+                        * the only supported SGMII PHY product.
+                        */
+                       if (phy_id == M88_VENDOR)
+                               break;
+               } else {
+                       hw_dbg(hw, "PHY address %u was unreadable\n",
+                                 phy->addr);
+               }
+       }
+
+       /* A valid PHY type couldn't be found. */
+       if (phy->addr == 8) {
+               phy->addr = 0;
+               ret_val = -E1000_ERR_PHY;
+               goto out;
+       }
+
+       ret_val = igb_get_phy_id(hw);
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_phy_hw_reset_sgmii_82575 - Performs a PHY reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Resets the PHY using the serial gigabit media independent interface.
+ **/
+static s32 igb_phy_hw_reset_sgmii_82575(struct e1000_hw *hw)
+{
+       s32 ret_val;
+
+       /*
+        * This isn't a true "hard" reset, but is the only reset
+        * available to us at this time.
+        */
+
+       hw_dbg(hw, "Soft resetting SGMII attached PHY...\n");
+
+       /*
+        * SFP documentation requires the following to configure the SPF module
+        * to work on SGMII.  No further documentation is given.
+        */
+       ret_val = hw->phy.ops.write_phy_reg(hw, 0x1B, 0x8084);
+       if (ret_val)
+               goto out;
+
+       ret_val = igb_phy_sw_reset(hw);
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_set_d0_lplu_state_82575 - Set Low Power Linkup D0 state
+ *  @hw: pointer to the HW structure
+ *  @active: true to enable LPLU, false to disable
+ *
+ *  Sets the LPLU D0 state according to the active flag.  When
+ *  activating LPLU this function also disables smart speed
+ *  and vice versa.  LPLU will not be activated unless the
+ *  device autonegotiation advertisement meets standards of
+ *  either 10 or 10/100 or 10/100/1000 at all duplexes.
+ *  This is a function pointer entry point only called by
+ *  PHY setup routines.
+ **/
+static s32 igb_set_d0_lplu_state_82575(struct e1000_hw *hw, bool active)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32 ret_val;
+       u16 data;
+
+       ret_val = hw->phy.ops.read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+                                          &data);
+       if (ret_val)
+               goto out;
+
+       if (active) {
+               data |= IGP02E1000_PM_D0_LPLU;
+               ret_val = hw->phy.ops.write_phy_reg(hw,
+                                             IGP02E1000_PHY_POWER_MGMT,
+                                             data);
+               if (ret_val)
+                       goto out;
+
+               /* When LPLU is enabled, we should disable SmartSpeed */
+               ret_val = hw->phy.ops.read_phy_reg(hw,
+                                            IGP01E1000_PHY_PORT_CONFIG,
+                                            &data);
+               data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+               ret_val = hw->phy.ops.write_phy_reg(hw,
+                                             IGP01E1000_PHY_PORT_CONFIG,
+                                             data);
+               if (ret_val)
+                       goto out;
+       } else {
+               data &= ~IGP02E1000_PM_D0_LPLU;
+               ret_val = hw->phy.ops.write_phy_reg(hw,
+                                             IGP02E1000_PHY_POWER_MGMT,
+                                             data);
+               /*
+                * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
+                * during Dx states where the power conservation is most
+                * important.  During driver activity we should enable
+                * SmartSpeed, so performance is maintained.
+                */
+               if (phy->smart_speed == e1000_smart_speed_on) {
+                       ret_val = hw->phy.ops.read_phy_reg(hw,
+                                                    IGP01E1000_PHY_PORT_CONFIG,
+                                                    &data);
+                       if (ret_val)
+                               goto out;
+
+                       data |= IGP01E1000_PSCFR_SMART_SPEED;
+                       ret_val = hw->phy.ops.write_phy_reg(hw,
+                                                    IGP01E1000_PHY_PORT_CONFIG,
+                                                    data);
+                       if (ret_val)
+                               goto out;
+               } else if (phy->smart_speed == e1000_smart_speed_off) {
+                       ret_val = hw->phy.ops.read_phy_reg(hw,
+                                                    IGP01E1000_PHY_PORT_CONFIG,
+                                                    &data);
+                       if (ret_val)
+                               goto out;
+
+                       data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+                       ret_val = hw->phy.ops.write_phy_reg(hw,
+                                                    IGP01E1000_PHY_PORT_CONFIG,
+                                                    data);
+                       if (ret_val)
+                               goto out;
+               }
+       }
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_acquire_nvm_82575 - Request for access to EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire the necessary semaphores for exclussive access to the EEPROM.
+ *  Set the EEPROM access request bit and wait for EEPROM access grant bit.
+ *  Return successful if access grant bit set, else clear the request for
+ *  EEPROM access and return -E1000_ERR_NVM (-1).
+ **/
+static s32 igb_acquire_nvm_82575(struct e1000_hw *hw)
+{
+       s32 ret_val;
+
+       ret_val = igb_acquire_swfw_sync_82575(hw, E1000_SWFW_EEP_SM);
+       if (ret_val)
+               goto out;
+
+       ret_val = igb_acquire_nvm(hw);
+
+       if (ret_val)
+               igb_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM);
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_release_nvm_82575 - Release exclusive access to EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Stop any current commands to the EEPROM and clear the EEPROM request bit,
+ *  then release the semaphores acquired.
+ **/
+static void igb_release_nvm_82575(struct e1000_hw *hw)
+{
+       igb_release_nvm(hw);
+       igb_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM);
+}
+
+/**
+ *  e1000_acquire_swfw_sync_82575 - Acquire SW/FW semaphore
+ *  @hw: pointer to the HW structure
+ *  @mask: specifies which semaphore to acquire
+ *
+ *  Acquire the SW/FW semaphore to access the PHY or NVM.  The mask
+ *  will also specify which port we're acquiring the lock for.
+ **/
+static s32 igb_acquire_swfw_sync_82575(struct e1000_hw *hw, u16 mask)
+{
+       u32 swfw_sync;
+       u32 swmask = mask;
+       u32 fwmask = mask << 16;
+       s32 ret_val = 0;
+       s32 i = 0, timeout = 200; /* FIXME: find real value to use here */
+
+       while (i < timeout) {
+               if (igb_get_hw_semaphore(hw)) {
+                       ret_val = -E1000_ERR_SWFW_SYNC;
+                       goto out;
+               }
+
+               swfw_sync = rd32(E1000_SW_FW_SYNC);
+               if (!(swfw_sync & (fwmask | swmask)))
+                       break;
+
+               /*
+                * Firmware currently using resource (fwmask)
+                * or other software thread using resource (swmask)
+                */
+               igb_put_hw_semaphore(hw);
+               mdelay(5);
+               i++;
+       }
+
+       if (i == timeout) {
+               hw_dbg(hw, "Can't access resource, SW_FW_SYNC timeout.\n");
+               ret_val = -E1000_ERR_SWFW_SYNC;
+               goto out;
+       }
+
+       swfw_sync |= swmask;
+       wr32(E1000_SW_FW_SYNC, swfw_sync);
+
+       igb_put_hw_semaphore(hw);
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_release_swfw_sync_82575 - Release SW/FW semaphore
+ *  @hw: pointer to the HW structure
+ *  @mask: specifies which semaphore to acquire
+ *
+ *  Release the SW/FW semaphore used to access the PHY or NVM.  The mask
+ *  will also specify which port we're releasing the lock for.
+ **/
+static void igb_release_swfw_sync_82575(struct e1000_hw *hw, u16 mask)
+{
+       u32 swfw_sync;
+
+       while (igb_get_hw_semaphore(hw) != 0);
+       /* Empty */
+
+       swfw_sync = rd32(E1000_SW_FW_SYNC);
+       swfw_sync &= ~mask;
+       wr32(E1000_SW_FW_SYNC, swfw_sync);
+
+       igb_put_hw_semaphore(hw);
+}
+
+/**
+ *  e1000_get_cfg_done_82575 - Read config done bit
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the management control register for the config done bit for
+ *  completion status.  NOTE: silicon which is EEPROM-less will fail trying
+ *  to read the config done bit, so an error is *ONLY* logged and returns
+ *  0.  If we were to return with error, EEPROM-less silicon
+ *  would not be able to be reset or change link.
+ **/
+static s32 igb_get_cfg_done_82575(struct e1000_hw *hw)
+{
+       s32 timeout = PHY_CFG_TIMEOUT;
+       s32 ret_val = 0;
+       u32 mask = E1000_NVM_CFG_DONE_PORT_0;
+
+       if (hw->bus.func == 1)
+               mask = E1000_NVM_CFG_DONE_PORT_1;
+
+       while (timeout) {
+               if (rd32(E1000_EEMNGCTL) & mask)
+                       break;
+               msleep(1);
+               timeout--;
+       }
+       if (!timeout)
+               hw_dbg(hw, "MNG configuration cycle has not completed.\n");
+
+       /* If EEPROM is not marked present, init the PHY manually */
+       if (((rd32(E1000_EECD) & E1000_EECD_PRES) == 0) &&
+           (hw->phy.type == e1000_phy_igp_3))
+               igb_phy_init_script_igp3(hw);
+
+       return ret_val;
+}
+
+/**
+ *  e1000_check_for_link_82575 - Check for link
+ *  @hw: pointer to the HW structure
+ *
+ *  If sgmii is enabled, then use the pcs register to determine link, otherwise
+ *  use the generic interface for determining link.
+ **/
+static s32 igb_check_for_link_82575(struct e1000_hw *hw)
+{
+       s32 ret_val;
+       u16 speed, duplex;
+
+       /* SGMII link check is done through the PCS register. */
+       if ((hw->phy.media_type != e1000_media_type_copper) ||
+           (igb_sgmii_active_82575(hw)))
+               ret_val = igb_get_pcs_speed_and_duplex_82575(hw, &speed,
+                                                              &duplex);
+       else
+               ret_val = igb_check_for_copper_link(hw);
+
+       return ret_val;
+}
+
+/**
+ *  e1000_get_pcs_speed_and_duplex_82575 - Retrieve current speed/duplex
+ *  @hw: pointer to the HW structure
+ *  @speed: stores the current speed
+ *  @duplex: stores the current duplex
+ *
+ *  Using the physical coding sub-layer (PCS), retreive the current speed and
+ *  duplex, then store the values in the pointers provided.
+ **/
+static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw, u16 *speed,
+                                               u16 *duplex)
+{
+       struct e1000_mac_info *mac = &hw->mac;
+       u32 pcs;
+
+       /* Set up defaults for the return values of this function */
+       mac->serdes_has_link = false;
+       *speed = 0;
+       *duplex = 0;
+
+       /*
+        * Read the PCS Status register for link state. For non-copper mode,
+        * the status register is not accurate. The PCS status register is
+        * used instead.
+        */
+       pcs = rd32(E1000_PCS_LSTAT);
+
+       /*
+        * The link up bit determines when link is up on autoneg. The sync ok
+        * gets set once both sides sync up and agree upon link. Stable link
+        * can be determined by checking for both link up and link sync ok
+        */
+       if ((pcs & E1000_PCS_LSTS_LINK_OK) && (pcs & E1000_PCS_LSTS_SYNK_OK)) {
+               mac->serdes_has_link = true;
+
+               /* Detect and store PCS speed */
+               if (pcs & E1000_PCS_LSTS_SPEED_1000) {
+                       *speed = SPEED_1000;
+               } else if (pcs & E1000_PCS_LSTS_SPEED_100) {
+                       *speed = SPEED_100;
+               } else {
+                       *speed = SPEED_10;
+               }
+
+               /* Detect and store PCS duplex */
+               if (pcs & E1000_PCS_LSTS_DUPLEX_FULL) {
+                       *duplex = FULL_DUPLEX;
+               } else {
+                       *duplex = HALF_DUPLEX;
+               }
+       }
+
+       return 0;
+}
+
+/**
+ *  e1000_rar_set_82575 - Set receive address register
+ *  @hw: pointer to the HW structure
+ *  @addr: pointer to the receive address
+ *  @index: receive address array register
+ *
+ *  Sets the receive address array register at index to the address passed
+ *  in by addr.
+ **/
+static void igb_rar_set_82575(struct e1000_hw *hw, u8 *addr, u32 index)
+{
+       if (index < E1000_RAR_ENTRIES_82575)
+               igb_rar_set(hw, addr, index);
+
+       return;
+}
+
+/**
+ *  e1000_reset_hw_82575 - Reset hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This resets the hardware into a known state.  This is a
+ *  function pointer entry point called by the api module.
+ **/
+static s32 igb_reset_hw_82575(struct e1000_hw *hw)
+{
+       u32 ctrl, icr;
+       s32 ret_val;
+
+       /*
+        * 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 = igb_disable_pcie_master(hw);
+       if (ret_val)
+               hw_dbg(hw, "PCI-E Master disable polling has failed.\n");
+
+       hw_dbg(hw, "Masking off all interrupts\n");
+       wr32(E1000_IMC, 0xffffffff);
+
+       wr32(E1000_RCTL, 0);
+       wr32(E1000_TCTL, E1000_TCTL_PSP);
+       wrfl();
+
+       msleep(10);
+
+       ctrl = rd32(E1000_CTRL);
+
+       hw_dbg(hw, "Issuing a global reset to MAC\n");
+       wr32(E1000_CTRL, ctrl | E1000_CTRL_RST);
+
+       ret_val = igb_get_auto_rd_done(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.
+                */
+               hw_dbg(hw, "Auto Read Done did not complete\n");
+       }
+
+       /* If EEPROM is not present, run manual init scripts */
+       if ((rd32(E1000_EECD) & E1000_EECD_PRES) == 0)
+               igb_reset_init_script_82575(hw);
+
+       /* Clear any pending interrupt events. */
+       wr32(E1000_IMC, 0xffffffff);
+       icr = rd32(E1000_ICR);
+
+       igb_check_alt_mac_addr(hw);
+
+       return ret_val;
+}
+
+/**
+ *  e1000_init_hw_82575 - Initialize hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This inits the hardware readying it for operation.
+ **/
+static s32 igb_init_hw_82575(struct e1000_hw *hw)
+{
+       struct e1000_mac_info *mac = &hw->mac;
+       s32 ret_val;
+       u16 i, rar_count = mac->rar_entry_count;
+
+       /* Initialize identification LED */
+       ret_val = igb_id_led_init(hw);
+       if (ret_val) {
+               hw_dbg(hw, "Error initializing identification LED\n");
+               /* This is not fatal and we should not stop init due to this */
+       }
+
+       /* Disabling VLAN filtering */
+       hw_dbg(hw, "Initializing the IEEE VLAN\n");
+       igb_clear_vfta(hw);
+
+       /* Setup the receive address */
+       igb_init_rx_addrs(hw, rar_count);
+       /* Zero out the Multicast HASH table */
+       hw_dbg(hw, "Zeroing the MTA\n");
+       for (i = 0; i < mac->mta_reg_count; i++)
+               array_wr32(E1000_MTA, i, 0);
+
+       /* Setup link and flow control */
+       ret_val = igb_setup_link(hw);
+
+       /*
+        * Clear all of the statistics registers (clear on read).  It is
+        * important that we do this after we have tried to establish link
+        * because the symbol error count will increment wildly if there
+        * is no link.
+        */
+       igb_clear_hw_cntrs_82575(hw);
+
+       return ret_val;
+}
+
+/**
+ *  e1000_setup_copper_link_82575 - Configure copper link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures the link for auto-neg or forced speed and duplex.  Then we check
+ *  for link, once link is established calls to configure collision distance
+ *  and flow control are called.
+ **/
+static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
+{
+       u32 ctrl, led_ctrl;
+       s32  ret_val;
+       bool link;
+
+       ctrl = rd32(E1000_CTRL);
+       ctrl |= E1000_CTRL_SLU;
+       ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+       wr32(E1000_CTRL, ctrl);
+
+       switch (hw->phy.type) {
+       case e1000_phy_m88:
+               ret_val = igb_copper_link_setup_m88(hw);
+               break;
+       case e1000_phy_igp_3:
+               ret_val = igb_copper_link_setup_igp(hw);
+               /* Setup activity LED */
+               led_ctrl = rd32(E1000_LEDCTL);
+               led_ctrl &= IGP_ACTIVITY_LED_MASK;
+               led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
+               wr32(E1000_LEDCTL, led_ctrl);
+               break;
+       default:
+               ret_val = -E1000_ERR_PHY;
+               break;
+       }
+
+       if (ret_val)
+               goto out;
+
+       if (hw->mac.autoneg) {
+               /*
+                * Setup autoneg and flow control advertisement
+                * and perform autonegotiation.
+                */
+               ret_val = igb_copper_link_autoneg(hw);
+               if (ret_val)
+                       goto out;
+       } else {
+               /*
+                * PHY will be set to 10H, 10F, 100H or 100F
+                * depending on user settings.
+                */
+               hw_dbg(hw, "Forcing Speed and Duplex\n");
+               ret_val = igb_phy_force_speed_duplex(hw);
+               if (ret_val) {
+                       hw_dbg(hw, "Error Forcing Speed and Duplex\n");
+                       goto out;
+               }
+       }
+
+       ret_val = igb_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 = igb_phy_has_link(hw,
+                                            COPPER_LINK_UP_LIMIT,
+                                            10,
+                                            &link);
+       if (ret_val)
+               goto out;
+
+       if (link) {
+               hw_dbg(hw, "Valid link established!!!\n");
+               /* Config the MAC and PHY after link is up */
+               igb_config_collision_dist(hw);
+               ret_val = igb_config_fc_after_link_up(hw);
+       } else {
+               hw_dbg(hw, "Unable to establish link!!!\n");
+       }
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_setup_fiber_serdes_link_82575 - Setup link for fiber/serdes
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures speed and duplex for fiber and serdes links.
+ **/
+static s32 igb_setup_fiber_serdes_link_82575(struct e1000_hw *hw)
+{
+       u32 reg;
+
+       /*
+        * On the 82575, SerDes loopback mode persists until it is
+        * explicitly turned off or a power cycle is performed.  A read to
+        * the register does not indicate its status.  Therefore, we ensure
+        * loopback mode is disabled during initialization.
+        */
+       wr32(E1000_SCTL, E1000_SCTL_DISABLE_SERDES_LOOPBACK);
+
+       /* Force link up, set 1gb, set both sw defined pins */
+       reg = rd32(E1000_CTRL);
+       reg |= E1000_CTRL_SLU |
+              E1000_CTRL_SPD_1000 |
+              E1000_CTRL_FRCSPD |
+              E1000_CTRL_SWDPIN0 |
+              E1000_CTRL_SWDPIN1;
+       wr32(E1000_CTRL, reg);
+
+       /* Set switch control to serdes energy detect */
+       reg = rd32(E1000_CONNSW);
+       reg |= E1000_CONNSW_ENRGSRC;
+       wr32(E1000_CONNSW, reg);
+
+       /*
+        * New SerDes mode allows for forcing speed or autonegotiating speed
+        * at 1gb. Autoneg should be default set by most drivers. This is the
+        * mode that will be compatible with older link partners and switches.
+        * However, both are supported by the hardware and some drivers/tools.
+        */
+       reg = rd32(E1000_PCS_LCTL);
+
+       reg &= ~(E1000_PCS_LCTL_AN_ENABLE | E1000_PCS_LCTL_FLV_LINK_UP |
+               E1000_PCS_LCTL_FSD | E1000_PCS_LCTL_FORCE_LINK);
+
+       if (hw->mac.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 */
+               hw_dbg(hw, "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 */
+               hw_dbg(hw, "Configuring Forced Link; PCS_LCTL = 0x%08X\n", reg);
+       }
+       wr32(E1000_PCS_LCTL, reg);
+
+       return 0;
+}
+
+/**
+ *  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 igb_configure_pcs_link_82575(struct e1000_hw *hw)
+{
+       struct e1000_mac_info *mac = &hw->mac;
+       u32 reg = 0;
+
+       if (hw->phy.media_type != e1000_media_type_copper ||
+           !(igb_sgmii_active_82575(hw)))
+               goto out;
+
+       /* For SGMII, we need to issue a PCS autoneg restart */
+       reg = rd32(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 regiseter 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;
+
+               hw_dbg(hw,
+                      "Wrote 0x%08X to PCS_LCTL to configure forced link\n",
+                      reg);
+       }
+       wr32(E1000_PCS_LCTL, reg);
+
+out:
+       return 0;
+}
+
+/**
+ *  e1000_sgmii_active_82575 - Return sgmii state
+ *  @hw: pointer to the HW structure
+ *
+ *  82575 silicon has a serialized gigabit media independent interface (sgmii)
+ *  which can be enabled for use in the embedded applications.  Simply
+ *  return the current state of the sgmii interface.
+ **/
+static bool igb_sgmii_active_82575(struct e1000_hw *hw)
+{
+       struct e1000_dev_spec_82575 *dev_spec;
+       bool ret_val;
+
+       if (hw->mac.type != e1000_82575) {
+               ret_val = false;
+               goto out;
+       }
+
+       dev_spec = (struct e1000_dev_spec_82575 *)hw->dev_spec;
+
+       ret_val = dev_spec->sgmii_active;
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_reset_init_script_82575 - Inits HW defaults after reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Inits recommended HW defaults after a reset when there is no EEPROM
+ *  detected. This is only for the 82575.
+ **/
+static s32 igb_reset_init_script_82575(struct e1000_hw *hw)
+{
+       if (hw->mac.type == e1000_82575) {
+               hw_dbg(hw, "Running reset init script for 82575\n");
+               /* SerDes configuration via SERDESCTRL */
+               igb_write_8bit_ctrl_reg(hw, E1000_SCTL, 0x00, 0x0C);
+               igb_write_8bit_ctrl_reg(hw, E1000_SCTL, 0x01, 0x78);
+               igb_write_8bit_ctrl_reg(hw, E1000_SCTL, 0x1B, 0x23);
+               igb_write_8bit_ctrl_reg(hw, E1000_SCTL, 0x23, 0x15);
+
+               /* CCM configuration via CCMCTL register */
+               igb_write_8bit_ctrl_reg(hw, E1000_CCMCTL, 0x14, 0x00);
+               igb_write_8bit_ctrl_reg(hw, E1000_CCMCTL, 0x10, 0x00);
+
+               /* PCIe lanes configuration */
+               igb_write_8bit_ctrl_reg(hw, E1000_GIOCTL, 0x00, 0xEC);
+               igb_write_8bit_ctrl_reg(hw, E1000_GIOCTL, 0x61, 0xDF);
+               igb_write_8bit_ctrl_reg(hw, E1000_GIOCTL, 0x34, 0x05);
+               igb_write_8bit_ctrl_reg(hw, E1000_GIOCTL, 0x2F, 0x81);
+
+               /* PCIe PLL Configuration */
+               igb_write_8bit_ctrl_reg(hw, E1000_SCCTL, 0x02, 0x47);
+               igb_write_8bit_ctrl_reg(hw, E1000_SCCTL, 0x14, 0x00);
+               igb_write_8bit_ctrl_reg(hw, E1000_SCCTL, 0x10, 0x00);
+       }
+
+       return 0;
+}
+
+/**
+ *  e1000_read_mac_addr_82575 - Read device MAC address
+ *  @hw: pointer to the HW structure
+ **/
+static s32 igb_read_mac_addr_82575(struct e1000_hw *hw)
+{
+       s32 ret_val = 0;
+
+       if (igb_check_alt_mac_addr(hw))
+               ret_val = igb_read_mac_addr(hw);
+
+       return ret_val;
+}
+
+/**
+ *  e1000_clear_hw_cntrs_82575 - Clear device specific hardware counters
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the hardware counters by reading the counter registers.
+ **/
+static void igb_clear_hw_cntrs_82575(struct e1000_hw *hw)
+{
+       u32 temp;
+
+       igb_clear_hw_cntrs_base(hw);
+
+       temp = rd32(E1000_PRC64);
+       temp = rd32(E1000_PRC127);
+       temp = rd32(E1000_PRC255);
+       temp = rd32(E1000_PRC511);
+       temp = rd32(E1000_PRC1023);
+       temp = rd32(E1000_PRC1522);
+       temp = rd32(E1000_PTC64);
+       temp = rd32(E1000_PTC127);
+       temp = rd32(E1000_PTC255);
+       temp = rd32(E1000_PTC511);
+       temp = rd32(E1000_PTC1023);
+       temp = rd32(E1000_PTC1522);
+
+       temp = rd32(E1000_ALGNERRC);
+       temp = rd32(E1000_RXERRC);
+       temp = rd32(E1000_TNCRS);
+       temp = rd32(E1000_CEXTERR);
+       temp = rd32(E1000_TSCTC);
+       temp = rd32(E1000_TSCTFC);
+
+       temp = rd32(E1000_MGTPRC);
+       temp = rd32(E1000_MGTPDC);
+       temp = rd32(E1000_MGTPTC);
+
+       temp = rd32(E1000_IAC);
+       temp = rd32(E1000_ICRXOC);
+
+       temp = rd32(E1000_ICRXPTC);
+       temp = rd32(E1000_ICRXATC);
+       temp = rd32(E1000_ICTXPTC);
+       temp = rd32(E1000_ICTXATC);
+       temp = rd32(E1000_ICTXQEC);
+       temp = rd32(E1000_ICTXQMTC);
+       temp = rd32(E1000_ICRXDMTC);
+
+       temp = rd32(E1000_CBTMPC);
+       temp = rd32(E1000_HTDPMC);
+       temp = rd32(E1000_CBRMPC);
+       temp = rd32(E1000_RPTHC);
+       temp = rd32(E1000_HGPTC);
+       temp = rd32(E1000_HTCBDPC);
+       temp = rd32(E1000_HGORCL);
+       temp = rd32(E1000_HGORCH);
+       temp = rd32(E1000_HGOTCL);
+       temp = rd32(E1000_HGOTCH);
+       temp = rd32(E1000_LENERRS);
+
+       /* This register should not be read in copper configurations */
+       if (hw->phy.media_type == e1000_media_type_internal_serdes)
+               temp = rd32(E1000_SCVPC);
+}
+
+static struct e1000_mac_operations e1000_mac_ops_82575 = {
+       .reset_hw             = igb_reset_hw_82575,
+       .init_hw              = igb_init_hw_82575,
+       .check_for_link       = igb_check_for_link_82575,
+       .rar_set              = igb_rar_set_82575,
+       .read_mac_addr        = igb_read_mac_addr_82575,
+       .get_speed_and_duplex = igb_get_speed_and_duplex_copper,
+};
+
+static struct e1000_phy_operations e1000_phy_ops_82575 = {
+       .acquire_phy          = igb_acquire_phy_82575,
+       .get_cfg_done         = igb_get_cfg_done_82575,
+       .release_phy          = igb_release_phy_82575,
+};
+
+static struct e1000_nvm_operations e1000_nvm_ops_82575 = {
+       .acquire_nvm          = igb_acquire_nvm_82575,
+       .read_nvm             = igb_read_nvm_eerd,
+       .release_nvm          = igb_release_nvm_82575,
+       .write_nvm            = igb_write_nvm_spi,
+};
+
+const struct e1000_info e1000_82575_info = {
+       .get_invariants = igb_get_invariants_82575,
+       .mac_ops = &e1000_mac_ops_82575,
+       .phy_ops = &e1000_phy_ops_82575,
+       .nvm_ops = &e1000_nvm_ops_82575,
+};
+
diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h
new file mode 100644 (file)
index 0000000..6604d96
--- /dev/null
@@ -0,0 +1,150 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_82575_H_
+#define _E1000_82575_H_
+
+#define E1000_RAR_ENTRIES_82575   16
+
+/* SRRCTL bit definitions */
+#define E1000_SRRCTL_BSIZEPKT_SHIFT                     10 /* Shift _right_ */
+#define E1000_SRRCTL_BSIZEHDRSIZE_SHIFT                 2  /* Shift _left_ */
+#define E1000_SRRCTL_DESCTYPE_ADV_ONEBUF                0x02000000
+#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS          0x0A000000
+
+#define E1000_MRQC_ENABLE_RSS_4Q            0x00000002
+#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_EICR_TX_QUEUE ( \
+    E1000_EICR_TX_QUEUE0 |    \
+    E1000_EICR_TX_QUEUE1 |    \
+    E1000_EICR_TX_QUEUE2 |    \
+    E1000_EICR_TX_QUEUE3)
+
+#define E1000_EICR_RX_QUEUE ( \
+    E1000_EICR_RX_QUEUE0 |    \
+    E1000_EICR_RX_QUEUE1 |    \
+    E1000_EICR_RX_QUEUE2 |    \
+    E1000_EICR_RX_QUEUE3)
+
+#define E1000_EIMS_RX_QUEUE E1000_EICR_RX_QUEUE
+#define E1000_EIMS_TX_QUEUE E1000_EICR_TX_QUEUE
+
+/* Immediate Interrupt RX (A.K.A. Low Latency Interrupt) */
+
+/* Receive Descriptor - Advanced */
+union e1000_adv_rx_desc {
+       struct {
+               u64 pkt_addr;             /* Packet buffer address */
+               u64 hdr_addr;             /* Header buffer address */
+       } read;
+       struct {
+               struct {
+                       struct {
+                               u16 pkt_info;   /* RSS type, Packet type */
+                               u16 hdr_info;   /* Split Header,
+                                                * header buffer length */
+                       } lo_dword;
+                       union {
+                               u32 rss;          /* RSS Hash */
+                               struct {
+                                       u16 ip_id;    /* IP id */
+                                       u16 csum;     /* Packet Checksum */
+                               } csum_ip;
+                       } hi_dword;
+               } lower;
+               struct {
+                       u32 status_error;     /* ext status/error */
+                       u16 length;           /* Packet length */
+                       u16 vlan;             /* VLAN tag */
+               } upper;
+       } wb;  /* writeback */
+};
+
+#define E1000_RXDADV_HDRBUFLEN_MASK      0x7FE0
+#define E1000_RXDADV_HDRBUFLEN_SHIFT     5
+
+/* RSS Hash results */
+
+/* RSS Packet Types as indicated in the receive descriptor */
+
+/* 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;
+       } read;
+       struct {
+               u64 rsvd;       /* Reserved */
+               u32 nxtseq_seed;
+               u32 status;
+       } wb;
+};
+
+/* Adv Transmit Descriptor Config Masks */
+#define E1000_ADVTXD_DTYP_CTXT    0x00200000 /* Advanced Context Descriptor */
+#define E1000_ADVTXD_DTYP_DATA    0x00300000 /* Advanced Data Descriptor */
+#define E1000_ADVTXD_DCMD_IFCS    0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_ADVTXD_DCMD_DEXT    0x20000000 /* Descriptor extension (1=Adv) */
+#define E1000_ADVTXD_DCMD_VLE     0x40000000 /* VLAN pkt enable */
+#define E1000_ADVTXD_DCMD_TSE     0x80000000 /* TCP Seg enable */
+#define E1000_ADVTXD_PAYLEN_SHIFT    14 /* Adv desc PAYLEN shift */
+
+/* Context descriptors */
+struct e1000_adv_tx_context_desc {
+       u32 vlan_macip_lens;
+       u32 seqnum_seed;
+       u32 type_tucmd_mlhl;
+       u32 mss_l4len_idx;
+};
+
+#define E1000_ADVTXD_MACLEN_SHIFT    9  /* Adv ctxt desc mac len shift */
+#define E1000_ADVTXD_TUCMD_IPV4    0x00000400  /* IP Packet Type: 1=IPv4 */
+#define E1000_ADVTXD_TUCMD_L4T_TCP 0x00000800  /* L4 Packet TYPE of TCP */
+/* IPSec Encrypt Enable for ESP */
+#define E1000_ADVTXD_L4LEN_SHIFT     8  /* Adv ctxt L4LEN shift */
+#define E1000_ADVTXD_MSS_SHIFT      16  /* Adv ctxt MSS shift */
+/* Adv ctxt IPSec SA IDX mask */
+/* Adv ctxt IPSec ESP len mask */
+
+/* Additional Transmit Descriptor Control definitions */
+#define E1000_TXDCTL_QUEUE_ENABLE  0x02000000 /* Enable specific Tx Queue */
+/* Tx Queue Arbitration Priority 0=low, 1=high */
+
+/* Additional Receive Descriptor Control definitions */
+#define E1000_RXDCTL_QUEUE_ENABLE  0x02000000 /* Enable specific Rx Queue */
+
+/* Direct Cache Access (DCA) definitions */
+
+
+
+#define E1000_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* TX Desc writeback RO bit */
+
+#endif
diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h
new file mode 100644 (file)
index 0000000..8da9ffe
--- /dev/null
@@ -0,0 +1,772 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_DEFINES_H_
+#define _E1000_DEFINES_H_
+
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define REQ_TX_DESCRIPTOR_MULTIPLE  8
+#define REQ_RX_DESCRIPTOR_MULTIPLE  8
+
+/* Definitions for power management and wakeup registers */
+/* Wake Up Control */
+#define E1000_WUC_PME_EN     0x00000002 /* PME Enable */
+
+/* Wake Up Filter Control */
+#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
+#define E1000_WUFC_MAG  0x00000002 /* Magic Packet Wakeup Enable */
+#define E1000_WUFC_EX   0x00000004 /* Directed Exact Wakeup Enable */
+#define E1000_WUFC_MC   0x00000008 /* Directed Multicast Wakeup Enable */
+#define E1000_WUFC_BC   0x00000010 /* Broadcast Wakeup Enable */
+#define E1000_WUFC_ARP  0x00000020 /* ARP Request Packet Wakeup Enable */
+#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */
+#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */
+#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */
+#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */
+#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */
+#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */
+#define E1000_WUFC_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */
+
+/* Wake Up Status */
+
+/* Wake Up Packet Length */
+
+/* Four Flexible Filters are supported */
+#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4
+
+/* Each Flexible Filter is at most 128 (0x80) bytes in length */
+#define E1000_FLEXIBLE_FILTER_SIZE_MAX  128
+
+
+/* Extended Device Control */
+#define E1000_CTRL_EXT_GPI1_EN   0x00000002 /* Maps SDP5 to GPI1 */
+#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Defineable Pin 4 */
+#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Defineable Pin 5 */
+#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */
+#define E1000_CTRL_EXT_SDP4_DIR  0x00000100 /* Direction of SDP4 0=in 1=out */
+#define E1000_CTRL_EXT_EE_RST    0x00002000 /* Reinitialize from EEPROM */
+#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES  0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_SGMII   0x00800000
+#define E1000_CTRL_EXT_EIAME          0x01000000
+#define E1000_CTRL_EXT_IRCA           0x00000001
+/* Interrupt delay cancellation */
+/* Driver loaded bit for FW */
+#define E1000_CTRL_EXT_DRV_LOAD       0x10000000
+/* Interrupt acknowledge Auto-mask */
+/* Clear Interrupt timers after IMS clear */
+/* packet buffer parity error detection enabled */
+/* descriptor FIFO parity error detection enable */
+#define E1000_CTRL_EXT_PBA_CLR        0x80000000 /* PBA Clear */
+#define E1000_I2CCMD_REG_ADDR_SHIFT   16
+#define E1000_I2CCMD_PHY_ADDR_SHIFT   24
+#define E1000_I2CCMD_OPCODE_READ      0x08000000
+#define E1000_I2CCMD_OPCODE_WRITE     0x00000000
+#define E1000_I2CCMD_READY            0x20000000
+#define E1000_I2CCMD_ERROR            0x80000000
+#define E1000_MAX_SGMII_PHY_REG_ADDR  255
+#define E1000_I2CCMD_PHY_TIMEOUT      200
+
+/* Receive Decriptor bit definitions */
+#define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
+#define E1000_RXD_STAT_EOP      0x02    /* End of Packet */
+#define E1000_RXD_STAT_IXSM     0x04    /* Ignore checksum */
+#define E1000_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
+#define E1000_RXD_STAT_UDPCS    0x10    /* UDP xsum caculated */
+#define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
+#define E1000_RXD_STAT_DYNINT   0x800   /* Pkt caused INT via DYNINT */
+#define E1000_RXD_ERR_CE        0x01    /* CRC Error */
+#define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
+#define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
+#define E1000_RXD_ERR_CXE       0x10    /* Carrier Extension Error */
+#define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
+#define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
+
+#define E1000_RXDEXT_STATERR_CE    0x01000000
+#define E1000_RXDEXT_STATERR_SE    0x02000000
+#define E1000_RXDEXT_STATERR_SEQ   0x04000000
+#define E1000_RXDEXT_STATERR_CXE   0x10000000
+#define E1000_RXDEXT_STATERR_TCPE  0x20000000
+#define E1000_RXDEXT_STATERR_IPE   0x40000000
+#define E1000_RXDEXT_STATERR_RXE   0x80000000
+
+/* mask to determine if packets should be dropped due to frame errors */
+#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
+    E1000_RXD_ERR_CE  |                \
+    E1000_RXD_ERR_SE  |                \
+    E1000_RXD_ERR_SEQ |                \
+    E1000_RXD_ERR_CXE |                \
+    E1000_RXD_ERR_RXE)
+
+/* Same mask, but for extended and packet split descriptors */
+#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \
+    E1000_RXDEXT_STATERR_CE  |            \
+    E1000_RXDEXT_STATERR_SE  |            \
+    E1000_RXDEXT_STATERR_SEQ |            \
+    E1000_RXDEXT_STATERR_CXE |            \
+    E1000_RXDEXT_STATERR_RXE)
+
+#define E1000_MRQC_RSS_FIELD_IPV4_TCP          0x00010000
+#define E1000_MRQC_RSS_FIELD_IPV4              0x00020000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX       0x00040000
+#define E1000_MRQC_RSS_FIELD_IPV6              0x00100000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP          0x00200000
+
+
+/* Management Control */
+#define E1000_MANC_SMBUS_EN      0x00000001 /* SMBus Enabled - RO */
+#define E1000_MANC_ASF_EN        0x00000002 /* ASF Enabled - RO */
+#define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
+/* Enable Neighbor Discovery Filtering */
+#define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
+#define E1000_MANC_BLK_PHY_RST_ON_IDE   0x00040000 /* Block phy resets */
+/* Enable MAC address filtering */
+#define E1000_MANC_EN_MAC_ADDR_FILTER   0x00100000
+/* Enable MNG packets to host memory */
+#define E1000_MANC_EN_MNG2HOST   0x00200000
+/* Enable IP address filtering */
+
+
+/* Receive Control */
+#define E1000_RCTL_EN             0x00000002    /* enable */
+#define E1000_RCTL_SBP            0x00000004    /* store bad packet */
+#define E1000_RCTL_UPE            0x00000008    /* unicast promiscuous enable */
+#define E1000_RCTL_MPE            0x00000010    /* multicast promiscuous enab */
+#define E1000_RCTL_LPE            0x00000020    /* long packet enable */
+#define E1000_RCTL_LBM_NO         0x00000000    /* no loopback mode */
+#define E1000_RCTL_LBM_MAC        0x00000040    /* MAC loopback mode */
+#define E1000_RCTL_LBM_TCVR       0x000000C0    /* tcvr loopback mode */
+#define E1000_RCTL_RDMTS_HALF     0x00000000    /* rx desc min threshold size */
+#define E1000_RCTL_MO_SHIFT       12            /* multicast offset shift */
+#define E1000_RCTL_BAM            0x00008000    /* broadcast enable */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
+#define E1000_RCTL_SZ_2048        0x00000000    /* rx buffer size 2048 */
+#define E1000_RCTL_SZ_1024        0x00010000    /* rx buffer size 1024 */
+#define E1000_RCTL_SZ_512         0x00020000    /* rx buffer size 512 */
+#define E1000_RCTL_SZ_256         0x00030000    /* rx buffer size 256 */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
+#define E1000_RCTL_SZ_16384       0x00010000    /* rx buffer size 16384 */
+#define E1000_RCTL_SZ_8192        0x00020000    /* rx buffer size 8192 */
+#define E1000_RCTL_SZ_4096        0x00030000    /* rx buffer size 4096 */
+#define E1000_RCTL_VFE            0x00040000    /* vlan filter enable */
+#define E1000_RCTL_CFIEN          0x00080000    /* canonical form enable */
+#define E1000_RCTL_BSEX           0x02000000    /* Buffer size extension */
+#define E1000_RCTL_SECRC          0x04000000    /* Strip Ethernet CRC */
+
+/*
+ * Use byte values for the following shift parameters
+ * Usage:
+ *     psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE0_MASK) |
+ *                ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE1_MASK) |
+ *                ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE2_MASK) |
+ *                ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |;
+ *                  E1000_PSRCTL_BSIZE3_MASK))
+ * where value0 = [128..16256],  default=256
+ *       value1 = [1024..64512], default=4096
+ *       value2 = [0..64512],    default=4096
+ *       value3 = [0..64512],    default=0
+ */
+
+#define E1000_PSRCTL_BSIZE0_MASK   0x0000007F
+#define E1000_PSRCTL_BSIZE1_MASK   0x00003F00
+#define E1000_PSRCTL_BSIZE2_MASK   0x003F0000
+#define E1000_PSRCTL_BSIZE3_MASK   0x3F000000
+
+#define E1000_PSRCTL_BSIZE0_SHIFT  7            /* Shift _right_ 7 */
+#define E1000_PSRCTL_BSIZE1_SHIFT  2            /* Shift _right_ 2 */
+#define E1000_PSRCTL_BSIZE2_SHIFT  6            /* Shift _left_ 6 */
+#define E1000_PSRCTL_BSIZE3_SHIFT 14            /* Shift _left_ 14 */
+
+/* SWFW_SYNC Definitions */
+#define E1000_SWFW_EEP_SM   0x1
+#define E1000_SWFW_PHY0_SM  0x2
+#define E1000_SWFW_PHY1_SM  0x4
+
+/* FACTPS Definitions */
+/* Device Control */
+#define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
+#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */
+#define E1000_CTRL_ASDE     0x00000020  /* Auto-speed detect enable */
+#define E1000_CTRL_SLU      0x00000040  /* Set link up (Force Link) */
+#define E1000_CTRL_ILOS     0x00000080  /* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL  0x00000300  /* Speed Select Mask */
+#define E1000_CTRL_SPD_100  0x00000100  /* Force 100Mb */
+#define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
+#define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
+#define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
+/* Defined polarity of Dock/Undock indication in SDP[0] */
+/* Reset both PHY ports, through PHYRST_N pin */
+/* enable link status from external LINK_0 and LINK_1 pins */
+#define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
+#define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
+#define E1000_CTRL_SWDPIN2  0x00100000  /* SWDPIN 2 value */
+#define E1000_CTRL_SWDPIN3  0x00200000  /* SWDPIN 3 value */
+#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
+#define E1000_CTRL_SWDPIO2  0x01000000  /* SWDPIN 2 input or output */
+#define E1000_CTRL_SWDPIO3  0x02000000  /* SWDPIN 3 input or output */
+#define E1000_CTRL_RST      0x04000000  /* Global reset */
+#define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
+#define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
+#define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
+/* Initiate an interrupt to manageability engine */
+#define E1000_CTRL_I2C_ENA  0x02000000  /* I2C enable */
+
+/* Bit definitions for the Management Data IO (MDIO) and Management Data
+ * Clock (MDC) pins in the Device Control Register.
+ */
+
+#define E1000_CONNSW_ENRGSRC             0x4
+#define E1000_PCS_LCTL_FLV_LINK_UP       1
+#define E1000_PCS_LCTL_FSV_100           2
+#define E1000_PCS_LCTL_FSV_1000          4
+#define E1000_PCS_LCTL_FDV_FULL          8
+#define E1000_PCS_LCTL_FSD               0x10
+#define E1000_PCS_LCTL_FORCE_LINK        0x20
+#define E1000_PCS_LCTL_AN_ENABLE         0x10000
+#define E1000_PCS_LCTL_AN_RESTART        0x20000
+#define E1000_PCS_LCTL_AN_TIMEOUT        0x40000
+
+#define E1000_PCS_LSTS_LINK_OK           1
+#define E1000_PCS_LSTS_SPEED_100         2
+#define E1000_PCS_LSTS_SPEED_1000        4
+#define E1000_PCS_LSTS_DUPLEX_FULL       8
+#define E1000_PCS_LSTS_SYNK_OK           0x10
+
+/* Device Status */
+#define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
+#define E1000_STATUS_FUNC_MASK  0x0000000C      /* PCI Function Mask */
+#define E1000_STATUS_FUNC_SHIFT 2
+#define E1000_STATUS_FUNC_1     0x00000004      /* Function 1 */
+#define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
+#define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
+/* Change in Dock/Undock state. Clear on write '0'. */
+/* Status of Master requests. */
+#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000
+/* BMC external code execution disabled */
+
+/* Constants used to intrepret the masked PCI-X bus speed. */
+
+#define SPEED_10    10
+#define SPEED_100   100
+#define SPEED_1000  1000
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+
+#define ADVERTISE_10_HALF                 0x0001
+#define ADVERTISE_10_FULL                 0x0002
+#define ADVERTISE_100_HALF                0x0004
+#define ADVERTISE_100_FULL                0x0008
+#define ADVERTISE_1000_HALF               0x0010 /* Not used, just FYI */
+#define ADVERTISE_1000_FULL               0x0020
+
+/* 1000/H is not supported, nor spec-compliant. */
+#define E1000_ALL_SPEED_DUPLEX (ADVERTISE_10_HALF  |  ADVERTISE_10_FULL | \
+                               ADVERTISE_100_HALF |  ADVERTISE_100_FULL | \
+                                                     ADVERTISE_1000_FULL)
+#define E1000_ALL_NOT_GIG      (ADVERTISE_10_HALF  |  ADVERTISE_10_FULL | \
+                               ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
+#define E1000_ALL_100_SPEED    (ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
+#define E1000_ALL_10_SPEED     (ADVERTISE_10_HALF  |  ADVERTISE_10_FULL)
+#define E1000_ALL_FULL_DUPLEX  (ADVERTISE_10_FULL  |  ADVERTISE_100_FULL | \
+                                                     ADVERTISE_1000_FULL)
+#define E1000_ALL_HALF_DUPLEX  (ADVERTISE_10_HALF  |  ADVERTISE_100_HALF)
+
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT   E1000_ALL_SPEED_DUPLEX
+
+/* LED Control */
+#define E1000_LEDCTL_LED0_MODE_MASK       0x0000000F
+#define E1000_LEDCTL_LED0_MODE_SHIFT      0
+#define E1000_LEDCTL_LED0_IVRT            0x00000040
+#define E1000_LEDCTL_LED0_BLINK           0x00000080
+
+#define E1000_LEDCTL_MODE_LED_ON        0xE
+#define E1000_LEDCTL_MODE_LED_OFF       0xF
+
+/* Transmit Descriptor bit definitions */
+#define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
+#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
+#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
+/* Extended desc bits for Linksec and timesync */
+
+/* Transmit Control */
+#define E1000_TCTL_EN     0x00000002    /* enable tx */
+#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
+#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
+#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
+#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
+
+/* Transmit Arbitration Count */
+
+/* SerDes Control */
+#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400
+
+/* Receive Checksum Control */
+#define E1000_RXCSUM_TUOFL     0x00000200   /* TCP / UDP checksum offload */
+#define E1000_RXCSUM_IPPCSE    0x00001000   /* IP payload checksum enable */
+#define E1000_RXCSUM_PCSD      0x00002000   /* packet checksum disabled */
+
+/* Header split receive */
+
+/* Collision related configuration parameters */
+#define E1000_COLLISION_THRESHOLD       15
+#define E1000_CT_SHIFT                  4
+#define E1000_COLLISION_DISTANCE        63
+#define E1000_COLD_SHIFT                12
+
+/* Ethertype field values */
+#define ETHERNET_IEEE_VLAN_TYPE 0x8100  /* 802.3ac packet */
+
+#define MAX_JUMBO_FRAME_SIZE    0x3F00
+
+/* Extended Configuration Control and Size */
+#define E1000_PHY_CTRL_GBE_DISABLE        0x00000040
+
+/* PBA constants */
+#define E1000_PBA_16K 0x0010    /* 16KB, default TX allocation */
+#define E1000_PBA_24K 0x0018
+#define E1000_PBA_34K 0x0022
+
+#define IFS_MAX       80
+#define IFS_MIN       40
+#define IFS_RATIO     4
+#define IFS_STEP      10
+#define MIN_NUM_XMITS 1000
+
+/* SW Semaphore Register */
+#define E1000_SWSM_SMBI         0x00000001 /* Driver Semaphore bit */
+#define E1000_SWSM_SWESMBI      0x00000002 /* FW Semaphore bit */
+
+/* Interrupt Cause Read */
+#define E1000_ICR_TXDW          0x00000001 /* Transmit desc written back */
+#define E1000_ICR_TXQE          0x00000002 /* Transmit Queue empty */
+#define E1000_ICR_LSC           0x00000004 /* Link Status Change */
+#define E1000_ICR_RXSEQ         0x00000008 /* rx sequence error */
+#define E1000_ICR_RXDMT0        0x00000010 /* rx desc min. threshold (0) */
+#define E1000_ICR_RXO           0x00000040 /* rx overrun */
+#define E1000_ICR_RXT0          0x00000080 /* rx timer intr (ring 0) */
+#define E1000_ICR_MDAC          0x00000200 /* MDIO access complete */
+#define E1000_ICR_RXCFG         0x00000400 /* RX /c/ ordered set */
+#define E1000_ICR_GPI_EN0       0x00000800 /* GP Int 0 */
+#define E1000_ICR_GPI_EN1       0x00001000 /* GP Int 1 */
+#define E1000_ICR_GPI_EN2       0x00002000 /* GP Int 2 */
+#define E1000_ICR_GPI_EN3       0x00004000 /* GP Int 3 */
+#define E1000_ICR_TXD_LOW       0x00008000
+#define E1000_ICR_SRPD          0x00010000
+#define E1000_ICR_ACK           0x00020000 /* Receive Ack frame */
+#define E1000_ICR_MNG           0x00040000 /* Manageability event */
+#define E1000_ICR_DOCK          0x00080000 /* Dock/Undock */
+/* If this bit asserted, the driver should claim the interrupt */
+#define E1000_ICR_INT_ASSERTED  0x80000000
+/* queue 0 Rx descriptor FIFO parity error */
+#define E1000_ICR_RXD_FIFO_PAR0 0x00100000
+/* queue 0 Tx descriptor FIFO parity error */
+#define E1000_ICR_TXD_FIFO_PAR0 0x00200000
+/* host arb read buffer parity error */
+#define E1000_ICR_HOST_ARB_PAR  0x00400000
+#define E1000_ICR_PB_PAR        0x00800000 /* packet buffer parity error */
+/* queue 1 Rx descriptor FIFO parity error */
+#define E1000_ICR_RXD_FIFO_PAR1 0x01000000
+/* queue 1 Tx descriptor FIFO parity error */
+#define E1000_ICR_TXD_FIFO_PAR1 0x02000000
+/* FW changed the status of DISSW bit in the FWSM */
+#define E1000_ICR_DSW           0x00000020
+/* LAN connected device generates an interrupt */
+#define E1000_ICR_PHYINT        0x00001000
+#define E1000_ICR_EPRST         0x00100000 /* ME handware reset occurs */
+
+/* Extended Interrupt Cause Read */
+#define E1000_EICR_RX_QUEUE0    0x00000001 /* Rx Queue 0 Interrupt */
+#define E1000_EICR_RX_QUEUE1    0x00000002 /* Rx Queue 1 Interrupt */
+#define E1000_EICR_RX_QUEUE2    0x00000004 /* Rx Queue 2 Interrupt */
+#define E1000_EICR_RX_QUEUE3    0x00000008 /* Rx Queue 3 Interrupt */
+#define E1000_EICR_TX_QUEUE0    0x00000100 /* Tx Queue 0 Interrupt */
+#define E1000_EICR_TX_QUEUE1    0x00000200 /* Tx Queue 1 Interrupt */
+#define E1000_EICR_TX_QUEUE2    0x00000400 /* Tx Queue 2 Interrupt */
+#define E1000_EICR_TX_QUEUE3    0x00000800 /* Tx Queue 3 Interrupt */
+#define E1000_EICR_TCP_TIMER    0x40000000 /* TCP Timer */
+#define E1000_EICR_OTHER        0x80000000 /* Interrupt Cause Active */
+/* TCP Timer */
+
+/*
+ * This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register.  Each bit is documented below:
+ *   o RXT0   = Receiver Timer Interrupt (ring 0)
+ *   o TXDW   = Transmit Descriptor Written Back
+ *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ *   o RXSEQ  = Receive Sequence Error
+ *   o LSC    = Link Status Change
+ */
+#define IMS_ENABLE_MASK ( \
+    E1000_IMS_RXT0   |    \
+    E1000_IMS_TXDW   |    \
+    E1000_IMS_RXDMT0 |    \
+    E1000_IMS_RXSEQ  |    \
+    E1000_IMS_LSC)
+
+/* Interrupt Mask Set */
+#define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
+#define E1000_IMS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_IMS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+/* queue 0 Rx descriptor FIFO parity error */
+/* queue 0 Tx descriptor FIFO parity error */
+/* host arb read buffer parity error */
+/* packet buffer parity error */
+/* queue 1 Rx descriptor FIFO parity error */
+/* queue 1 Tx descriptor FIFO parity error */
+
+/* Extended Interrupt Mask Set */
+#define E1000_EIMS_TCP_TIMER    E1000_EICR_TCP_TIMER /* TCP Timer */
+#define E1000_EIMS_OTHER        E1000_EICR_OTHER   /* Interrupt Cause Active */
+
+/* Interrupt Cause Set */
+#define E1000_ICS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_ICS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+/* queue 0 Rx descriptor FIFO parity error */
+/* queue 0 Tx descriptor FIFO parity error */
+/* host arb read buffer parity error */
+/* packet buffer parity error */
+/* queue 1 Rx descriptor FIFO parity error */
+/* queue 1 Tx descriptor FIFO parity error */
+
+/* Extended Interrupt Cause Set */
+
+/* Transmit Descriptor Control */
+/* Enable the counting of descriptors still to be processed. */
+
+/* Flow Control Constants */
+#define FLOW_CONTROL_ADDRESS_LOW  0x00C28001
+#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
+#define FLOW_CONTROL_TYPE         0x8808
+
+/* 802.1q VLAN Packet Size */
+#define VLAN_TAG_SIZE              4    /* 802.3ac tag (not DMA'd) */
+#define E1000_VLAN_FILTER_TBL_SIZE 128  /* VLAN Filter Table (4096 bits) */
+
+/* Receive Address */
+/*
+ * Number of high/low register pairs in the RAR. The RAR (Receive Address
+ * Registers) holds the directed and multicast addresses that we monitor.
+ * Technically, we have 16 spots.  However, we reserve one of these spots
+ * (RAR[15]) for our directed address used by controllers with
+ * manageability enabled, allowing us room for 15 multicast addresses.
+ */
+#define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
+
+/* Error Codes */
+#define E1000_ERR_NVM      1
+#define E1000_ERR_PHY      2
+#define E1000_ERR_CONFIG   3
+#define E1000_ERR_PARAM    4
+#define E1000_ERR_MAC_INIT 5
+#define E1000_ERR_RESET   9
+#define E1000_ERR_MASTER_REQUESTS_PENDING 10
+#define E1000_ERR_HOST_INTERFACE_COMMAND 11
+#define E1000_BLK_PHY_RESET   12
+#define E1000_ERR_SWFW_SYNC 13
+#define E1000_NOT_IMPLEMENTED 14
+
+/* Loop limit on how long we wait for auto-negotiation to complete */
+#define COPPER_LINK_UP_LIMIT              10
+#define PHY_AUTO_NEG_LIMIT                45
+#define PHY_FORCE_LIMIT                   20
+/* Number of 100 microseconds we wait for PCI Express master disable */
+#define MASTER_DISABLE_TIMEOUT      800
+/* Number of milliseconds we wait for PHY configuration done after MAC reset */
+#define PHY_CFG_TIMEOUT             100
+/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */
+/* Number of milliseconds for NVM auto read done after MAC reset. */
+#define AUTO_READ_DONE_TIMEOUT      10
+
+/* Flow Control */
+#define E1000_FCRTL_XONE 0x80000000     /* Enable XON frame transmission */
+
+/* Transmit Configuration Word */
+#define E1000_TXCW_ANE        0x80000000        /* Auto-neg enable */
+
+/* Receive Configuration Word */
+
+/* PCI Express Control */
+#define E1000_GCR_RXD_NO_SNOOP          0x00000001
+#define E1000_GCR_RXDSCW_NO_SNOOP       0x00000002
+#define E1000_GCR_RXDSCR_NO_SNOOP       0x00000004
+#define E1000_GCR_TXD_NO_SNOOP          0x00000008
+#define E1000_GCR_TXDSCW_NO_SNOOP       0x00000010
+#define E1000_GCR_TXDSCR_NO_SNOOP       0x00000020
+
+#define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP         | \
+                          E1000_GCR_RXDSCW_NO_SNOOP      | \
+                          E1000_GCR_RXDSCR_NO_SNOOP      | \
+                          E1000_GCR_TXD_NO_SNOOP         | \
+                          E1000_GCR_TXDSCW_NO_SNOOP      | \
+                          E1000_GCR_TXDSCR_NO_SNOOP)
+
+/* PHY Control Register */
+#define MII_CR_FULL_DUPLEX      0x0100  /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200  /* Restart auto negotiation */
+#define MII_CR_AUTO_NEG_EN      0x1000  /* Auto Neg Enable */
+#define MII_CR_LOOPBACK         0x4000  /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET            0x8000  /* 0 = normal, 1 = PHY reset */
+#define MII_CR_SPEED_1000       0x0040
+#define MII_CR_SPEED_100        0x2000
+#define MII_CR_SPEED_10         0x0000
+
+/* PHY Status Register */
+#define MII_SR_LINK_STATUS       0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_COMPLETE  0x0020 /* Auto Neg Complete */
+
+/* Autoneg Advertisement Register */
+#define NWAY_AR_10T_HD_CAPS      0x0020   /* 10T   Half Duplex Capable */
+#define NWAY_AR_10T_FD_CAPS      0x0040   /* 10T   Full Duplex Capable */
+#define NWAY_AR_100TX_HD_CAPS    0x0080   /* 100TX Half Duplex Capable */
+#define NWAY_AR_100TX_FD_CAPS    0x0100   /* 100TX Full Duplex Capable */
+#define NWAY_AR_PAUSE            0x0400   /* Pause operation desired */
+#define NWAY_AR_ASM_DIR          0x0800   /* Asymmetric Pause Direction bit */
+
+/* Link Partner Ability Register (Base Page) */
+#define NWAY_LPAR_PAUSE          0x0400 /* LP Pause operation desired */
+#define NWAY_LPAR_ASM_DIR        0x0800 /* LP Asymmetric Pause Direction bit */
+
+/* Autoneg Expansion Register */
+
+/* 1000BASE-T Control Register */
+#define CR_1000T_HD_CAPS         0x0100 /* Advertise 1000T HD capability */
+#define CR_1000T_FD_CAPS         0x0200 /* Advertise 1000T FD capability  */
+                                       /* 0=DTE device */
+#define CR_1000T_MS_VALUE        0x0800 /* 1=Configure PHY as Master */
+                                       /* 0=Configure PHY as Slave */
+#define CR_1000T_MS_ENABLE       0x1000 /* 1=Master/Slave manual config value */
+                                       /* 0=Automatic Master/Slave config */
+
+/* 1000BASE-T Status Register */
+#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define SR_1000T_LOCAL_RX_STATUS  0x2000 /* Local receiver OK */
+
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CONTROL      0x00 /* Control Register */
+#define PHY_STATUS       0x01 /* Status Regiser */
+#define PHY_ID1          0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2          0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV  0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY   0x05 /* Link Partner Ability (Base Page) */
+#define PHY_1000T_CTRL   0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+
+/* NVM Control */
+#define E1000_EECD_SK        0x00000001 /* NVM Clock */
+#define E1000_EECD_CS        0x00000002 /* NVM Chip Select */
+#define E1000_EECD_DI        0x00000004 /* NVM Data In */
+#define E1000_EECD_DO        0x00000008 /* NVM Data Out */
+#define E1000_EECD_REQ       0x00000040 /* NVM Access Request */
+#define E1000_EECD_GNT       0x00000080 /* NVM Access Grant */
+#define E1000_EECD_PRES      0x00000100 /* NVM Present */
+/* NVM Addressing bits based on type 0=small, 1=large */
+#define E1000_EECD_ADDR_BITS 0x00000400
+#define E1000_NVM_GRANT_ATTEMPTS   1000 /* NVM # attempts to gain grant */
+#define E1000_EECD_AUTO_RD          0x00000200  /* NVM Auto Read done */
+#define E1000_EECD_SIZE_EX_MASK     0x00007800  /* NVM Size */
+#define E1000_EECD_SIZE_EX_SHIFT     11
+
+/* Offset to data in NVM read/write registers */
+#define E1000_NVM_RW_REG_DATA   16
+#define E1000_NVM_RW_REG_DONE   2    /* Offset to READ/WRITE done bit */
+#define E1000_NVM_RW_REG_START  1    /* Start operation */
+#define E1000_NVM_RW_ADDR_SHIFT 2    /* Shift to the address bits */
+#define E1000_NVM_POLL_READ     0    /* Flag for polling for read complete */
+
+/* NVM Word Offsets */
+#define NVM_ID_LED_SETTINGS        0x0004
+/* For SERDES output amplitude adjustment. */
+#define NVM_INIT_CONTROL2_REG      0x000F
+#define NVM_INIT_CONTROL3_PORT_A   0x0024
+#define NVM_ALT_MAC_ADDR_PTR       0x0037
+#define NVM_CHECKSUM_REG           0x003F
+
+#define E1000_NVM_CFG_DONE_PORT_0  0x40000 /* MNG config cycle done */
+#define E1000_NVM_CFG_DONE_PORT_1  0x80000 /* ...for second port */
+
+/* Mask bits for fields in Word 0x0f of the NVM */
+#define NVM_WORD0F_PAUSE_MASK       0x3000
+#define NVM_WORD0F_ASM_DIR          0x2000
+
+/* Mask bits for fields in Word 0x1a of the NVM */
+
+/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */
+#define NVM_SUM                    0xBABA
+
+#define NVM_PBA_OFFSET_0           8
+#define NVM_PBA_OFFSET_1           9
+#define NVM_WORD_SIZE_BASE_SHIFT   6
+
+/* NVM Commands - Microwire */
+
+/* NVM Commands - SPI */
+#define NVM_MAX_RETRY_SPI          5000 /* Max wait of 5ms, for RDY signal */
+#define NVM_WRITE_OPCODE_SPI       0x02 /* NVM write opcode */
+#define NVM_A8_OPCODE_SPI          0x08 /* opcode bit-3 = address bit-8 */
+#define NVM_WREN_OPCODE_SPI        0x06 /* NVM set Write Enable latch */
+#define NVM_RDSR_OPCODE_SPI        0x05 /* NVM read Status register */
+
+/* SPI NVM Status Register */
+#define NVM_STATUS_RDY_SPI         0x01
+
+/* Word definitions for ID LED Settings */
+#define ID_LED_RESERVED_0000 0x0000
+#define ID_LED_RESERVED_FFFF 0xFFFF
+#define ID_LED_DEFAULT       ((ID_LED_OFF1_ON2  << 12) | \
+                             (ID_LED_OFF1_OFF2 <<  8) | \
+                             (ID_LED_DEF1_DEF2 <<  4) | \
+                             (ID_LED_DEF1_DEF2))
+#define ID_LED_DEF1_DEF2     0x1
+#define ID_LED_DEF1_ON2      0x2
+#define ID_LED_DEF1_OFF2     0x3
+#define ID_LED_ON1_DEF2      0x4
+#define ID_LED_ON1_ON2       0x5
+#define ID_LED_ON1_OFF2      0x6
+#define ID_LED_OFF1_DEF2     0x7
+#define ID_LED_OFF1_ON2      0x8
+#define ID_LED_OFF1_OFF2     0x9
+
+#define IGP_ACTIVITY_LED_MASK   0xFFFFF0FF
+#define IGP_ACTIVITY_LED_ENABLE 0x0300
+#define IGP_LED3_MODE           0x07000000
+
+/* PCI/PCI-X/PCI-EX Config space */
+#define PCI_HEADER_TYPE_REGISTER     0x0E
+#define PCIE_LINK_STATUS             0x12
+
+#define PCI_HEADER_TYPE_MULTIFUNC    0x80
+#define PCIE_LINK_WIDTH_MASK         0x3F0
+#define PCIE_LINK_WIDTH_SHIFT        4
+
+#define PHY_REVISION_MASK      0xFFFFFFF0
+#define MAX_PHY_REG_ADDRESS    0x1F  /* 5 bit address bus (0-0x1F) */
+#define MAX_PHY_MULTI_PAGE_REG 0xF
+
+/* Bit definitions for valid PHY IDs. */
+/*
+ * I = Integrated
+ * E = External
+ */
+#define M88E1111_I_PHY_ID    0x01410CC0
+#define IGP03E1000_E_PHY_ID  0x02A80390
+#define M88_VENDOR           0x0141
+
+/* M88E1000 Specific Registers */
+#define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
+#define M88E1000_PHY_SPEC_STATUS   0x11  /* PHY Specific Status Register */
+#define M88E1000_EXT_PHY_SPEC_CTRL 0x14  /* Extended PHY Specific Control */
+
+#define M88E1000_PHY_PAGE_SELECT   0x1D  /* Reg 29 for page number setting */
+#define M88E1000_PHY_GEN_CONTROL   0x1E  /* Its meaning depends on reg 29 */
+
+/* M88E1000 PHY Specific Control Register */
+#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */
+/* 1=CLK125 low, 0=CLK125 toggling */
+#define M88E1000_PSCR_MDI_MANUAL_MODE  0x0000  /* MDI Crossover Mode bits 6:5 */
+                                              /* Manual MDI configuration */
+#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020  /* Manual MDIX configuration */
+/* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */
+#define M88E1000_PSCR_AUTO_X_1000T     0x0040
+/* Auto crossover enabled all speeds */
+#define M88E1000_PSCR_AUTO_X_MODE      0x0060
+/*
+ * 1=Enable Extended 10BASE-T distance (Lower 10BASE-T RX Threshold
+ * 0=Normal 10BASE-T RX Threshold
+ */
+/* 1=5-bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */
+#define M88E1000_PSCR_ASSERT_CRS_ON_TX     0x0800 /* 1=Assert CRS on Transmit */
+
+/* M88E1000 PHY Specific Status Register */
+#define M88E1000_PSSR_REV_POLARITY       0x0002 /* 1=Polarity reversed */
+#define M88E1000_PSSR_DOWNSHIFT          0x0020 /* 1=Downshifted */
+#define M88E1000_PSSR_MDIX               0x0040 /* 1=MDIX; 0=MDI */
+/*
+ * 0 = <50M
+ * 1 = 50-80M
+ * 2 = 80-110M
+ * 3 = 110-140M
+ * 4 = >140M
+ */
+#define M88E1000_PSSR_CABLE_LENGTH       0x0380
+#define M88E1000_PSSR_SPEED              0xC000 /* Speed, bits 14:15 */
+#define M88E1000_PSSR_1000MBS            0x8000 /* 10=1000Mbs */
+
+#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
+
+/* M88E1000 Extended PHY Specific Control Register */
+/*
+ * 1 = Lost lock detect enabled.
+ * Will assert lost lock and bring
+ * link down if idle not seen
+ * within 1ms in 1000BASE-T
+ */
+/*
+ * Number of times we will attempt to autonegotiate before downshifting if we
+ * are the master
+ */
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X   0x0000
+/*
+ * Number of times we will attempt to autonegotiate before downshifting if we
+ * are the slave
+ */
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK  0x0300
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X    0x0100
+#define M88E1000_EPSCR_TX_CLK_25      0x0070 /* 25  MHz TX_CLK */
+
+/* M88EC018 Rev 2 specific DownShift settings */
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK  0x0E00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X    0x0800
+
+/* MDI Control */
+#define E1000_MDIC_REG_SHIFT 16
+#define E1000_MDIC_PHY_SHIFT 21
+#define E1000_MDIC_OP_WRITE  0x04000000
+#define E1000_MDIC_OP_READ   0x08000000
+#define E1000_MDIC_READY     0x10000000
+#define E1000_MDIC_ERROR     0x40000000
+
+/* SerDes Control */
+#define E1000_GEN_CTL_READY             0x80000000
+#define E1000_GEN_CTL_ADDRESS_SHIFT     8
+#define E1000_GEN_POLL_TIMEOUT          640
+
+#endif
diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h
new file mode 100644 (file)
index 0000000..161fb68
--- /dev/null
@@ -0,0 +1,599 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_HW_H_
+#define _E1000_HW_H_
+
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include "e1000_mac.h"
+#include "e1000_regs.h"
+#include "e1000_defines.h"
+
+struct e1000_hw;
+
+#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_REVISION_2 2
+#define E1000_REVISION_4 4
+
+#define E1000_FUNC_1     1
+
+enum e1000_mac_type {
+       e1000_undefined = 0,
+       e1000_82575,
+       e1000_num_macs  /* List is 1-based, so subtract 1 for true count. */
+};
+
+enum e1000_media_type {
+       e1000_media_type_unknown = 0,
+       e1000_media_type_copper = 1,
+       e1000_media_type_fiber = 2,
+       e1000_media_type_internal_serdes = 3,
+       e1000_num_media_types
+};
+
+enum e1000_nvm_type {
+       e1000_nvm_unknown = 0,
+       e1000_nvm_none,
+       e1000_nvm_eeprom_spi,
+       e1000_nvm_eeprom_microwire,
+       e1000_nvm_flash_hw,
+       e1000_nvm_flash_sw
+};
+
+enum e1000_nvm_override {
+       e1000_nvm_override_none = 0,
+       e1000_nvm_override_spi_small,
+       e1000_nvm_override_spi_large,
+       e1000_nvm_override_microwire_small,
+       e1000_nvm_override_microwire_large
+};
+
+enum e1000_phy_type {
+       e1000_phy_unknown = 0,
+       e1000_phy_none,
+       e1000_phy_m88,
+       e1000_phy_igp,
+       e1000_phy_igp_2,
+       e1000_phy_gg82563,
+       e1000_phy_igp_3,
+       e1000_phy_ife,
+};
+
+enum e1000_bus_type {
+       e1000_bus_type_unknown = 0,
+       e1000_bus_type_pci,
+       e1000_bus_type_pcix,
+       e1000_bus_type_pci_express,
+       e1000_bus_type_reserved
+};
+
+enum e1000_bus_speed {
+       e1000_bus_speed_unknown = 0,
+       e1000_bus_speed_33,
+       e1000_bus_speed_66,
+       e1000_bus_speed_100,
+       e1000_bus_speed_120,
+       e1000_bus_speed_133,
+       e1000_bus_speed_2500,
+       e1000_bus_speed_5000,
+       e1000_bus_speed_reserved
+};
+
+enum e1000_bus_width {
+       e1000_bus_width_unknown = 0,
+       e1000_bus_width_pcie_x1,
+       e1000_bus_width_pcie_x2,
+       e1000_bus_width_pcie_x4 = 4,
+       e1000_bus_width_pcie_x8 = 8,
+       e1000_bus_width_32,
+       e1000_bus_width_64,
+       e1000_bus_width_reserved
+};
+
+enum e1000_1000t_rx_status {
+       e1000_1000t_rx_status_not_ok = 0,
+       e1000_1000t_rx_status_ok,
+       e1000_1000t_rx_status_undefined = 0xFF
+};
+
+enum e1000_rev_polarity {
+       e1000_rev_polarity_normal = 0,
+       e1000_rev_polarity_reversed,
+       e1000_rev_polarity_undefined = 0xFF
+};
+
+enum e1000_fc_type {
+       e1000_fc_none = 0,
+       e1000_fc_rx_pause,
+       e1000_fc_tx_pause,
+       e1000_fc_full,
+       e1000_fc_default = 0xFF
+};
+
+
+/* Receive Descriptor */
+struct e1000_rx_desc {
+       u64 buffer_addr; /* Address of the descriptor's data buffer */
+       u16 length;      /* Length of data DMAed into data buffer */
+       u16 csum;        /* Packet checksum */
+       u8  status;      /* Descriptor status */
+       u8  errors;      /* Descriptor Errors */
+       u16 special;
+};
+
+/* Receive Descriptor - Extended */
+union e1000_rx_desc_extended {
+       struct {
+               u64 buffer_addr;
+               u64 reserved;
+       } read;
+       struct {
+               struct {
+                       u32 mrq;              /* Multiple Rx Queues */
+                       union {
+                               u32 rss;            /* RSS Hash */
+                               struct {
+                                       u16 ip_id;  /* IP id */
+                                       u16 csum;   /* Packet Checksum */
+                               } csum_ip;
+                       } hi_dword;
+               } lower;
+               struct {
+                       u32 status_error;     /* ext status/error */
+                       u16 length;
+                       u16 vlan;             /* VLAN tag */
+               } upper;
+       } wb;  /* writeback */
+};
+
+#define MAX_PS_BUFFERS 4
+/* Receive Descriptor - Packet Split */
+union e1000_rx_desc_packet_split {
+       struct {
+               /* one buffer for protocol header(s), three data buffers */
+               u64 buffer_addr[MAX_PS_BUFFERS];
+       } read;
+       struct {
+               struct {
+                       u32 mrq;              /* Multiple Rx Queues */
+                       union {
+                               u32 rss;              /* RSS Hash */
+                               struct {
+                                       u16 ip_id;    /* IP id */
+                                       u16 csum;     /* Packet Checksum */
+                               } csum_ip;
+                       } hi_dword;
+               } lower;
+               struct {
+                       u32 status_error;     /* ext status/error */
+                       u16 length0;          /* length of buffer 0 */
+                       u16 vlan;             /* VLAN tag */
+               } middle;
+               struct {
+                       u16 header_status;
+                       u16 length[3];        /* length of buffers 1-3 */
+               } upper;
+               u64 reserved;
+       } wb; /* writeback */
+};
+
+/* Transmit Descriptor */
+struct e1000_tx_desc {
+       u64 buffer_addr;      /* Address of the descriptor's data buffer */
+       union {
+               u32 data;
+               struct {
+                       u16 length;    /* Data buffer length */
+                       u8 cso;        /* Checksum offset */
+                       u8 cmd;        /* Descriptor control */
+               } flags;
+       } lower;
+       union {
+               u32 data;
+               struct {
+                       u8 status;     /* Descriptor status */
+                       u8 css;        /* Checksum start */
+                       u16 special;
+               } fields;
+       } upper;
+};
+
+/* Offload Context Descriptor */
+struct e1000_context_desc {
+       union {
+               u32 ip_config;
+               struct {
+                       u8 ipcss;      /* IP checksum start */
+                       u8 ipcso;      /* IP checksum offset */
+                       u16 ipcse;     /* IP checksum end */
+               } ip_fields;
+       } lower_setup;
+       union {
+               u32 tcp_config;
+               struct {
+                       u8 tucss;      /* TCP checksum start */
+                       u8 tucso;      /* TCP checksum offset */
+                       u16 tucse;     /* TCP checksum end */
+               } tcp_fields;
+       } upper_setup;
+       u32 cmd_and_length;
+       union {
+               u32 data;
+               struct {
+                       u8 status;     /* Descriptor status */
+                       u8 hdr_len;    /* Header length */
+                       u16 mss;       /* Maximum segment size */
+               } fields;
+       } tcp_seg_setup;
+};
+
+/* Offload data descriptor */
+struct e1000_data_desc {
+       u64 buffer_addr;   /* Address of the descriptor's buffer address */
+       union {
+               u32 data;
+               struct {
+                       u16 length;    /* Data buffer length */
+                       u8 typ_len_ext;
+                       u8 cmd;
+               } flags;
+       } lower;
+       union {
+               u32 data;
+               struct {
+                       u8 status;     /* Descriptor status */
+                       u8 popts;      /* Packet Options */
+                       u16 special;
+               } fields;
+       } upper;
+};
+
+/* Statistics counters collected by the MAC */
+struct e1000_hw_stats {
+       u64 crcerrs;
+       u64 algnerrc;
+       u64 symerrs;
+       u64 rxerrc;
+       u64 mpc;
+       u64 scc;
+       u64 ecol;
+       u64 mcc;
+       u64 latecol;
+       u64 colc;
+       u64 dc;
+       u64 tncrs;
+       u64 sec;
+       u64 cexterr;
+       u64 rlec;
+       u64 xonrxc;
+       u64 xontxc;
+       u64 xoffrxc;
+       u64 xofftxc;
+       u64 fcruc;
+       u64 prc64;
+       u64 prc127;
+       u64 prc255;
+       u64 prc511;
+       u64 prc1023;
+       u64 prc1522;
+       u64 gprc;
+       u64 bprc;
+       u64 mprc;
+       u64 gptc;
+       u64 gorc;
+       u64 gotc;
+       u64 rnbc;
+       u64 ruc;
+       u64 rfc;
+       u64 roc;
+       u64 rjc;
+       u64 mgprc;
+       u64 mgpdc;
+       u64 mgptc;
+       u64 tor;
+       u64 tot;
+       u64 tpr;
+       u64 tpt;
+       u64 ptc64;
+       u64 ptc127;
+       u64 ptc255;
+       u64 ptc511;
+       u64 ptc1023;
+       u64 ptc1522;
+       u64 mptc;
+       u64 bptc;
+       u64 tsctc;
+       u64 tsctfc;
+       u64 iac;
+       u64 icrxptc;
+       u64 icrxatc;
+       u64 ictxptc;
+       u64 ictxatc;
+       u64 ictxqec;
+       u64 ictxqmtc;
+       u64 icrxdmtc;
+       u64 icrxoc;
+       u64 cbtmpc;
+       u64 htdpmc;
+       u64 cbrdpc;
+       u64 cbrmpc;
+       u64 rpthc;
+       u64 hgptc;
+       u64 htcbdpc;
+       u64 hgorc;
+       u64 hgotc;
+       u64 lenerrs;
+       u64 scvpc;
+       u64 hrmpc;
+};
+
+struct e1000_phy_stats {
+       u32 idle_errors;
+       u32 receive_errors;
+};
+
+struct e1000_host_mng_dhcp_cookie {
+       u32 signature;
+       u8  status;
+       u8  reserved0;
+       u16 vlan_id;
+       u32 reserved1;
+       u16 reserved2;
+       u8  reserved3;
+       u8  checksum;
+};
+
+/* Host Interface "Rev 1" */
+struct e1000_host_command_header {
+       u8 command_id;
+       u8 command_length;
+       u8 command_options;
+       u8 checksum;
+};
+
+#define E1000_HI_MAX_DATA_LENGTH     252
+struct e1000_host_command_info {
+       struct e1000_host_command_header command_header;
+       u8 command_data[E1000_HI_MAX_DATA_LENGTH];
+};
+
+/* Host Interface "Rev 2" */
+struct e1000_host_mng_command_header {
+       u8  command_id;
+       u8  checksum;
+       u16 reserved1;
+       u16 reserved2;
+       u16 command_length;
+};
+
+#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8
+struct e1000_host_mng_command_info {
+       struct e1000_host_mng_command_header command_header;
+       u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH];
+};
+
+#include "e1000_mac.h"
+#include "e1000_phy.h"
+#include "e1000_nvm.h"
+
+struct e1000_mac_operations {
+       s32  (*check_for_link)(struct e1000_hw *);
+       s32  (*reset_hw)(struct e1000_hw *);
+       s32  (*init_hw)(struct e1000_hw *);
+       s32  (*setup_physical_interface)(struct e1000_hw *);
+       void (*rar_set)(struct e1000_hw *, u8 *, u32);
+       s32  (*read_mac_addr)(struct e1000_hw *);
+       s32  (*get_speed_and_duplex)(struct e1000_hw *, u16 *, u16 *);
+};
+
+struct e1000_phy_operations {
+       s32  (*acquire_phy)(struct e1000_hw *);
+       s32  (*force_speed_duplex)(struct e1000_hw *);
+       s32  (*get_cfg_done)(struct e1000_hw *hw);
+       s32  (*get_cable_length)(struct e1000_hw *);
+       s32  (*get_phy_info)(struct e1000_hw *);
+       s32  (*read_phy_reg)(struct e1000_hw *, u32, u16 *);
+       void (*release_phy)(struct e1000_hw *);
+       s32  (*reset_phy)(struct e1000_hw *);
+       s32  (*set_d0_lplu_state)(struct e1000_hw *, bool);
+       s32  (*set_d3_lplu_state)(struct e1000_hw *, bool);
+       s32  (*write_phy_reg)(struct e1000_hw *, u32, u16);
+};
+
+struct e1000_nvm_operations {
+       s32  (*acquire_nvm)(struct e1000_hw *);
+       s32  (*read_nvm)(struct e1000_hw *, u16, u16, u16 *);
+       void (*release_nvm)(struct e1000_hw *);
+       s32  (*write_nvm)(struct e1000_hw *, u16, u16, u16 *);
+};
+
+struct e1000_info {
+       s32 (*get_invariants)(struct e1000_hw *);
+       struct e1000_mac_operations *mac_ops;
+       struct e1000_phy_operations *phy_ops;
+       struct e1000_nvm_operations *nvm_ops;
+};
+
+extern const struct e1000_info e1000_82575_info;
+
+struct e1000_mac_info {
+       struct e1000_mac_operations ops;
+
+       u8 addr[6];
+       u8 perm_addr[6];
+
+       enum e1000_mac_type type;
+
+       u32 collision_delta;
+       u32 ledctl_default;
+       u32 ledctl_mode1;
+       u32 ledctl_mode2;
+       u32 mc_filter_type;
+       u32 tx_packet_delta;
+       u32 txcw;
+
+       u16 current_ifs_val;
+       u16 ifs_max_val;
+       u16 ifs_min_val;
+       u16 ifs_ratio;
+       u16 ifs_step_size;
+       u16 mta_reg_count;
+       u16 rar_entry_count;
+
+       u8  forced_speed_duplex;
+
+       bool adaptive_ifs;
+       bool arc_subsystem_valid;
+       bool asf_firmware_present;
+       bool autoneg;
+       bool autoneg_failed;
+       bool disable_av;
+       bool disable_hw_init_bits;
+       bool get_link_status;
+       bool ifs_params_forced;
+       bool in_ifs_mode;
+       bool report_tx_early;
+       bool serdes_has_link;
+       bool tx_pkt_filtering;
+};
+
+struct e1000_phy_info {
+       struct e1000_phy_operations ops;
+
+       enum e1000_phy_type type;
+
+       enum e1000_1000t_rx_status local_rx;
+       enum e1000_1000t_rx_status remote_rx;
+       enum e1000_ms_type ms_type;
+       enum e1000_ms_type original_ms_type;
+       enum e1000_rev_polarity cable_polarity;
+       enum e1000_smart_speed smart_speed;
+
+       u32 addr;
+       u32 id;
+       u32 reset_delay_us; /* in usec */
+       u32 revision;
+
+       enum e1000_media_type media_type;
+
+       u16 autoneg_advertised;
+       u16 autoneg_mask;
+       u16 cable_length;
+       u16 max_cable_length;
+       u16 min_cable_length;
+
+       u8 mdix;
+
+       bool disable_polarity_correction;
+       bool is_mdix;
+       bool polarity_correction;
+       bool reset_disable;
+       bool speed_downgraded;
+       bool autoneg_wait_to_complete;
+};
+
+struct e1000_nvm_info {
+       struct e1000_nvm_operations ops;
+
+       enum e1000_nvm_type type;
+       enum e1000_nvm_override override;
+
+       u32 flash_bank_size;
+       u32 flash_base_addr;
+
+       u16 word_size;
+       u16 delay_usec;
+       u16 address_bits;
+       u16 opcode_bits;
+       u16 page_size;
+};
+
+struct e1000_bus_info {
+       enum e1000_bus_type type;
+       enum e1000_bus_speed speed;
+       enum e1000_bus_width width;
+
+       u32 snoop;
+
+       u16 func;
+       u16 pci_cmd_word;
+};
+
+struct e1000_fc_info {
+       u32 high_water;     /* Flow control high-water mark */
+       u32 low_water;      /* Flow control low-water mark */
+       u16 pause_time;     /* Flow control pause timer */
+       bool send_xon;      /* Flow control send XON */
+       bool strict_ieee;   /* Strict IEEE mode */
+       enum e1000_fc_type type; /* Type of flow control */
+       enum e1000_fc_type original_type;
+};
+
+struct e1000_hw {
+       void *back;
+       void *dev_spec;
+
+       u8 __iomem *hw_addr;
+       u8 __iomem *flash_address;
+       unsigned long io_base;
+
+       struct e1000_mac_info  mac;
+       struct e1000_fc_info   fc;
+       struct e1000_phy_info  phy;
+       struct e1000_nvm_info  nvm;
+       struct e1000_bus_info  bus;
+       struct e1000_host_mng_dhcp_cookie mng_cookie;
+
+       u32 dev_spec_size;
+
+       u16 device_id;
+       u16 subsystem_vendor_id;
+       u16 subsystem_device_id;
+       u16 vendor_id;
+
+       u8  revision_id;
+};
+
+#ifdef DEBUG
+extern char *igb_get_hw_dev_name(struct e1000_hw *hw);
+#define hw_dbg(hw, format, arg...) \
+       printk(KERN_DEBUG "%s: " format, igb_get_hw_dev_name(hw), ##arg)
+#else
+static inline int __attribute__ ((format (printf, 2, 3)))
+hw_dbg(struct e1000_hw *hw, const char *format, ...)
+{
+       return 0;
+}
+#endif
+
+#endif
diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c
new file mode 100644 (file)
index 0000000..3e84a3f
--- /dev/null
@@ -0,0 +1,1505 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/if_ether.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+
+#include "e1000_mac.h"
+
+#include "igb.h"
+
+static s32 igb_set_default_fc(struct e1000_hw *hw);
+static s32 igb_set_fc_watermarks(struct e1000_hw *hw);
+static u32 igb_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr);
+
+/**
+ *  e1000_remove_device - Free device specific structure
+ *  @hw: pointer to the HW structure
+ *
+ *  If a device specific structure was allocated, this function will
+ *  free it.
+ **/
+void igb_remove_device(struct e1000_hw *hw)
+{
+       /* Freeing the dev_spec member of e1000_hw structure */
+       kfree(hw->dev_spec);
+}
+
+static void igb_read_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value)
+{
+       struct igb_adapter *adapter = hw->back;
+
+       pci_read_config_word(adapter->pdev, reg, value);
+}
+
+static s32 igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value)
+{
+       struct igb_adapter *adapter = hw->back;
+       u16 cap_offset;
+
+       cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+       if (!cap_offset)
+               return -E1000_ERR_CONFIG;
+
+       pci_read_config_word(adapter->pdev, cap_offset + reg, value);
+
+       return 0;
+}
+
+/**
+ *  e1000_get_bus_info_pcie - Get PCIe bus information
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines and stores the system bus information for a particular
+ *  network interface.  The following bus information is determined and stored:
+ *  bus speed, bus width, type (PCIe), and PCIe function.
+ **/
+s32 igb_get_bus_info_pcie(struct e1000_hw *hw)
+{
+       struct e1000_bus_info *bus = &hw->bus;
+       s32 ret_val;
+       u32 status;
+       u16 pcie_link_status, pci_header_type;
+
+       bus->type = e1000_bus_type_pci_express;
+       bus->speed = e1000_bus_speed_2500;
+
+       ret_val = igb_read_pcie_cap_reg(hw,
+                                         PCIE_LINK_STATUS,
+                                         &pcie_link_status);
+       if (ret_val)
+               bus->width = e1000_bus_width_unknown;
+       else
+               bus->width = (enum e1000_bus_width)((pcie_link_status &
+                                                    PCIE_LINK_WIDTH_MASK) >>
+                                                    PCIE_LINK_WIDTH_SHIFT);
+
+       igb_read_pci_cfg(hw, PCI_HEADER_TYPE_REGISTER, &pci_header_type);
+       if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) {
+               status = rd32(E1000_STATUS);
+               bus->func = (status & E1000_STATUS_FUNC_MASK)
+                           >> E1000_STATUS_FUNC_SHIFT;
+       } else {
+               bus->func = 0;
+       }
+
+       return 0;
+}
+
+/**
+ *  e1000_clear_vfta - Clear VLAN filter table
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the register array which contains the VLAN filter table by
+ *  setting all the values to 0.
+ **/
+void igb_clear_vfta(struct e1000_hw *hw)
+{
+       u32 offset;
+
+       for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
+               array_wr32(E1000_VFTA, offset, 0);
+               wrfl();
+       }
+}
+
+/**
+ *  e1000_write_vfta - Write value to VLAN filter table
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset in VLAN filter table
+ *  @value: register value written to VLAN filter table
+ *
+ *  Writes value at the given offset in the register array which stores
+ *  the VLAN filter table.
+ **/
+void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
+{
+       array_wr32(E1000_VFTA, offset, value);
+       wrfl();
+}
+
+/**
+ *  e1000_init_rx_addrs - Initialize receive address's
+ *  @hw: pointer to the HW structure
+ *  @rar_count: receive address registers
+ *
+ *  Setups the receive address registers by setting the base receive address
+ *  register to the devices MAC address and clearing all the other receive
+ *  address registers to 0.
+ **/
+void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count)
+{
+       u32 i;
+
+       /* Setup the receive address */
+       hw_dbg(hw, "Programming MAC Address into RAR[0]\n");
+
+       hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
+
+       /* Zero out the other (rar_entry_count - 1) receive addresses */
+       hw_dbg(hw, "Clearing RAR[1-%u]\n", rar_count-1);
+       for (i = 1; i < rar_count; i++) {
+               array_wr32(E1000_RA, (i << 1), 0);
+               wrfl();
+               array_wr32(E1000_RA, ((i << 1) + 1), 0);
+               wrfl();
+       }
+}
+
+/**
+ *  e1000_check_alt_mac_addr - Check for alternate MAC addr
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks the nvm for an alternate MAC address.  An alternate MAC address
+ *  can be setup by pre-boot software and must be treated like a permanent
+ *  address and must override the actual permanent MAC address.  If an
+ *  alternate MAC address is fopund it is saved in the hw struct and
+ *  prgrammed into RAR0 and the cuntion returns success, otherwise the
+ *  fucntion returns an error.
+ **/
+s32 igb_check_alt_mac_addr(struct e1000_hw *hw)
+{
+       u32 i;
+       s32 ret_val = 0;
+       u16 offset, nvm_alt_mac_addr_offset, nvm_data;
+       u8 alt_mac_addr[ETH_ALEN];
+
+       ret_val = hw->nvm.ops.read_nvm(hw, NVM_ALT_MAC_ADDR_PTR, 1,
+                                &nvm_alt_mac_addr_offset);
+       if (ret_val) {
+               hw_dbg(hw, "NVM Read Error\n");
+               goto out;
+       }
+
+       if (nvm_alt_mac_addr_offset == 0xFFFF) {
+               ret_val = -(E1000_NOT_IMPLEMENTED);
+               goto out;
+       }
+
+       if (hw->bus.func == E1000_FUNC_1)
+               nvm_alt_mac_addr_offset += ETH_ALEN/sizeof(u16);
+
+       for (i = 0; i < ETH_ALEN; i += 2) {
+               offset = nvm_alt_mac_addr_offset + (i >> 1);
+               ret_val = hw->nvm.ops.read_nvm(hw, offset, 1, &nvm_data);
+               if (ret_val) {
+                       hw_dbg(hw, "NVM Read Error\n");
+                       goto out;
+               }
+
+               alt_mac_addr[i] = (u8)(nvm_data & 0xFF);
+               alt_mac_addr[i + 1] = (u8)(nvm_data >> 8);
+       }
+
+       /* if multicast bit is set, the alternate address will not be used */
+       if (alt_mac_addr[0] & 0x01) {
+               ret_val = -(E1000_NOT_IMPLEMENTED);
+               goto out;
+       }
+
+       for (i = 0; i < ETH_ALEN; i++)
+               hw->mac.addr[i] = hw->mac.perm_addr[i] = alt_mac_addr[i];
+
+       hw->mac.ops.rar_set(hw, hw->mac.perm_addr, 0);
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_rar_set - Set receive address register
+ *  @hw: pointer to the HW structure
+ *  @addr: pointer to the receive address
+ *  @index: receive address array register
+ *
+ *  Sets the receive address array register at index to the address passed
+ *  in by addr.
+ **/
+void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index)
+{
+       u32 rar_low, rar_high;
+
+       /*
+        * HW expects these in little endian so we reverse the byte order
+        * from network order (big endian) to little endian
+        */
+       rar_low = ((u32) addr[0] |
+                  ((u32) addr[1] << 8) |
+                   ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
+
+       rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
+
+       if (!hw->mac.disable_av)
+               rar_high |= E1000_RAH_AV;
+
+       array_wr32(E1000_RA, (index << 1), rar_low);
+       array_wr32(E1000_RA, ((index << 1) + 1), rar_high);
+}
+
+/**
+ *  e1000_mta_set - 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 igb_mta_set(struct e1000_hw *hw, u32 hash_value)
+{
+       u32 hash_bit, hash_reg, mta;
+
+       /*
+        * 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 = array_rd32(E1000_MTA, hash_reg);
+
+       mta |= (1 << hash_bit);
+
+       array_wr32(E1000_MTA, hash_reg, mta);
+       wrfl();
+}
+
+/**
+ *  e1000_update_mc_addr_list - Update Multicast addresses
+ *  @hw: pointer to the HW structure
+ *  @mc_addr_list: array of multicast addresses to program
+ *  @mc_addr_count: number of multicast addresses to program
+ *  @rar_used_count: the first RAR register free to program
+ *  @rar_count: total number of supported Receive Address Registers
+ *
+ *  Updates the Receive Address Registers and Multicast Table Array.
+ *  The caller must have a packed mc_addr_list of multicast addresses.
+ *  The parameter rar_count will usually be hw->mac.rar_entry_count
+ *  unless there are workarounds that change this.
+ **/
+void igb_update_mc_addr_list(struct e1000_hw *hw,
+                              u8 *mc_addr_list, u32 mc_addr_count,
+                              u32 rar_used_count, u32 rar_count)
+{
+       u32 hash_value;
+       u32 i;
+
+       /*
+        * Load the first set of multicast addresses into the exact
+        * filters (RAR).  If there are not enough to fill the RAR
+        * array, clear the filters.
+        */
+       for (i = rar_used_count; i < rar_count; i++) {
+               if (mc_addr_count) {
+                       hw->mac.ops.rar_set(hw, mc_addr_list, i);
+                       mc_addr_count--;
+                       mc_addr_list += ETH_ALEN;
+               } else {
+                       array_wr32(E1000_RA, i << 1, 0);
+                       wrfl();
+                       array_wr32(E1000_RA, (i << 1) + 1, 0);
+                       wrfl();
+               }
+       }
+
+       /* Clear the old settings from the MTA */
+       hw_dbg(hw, "Clearing MTA\n");
+       for (i = 0; i < hw->mac.mta_reg_count; i++) {
+               array_wr32(E1000_MTA, i, 0);
+               wrfl();
+       }
+
+       /* Load any remaining multicast addresses into the hash table. */
+       for (; mc_addr_count > 0; mc_addr_count--) {
+               hash_value = igb_hash_mc_addr(hw, mc_addr_list);
+               hw_dbg(hw, "Hash value = 0x%03X\n", hash_value);
+               igb_mta_set(hw, hash_value);
+               mc_addr_list += ETH_ALEN;
+       }
+}
+
+/**
+ *  e1000_hash_mc_addr - Generate a multicast hash value
+ *  @hw: pointer to the HW structure
+ *  @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
+ *  igb_mta_set()
+ **/
+static u32 igb_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr)
+{
+       u32 hash_value, hash_mask;
+       u8 bit_shift = 0;
+
+       /* Register count multiplied by bits per register */
+       hash_mask = (hw->mac.mta_reg_count * 32) - 1;
+
+       /*
+        * For a mc_filter_type of 0, bit_shift is the number of left-shifts
+        * where 0xFF would still fall within the hash mask.
+        */
+       while (hash_mask >> bit_shift != 0xFF)
+               bit_shift++;
+
+       /*
+        * The portion of the address that is used for the hash table
+        * is determined by the mc_filter_type setting.
+        * The algorithm is such that there is a total of 8 bits of shifting.
+        * The bit_shift for a mc_filter_type of 0 represents the number of
+        * left-shifts where the MSB of mc_addr[5] would still fall within
+        * the hash_mask.  Case 0 does this exactly.  Since there are a total
+        * of 8 bits of shifting, then mc_addr[4] will shift right the
+        * remaining number of bits. Thus 8 - bit_shift.  The rest of the
+        * cases are a variation of this algorithm...essentially raising the
+        * number of bits to shift mc_addr[5] left, while still keeping the
+        * 8-bit shifting total.
+        *
+        * For example, given the following Destination MAC Address and an
+        * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask),
+        * we can see that the bit_shift for case 0 is 4.  These are the hash
+        * values resulting from each mc_filter_type...
+        * [0] [1] [2] [3] [4] [5]
+        * 01  AA  00  12  34  56
+        * LSB                 MSB
+        *
+        * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563
+        * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6
+        * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163
+        * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634
+        */
+       switch (hw->mac.mc_filter_type) {
+       default:
+       case 0:
+               break;
+       case 1:
+               bit_shift += 1;
+               break;
+       case 2:
+               bit_shift += 2;
+               break;
+       case 3:
+               bit_shift += 4;
+               break;
+       }
+
+       hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
+                                 (((u16) mc_addr[5]) << bit_shift)));
+
+       return hash_value;
+}
+
+/**
+ *  e1000_clear_hw_cntrs_base - Clear base hardware counters
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the base hardware counters by reading the counter registers.
+ **/
+void igb_clear_hw_cntrs_base(struct e1000_hw *hw)
+{
+       u32 temp;
+
+       temp = rd32(E1000_CRCERRS);
+       temp = rd32(E1000_SYMERRS);
+       temp = rd32(E1000_MPC);
+       temp = rd32(E1000_SCC);
+       temp = rd32(E1000_ECOL);
+       temp = rd32(E1000_MCC);
+       temp = rd32(E1000_LATECOL);
+       temp = rd32(E1000_COLC);
+       temp = rd32(E1000_DC);
+       temp = rd32(E1000_SEC);
+       temp = rd32(E1000_RLEC);
+       temp = rd32(E1000_XONRXC);
+       temp = rd32(E1000_XONTXC);
+       temp = rd32(E1000_XOFFRXC);
+       temp = rd32(E1000_XOFFTXC);
+       temp = rd32(E1000_FCRUC);
+       temp = rd32(E1000_GPRC);
+       temp = rd32(E1000_BPRC);
+       temp = rd32(E1000_MPRC);
+       temp = rd32(E1000_GPTC);
+       temp = rd32(E1000_GORCL);
+       temp = rd32(E1000_GORCH);
+       temp = rd32(E1000_GOTCL);
+       temp = rd32(E1000_GOTCH);
+       temp = rd32(E1000_RNBC);
+       temp = rd32(E1000_RUC);
+       temp = rd32(E1000_RFC);
+       temp = rd32(E1000_ROC);
+       temp = rd32(E1000_RJC);
+       temp = rd32(E1000_TORL);
+       temp = rd32(E1000_TORH);
+       temp = rd32(E1000_TOTL);
+       temp = rd32(E1000_TOTH);
+       temp = rd32(E1000_TPR);
+       temp = rd32(E1000_TPT);
+       temp = rd32(E1000_MPTC);
+       temp = rd32(E1000_BPTC);
+}
+
+/**
+ *  e1000_check_for_copper_link - 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.
+ **/
+s32 igb_check_for_copper_link(struct e1000_hw *hw)
+{
+       struct e1000_mac_info *mac = &hw->mac;
+       s32 ret_val;
+       bool link;
+
+       /*
+        * 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 = 0;
+               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 = igb_phy_has_link(hw, 1, 0, &link);
+       if (ret_val)
+               goto out;
+
+       if (!link)
+               goto out; /* No link detected */
+
+       mac->get_link_status = false;
+
+       /*
+        * Check if there was DownShift, must be checked
+        * immediately after link-up
+        */
+       igb_check_downshift(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.
+        */
+       igb_config_collision_dist(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 = igb_config_fc_after_link_up(hw);
+       if (ret_val)
+               hw_dbg(hw, "Error configuring flow control\n");
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_setup_link - Setup flow control and link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines which flow control settings to use, then configures flow
+ *  control.  Calls the appropriate media-specific link configuration
+ *  function.  Assuming the adapter has a valid link partner, a valid link
+ *  should be established.  Assumes the hardware has previously been reset
+ *  and the transmitter and receiver are not enabled.
+ **/
+s32 igb_setup_link(struct e1000_hw *hw)
+{
+       s32 ret_val = 0;
+
+       /*
+        * In the case of the phy reset being blocked, we already have a link.
+        * We do not need to set it up again.
+        */
+       if (igb_check_reset_block(hw))
+               goto out;
+
+       ret_val = igb_set_default_fc(hw);
+       if (ret_val)
+               goto out;
+
+       /*
+        * We want to save off the original Flow Control configuration just
+        * in case we get disconnected and then reconnected into a different
+        * hub or switch with different Flow Control capabilities.
+        */
+       hw->fc.original_type = hw->fc.type;
+
+       hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", hw->fc.type);
+
+       /* Call the necessary media_type subroutine to configure the link. */
+       ret_val = hw->mac.ops.setup_physical_interface(hw);
+       if (ret_val)
+               goto out;
+
+       /*
+        * Initialize the flow control address, type, and PAUSE timer
+        * registers to their default values.  This is done even if flow
+        * control is disabled, because it does not hurt anything to
+        * initialize these registers.
+        */
+       hw_dbg(hw,
+              "Initializing the Flow Control address, type and timer regs\n");
+       wr32(E1000_FCT, FLOW_CONTROL_TYPE);
+       wr32(E1000_FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+       wr32(E1000_FCAL, FLOW_CONTROL_ADDRESS_LOW);
+
+       wr32(E1000_FCTTV, hw->fc.pause_time);
+
+       ret_val = igb_set_fc_watermarks(hw);
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_config_collision_dist - Configure collision distance
+ *  @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.
+ **/
+void igb_config_collision_dist(struct e1000_hw *hw)
+{
+       u32 tctl;
+
+       tctl = rd32(E1000_TCTL);
+
+       tctl &= ~E1000_TCTL_COLD;
+       tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+
+       wr32(E1000_TCTL, tctl);
+       wrfl();
+}
+
+/**
+ *  e1000_set_fc_watermarks - Set flow control high/low watermarks
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets the flow control high/low threshold (watermark) registers.  If
+ *  flow control XON frame transmission is enabled, then set XON frame
+ *  tansmission as well.
+ **/
+static s32 igb_set_fc_watermarks(struct e1000_hw *hw)
+{
+       s32 ret_val = 0;
+       u32 fcrtl = 0, fcrth = 0;
+
+       /*
+        * Set the flow control receive threshold registers.  Normally,
+        * these registers will be set to a default threshold that may be
+        * adjusted later by the driver's runtime code.  However, if the
+        * ability to transmit pause frames is not enabled, then these
+        * registers will be set to 0.
+        */
+       if (hw->fc.type & e1000_fc_tx_pause) {
+               /*
+                * We need to set up the Receive Threshold high and low water
+                * marks as well as (optionally) enabling the transmission of
+                * XON frames.
+                */
+               fcrtl = hw->fc.low_water;
+               if (hw->fc.send_xon)
+                       fcrtl |= E1000_FCRTL_XONE;
+
+               fcrth = hw->fc.high_water;
+       }
+       wr32(E1000_FCRTL, fcrtl);
+       wr32(E1000_FCRTH, fcrth);
+
+       return ret_val;
+}
+
+/**
+ *  e1000_set_default_fc - Set flow control default values
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the EEPROM for the default values for flow control and store the
+ *  values.
+ **/
+static s32 igb_set_default_fc(struct e1000_hw *hw)
+{
+       s32 ret_val = 0;
+       u16 nvm_data;
+
+       /*
+        * Read and store word 0x0F of the EEPROM. This word contains bits
+        * that determine the hardware's default PAUSE (flow control) mode,
+        * a bit that determines whether the HW defaults to enabling or
+        * disabling auto-negotiation, and the direction of the
+        * SW defined pins. If there is no SW over-ride of the flow
+        * control setting, then the variable hw->fc will
+        * be initialized based on a value in the EEPROM.
+        */
+       ret_val = hw->nvm.ops.read_nvm(hw, NVM_INIT_CONTROL2_REG, 1,
+                                      &nvm_data);
+
+       if (ret_val) {
+               hw_dbg(hw, "NVM Read Error\n");
+               goto out;
+       }
+
+       if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0)
+               hw->fc.type = e1000_fc_none;
+       else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) ==
+                NVM_WORD0F_ASM_DIR)
+               hw->fc.type = e1000_fc_tx_pause;
+       else
+               hw->fc.type = e1000_fc_full;
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_force_mac_fc - Force the MAC's flow control settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Force the MAC's flow control settings.  Sets the TFCE and RFCE bits in the
+ *  device control register to reflect the adapter settings.  TFCE and RFCE
+ *  need to be explicitly set by software when a copper PHY is used because
+ *  autonegotiation is managed by the PHY rather than the MAC.  Software must
+ *  also configure these bits when link is forced on a fiber connection.
+ **/
+s32 igb_force_mac_fc(struct e1000_hw *hw)
+{
+       u32 ctrl;
+       s32 ret_val = 0;
+
+       ctrl = rd32(E1000_CTRL);
+
+       /*
+        * Because we didn't get link via the internal auto-negotiation
+        * mechanism (we either forced link or we got link via PHY
+        * auto-neg), we have to manually enable/disable transmit an
+        * receive flow control.
+        *
+        * The "Case" statement below enables/disable flow control
+        * according to the "hw->fc.type" parameter.
+        *
+        * The possible values of the "fc" parameter are:
+        *      0:  Flow control is completely disabled
+        *      1:  Rx flow control is enabled (we can receive pause
+        *          frames but not send pause frames).
+        *      2:  Tx flow control is enabled (we can send pause frames
+        *          frames but we do not receive pause frames).
+        *      3:  Both Rx and TX flow control (symmetric) is enabled.
+        *  other:  No other values should be possible at this point.
+        */
+       hw_dbg(hw, "hw->fc.type = %u\n", hw->fc.type);
+
+       switch (hw->fc.type) {
+       case e1000_fc_none:
+               ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
+               break;
+       case e1000_fc_rx_pause:
+               ctrl &= (~E1000_CTRL_TFCE);
+               ctrl |= E1000_CTRL_RFCE;
+               break;
+       case e1000_fc_tx_pause:
+               ctrl &= (~E1000_CTRL_RFCE);
+               ctrl |= E1000_CTRL_TFCE;
+               break;
+       case e1000_fc_full:
+               ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
+               break;
+       default:
+               hw_dbg(hw, "Flow control param set incorrectly\n");
+               ret_val = -E1000_ERR_CONFIG;
+               goto out;
+       }
+
+       wr32(E1000_CTRL, ctrl);
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_config_fc_after_link_up - Configures flow control after link
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks the status of auto-negotiation after link up to ensure that the
+ *  speed and duplex were not forced.  If the link needed to be forced, then
+ *  flow control needs to be forced also.  If auto-negotiation is enabled
+ *  and did not fail, then we configure flow control based on our link
+ *  partner.
+ **/
+s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
+{
+       struct e1000_mac_info *mac = &hw->mac;
+       s32 ret_val = 0;
+       u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
+       u16 speed, duplex;
+
+       /*
+        * Check for the case where we have fiber media and auto-neg failed
+        * so we had to force link.  In this case, we need to force the
+        * configuration of the MAC to match the "fc" parameter.
+        */
+       if (mac->autoneg_failed) {
+               if (hw->phy.media_type == e1000_media_type_fiber ||
+                   hw->phy.media_type == e1000_media_type_internal_serdes)
+                       ret_val = igb_force_mac_fc(hw);
+       } else {
+               if (hw->phy.media_type == e1000_media_type_copper)
+                       ret_val = igb_force_mac_fc(hw);
+       }
+
+       if (ret_val) {
+               hw_dbg(hw, "Error forcing flow control settings\n");
+               goto out;
+       }
+
+       /*
+        * Check for the case where we have copper media and auto-neg is
+        * enabled.  In this case, we need to check and see if Auto-Neg
+        * has completed, and if so, how the PHY and link partner has
+        * flow control configured.
+        */
+       if ((hw->phy.media_type == e1000_media_type_copper) && mac->autoneg) {
+               /*
+                * Read the MII Status Register and check to see if AutoNeg
+                * has completed.  We read this twice because this reg has
+                * some "sticky" (latched) bits.
+                */
+               ret_val = hw->phy.ops.read_phy_reg(hw, PHY_STATUS,
+                                                  &mii_status_reg);
+               if (ret_val)
+                       goto out;
+               ret_val = hw->phy.ops.read_phy_reg(hw, PHY_STATUS,
+                                                  &mii_status_reg);
+               if (ret_val)
+                       goto out;
+
+               if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
+                       hw_dbg(hw, "Copper PHY and Auto Neg "
+                                "has not completed.\n");
+                       goto out;
+               }
+
+               /*
+                * The AutoNeg process has completed, so we now need to
+                * read both the Auto Negotiation Advertisement
+                * Register (Address 4) and the Auto_Negotiation Base
+                * Page Ability Register (Address 5) to determine how
+                * flow control was negotiated.
+                */
+               ret_val = hw->phy.ops.read_phy_reg(hw, PHY_AUTONEG_ADV,
+                                           &mii_nway_adv_reg);
+               if (ret_val)
+                       goto out;
+               ret_val = hw->phy.ops.read_phy_reg(hw, PHY_LP_ABILITY,
+                                           &mii_nway_lp_ability_reg);
+               if (ret_val)
+                       goto out;
+
+               /*
+                * Two bits in the Auto Negotiation Advertisement Register
+                * (Address 4) and two bits in the Auto Negotiation Base
+                * Page Ability Register (Address 5) determine flow control
+                * for both the PHY and the link partner.  The following
+                * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+                * 1999, describes these PAUSE resolution bits and how flow
+                * control is determined based upon these settings.
+                * NOTE:  DC = Don't Care
+                *
+                *   LOCAL DEVICE  |   LINK PARTNER
+                * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+                *-------|---------|-------|---------|--------------------
+                *   0   |    0    |  DC   |   DC    | e1000_fc_none
+                *   0   |    1    |   0   |   DC    | e1000_fc_none
+                *   0   |    1    |   1   |    0    | e1000_fc_none
+                *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+                *   1   |    0    |   0   |   DC    | e1000_fc_none
+                *   1   |   DC    |   1   |   DC    | e1000_fc_full
+                *   1   |    1    |   0   |    0    | e1000_fc_none
+                *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+                *
+                * Are both PAUSE bits set to 1?  If so, this implies
+                * Symmetric Flow Control is enabled at both ends.  The
+                * ASM_DIR bits are irrelevant per the spec.
+                *
+                * For Symmetric Flow Control:
+                *
+                *   LOCAL DEVICE  |   LINK PARTNER
+                * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+                *-------|---------|-------|---------|--------------------
+                *   1   |   DC    |   1   |   DC    | E1000_fc_full
+                *
+                */
+               if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+                   (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+                       /*
+                        * Now we need to check if the user selected RX ONLY
+                        * of pause frames.  In this case, we had to advertise
+                        * FULL flow control because we could not advertise RX
+                        * ONLY. Hence, we must now check to see if we need to
+                        * turn OFF  the TRANSMISSION of PAUSE frames.
+                        */
+                       if (hw->fc.original_type == e1000_fc_full) {
+                               hw->fc.type = e1000_fc_full;
+                               hw_dbg(hw, "Flow Control = FULL.\r\n");
+                       } else {
+                               hw->fc.type = e1000_fc_rx_pause;
+                               hw_dbg(hw, "Flow Control = "
+                                        "RX PAUSE frames only.\r\n");
+                       }
+               }
+               /*
+                * For receiving PAUSE frames ONLY.
+                *
+                *   LOCAL DEVICE  |   LINK PARTNER
+                * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+                *-------|---------|-------|---------|--------------------
+                *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+                */
+               else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+                         (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+                         (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+                         (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+                       hw->fc.type = e1000_fc_tx_pause;
+                       hw_dbg(hw, "Flow Control = TX PAUSE frames only.\r\n");
+               }
+               /*
+                * For transmitting PAUSE frames ONLY.
+                *
+                *   LOCAL DEVICE  |   LINK PARTNER
+                * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+                *-------|---------|-------|---------|--------------------
+                *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+                */
+               else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+                        (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+                        !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+                        (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+                       hw->fc.type = e1000_fc_rx_pause;
+                       hw_dbg(hw, "Flow Control = RX PAUSE frames only.\r\n");
+               }
+               /*
+                * Per the IEEE spec, at this point flow control should be
+                * disabled.  However, we want to consider that we could
+                * be connected to a legacy switch that doesn't advertise
+                * desired flow control, but can be forced on the link
+                * partner.  So if we advertised no flow control, that is
+                * what we will resolve to.  If we advertised some kind of
+                * receive capability (Rx Pause Only or Full Flow Control)
+                * and the link partner advertised none, we will configure
+                * ourselves to enable Rx Flow Control only.  We can do
+                * this safely for two reasons:  If the link partner really
+                * didn't want flow control enabled, and we enable Rx, no
+                * harm done since we won't be receiving any PAUSE frames
+                * anyway.  If the intent on the link partner was to have
+                * flow control enabled, then by us enabling RX only, we
+                * can at least receive pause frames and process them.
+                * This is a good idea because in most cases, since we are
+                * predominantly a server NIC, more times than not we will
+                * be asked to delay transmission of packets than asking
+                * our link partner to pause transmission of frames.
+                */
+               else if ((hw->fc.original_type == e1000_fc_none ||
+                         hw->fc.original_type == e1000_fc_tx_pause) ||
+                        hw->fc.strict_ieee) {
+                       hw->fc.type = e1000_fc_none;
+                       hw_dbg(hw, "Flow Control = NONE.\r\n");
+               } else {
+                       hw->fc.type = e1000_fc_rx_pause;
+                       hw_dbg(hw, "Flow Control = RX PAUSE frames only.\r\n");
+               }
+
+               /*
+                * Now we need to do one last check...  If we auto-
+                * negotiated to HALF DUPLEX, flow control should not be
+                * enabled per IEEE 802.3 spec.
+                */
+               ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex);
+               if (ret_val) {
+                       hw_dbg(hw, "Error getting link speed and duplex\n");
+                       goto out;
+               }
+
+               if (duplex == HALF_DUPLEX)
+                       hw->fc.type = e1000_fc_none;
+
+               /*
+                * Now we call a subroutine to actually force the MAC
+                * controller to use the correct flow control settings.
+                */
+               ret_val = igb_force_mac_fc(hw);
+               if (ret_val) {
+                       hw_dbg(hw, "Error forcing flow control settings\n");
+                       goto out;
+               }
+       }
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_get_speed_and_duplex_copper - Retreive current speed/duplex
+ *  @hw: pointer to the HW structure
+ *  @speed: stores the current speed
+ *  @duplex: stores the current duplex
+ *
+ *  Read the status register for the current speed/duplex and store the current
+ *  speed and duplex for copper connections.
+ **/
+s32 igb_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed,
+                                     u16 *duplex)
+{
+       u32 status;
+
+       status = rd32(E1000_STATUS);
+       if (status & E1000_STATUS_SPEED_1000) {
+               *speed = SPEED_1000;
+               hw_dbg(hw, "1000 Mbs, ");
+       } else if (status & E1000_STATUS_SPEED_100) {
+               *speed = SPEED_100;
+               hw_dbg(hw, "100 Mbs, ");
+       } else {
+               *speed = SPEED_10;
+               hw_dbg(hw, "10 Mbs, ");
+       }
+
+       if (status & E1000_STATUS_FD) {
+               *duplex = FULL_DUPLEX;
+               hw_dbg(hw, "Full Duplex\n");
+       } else {
+               *duplex = HALF_DUPLEX;
+               hw_dbg(hw, "Half Duplex\n");
+       }
+
+       return 0;
+}
+
+/**
+ *  e1000_get_hw_semaphore - Acquire hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire the HW semaphore to access the PHY or NVM
+ **/
+s32 igb_get_hw_semaphore(struct e1000_hw *hw)
+{
+       u32 swsm;
+       s32 ret_val = 0;
+       s32 timeout = hw->nvm.word_size + 1;
+       s32 i = 0;
+
+       /* Get the SW semaphore */
+       while (i < timeout) {
+               swsm = rd32(E1000_SWSM);
+               if (!(swsm & E1000_SWSM_SMBI))
+                       break;
+
+               udelay(50);
+               i++;
+       }
+
+       if (i == timeout) {
+               hw_dbg(hw, "Driver can't access device - SMBI bit is set.\n");
+               ret_val = -E1000_ERR_NVM;
+               goto out;
+       }
+
+       /* Get the FW semaphore. */
+       for (i = 0; i < timeout; i++) {
+               swsm = rd32(E1000_SWSM);
+               wr32(E1000_SWSM, swsm | E1000_SWSM_SWESMBI);
+
+               /* Semaphore acquired if bit latched */
+               if (rd32(E1000_SWSM) & E1000_SWSM_SWESMBI)
+                       break;
+
+               udelay(50);
+       }
+
+       if (i == timeout) {
+               /* Release semaphores */
+               igb_put_hw_semaphore(hw);
+               hw_dbg(hw, "Driver can't access the NVM\n");
+               ret_val = -E1000_ERR_NVM;
+               goto out;
+       }
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_put_hw_semaphore - Release hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Release hardware semaphore used to access the PHY or NVM
+ **/
+void igb_put_hw_semaphore(struct e1000_hw *hw)
+{
+       u32 swsm;
+
+       swsm = rd32(E1000_SWSM);
+
+       swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+
+       wr32(E1000_SWSM, swsm);
+}
+
+/**
+ *  e1000_get_auto_rd_done - Check for auto read completion
+ *  @hw: pointer to the HW structure
+ *
+ *  Check EEPROM for Auto Read done bit.
+ **/
+s32 igb_get_auto_rd_done(struct e1000_hw *hw)
+{
+       s32 i = 0;
+       s32 ret_val = 0;
+
+
+       while (i < AUTO_READ_DONE_TIMEOUT) {
+               if (rd32(E1000_EECD) & E1000_EECD_AUTO_RD)
+                       break;
+               msleep(1);
+               i++;
+       }
+
+       if (i == AUTO_READ_DONE_TIMEOUT) {
+               hw_dbg(hw, "Auto read by HW from NVM has not completed.\n");
+               ret_val = -E1000_ERR_RESET;
+               goto out;
+       }
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_valid_led_default - Verify a valid default LED config
+ *  @hw: pointer to the HW structure
+ *  @data: pointer to the NVM (EEPROM)
+ *
+ *  Read the EEPROM for the current default LED configuration.  If the
+ *  LED configuration is not valid, set to a valid LED configuration.
+ **/
+static s32 igb_valid_led_default(struct e1000_hw *hw, u16 *data)
+{
+       s32 ret_val;
+
+       ret_val = hw->nvm.ops.read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data);
+       if (ret_val) {
+               hw_dbg(hw, "NVM Read Error\n");
+               goto out;
+       }
+
+       if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
+               *data = ID_LED_DEFAULT;
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_id_led_init -
+ *  @hw: pointer to the HW structure
+ *
+ **/
+s32 igb_id_led_init(struct e1000_hw *hw)
+{
+       struct e1000_mac_info *mac = &hw->mac;
+       s32 ret_val;
+       const u32 ledctl_mask = 0x000000FF;
+       const u32 ledctl_on = E1000_LEDCTL_MODE_LED_ON;
+       const u32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
+       u16 data, i, temp;
+       const u16 led_mask = 0x0F;
+
+       ret_val = igb_valid_led_default(hw, &data);
+       if (ret_val)
+               goto out;
+
+       mac->ledctl_default = rd32(E1000_LEDCTL);
+       mac->ledctl_mode1 = mac->ledctl_default;
+       mac->ledctl_mode2 = mac->ledctl_default;
+
+       for (i = 0; i < 4; i++) {
+               temp = (data >> (i << 2)) & led_mask;
+               switch (temp) {
+               case ID_LED_ON1_DEF2:
+               case ID_LED_ON1_ON2:
+               case ID_LED_ON1_OFF2:
+                       mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+                       mac->ledctl_mode1 |= ledctl_on << (i << 3);
+                       break;
+               case ID_LED_OFF1_DEF2:
+               case ID_LED_OFF1_ON2:
+               case ID_LED_OFF1_OFF2:
+                       mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+                       mac->ledctl_mode1 |= ledctl_off << (i << 3);
+                       break;
+               default:
+                       /* Do nothing */
+                       break;
+               }
+               switch (temp) {
+               case ID_LED_DEF1_ON2:
+               case ID_LED_ON1_ON2:
+               case ID_LED_OFF1_ON2:
+                       mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+                       mac->ledctl_mode2 |= ledctl_on << (i << 3);
+                       break;
+               case ID_LED_DEF1_OFF2:
+               case ID_LED_ON1_OFF2:
+               case ID_LED_OFF1_OFF2:
+                       mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+                       mac->ledctl_mode2 |= ledctl_off << (i << 3);
+                       break;
+               default:
+                       /* Do nothing */
+                       break;
+               }
+       }
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_cleanup_led - Set LED config to default operation
+ *  @hw: pointer to the HW structure
+ *
+ *  Remove the current LED configuration and set the LED configuration
+ *  to the default value, saved from the EEPROM.
+ **/
+s32 igb_cleanup_led(struct e1000_hw *hw)
+{
+       wr32(E1000_LEDCTL, hw->mac.ledctl_default);
+       return 0;
+}
+
+/**
+ *  e1000_blink_led - Blink LED
+ *  @hw: pointer to the HW structure
+ *
+ *  Blink the led's which are set to be on.
+ **/
+s32 igb_blink_led(struct e1000_hw *hw)
+{
+       u32 ledctl_blink = 0;
+       u32 i;
+
+       if (hw->phy.media_type == e1000_media_type_fiber) {
+               /* always blink LED0 for PCI-E fiber */
+               ledctl_blink = E1000_LEDCTL_LED0_BLINK |
+                    (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT);
+       } else {
+               /*
+                * set the blink bit for each LED that's "on" (0x0E)
+                * in ledctl_mode2
+                */
+               ledctl_blink = hw->mac.ledctl_mode2;
+               for (i = 0; i < 4; i++)
+                       if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
+                           E1000_LEDCTL_MODE_LED_ON)
+                               ledctl_blink |= (E1000_LEDCTL_LED0_BLINK <<
+                                                (i * 8));
+       }
+
+       wr32(E1000_LEDCTL, ledctl_blink);
+
+       return 0;
+}
+
+/**
+ *  e1000_led_off - Turn LED off
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn LED off.
+ **/
+s32 igb_led_off(struct e1000_hw *hw)
+{
+       u32 ctrl;
+
+       switch (hw->phy.media_type) {
+       case e1000_media_type_fiber:
+               ctrl = rd32(E1000_CTRL);
+               ctrl |= E1000_CTRL_SWDPIN0;
+               ctrl |= E1000_CTRL_SWDPIO0;
+               wr32(E1000_CTRL, ctrl);
+               break;
+       case e1000_media_type_copper:
+               wr32(E1000_LEDCTL, hw->mac.ledctl_mode1);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+/**
+ *  e1000_disable_pcie_master - Disables PCI-express master access
+ *  @hw: pointer to the HW structure
+ *
+ *  Returns 0 (0) if successful, else returns -10
+ *  (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not casued
+ *  the master requests to be disabled.
+ *
+ *  Disables PCI-Express master access and verifies there are no pending
+ *  requests.
+ **/
+s32 igb_disable_pcie_master(struct e1000_hw *hw)
+{
+       u32 ctrl;
+       s32 timeout = MASTER_DISABLE_TIMEOUT;
+       s32 ret_val = 0;
+
+       if (hw->bus.type != e1000_bus_type_pci_express)
+               goto out;
+
+       ctrl = rd32(E1000_CTRL);
+       ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
+       wr32(E1000_CTRL, ctrl);
+
+       while (timeout) {
+               if (!(rd32(E1000_STATUS) &
+                     E1000_STATUS_GIO_MASTER_ENABLE))
+                       break;
+               udelay(100);
+               timeout--;
+       }
+
+       if (!timeout) {
+               hw_dbg(hw, "Master requests are pending.\n");
+               ret_val = -E1000_ERR_MASTER_REQUESTS_PENDING;
+               goto out;
+       }
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_reset_adaptive - Reset Adaptive Interframe Spacing
+ *  @hw: pointer to the HW structure
+ *
+ *  Reset the Adaptive Interframe Spacing throttle to default values.
+ **/
+void igb_reset_adaptive(struct e1000_hw *hw)
+{
+       struct e1000_mac_info *mac = &hw->mac;
+
+       if (!mac->adaptive_ifs) {
+               hw_dbg(hw, "Not in Adaptive IFS mode!\n");
+               goto out;
+       }
+
+       if (!mac->ifs_params_forced) {
+               mac->current_ifs_val = 0;
+               mac->ifs_min_val = IFS_MIN;
+               mac->ifs_max_val = IFS_MAX;
+               mac->ifs_step_size = IFS_STEP;
+               mac->ifs_ratio = IFS_RATIO;
+       }
+
+       mac->in_ifs_mode = false;
+       wr32(E1000_AIT, 0);
+out:
+       return;
+}
+
+/**
+ *  e1000_update_adaptive - Update Adaptive Interframe Spacing
+ *  @hw: pointer to the HW structure
+ *
+ *  Update the Adaptive Interframe Spacing Throttle value based on the
+ *  time between transmitted packets and time between collisions.
+ **/
+void igb_update_adaptive(struct e1000_hw *hw)
+{
+       struct e1000_mac_info *mac = &hw->mac;
+
+       if (!mac->adaptive_ifs) {
+               hw_dbg(hw, "Not in Adaptive IFS mode!\n");
+               goto out;
+       }
+
+       if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) {
+               if (mac->tx_packet_delta > MIN_NUM_XMITS) {
+                       mac->in_ifs_mode = true;
+                       if (mac->current_ifs_val < mac->ifs_max_val) {
+                               if (!mac->current_ifs_val)
+                                       mac->current_ifs_val = mac->ifs_min_val;
+                               else
+                                       mac->current_ifs_val +=
+                                               mac->ifs_step_size;
+                               wr32(E1000_AIT,
+                                               mac->current_ifs_val);
+                       }
+               }
+       } else {
+               if (mac->in_ifs_mode &&
+                   (mac->tx_packet_delta <= MIN_NUM_XMITS)) {
+                       mac->current_ifs_val = 0;
+                       mac->in_ifs_mode = false;
+                       wr32(E1000_AIT, 0);
+               }
+       }
+out:
+       return;
+}
+
+/**
+ *  e1000_validate_mdi_setting - Verify MDI/MDIx settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Verify that when not using auto-negotitation that MDI/MDIx is correctly
+ *  set, which is forced to MDI mode only.
+ **/
+s32 igb_validate_mdi_setting(struct e1000_hw *hw)
+{
+       s32 ret_val = 0;
+
+       if (!hw->mac.autoneg && (hw->phy.mdix == 0 || hw->phy.mdix == 3)) {
+               hw_dbg(hw, "Invalid MDI setting detected\n");
+               hw->phy.mdix = 1;
+               ret_val = -E1000_ERR_CONFIG;
+               goto out;
+       }
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_write_8bit_ctrl_reg - Write a 8bit CTRL register
+ *  @hw: pointer to the HW structure
+ *  @reg: 32bit register offset such as E1000_SCTL
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Writes an address/data control type register.  There are several of these
+ *  and they all have the format address << 8 | data and bit 31 is polled for
+ *  completion.
+ **/
+s32 igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg,
+                             u32 offset, u8 data)
+{
+       u32 i, regvalue = 0;
+       s32 ret_val = 0;
+
+       /* Set up the address and data */
+       regvalue = ((u32)data) | (offset << E1000_GEN_CTL_ADDRESS_SHIFT);
+       wr32(reg, regvalue);
+
+       /* Poll the ready bit to see if the MDI read completed */
+       for (i = 0; i < E1000_GEN_POLL_TIMEOUT; i++) {
+               udelay(5);
+               regvalue = rd32(reg);
+               if (regvalue & E1000_GEN_CTL_READY)
+                       break;
+       }
+       if (!(regvalue & E1000_GEN_CTL_READY)) {
+               hw_dbg(hw, "Reg %08x did not indicate ready\n", reg);
+               ret_val = -E1000_ERR_PHY;
+               goto out;
+       }
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_enable_mng_pass_thru - Enable processing of ARP's
+ *  @hw: pointer to the HW structure
+ *
+ *  Verifies the hardware needs to allow ARPs to be processed by the host.
+ **/
+bool igb_enable_mng_pass_thru(struct e1000_hw *hw)
+{
+       u32 manc;
+       u32 fwsm, factps;
+       bool ret_val = false;
+
+       if (!hw->mac.asf_firmware_present)
+               goto out;
+
+       manc = rd32(E1000_MANC);
+
+       if (!(manc & E1000_MANC_RCV_TCO_EN) ||
+           !(manc & E1000_MANC_EN_MAC_ADDR_FILTER))
+               goto out;
+
+       if (hw->mac.arc_subsystem_valid) {
+               fwsm = rd32(E1000_FWSM);
+               factps = rd32(E1000_FACTPS);
+
+               if (!(factps & E1000_FACTPS_MNGCG) &&
+                   ((fwsm & E1000_FWSM_MODE_MASK) ==
+                    (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) {
+                       ret_val = true;
+                       goto out;
+               }
+       } else {
+               if ((manc & E1000_MANC_SMBUS_EN) &&
+                   !(manc & E1000_MANC_ASF_EN)) {
+                       ret_val = true;
+                       goto out;
+               }
+       }
+
+out:
+       return ret_val;
+}
diff --git a/drivers/net/igb/e1000_mac.h b/drivers/net/igb/e1000_mac.h
new file mode 100644 (file)
index 0000000..326b659
--- /dev/null
@@ -0,0 +1,98 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_MAC_H_
+#define _E1000_MAC_H_
+
+#include "e1000_hw.h"
+
+#include "e1000_phy.h"
+#include "e1000_nvm.h"
+#include "e1000_defines.h"
+
+/*
+ * Functions that should not be called directly from drivers but can be used
+ * by other files in this 'shared code'
+ */
+s32  igb_blink_led(struct e1000_hw *hw);
+s32  igb_check_for_copper_link(struct e1000_hw *hw);
+s32  igb_cleanup_led(struct e1000_hw *hw);
+s32  igb_config_fc_after_link_up(struct e1000_hw *hw);
+s32  igb_disable_pcie_master(struct e1000_hw *hw);
+s32  igb_force_mac_fc(struct e1000_hw *hw);
+s32  igb_get_auto_rd_done(struct e1000_hw *hw);
+s32  igb_get_bus_info_pcie(struct e1000_hw *hw);
+s32  igb_get_hw_semaphore(struct e1000_hw *hw);
+s32  igb_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed,
+                                      u16 *duplex);
+s32  igb_id_led_init(struct e1000_hw *hw);
+s32  igb_led_off(struct e1000_hw *hw);
+void igb_update_mc_addr_list(struct e1000_hw *hw,
+                              u8 *mc_addr_list, u32 mc_addr_count,
+                              u32 rar_used_count, u32 rar_count);
+s32  igb_setup_link(struct e1000_hw *hw);
+s32  igb_validate_mdi_setting(struct e1000_hw *hw);
+s32  igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg,
+                              u32 offset, u8 data);
+
+void igb_clear_hw_cntrs_base(struct e1000_hw *hw);
+void igb_clear_vfta(struct e1000_hw *hw);
+void igb_config_collision_dist(struct e1000_hw *hw);
+void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
+void igb_put_hw_semaphore(struct e1000_hw *hw);
+void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index);
+s32  igb_check_alt_mac_addr(struct e1000_hw *hw);
+void igb_remove_device(struct e1000_hw *hw);
+void igb_reset_adaptive(struct e1000_hw *hw);
+void igb_update_adaptive(struct e1000_hw *hw);
+void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value);
+
+bool igb_enable_mng_pass_thru(struct e1000_hw *hw);
+
+enum e1000_mng_mode {
+       e1000_mng_mode_none = 0,
+       e1000_mng_mode_asf,
+       e1000_mng_mode_pt,
+       e1000_mng_mode_ipmi,
+       e1000_mng_mode_host_if_only
+};
+
+#define E1000_FACTPS_MNGCG    0x20000000
+
+#define E1000_FWSM_MODE_MASK  0xE
+#define E1000_FWSM_MODE_SHIFT 1
+
+#define E1000_MNG_DHCP_COMMAND_TIMEOUT       10
+#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN    0x2
+
+#define E1000_HICR_EN              0x01  /* Enable bit - RO */
+/* Driver sets this bit when done to put command in RAM */
+#define E1000_HICR_C               0x02
+
+extern void e1000_init_function_pointers_82575(struct e1000_hw *hw);
+
+#endif
diff --git a/drivers/net/igb/e1000_nvm.c b/drivers/net/igb/e1000_nvm.c
new file mode 100644 (file)
index 0000000..2897106
--- /dev/null
@@ -0,0 +1,605 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/if_ether.h>
+#include <linux/delay.h>
+
+#include "e1000_mac.h"
+#include "e1000_nvm.h"
+
+/**
+ *  e1000_raise_eec_clk - Raise EEPROM clock
+ *  @hw: pointer to the HW structure
+ *  @eecd: pointer to the EEPROM
+ *
+ *  Enable/Raise the EEPROM clock bit.
+ **/
+static void igb_raise_eec_clk(struct e1000_hw *hw, u32 *eecd)
+{
+       *eecd = *eecd | E1000_EECD_SK;
+       wr32(E1000_EECD, *eecd);
+       wrfl();
+       udelay(hw->nvm.delay_usec);
+}
+
+/**
+ *  e1000_lower_eec_clk - Lower EEPROM clock
+ *  @hw: pointer to the HW structure
+ *  @eecd: pointer to the EEPROM
+ *
+ *  Clear/Lower the EEPROM clock bit.
+ **/
+static void igb_lower_eec_clk(struct e1000_hw *hw, u32 *eecd)
+{
+       *eecd = *eecd & ~E1000_EECD_SK;
+       wr32(E1000_EECD, *eecd);
+       wrfl();
+       udelay(hw->nvm.delay_usec);
+}
+
+/**
+ *  e1000_shift_out_eec_bits - Shift data bits our to the EEPROM
+ *  @hw: pointer to the HW structure
+ *  @data: data to send to the EEPROM
+ *  @count: number of bits to shift out
+ *
+ *  We need to shift 'count' bits out to the EEPROM.  So, the value in the
+ *  "data" parameter will be shifted out to the EEPROM one bit at a time.
+ *  In order to do this, "data" must be broken down into bits.
+ **/
+static void igb_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count)
+{
+       struct e1000_nvm_info *nvm = &hw->nvm;
+       u32 eecd = rd32(E1000_EECD);
+       u32 mask;
+
+       mask = 0x01 << (count - 1);
+       if (nvm->type == e1000_nvm_eeprom_microwire)
+               eecd &= ~E1000_EECD_DO;
+       else if (nvm->type == e1000_nvm_eeprom_spi)
+               eecd |= E1000_EECD_DO;
+
+       do {
+               eecd &= ~E1000_EECD_DI;
+
+               if (data & mask)
+                       eecd |= E1000_EECD_DI;
+
+               wr32(E1000_EECD, eecd);
+               wrfl();
+
+               udelay(nvm->delay_usec);
+
+               igb_raise_eec_clk(hw, &eecd);
+               igb_lower_eec_clk(hw, &eecd);
+
+               mask >>= 1;
+       } while (mask);
+
+       eecd &= ~E1000_EECD_DI;
+       wr32(E1000_EECD, eecd);
+}
+
+/**
+ *  e1000_shift_in_eec_bits - Shift data bits in from the EEPROM
+ *  @hw: pointer to the HW structure
+ *  @count: number of bits to shift in
+ *
+ *  In order to read a register from the EEPROM, we need to shift 'count' bits
+ *  in from the EEPROM.  Bits are "shifted in" by raising the clock input to
+ *  the EEPROM (setting the SK bit), and then reading the value of the data out
+ *  "DO" bit.  During this "shifting in" process the data in "DI" bit should
+ *  always be clear.
+ **/
+static u16 igb_shift_in_eec_bits(struct e1000_hw *hw, u16 count)
+{
+       u32 eecd;
+       u32 i;
+       u16 data;
+
+       eecd = rd32(E1000_EECD);
+
+       eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+       data = 0;
+
+       for (i = 0; i < count; i++) {
+               data <<= 1;
+               igb_raise_eec_clk(hw, &eecd);
+
+               eecd = rd32(E1000_EECD);
+
+               eecd &= ~E1000_EECD_DI;
+               if (eecd & E1000_EECD_DO)
+                       data |= 1;
+
+               igb_lower_eec_clk(hw, &eecd);
+       }
+
+       return data;
+}
+
+/**
+ *  e1000_poll_eerd_eewr_done - Poll for EEPROM read/write completion
+ *  @hw: pointer to the HW structure
+ *  @ee_reg: EEPROM flag for polling
+ *
+ *  Polls the EEPROM status bit for either read or write completion based
+ *  upon the value of 'ee_reg'.
+ **/
+static s32 igb_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg)
+{
+       u32 attempts = 100000;
+       u32 i, reg = 0;
+       s32 ret_val = -E1000_ERR_NVM;
+
+       for (i = 0; i < attempts; i++) {
+               if (ee_reg == E1000_NVM_POLL_READ)
+                       reg = rd32(E1000_EERD);
+               else
+                       reg = rd32(E1000_EEWR);
+
+               if (reg & E1000_NVM_RW_REG_DONE) {
+                       ret_val = 0;
+                       break;
+               }
+
+               udelay(5);
+       }
+
+       return ret_val;
+}
+
+/**
+ *  e1000_acquire_nvm - Generic request for access to EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Set the EEPROM access request bit and wait for EEPROM access grant bit.
+ *  Return successful if access grant bit set, else clear the request for
+ *  EEPROM access and return -E1000_ERR_NVM (-1).
+ **/
+s32 igb_acquire_nvm(struct e1000_hw *hw)
+{
+       u32 eecd = rd32(E1000_EECD);
+       s32 timeout = E1000_NVM_GRANT_ATTEMPTS;
+       s32 ret_val = 0;
+
+
+       wr32(E1000_EECD, eecd | E1000_EECD_REQ);
+       eecd = rd32(E1000_EECD);
+
+       while (timeout) {
+               if (eecd & E1000_EECD_GNT)
+                       break;
+               udelay(5);
+               eecd = rd32(E1000_EECD);
+               timeout--;
+       }
+
+       if (!timeout) {
+               eecd &= ~E1000_EECD_REQ;
+               wr32(E1000_EECD, eecd);
+               hw_dbg(hw, "Could not acquire NVM grant\n");
+               ret_val = -E1000_ERR_NVM;
+       }
+
+       return ret_val;
+}
+
+/**
+ *  e1000_standby_nvm - Return EEPROM to standby state
+ *  @hw: pointer to the HW structure
+ *
+ *  Return the EEPROM to a standby state.
+ **/
+static void igb_standby_nvm(struct e1000_hw *hw)
+{
+       struct e1000_nvm_info *nvm = &hw->nvm;
+       u32 eecd = rd32(E1000_EECD);
+
+       if (nvm->type == e1000_nvm_eeprom_microwire) {
+               eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+               wr32(E1000_EECD, eecd);
+               wrfl();
+               udelay(nvm->delay_usec);
+
+               igb_raise_eec_clk(hw, &eecd);
+
+               /* Select EEPROM */
+               eecd |= E1000_EECD_CS;
+               wr32(E1000_EECD, eecd);
+               wrfl();
+               udelay(nvm->delay_usec);
+
+               igb_lower_eec_clk(hw, &eecd);
+       } else if (nvm->type == e1000_nvm_eeprom_spi) {
+               /* Toggle CS to flush commands */
+               eecd |= E1000_EECD_CS;
+               wr32(E1000_EECD, eecd);
+               wrfl();
+               udelay(nvm->delay_usec);
+               eecd &= ~E1000_EECD_CS;
+               wr32(E1000_EECD, eecd);
+               wrfl();
+               udelay(nvm->delay_usec);
+       }
+}
+
+/**
+ *  e1000_stop_nvm - Terminate EEPROM command
+ *  @hw: pointer to the HW structure
+ *
+ *  Terminates the current command by inverting the EEPROM's chip select pin.
+ **/
+static void e1000_stop_nvm(struct e1000_hw *hw)
+{
+       u32 eecd;
+
+       eecd = rd32(E1000_EECD);
+       if (hw->nvm.type == e1000_nvm_eeprom_spi) {
+               /* Pull CS high */
+               eecd |= E1000_EECD_CS;
+               igb_lower_eec_clk(hw, &eecd);
+       } else if (hw->nvm.type == e1000_nvm_eeprom_microwire) {
+               /* CS on Microcwire is active-high */
+               eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+               wr32(E1000_EECD, eecd);
+               igb_raise_eec_clk(hw, &eecd);
+               igb_lower_eec_clk(hw, &eecd);
+       }
+}
+
+/**
+ *  e1000_release_nvm - Release exclusive access to EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Stop any current commands to the EEPROM and clear the EEPROM request bit.
+ **/
+void igb_release_nvm(struct e1000_hw *hw)
+{
+       u32 eecd;
+
+       e1000_stop_nvm(hw);
+
+       eecd = rd32(E1000_EECD);
+       eecd &= ~E1000_EECD_REQ;
+       wr32(E1000_EECD, eecd);
+}
+
+/**
+ *  e1000_ready_nvm_eeprom - Prepares EEPROM for read/write
+ *  @hw: pointer to the HW structure
+ *
+ *  Setups the EEPROM for reading and writing.
+ **/
+static s32 igb_ready_nvm_eeprom(struct e1000_hw *hw)
+{
+       struct e1000_nvm_info *nvm = &hw->nvm;
+       u32 eecd = rd32(E1000_EECD);
+       s32 ret_val = 0;
+       u16 timeout = 0;
+       u8 spi_stat_reg;
+
+
+       if (nvm->type == e1000_nvm_eeprom_microwire) {
+               /* Clear SK and DI */
+               eecd &= ~(E1000_EECD_DI | E1000_EECD_SK);
+               wr32(E1000_EECD, eecd);
+               /* Set CS */
+               eecd |= E1000_EECD_CS;
+               wr32(E1000_EECD, eecd);
+       } else if (nvm->type == e1000_nvm_eeprom_spi) {
+               /* Clear SK and CS */
+               eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+               wr32(E1000_EECD, eecd);
+               udelay(1);
+               timeout = NVM_MAX_RETRY_SPI;
+
+               /*
+                * Read "Status Register" repeatedly until the LSB is cleared.
+                * The EEPROM will signal that the command has been completed
+                * by clearing bit 0 of the internal status register.  If it's
+                * not cleared within 'timeout', then error out.
+                */
+               while (timeout) {
+                       igb_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI,
+                                                hw->nvm.opcode_bits);
+                       spi_stat_reg = (u8)igb_shift_in_eec_bits(hw, 8);
+                       if (!(spi_stat_reg & NVM_STATUS_RDY_SPI))
+                               break;
+
+                       udelay(5);
+                       igb_standby_nvm(hw);
+                       timeout--;
+               }
+
+               if (!timeout) {
+                       hw_dbg(hw, "SPI NVM Status error\n");
+                       ret_val = -E1000_ERR_NVM;
+                       goto out;
+               }
+       }
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_read_nvm_eerd - Reads EEPROM using EERD register
+ *  @hw: pointer to the HW structure
+ *  @offset: offset of word in the EEPROM to read
+ *  @words: number of words to read
+ *  @data: word read from the EEPROM
+ *
+ *  Reads a 16 bit word from the EEPROM using the EERD register.
+ **/
+s32 igb_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+       struct e1000_nvm_info *nvm = &hw->nvm;
+       u32 i, eerd = 0;
+       s32 ret_val = 0;
+
+       /*
+        * A check for invalid values:  offset too large, too many words,
+        * and not enough words.
+        */
+       if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+           (words == 0)) {
+               hw_dbg(hw, "nvm parameter(s) out of bounds\n");
+               ret_val = -E1000_ERR_NVM;
+               goto out;
+       }
+
+       for (i = 0; i < words; i++) {
+               eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) +
+                      E1000_NVM_RW_REG_START;
+
+               wr32(E1000_EERD, eerd);
+               ret_val = igb_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ);
+               if (ret_val)
+                       break;
+
+               data[i] = (rd32(E1000_EERD) >>
+                          E1000_NVM_RW_REG_DATA);
+       }
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_write_nvm_spi - Write to EEPROM using SPI
+ *  @hw: pointer to the HW structure
+ *  @offset: offset within the EEPROM to be written to
+ *  @words: number of words to write
+ *  @data: 16 bit word(s) to be written to the EEPROM
+ *
+ *  Writes data to EEPROM at offset using SPI interface.
+ *
+ *  If e1000_update_nvm_checksum is not called after this function , the
+ *  EEPROM will most likley contain an invalid checksum.
+ **/
+s32 igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+       struct e1000_nvm_info *nvm = &hw->nvm;
+       s32 ret_val;
+       u16 widx = 0;
+
+       /*
+        * A check for invalid values:  offset too large, too many words,
+        * and not enough words.
+        */
+       if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+           (words == 0)) {
+               hw_dbg(hw, "nvm parameter(s) out of bounds\n");
+               ret_val = -E1000_ERR_NVM;
+               goto out;
+       }
+
+       ret_val = hw->nvm.ops.acquire_nvm(hw);
+       if (ret_val)
+               goto out;
+
+       msleep(10);
+
+       while (widx < words) {
+               u8 write_opcode = NVM_WRITE_OPCODE_SPI;
+
+               ret_val = igb_ready_nvm_eeprom(hw);
+               if (ret_val)
+                       goto release;
+
+               igb_standby_nvm(hw);
+
+               /* Send the WRITE ENABLE command (8 bit opcode) */
+               igb_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI,
+                                        nvm->opcode_bits);
+
+               igb_standby_nvm(hw);
+
+               /*
+                * Some SPI eeproms use the 8th address bit embedded in the
+                * opcode
+                */
+               if ((nvm->address_bits == 8) && (offset >= 128))
+                       write_opcode |= NVM_A8_OPCODE_SPI;
+
+               /* Send the Write command (8-bit opcode + addr) */
+               igb_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits);
+               igb_shift_out_eec_bits(hw, (u16)((offset + widx) * 2),
+                                        nvm->address_bits);
+
+               /* Loop to allow for up to whole page write of eeprom */
+               while (widx < words) {
+                       u16 word_out = data[widx];
+                       word_out = (word_out >> 8) | (word_out << 8);
+                       igb_shift_out_eec_bits(hw, word_out, 16);
+                       widx++;
+
+                       if ((((offset + widx) * 2) % nvm->page_size) == 0) {
+                               igb_standby_nvm(hw);
+                               break;
+                       }
+               }
+       }
+
+       msleep(10);
+release:
+       hw->nvm.ops.release_nvm(hw);
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_read_part_num - Read device part number
+ *  @hw: pointer to the HW structure
+ *  @part_num: pointer to device part number
+ *
+ *  Reads the product board assembly (PBA) number from the EEPROM and stores
+ *  the value in part_num.
+ **/
+s32 igb_read_part_num(struct e1000_hw *hw, u32 *part_num)
+{
+       s32  ret_val;
+       u16 nvm_data;
+
+       ret_val = hw->nvm.ops.read_nvm(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
+       if (ret_val) {
+               hw_dbg(hw, "NVM Read Error\n");
+               goto out;
+       }
+       *part_num = (u32)(nvm_data << 16);
+
+       ret_val = hw->nvm.ops.read_nvm(hw, NVM_PBA_OFFSET_1, 1, &nvm_data);
+       if (ret_val) {
+               hw_dbg(hw, "NVM Read Error\n");
+               goto out;
+       }
+       *part_num |= nvm_data;
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_read_mac_addr - 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 igb_read_mac_addr(struct e1000_hw *hw)
+{
+       s32  ret_val = 0;
+       u16 offset, nvm_data, i;
+
+       for (i = 0; i < ETH_ALEN; i += 2) {
+               offset = i >> 1;
+               ret_val = hw->nvm.ops.read_nvm(hw, offset, 1, &nvm_data);
+               if (ret_val) {
+                       hw_dbg(hw, "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_ALEN; i++)
+               hw->mac.addr[i] = hw->mac.perm_addr[i];
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_validate_nvm_checksum - Validate EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Calculates the EEPROM checksum by reading/adding each word of the EEPROM
+ *  and then verifies that the sum of the EEPROM is equal to 0xBABA.
+ **/
+s32 igb_validate_nvm_checksum(struct e1000_hw *hw)
+{
+       s32 ret_val = 0;
+       u16 checksum = 0;
+       u16 i, nvm_data;
+
+       for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
+               ret_val = hw->nvm.ops.read_nvm(hw, i, 1, &nvm_data);
+               if (ret_val) {
+                       hw_dbg(hw, "NVM Read Error\n");
+                       goto out;
+               }
+               checksum += nvm_data;
+       }
+
+       if (checksum != (u16) NVM_SUM) {
+               hw_dbg(hw, "NVM Checksum Invalid\n");
+               ret_val = -E1000_ERR_NVM;
+               goto out;
+       }
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_update_nvm_checksum - Update EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Updates the EEPROM checksum by reading/adding each word of the EEPROM
+ *  up to the checksum.  Then calculates the EEPROM checksum and writes the
+ *  value to the EEPROM.
+ **/
+s32 igb_update_nvm_checksum(struct e1000_hw *hw)
+{
+       s32  ret_val;
+       u16 checksum = 0;
+       u16 i, nvm_data;
+
+       for (i = 0; i < NVM_CHECKSUM_REG; i++) {
+               ret_val = hw->nvm.ops.read_nvm(hw, i, 1, &nvm_data);
+               if (ret_val) {
+                       hw_dbg(hw, "NVM Read Error while updating checksum.\n");
+                       goto out;
+               }
+               checksum += nvm_data;
+       }
+       checksum = (u16) NVM_SUM - checksum;
+       ret_val = hw->nvm.ops.write_nvm(hw, NVM_CHECKSUM_REG, 1, &checksum);
+       if (ret_val)
+               hw_dbg(hw, "NVM Write Error while updating checksum.\n");
+
+out:
+       return ret_val;
+}
+
diff --git a/drivers/net/igb/e1000_nvm.h b/drivers/net/igb/e1000_nvm.h
new file mode 100644 (file)
index 0000000..1041c34
--- /dev/null
@@ -0,0 +1,40 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_NVM_H_
+#define _E1000_NVM_H_
+
+s32  igb_acquire_nvm(struct e1000_hw *hw);
+void igb_release_nvm(struct e1000_hw *hw);
+s32  igb_read_mac_addr(struct e1000_hw *hw);
+s32  igb_read_part_num(struct e1000_hw *hw, u32 *part_num);
+s32  igb_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+s32  igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+s32  igb_validate_nvm_checksum(struct e1000_hw *hw);
+s32  igb_update_nvm_checksum(struct e1000_hw *hw);
+
+#endif
diff --git a/drivers/net/igb/e1000_phy.c b/drivers/net/igb/e1000_phy.c
new file mode 100644 (file)
index 0000000..08a86b1
--- /dev/null
@@ -0,0 +1,1807 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/if_ether.h>
+#include <linux/delay.h>
+
+#include "e1000_mac.h"
+#include "e1000_phy.h"
+
+static s32  igb_get_phy_cfg_done(struct e1000_hw *hw);
+static void igb_release_phy(struct e1000_hw *hw);
+static s32  igb_acquire_phy(struct e1000_hw *hw);
+static s32  igb_phy_reset_dsp(struct e1000_hw *hw);
+static s32  igb_phy_setup_autoneg(struct e1000_hw *hw);
+static void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw,
+                                              u16 *phy_ctrl);
+static s32  igb_wait_autoneg(struct e1000_hw *hw);
+
+/* Cable length tables */
+static const u16 e1000_m88_cable_length_table[] =
+       { 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
+#define M88E1000_CABLE_LENGTH_TABLE_SIZE \
+               (sizeof(e1000_m88_cable_length_table) / \
+                sizeof(e1000_m88_cable_length_table[0]))
+
+static const u16 e1000_igp_2_cable_length_table[] =
+    { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21,
+      0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41,
+      6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61,
+      21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82,
+      40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104,
+      60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121,
+      83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
+      104, 109, 114, 118, 121, 124};
+#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
+               (sizeof(e1000_igp_2_cable_length_table) / \
+                sizeof(e1000_igp_2_cable_length_table[0]))
+
+/**
+ *  e1000_check_reset_block - Check if PHY reset is blocked
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the PHY management control register and check whether a PHY reset
+ *  is blocked.  If a reset is not blocked return 0, otherwise
+ *  return E1000_BLK_PHY_RESET (12).
+ **/
+s32 igb_check_reset_block(struct e1000_hw *hw)
+{
+       u32 manc;
+
+       manc = rd32(E1000_MANC);
+
+       return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
+              E1000_BLK_PHY_RESET : 0;
+}
+
+/**
+ *  e1000_get_phy_id - Retrieve the PHY ID and revision
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the PHY registers and stores the PHY ID and possibly the PHY
+ *  revision in the hardware structure.
+ **/
+s32 igb_get_phy_id(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32 ret_val = 0;
+       u16 phy_id;
+
+       ret_val = hw->phy.ops.read_phy_reg(hw, PHY_ID1, &phy_id);
+       if (ret_val)
+               goto out;
+
+       phy->id = (u32)(phy_id << 16);
+       udelay(20);
+       ret_val = hw->phy.ops.read_phy_reg(hw, PHY_ID2, &phy_id);
+       if (ret_val)
+               goto out;
+
+       phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
+       phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_phy_reset_dsp - Reset PHY DSP
+ *  @hw: pointer to the HW structure
+ *
+ *  Reset the digital signal processor.
+ **/
+static s32 igb_phy_reset_dsp(struct e1000_hw *hw)
+{
+       s32 ret_val;
+
+       ret_val = hw->phy.ops.write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1);
+       if (ret_val)
+               goto out;
+
+       ret_val = hw->phy.ops.write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0);
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_read_phy_reg_mdic - Read 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 regsiter in the PHY at offset and stores the
+ *  information read to data.
+ **/
+static s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       u32 i, mdic = 0;
+       s32 ret_val = 0;
+
+       if (offset > MAX_PHY_REG_ADDRESS) {
+               hw_dbg(hw, "PHY Address %d is out of range\n", offset);
+               ret_val = -E1000_ERR_PARAM;
+               goto out;
+       }
+
+       /*
+        * Set up Op-code, Phy Address, and register offset in the MDI
+        * Control register.  The MAC will take care of interfacing with the
+        * PHY to retrieve the desired data.
+        */
+       mdic = ((offset << E1000_MDIC_REG_SHIFT) |
+               (phy->addr << E1000_MDIC_PHY_SHIFT) |
+               (E1000_MDIC_OP_READ));
+
+       wr32(E1000_MDIC, mdic);
+
+       /*
+        * Poll the ready bit to see if the MDI read completed
+        * Increasing the time out as testing showed failures with
+        * the lower time out
+        */
+       for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
+               udelay(50);
+               mdic = rd32(E1000_MDIC);
+               if (mdic & E1000_MDIC_READY)
+                       break;
+       }
+       if (!(mdic & E1000_MDIC_READY)) {
+               hw_dbg(hw, "MDI Read did not complete\n");
+               ret_val = -E1000_ERR_PHY;
+               goto out;
+       }
+       if (mdic & E1000_MDIC_ERROR) {
+               hw_dbg(hw, "MDI Error\n");
+               ret_val = -E1000_ERR_PHY;
+               goto out;
+       }
+       *data = (u16) mdic;
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_write_phy_reg_mdic - Write 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 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       u32 i, mdic = 0;
+       s32 ret_val = 0;
+
+       if (offset > MAX_PHY_REG_ADDRESS) {
+               hw_dbg(hw, "PHY Address %d is out of range\n", offset);
+               ret_val = -E1000_ERR_PARAM;
+               goto out;
+       }
+
+       /*
+        * Set up Op-code, Phy Address, and register offset in the MDI
+        * Control register.  The MAC will take care of interfacing with the
+        * PHY to retrieve the desired data.
+        */
+       mdic = (((u32)data) |
+               (offset << E1000_MDIC_REG_SHIFT) |
+               (phy->addr << E1000_MDIC_PHY_SHIFT) |
+               (E1000_MDIC_OP_WRITE));
+
+       wr32(E1000_MDIC, mdic);
+
+       /*
+        * Poll the ready bit to see if the MDI read completed
+        * Increasing the time out as testing showed failures with
+        * the lower time out
+        */
+       for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
+               udelay(50);
+               mdic = rd32(E1000_MDIC);
+               if (mdic & E1000_MDIC_READY)
+                       break;
+       }
+       if (!(mdic & E1000_MDIC_READY)) {
+               hw_dbg(hw, "MDI Write did not complete\n");
+               ret_val = -E1000_ERR_PHY;
+               goto out;
+       }
+       if (mdic & E1000_MDIC_ERROR) {
+               hw_dbg(hw, "MDI Error\n");
+               ret_val = -E1000_ERR_PHY;
+               goto out;
+       }
+
+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, if necessary, then reads the PHY register at offset
+ *  and storing the retrieved information in data.  Release any acquired
+ *  semaphores before exiting.
+ **/
+s32 igb_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+       s32 ret_val;
+
+       ret_val = igb_acquire_phy(hw);
+       if (ret_val)
+               goto out;
+
+       if (offset > MAX_PHY_MULTI_PAGE_REG) {
+               ret_val = igb_write_phy_reg_mdic(hw,
+                                                  IGP01E1000_PHY_PAGE_SELECT,
+                                                  (u16)offset);
+               if (ret_val) {
+                       igb_release_phy(hw);
+                       goto out;
+               }
+       }
+
+       ret_val = igb_read_phy_reg_mdic(hw,
+                                         MAX_PHY_REG_ADDRESS & offset,
+                                         data);
+
+       igb_release_phy(hw);
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_write_phy_reg_igp - Write igp PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore, if necessary, then writes the data to PHY register
+ *  at the offset.  Release any acquired semaphores before exiting.
+ **/
+s32 igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data)
+{
+       s32 ret_val;
+
+       ret_val = igb_acquire_phy(hw);
+       if (ret_val)
+               goto out;
+
+       if (offset > MAX_PHY_MULTI_PAGE_REG) {
+               ret_val = igb_write_phy_reg_mdic(hw,
+                                                  IGP01E1000_PHY_PAGE_SELECT,
+                                                  (u16)offset);
+               if (ret_val) {
+                       igb_release_phy(hw);
+                       goto out;
+               }
+       }
+
+       ret_val = igb_write_phy_reg_mdic(hw,
+                                          MAX_PHY_REG_ADDRESS & offset,
+                                          data);
+
+       igb_release_phy(hw);
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_copper_link_setup_m88 - Setup m88 PHY's for copper link
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets up MDI/MDI-X and polarity for m88 PHY's.  If necessary, transmit clock
+ *  and downshift values are set also.
+ **/
+s32 igb_copper_link_setup_m88(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32 ret_val;
+       u16 phy_data;
+
+       if (phy->reset_disable) {
+               ret_val = 0;
+               goto out;
+       }
+
+       /* Enable CRS on TX. This must be set for half-duplex operation. */
+       ret_val = hw->phy.ops.read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+                                          &phy_data);
+       if (ret_val)
+               goto out;
+
+       phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+
+       /*
+        * 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)
+        */
+       phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
+       switch (phy->mdix) {
+       case 1:
+               phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+               break;
+       case 2:
+               phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+               break;
+       case 3:
+               phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+               break;
+       case 0:
+       default:
+               phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+               break;
+       }
+
+       /*
+        * Options:
+        *   disable_polarity_correction = 0 (default)
+        *       Automatic Correction for Reversed Cable Polarity
+        *   0 - Disabled
+        *   1 - Enabled
+        */
+       phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+       if (phy->disable_polarity_correction == 1)
+               phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+
+       ret_val = hw->phy.ops.write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+                                           phy_data);
+       if (ret_val)
+               goto out;
+
+       if (phy->revision < E1000_REVISION_4) {
+               /*
+                * Force TX_CLK in the Extended PHY Specific Control Register
+                * to 25MHz clock.
+                */
+               ret_val = hw->phy.ops.read_phy_reg(hw,
+                                            M88E1000_EXT_PHY_SPEC_CTRL,
+                                            &phy_data);
+               if (ret_val)
+                       goto out;
+
+               phy_data |= M88E1000_EPSCR_TX_CLK_25;
+
+               if ((phy->revision == E1000_REVISION_2) &&
+                   (phy->id == M88E1111_I_PHY_ID)) {
+                       /* 82573L PHY - set the downshift counter to 5x. */
+                       phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK;
+                       phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
+               } else {
+                       /* Configure Master and Slave downshift values */
+                       phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+                                     M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+                       phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+                                    M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+               }
+               ret_val = hw->phy.ops.write_phy_reg(hw,
+                                            M88E1000_EXT_PHY_SPEC_CTRL,
+                                            phy_data);
+               if (ret_val)
+                       goto out;
+       }
+
+       /* Commit the changes. */
+       ret_val = igb_phy_sw_reset(hw);
+       if (ret_val) {
+               hw_dbg(hw, "Error committing the PHY changes\n");
+               goto out;
+       }
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_copper_link_setup_igp - Setup igp PHY's for copper link
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for
+ *  igp PHY's.
+ **/
+s32 igb_copper_link_setup_igp(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32 ret_val;
+       u16 data;
+
+       if (phy->reset_disable) {
+               ret_val = 0;
+               goto out;
+       }
+
+       ret_val = hw->phy.ops.reset_phy(hw);
+       if (ret_val) {
+               hw_dbg(hw, "Error resetting the PHY.\n");
+               goto out;
+       }
+
+       /* Wait 15ms for MAC to configure PHY from NVM settings. */
+       msleep(15);
+
+       /*
+        * The NVM settings will configure LPLU in D3 for
+        * non-IGP1 PHYs.
+        */
+       if (phy->type == e1000_phy_igp) {
+               /* disable lplu d3 during driver init */
+               if (hw->phy.ops.set_d3_lplu_state)
+                       ret_val = hw->phy.ops.set_d3_lplu_state(hw, false);
+               if (ret_val) {
+                       hw_dbg(hw, "Error Disabling LPLU D3\n");
+                       goto out;
+               }
+       }
+
+       /* disable lplu d0 during driver init */
+       ret_val = hw->phy.ops.set_d0_lplu_state(hw, false);
+       if (ret_val) {
+               hw_dbg(hw, "Error Disabling LPLU D0\n");
+               goto out;
+       }
+       /* Configure mdi-mdix settings */
+       ret_val = hw->phy.ops.read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &data);
+       if (ret_val)
+               goto out;
+
+       data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+
+       switch (phy->mdix) {
+       case 1:
+               data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+               break;
+       case 2:
+               data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
+               break;
+       case 0:
+       default:
+               data |= IGP01E1000_PSCR_AUTO_MDIX;
+               break;
+       }
+       ret_val = hw->phy.ops.write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, data);
+       if (ret_val)
+               goto out;
+
+       /* set auto-master slave resolution settings */
+       if (hw->mac.autoneg) {
+               /*
+                * when autonegotiation advertisement is only 1000Mbps then we
+                * should disable SmartSpeed and enable Auto MasterSlave
+                * resolution as hardware default.
+                */
+               if (phy->autoneg_advertised == ADVERTISE_1000_FULL) {
+                       /* Disable SmartSpeed */
+                       ret_val = hw->phy.ops.read_phy_reg(hw,
+                                                    IGP01E1000_PHY_PORT_CONFIG,
+                                                    &data);
+                       if (ret_val)
+                               goto out;
+
+                       data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+                       ret_val = hw->phy.ops.write_phy_reg(hw,
+                                                    IGP01E1000_PHY_PORT_CONFIG,
+                                                    data);
+                       if (ret_val)
+                               goto out;
+
+                       /* Set auto Master/Slave resolution process */
+                       ret_val = hw->phy.ops.read_phy_reg(hw, PHY_1000T_CTRL,
+                                                          &data);
+                       if (ret_val)
+                               goto out;
+
+                       data &= ~CR_1000T_MS_ENABLE;
+                       ret_val = hw->phy.ops.write_phy_reg(hw, PHY_1000T_CTRL,
+                                                           data);
+                       if (ret_val)
+                               goto out;
+               }
+
+               ret_val = hw->phy.ops.read_phy_reg(hw, PHY_1000T_CTRL, &data);
+               if (ret_val)
+                       goto out;
+
+               /* load defaults for future use */
+               phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ?
+                       ((data & CR_1000T_MS_VALUE) ?
+                       e1000_ms_force_master :
+                       e1000_ms_force_slave) :
+                       e1000_ms_auto;
+
+               switch (phy->ms_type) {
+               case e1000_ms_force_master:
+                       data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
+                       break;
+               case e1000_ms_force_slave:
+                       data |= CR_1000T_MS_ENABLE;
+                       data &= ~(CR_1000T_MS_VALUE);
+                       break;
+               case e1000_ms_auto:
+                       data &= ~CR_1000T_MS_ENABLE;
+               default:
+                       break;
+               }
+               ret_val = hw->phy.ops.write_phy_reg(hw, PHY_1000T_CTRL, data);
+               if (ret_val)
+                       goto out;
+       }
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_copper_link_autoneg - Setup/Enable autoneg for copper link
+ *  @hw: pointer to the HW structure
+ *
+ *  Performs initial bounds checking on autoneg advertisement parameter, then
+ *  configure to advertise the full capability.  Setup the PHY to autoneg
+ *  and restart the negotiation process between the link partner.  If
+ *  autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
+ **/
+s32 igb_copper_link_autoneg(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32 ret_val;
+       u16 phy_ctrl;
+
+       /*
+        * Perform some bounds checking on the autoneg advertisement
+        * parameter.
+        */
+       phy->autoneg_advertised &= phy->autoneg_mask;
+
+       /*
+        * If autoneg_advertised is zero, we assume it was not defaulted
+        * by the calling code so we set to advertise full capability.
+        */
+       if (phy->autoneg_advertised == 0)
+               phy->autoneg_advertised = phy->autoneg_mask;
+
+       hw_dbg(hw, "Reconfiguring auto-neg advertisement params\n");
+       ret_val = igb_phy_setup_autoneg(hw);
+       if (ret_val) {
+               hw_dbg(hw, "Error Setting up Auto-Negotiation\n");
+               goto out;
+       }
+       hw_dbg(hw, "Restarting Auto-Neg\n");
+
+       /*
+        * Restart auto-negotiation by setting the Auto Neg Enable bit and
+        * the Auto Neg Restart bit in the PHY control register.
+        */
+       ret_val = hw->phy.ops.read_phy_reg(hw, PHY_CONTROL, &phy_ctrl);
+       if (ret_val)
+               goto out;
+
+       phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+       ret_val = hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, phy_ctrl);
+       if (ret_val)
+               goto out;
+
+       /*
+        * Does the user want to wait for Auto-Neg to complete here, or
+        * check at a later time (for example, callback routine).
+        */
+       if (phy->autoneg_wait_to_complete) {
+               ret_val = igb_wait_autoneg(hw);
+               if (ret_val) {
+                       hw_dbg(hw, "Error while waiting for "
+                                "autoneg to complete\n");
+                       goto out;
+               }
+       }
+
+       hw->mac.get_link_status = true;
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_phy_setup_autoneg - Configure PHY for auto-negotiation
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the MII auto-neg advertisement register and/or the 1000T control
+ *  register and if the PHY is already setup for auto-negotiation, then
+ *  return successful.  Otherwise, setup advertisement and flow control to
+ *  the appropriate values for the wanted auto-negotiation.
+ **/
+static s32 igb_phy_setup_autoneg(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32 ret_val;
+       u16 mii_autoneg_adv_reg;
+       u16 mii_1000t_ctrl_reg = 0;
+
+       phy->autoneg_advertised &= phy->autoneg_mask;
+
+       /* Read the MII Auto-Neg Advertisement Register (Address 4). */
+       ret_val = hw->phy.ops.read_phy_reg(hw, PHY_AUTONEG_ADV,
+                                          &mii_autoneg_adv_reg);
+       if (ret_val)
+               goto out;
+
+       if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+               /* Read the MII 1000Base-T Control Register (Address 9). */
+               ret_val = hw->phy.ops.read_phy_reg(hw,
+                                           PHY_1000T_CTRL,
+                                           &mii_1000t_ctrl_reg);
+               if (ret_val)
+                       goto out;
+       }
+
+       /*
+        * Need to parse both autoneg_advertised and fc and set up
+        * the appropriate PHY registers.  First we will parse for
+        * autoneg_advertised software override.  Since we can advertise
+        * a plethora of combinations, we need to check each bit
+        * individually.
+        */
+
+       /*
+        * First we clear all the 10/100 mb speed bits in the Auto-Neg
+        * Advertisement Register (Address 4) and the 1000 mb speed bits in
+        * the  1000Base-T Control Register (Address 9).
+        */
+       mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
+                                NWAY_AR_100TX_HD_CAPS |
+                                NWAY_AR_10T_FD_CAPS   |
+                                NWAY_AR_10T_HD_CAPS);
+       mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
+
+       hw_dbg(hw, "autoneg_advertised %x\n", phy->autoneg_advertised);
+
+       /* Do we want to advertise 10 Mb Half Duplex? */
+       if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
+               hw_dbg(hw, "Advertise 10mb Half duplex\n");
+               mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
+       }
+
+       /* Do we want to advertise 10 Mb Full Duplex? */
+       if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
+               hw_dbg(hw, "Advertise 10mb Full duplex\n");
+               mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
+       }
+
+       /* Do we want to advertise 100 Mb Half Duplex? */
+       if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
+               hw_dbg(hw, "Advertise 100mb Half duplex\n");
+               mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
+       }
+
+       /* Do we want to advertise 100 Mb Full Duplex? */
+       if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
+               hw_dbg(hw, "Advertise 100mb Full duplex\n");
+               mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
+       }
+
+       /* We do not allow the Phy to advertise 1000 Mb Half Duplex */
+       if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
+               hw_dbg(hw, "Advertise 1000mb Half duplex request denied!\n");
+
+       /* Do we want to advertise 1000 Mb Full Duplex? */
+       if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
+               hw_dbg(hw, "Advertise 1000mb Full duplex\n");
+               mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+       }
+
+       /*
+        * Check for a software override of the flow control settings, and
+        * setup the PHY advertisement registers accordingly.  If
+        * auto-negotiation is enabled, then software will have to set the
+        * "PAUSE" bits to the correct value in the Auto-Negotiation
+        * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
+        * negotiation.
+        *
+        * The possible values of the "fc" parameter are:
+        *      0:  Flow control is completely disabled
+        *      1:  Rx flow control is enabled (we can receive pause frames
+        *          but not send pause frames).
+        *      2:  Tx flow control is enabled (we can send pause frames
+        *          but we do not support receiving pause frames).
+        *      3:  Both Rx and TX flow control (symmetric) are enabled.
+        *  other:  No software override.  The flow control configuration
+        *          in the EEPROM is used.
+        */
+       switch (hw->fc.type) {
+       case e1000_fc_none:
+               /*
+                * Flow control (RX & TX) is completely disabled by a
+                * software over-ride.
+                */
+               mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+               break;
+       case e1000_fc_rx_pause:
+               /*
+                * RX Flow control is enabled, and TX Flow control is
+                * disabled, by a software over-ride.
+                *
+                * Since there really isn't a way to advertise that we are
+                * capable of RX Pause ONLY, we will advertise that we
+                * support both symmetric and asymmetric RX PAUSE.  Later
+                * (in e1000_config_fc_after_link_up) we will disable the
+                * hw's ability to send PAUSE frames.
+                */
+               mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+               break;
+       case e1000_fc_tx_pause:
+               /*
+                * TX Flow control is enabled, and RX Flow control is
+                * disabled, by a software over-ride.
+                */
+               mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
+               mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
+               break;
+       case e1000_fc_full:
+               /*
+                * Flow control (both RX and TX) is enabled by a software
+                * over-ride.
+                */
+               mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+               break;
+       default:
+               hw_dbg(hw, "Flow control param set incorrectly\n");
+               ret_val = -E1000_ERR_CONFIG;
+               goto out;
+       }
+
+       ret_val = hw->phy.ops.write_phy_reg(hw, PHY_AUTONEG_ADV,
+                                           mii_autoneg_adv_reg);
+       if (ret_val)
+               goto out;
+
+       hw_dbg(hw, "Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
+
+       if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+               ret_val = hw->phy.ops.write_phy_reg(hw,
+                                             PHY_1000T_CTRL,
+                                             mii_1000t_ctrl_reg);
+               if (ret_val)
+                       goto out;
+       }
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_phy_force_speed_duplex_igp - Force speed/duplex for igp 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).
+ **/
+s32 igb_phy_force_speed_duplex_igp(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32 ret_val;
+       u16 phy_data;
+       bool link;
+
+       ret_val = hw->phy.ops.read_phy_reg(hw, PHY_CONTROL, &phy_data);
+       if (ret_val)
+               goto out;
+
+       igb_phy_force_speed_duplex_setup(hw, &phy_data);
+
+       ret_val = hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, phy_data);
+       if (ret_val)
+               goto out;
+
+       /*
+        * Clear Auto-Crossover to force MDI manually.  IGP requires MDI
+        * forced whenever speed and duplex are forced.
+        */
+       ret_val = hw->phy.ops.read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL,
+                                          &phy_data);
+       if (ret_val)
+               goto out;
+
+       phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+       phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+
+       ret_val = hw->phy.ops.write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL,
+                                           phy_data);
+       if (ret_val)
+               goto out;
+
+       hw_dbg(hw, "IGP PSCR: %X\n", phy_data);
+
+       udelay(1);
+
+       if (phy->autoneg_wait_to_complete) {
+               hw_dbg(hw,
+                      "Waiting for forced speed/duplex link on IGP phy.\n");
+
+               ret_val = igb_phy_has_link(hw,
+                                                    PHY_FORCE_LIMIT,
+                                                    100000,
+                                                    &link);
+               if (ret_val)
+                       goto out;
+
+               if (!link)
+                       hw_dbg(hw, "Link taking longer than expected.\n");
+
+               /* Try once more */
+               ret_val = igb_phy_has_link(hw,
+                                                    PHY_FORCE_LIMIT,
+                                                    100000,
+                                                    &link);
+               if (ret_val)
+                       goto out;
+       }
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_phy_force_speed_duplex_m88 - Force speed/duplex for m88 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.  Resets the PHY to commit the
+ *  changes.  If time expires while waiting for link up, we reset the DSP.
+ *  After reset, TX_CLK and CRS on TX must be set.  Return successful upon
+ *  successful completion, else return corresponding error code.
+ **/
+s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32 ret_val;
+       u16 phy_data;
+       bool link;
+
+       /*
+        * Clear Auto-Crossover to force MDI manually.  M88E1000 requires MDI
+        * forced whenever speed and duplex are forced.
+        */
+       ret_val = hw->phy.ops.read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+                                          &phy_data);
+       if (ret_val)
+               goto out;
+
+       phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+       ret_val = hw->phy.ops.write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+                                           phy_data);
+       if (ret_val)
+               goto out;
+
+       hw_dbg(hw, "M88E1000 PSCR: %X\n", phy_data);
+
+       ret_val = hw->phy.ops.read_phy_reg(hw, PHY_CONTROL, &phy_data);
+       if (ret_val)
+               goto out;
+
+       igb_phy_force_speed_duplex_setup(hw, &phy_data);
+
+       /* Reset the phy to commit changes. */
+       phy_data |= MII_CR_RESET;
+
+       ret_val = hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, phy_data);
+       if (ret_val)
+               goto out;
+
+       udelay(1);
+
+       if (phy->autoneg_wait_to_complete) {
+               hw_dbg(hw,
+                      "Waiting for forced speed/duplex link on M88 phy.\n");
+
+               ret_val = igb_phy_has_link(hw,
+                                                    PHY_FORCE_LIMIT,
+                                                    100000,
+                                                    &link);
+               if (ret_val)
+                       goto out;
+
+               if (!link) {
+                       /*
+                        * We didn't get link.
+                        * Reset the DSP and cross our fingers.
+                        */
+                       ret_val = hw->phy.ops.write_phy_reg(hw,
+                                                     M88E1000_PHY_PAGE_SELECT,
+                                                     0x001d);
+                       if (ret_val)
+                               goto out;
+                       ret_val = igb_phy_reset_dsp(hw);
+                       if (ret_val)
+                               goto out;
+               }
+
+               /* Try once more */
+               ret_val = igb_phy_has_link(hw, PHY_FORCE_LIMIT,
+                                            100000, &link);
+               if (ret_val)
+                       goto out;
+       }
+
+       ret_val = hw->phy.ops.read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+                                          &phy_data);
+       if (ret_val)
+               goto out;
+
+       /*
+        * Resetting the phy means we need to re-force TX_CLK in the
+        * Extended PHY Specific Control Register to 25MHz clock from
+        * the reset value of 2.5MHz.
+        */
+       phy_data |= M88E1000_EPSCR_TX_CLK_25;
+       ret_val = hw->phy.ops.write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+                                           phy_data);
+       if (ret_val)
+               goto out;
+
+       /*
+        * In addition, we must re-enable CRS on Tx for both half and full
+        * duplex.
+        */
+       ret_val = hw->phy.ops.read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+                                          &phy_data);
+       if (ret_val)
+               goto out;
+
+       phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+       ret_val = hw->phy.ops.write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+                                           phy_data);
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex
+ *  @hw: pointer to the HW structure
+ *  @phy_ctrl: pointer to current value of PHY_CONTROL
+ *
+ *  Forces speed and duplex on the PHY by doing the following: disable flow
+ *  control, force speed/duplex on the MAC, disable auto speed detection,
+ *  disable auto-negotiation, configure duplex, configure speed, configure
+ *  the collision distance, write configuration to CTRL register.  The
+ *  caller must write to the PHY_CONTROL register for these settings to
+ *  take affect.
+ **/
+static void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw,
+                                              u16 *phy_ctrl)
+{
+       struct e1000_mac_info *mac = &hw->mac;
+       u32 ctrl;
+
+       /* Turn off flow control when forcing speed/duplex */
+       hw->fc.type = e1000_fc_none;
+
+       /* Force speed/duplex on the mac */
+       ctrl = rd32(E1000_CTRL);
+       ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+       ctrl &= ~E1000_CTRL_SPD_SEL;
+
+       /* Disable Auto Speed Detection */
+       ctrl &= ~E1000_CTRL_ASDE;
+
+       /* Disable autoneg on the phy */
+       *phy_ctrl &= ~MII_CR_AUTO_NEG_EN;
+
+       /* Forcing Full or Half Duplex? */
+       if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) {
+               ctrl &= ~E1000_CTRL_FD;
+               *phy_ctrl &= ~MII_CR_FULL_DUPLEX;
+               hw_dbg(hw, "Half Duplex\n");
+       } else {
+               ctrl |= E1000_CTRL_FD;
+               *phy_ctrl |= MII_CR_FULL_DUPLEX;
+               hw_dbg(hw, "Full Duplex\n");
+       }
+
+       /* Forcing 10mb or 100mb? */
+       if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) {
+               ctrl |= E1000_CTRL_SPD_100;
+               *phy_ctrl |= MII_CR_SPEED_100;
+               *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
+               hw_dbg(hw, "Forcing 100mb\n");
+       } else {
+               ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+               *phy_ctrl |= MII_CR_SPEED_10;
+               *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
+               hw_dbg(hw, "Forcing 10mb\n");
+       }
+
+       igb_config_collision_dist(hw);
+
+       wr32(E1000_CTRL, ctrl);
+}
+
+/**
+ *  e1000_set_d3_lplu_state - Sets low power link up state for D3
+ *  @hw: pointer to the HW structure
+ *  @active: boolean used to enable/disable lplu
+ *
+ *  Success returns 0, Failure returns 1
+ *
+ *  The low power link up (lplu) state is set to the power management level D3
+ *  and SmartSpeed is disabled when active is true, else clear lplu for D3
+ *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
+ *  is used during Dx states where the power conservation is most important.
+ *  During driver activity, SmartSpeed should be enabled so performance is
+ *  maintained.
+ **/
+s32 igb_set_d3_lplu_state(struct e1000_hw *hw, bool active)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32 ret_val;
+       u16 data;
+
+       ret_val = hw->phy.ops.read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+                                          &data);
+       if (ret_val)
+               goto out;
+
+       if (!active) {
+               data &= ~IGP02E1000_PM_D3_LPLU;
+               ret_val = hw->phy.ops.write_phy_reg(hw,
+                                            IGP02E1000_PHY_POWER_MGMT,
+                                            data);
+               if (ret_val)
+                       goto out;
+               /*
+                * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
+                * during Dx states where the power conservation is most
+                * important.  During driver activity we should enable
+                * SmartSpeed, so performance is maintained.
+                */
+               if (phy->smart_speed == e1000_smart_speed_on) {
+                       ret_val = hw->phy.ops.read_phy_reg(hw,
+                                                   IGP01E1000_PHY_PORT_CONFIG,
+                                                   &data);
+                       if (ret_val)
+                               goto out;
+
+                       data |= IGP01E1000_PSCFR_SMART_SPEED;
+                       ret_val = hw->phy.ops.write_phy_reg(hw,
+                                                    IGP01E1000_PHY_PORT_CONFIG,
+                                                    data);
+                       if (ret_val)
+                               goto out;
+               } else if (phy->smart_speed == e1000_smart_speed_off) {
+                       ret_val = hw->phy.ops.read_phy_reg(hw,
+                                                    IGP01E1000_PHY_PORT_CONFIG,
+                                                    &data);
+                       if (ret_val)
+                               goto out;
+
+                       data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+                       ret_val = hw->phy.ops.write_phy_reg(hw,
+                                                    IGP01E1000_PHY_PORT_CONFIG,
+                                                    data);
+                       if (ret_val)
+                               goto out;
+               }
+       } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
+                  (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
+                  (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
+               data |= IGP02E1000_PM_D3_LPLU;
+               ret_val = hw->phy.ops.write_phy_reg(hw,
+                                             IGP02E1000_PHY_POWER_MGMT,
+                                             data);
+               if (ret_val)
+                       goto out;
+
+               /* When LPLU is enabled, we should disable SmartSpeed */
+               ret_val = hw->phy.ops.read_phy_reg(hw,
+                                            IGP01E1000_PHY_PORT_CONFIG,
+                                            &data);
+               if (ret_val)
+                       goto out;
+
+               data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+               ret_val = hw->phy.ops.write_phy_reg(hw,
+                                             IGP01E1000_PHY_PORT_CONFIG,
+                                             data);
+       }
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_check_downshift - Checks whether a downshift in speed occured
+ *  @hw: pointer to the HW structure
+ *
+ *  Success returns 0, Failure returns 1
+ *
+ *  A downshift is detected by querying the PHY link health.
+ **/
+s32 igb_check_downshift(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32 ret_val;
+       u16 phy_data, offset, mask;
+
+       switch (phy->type) {
+       case e1000_phy_m88:
+       case e1000_phy_gg82563:
+               offset  = M88E1000_PHY_SPEC_STATUS;
+               mask    = M88E1000_PSSR_DOWNSHIFT;
+               break;
+       case e1000_phy_igp_2:
+       case e1000_phy_igp:
+       case e1000_phy_igp_3:
+               offset  = IGP01E1000_PHY_LINK_HEALTH;
+               mask    = IGP01E1000_PLHR_SS_DOWNGRADE;
+               break;
+       default:
+               /* speed downshift not supported */
+               phy->speed_downgraded = false;
+               ret_val = 0;
+               goto out;
+       }
+
+       ret_val = hw->phy.ops.read_phy_reg(hw, offset, &phy_data);
+
+       if (!ret_val)
+               phy->speed_downgraded = (phy_data & mask) ? true : false;
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_check_polarity_m88 - Checks the polarity.
+ *  @hw: pointer to the HW structure
+ *
+ *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ *  Polarity is determined based on the PHY specific status register.
+ **/
+static s32 igb_check_polarity_m88(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32 ret_val;
+       u16 data;
+
+       ret_val = hw->phy.ops.read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &data);
+
+       if (!ret_val)
+               phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY)
+                                     ? e1000_rev_polarity_reversed
+                                     : e1000_rev_polarity_normal;
+
+       return ret_val;
+}
+
+/**
+ *  e1000_check_polarity_igp - Checks the polarity.
+ *  @hw: pointer to the HW structure
+ *
+ *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ *  Polarity is determined based on the PHY port status register, and the
+ *  current speed (since there is no polarity at 100Mbps).
+ **/
+static s32 igb_check_polarity_igp(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32 ret_val;
+       u16 data, offset, mask;
+
+       /*
+        * Polarity is determined based on the speed of
+        * our connection.
+        */
+       ret_val = hw->phy.ops.read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS,
+                                          &data);
+       if (ret_val)
+               goto out;
+
+       if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
+           IGP01E1000_PSSR_SPEED_1000MBPS) {
+               offset  = IGP01E1000_PHY_PCS_INIT_REG;
+               mask    = IGP01E1000_PHY_POLARITY_MASK;
+       } else {
+               /*
+                * This really only applies to 10Mbps since
+                * there is no polarity for 100Mbps (always 0).
+                */
+               offset  = IGP01E1000_PHY_PORT_STATUS;
+               mask    = IGP01E1000_PSSR_POLARITY_REVERSED;
+       }
+
+       ret_val = hw->phy.ops.read_phy_reg(hw, offset, &data);
+
+       if (!ret_val)
+               phy->cable_polarity = (data & mask)
+                                     ? e1000_rev_polarity_reversed
+                                     : e1000_rev_polarity_normal;
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_wait_autoneg - Wait for auto-neg compeletion
+ *  @hw: pointer to the HW structure
+ *
+ *  Waits for auto-negotiation to complete or for the auto-negotiation time
+ *  limit to expire, which ever happens first.
+ **/
+static s32 igb_wait_autoneg(struct e1000_hw *hw)
+{
+       s32 ret_val = 0;
+       u16 i, phy_status;
+
+       /* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
+       for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
+               ret_val = hw->phy.ops.read_phy_reg(hw, PHY_STATUS, &phy_status);
+               if (ret_val)
+                       break;
+               ret_val = hw->phy.ops.read_phy_reg(hw, PHY_STATUS, &phy_status);
+               if (ret_val)
+                       break;
+               if (phy_status & MII_SR_AUTONEG_COMPLETE)
+                       break;
+               msleep(100);
+       }
+
+       /*
+        * PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
+        * has completed.
+        */
+       return ret_val;
+}
+
+/**
+ *  e1000_phy_has_link - Polls PHY for link
+ *  @hw: pointer to the HW structure
+ *  @iterations: number of times to poll for link
+ *  @usec_interval: delay between polling attempts
+ *  @success: pointer to whether polling was successful or not
+ *
+ *  Polls the PHY status register for link, 'iterations' number of times.
+ **/
+s32 igb_phy_has_link(struct e1000_hw *hw, u32 iterations,
+                              u32 usec_interval, bool *success)
+{
+       s32 ret_val = 0;
+       u16 i, phy_status;
+
+       for (i = 0; i < iterations; i++) {
+               /*
+                * Some PHYs require the PHY_STATUS register to be read
+                * twice due to the link bit being sticky.  No harm doing
+                * it across the board.
+                */
+               ret_val = hw->phy.ops.read_phy_reg(hw, PHY_STATUS, &phy_status);
+               if (ret_val)
+                       break;
+               ret_val = hw->phy.ops.read_phy_reg(hw, PHY_STATUS, &phy_status);
+               if (ret_val)
+                       break;
+               if (phy_status & MII_SR_LINK_STATUS)
+                       break;
+               if (usec_interval >= 1000)
+                       mdelay(usec_interval/1000);
+               else
+                       udelay(usec_interval);
+       }
+
+       *success = (i < iterations) ? true : false;
+
+       return ret_val;
+}
+
+/**
+ *  e1000_get_cable_length_m88 - Determine cable length for m88 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the PHY specific status register to retrieve the cable length
+ *  information.  The cable length is determined by averaging the minimum and
+ *  maximum values to get the "average" cable length.  The m88 PHY has four
+ *  possible cable length values, which are:
+ *     Register Value          Cable Length
+ *     0                       < 50 meters
+ *     1                       50 - 80 meters
+ *     2                       80 - 110 meters
+ *     3                       110 - 140 meters
+ *     4                       > 140 meters
+ **/
+s32 igb_get_cable_length_m88(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32 ret_val;
+       u16 phy_data, index;
+
+       ret_val = hw->phy.ops.read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+                                          &phy_data);
+       if (ret_val)
+               goto out;
+
+       index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+               M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+       phy->min_cable_length = e1000_m88_cable_length_table[index];
+       phy->max_cable_length = e1000_m88_cable_length_table[index+1];
+
+       phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_get_cable_length_igp_2 - Determine cable length for igp2 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  The automatic gain control (agc) normalizes the amplitude of the
+ *  received signal, adjusting for the attenuation produced by the
+ *  cable.  By reading the AGC registers, which reperesent the
+ *  cobination of course and fine gain value, the value can be put
+ *  into a lookup table to obtain the approximate cable length
+ *  for each channel.
+ **/
+s32 igb_get_cable_length_igp_2(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32 ret_val = 0;
+       u16 phy_data, i, agc_value = 0;
+       u16 cur_agc_index, max_agc_index = 0;
+       u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1;
+       u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
+                                                        {IGP02E1000_PHY_AGC_A,
+                                                         IGP02E1000_PHY_AGC_B,
+                                                         IGP02E1000_PHY_AGC_C,
+                                                         IGP02E1000_PHY_AGC_D};
+
+       /* Read the AGC registers for all channels */
+       for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
+               ret_val = hw->phy.ops.read_phy_reg(hw, agc_reg_array[i],
+                                                  &phy_data);
+               if (ret_val)
+                       goto out;
+
+               /*
+                * Getting bits 15:9, which represent the combination of
+                * course and fine gain values.  The result is a number
+                * that can be put into the lookup table to obtain the
+                * approximate cable length.
+                */
+               cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
+                               IGP02E1000_AGC_LENGTH_MASK;
+
+               /* Array index bound check. */
+               if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) ||
+                   (cur_agc_index == 0)) {
+                       ret_val = -E1000_ERR_PHY;
+                       goto out;
+               }
+
+               /* Remove min & max AGC values from calculation. */
+               if (e1000_igp_2_cable_length_table[min_agc_index] >
+                   e1000_igp_2_cable_length_table[cur_agc_index])
+                       min_agc_index = cur_agc_index;
+               if (e1000_igp_2_cable_length_table[max_agc_index] <
+                   e1000_igp_2_cable_length_table[cur_agc_index])
+                       max_agc_index = cur_agc_index;
+
+               agc_value += e1000_igp_2_cable_length_table[cur_agc_index];
+       }
+
+       agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] +
+                     e1000_igp_2_cable_length_table[max_agc_index]);
+       agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
+
+       /* Calculate cable length with the error range of +/- 10 meters. */
+       phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
+                                (agc_value - IGP02E1000_AGC_RANGE) : 0;
+       phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE;
+
+       phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_get_phy_info_m88 - Retrieve PHY information
+ *  @hw: pointer to the HW structure
+ *
+ *  Valid for only copper links.  Read the PHY status register (sticky read)
+ *  to verify that link is up.  Read the PHY special control register to
+ *  determine the polarity and 10base-T extended distance.  Read the PHY
+ *  special status register to determine MDI/MDIx and current speed.  If
+ *  speed is 1000, then determine cable length, local and remote receiver.
+ **/
+s32 igb_get_phy_info_m88(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32  ret_val;
+       u16 phy_data;
+       bool link;
+
+       if (hw->phy.media_type != e1000_media_type_copper) {
+               hw_dbg(hw, "Phy info is only valid for copper media\n");
+               ret_val = -E1000_ERR_CONFIG;
+               goto out;
+       }
+
+       ret_val = igb_phy_has_link(hw, 1, 0, &link);
+       if (ret_val)
+               goto out;
+
+       if (!link) {
+               hw_dbg(hw, "Phy info is only valid if link is up\n");
+               ret_val = -E1000_ERR_CONFIG;
+               goto out;
+       }
+
+       ret_val = hw->phy.ops.read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+                                          &phy_data);
+       if (ret_val)
+               goto out;
+
+       phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL)
+                                  ? true
+                                  : false;
+
+       ret_val = igb_check_polarity_m88(hw);
+       if (ret_val)
+               goto out;
+
+       ret_val = hw->phy.ops.read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+                                          &phy_data);
+       if (ret_val)
+               goto out;
+
+       phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? true : false;
+
+       if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
+               ret_val = hw->phy.ops.get_cable_length(hw);
+               if (ret_val)
+                       goto out;
+
+               ret_val = hw->phy.ops.read_phy_reg(hw, PHY_1000T_STATUS,
+                                                  &phy_data);
+               if (ret_val)
+                       goto out;
+
+               phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS)
+                               ? e1000_1000t_rx_status_ok
+                               : e1000_1000t_rx_status_not_ok;
+
+               phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS)
+                                ? e1000_1000t_rx_status_ok
+                                : e1000_1000t_rx_status_not_ok;
+       } else {
+               /* Set values to "undefined" */
+               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_get_phy_info_igp - Retrieve igp PHY information
+ *  @hw: pointer to the HW structure
+ *
+ *  Read PHY status to determine if link is up.  If link is up, then
+ *  set/determine 10base-T extended distance and polarity correction.  Read
+ *  PHY port status to determine MDI/MDIx and speed.  Based on the speed,
+ *  determine on the cable length, local and remote receiver.
+ **/
+s32 igb_get_phy_info_igp(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32 ret_val;
+       u16 data;
+       bool link;
+
+       ret_val = igb_phy_has_link(hw, 1, 0, &link);
+       if (ret_val)
+               goto out;
+
+       if (!link) {
+               hw_dbg(hw, "Phy info is only valid if link is up\n");
+               ret_val = -E1000_ERR_CONFIG;
+               goto out;
+       }
+
+       phy->polarity_correction = true;
+
+       ret_val = igb_check_polarity_igp(hw);
+       if (ret_val)
+               goto out;
+
+       ret_val = hw->phy.ops.read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS,
+                                          &data);
+       if (ret_val)
+               goto out;
+
+       phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? true : false;
+
+       if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
+           IGP01E1000_PSSR_SPEED_1000MBPS) {
+               ret_val = hw->phy.ops.get_cable_length(hw);
+               if (ret_val)
+                       goto out;
+
+               ret_val = hw->phy.ops.read_phy_reg(hw, PHY_1000T_STATUS,
+                                                  &data);
+               if (ret_val)
+                       goto out;
+
+               phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
+                               ? e1000_1000t_rx_status_ok
+                               : e1000_1000t_rx_status_not_ok;
+
+               phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
+                                ? e1000_1000t_rx_status_ok
+                                : e1000_1000t_rx_status_not_ok;
+       } else {
+               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 - PHY software reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Does a software reset of the PHY by reading the PHY control register and
+ *  setting/write the control register reset bit to the PHY.
+ **/
+s32 igb_phy_sw_reset(struct e1000_hw *hw)
+{
+       s32 ret_val;
+       u16 phy_ctrl;
+
+       ret_val = hw->phy.ops.read_phy_reg(hw, PHY_CONTROL, &phy_ctrl);
+       if (ret_val)
+               goto out;
+
+       phy_ctrl |= MII_CR_RESET;
+       ret_val = hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, phy_ctrl);
+       if (ret_val)
+               goto out;
+
+       udelay(1);
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_phy_hw_reset - PHY hardware reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Verify the reset block is not blocking us from resetting.  Acquire
+ *  semaphore (if necessary) and read/set/write the device control reset
+ *  bit in the PHY.  Wait the appropriate delay time for the device to
+ *  reset and relase the semaphore (if necessary).
+ **/
+s32 igb_phy_hw_reset(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32  ret_val;
+       u32 ctrl;
+
+       ret_val = igb_check_reset_block(hw);
+       if (ret_val) {
+               ret_val = 0;
+               goto out;
+       }
+
+       ret_val = igb_acquire_phy(hw);
+       if (ret_val)
+               goto out;
+
+       ctrl = rd32(E1000_CTRL);
+       wr32(E1000_CTRL, ctrl | E1000_CTRL_PHY_RST);
+       wrfl();
+
+       udelay(phy->reset_delay_us);
+
+       wr32(E1000_CTRL, ctrl);
+       wrfl();
+
+       udelay(150);
+
+       igb_release_phy(hw);
+
+       ret_val = igb_get_phy_cfg_done(hw);
+
+out:
+       return ret_val;
+}
+
+/* Internal function pointers */
+
+/**
+ *  e1000_get_phy_cfg_done - Generic PHY configuration done
+ *  @hw: pointer to the HW structure
+ *
+ *  Return success if silicon family did not implement a family specific
+ *  get_cfg_done function.
+ **/
+static s32 igb_get_phy_cfg_done(struct e1000_hw *hw)
+{
+       if (hw->phy.ops.get_cfg_done)
+               return hw->phy.ops.get_cfg_done(hw);
+
+       return 0;
+}
+
+/**
+ *  e1000_release_phy - Generic release PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Return if silicon family does not require a semaphore when accessing the
+ *  PHY.
+ **/
+static void igb_release_phy(struct e1000_hw *hw)
+{
+       if (hw->phy.ops.release_phy)
+               hw->phy.ops.release_phy(hw);
+}
+
+/**
+ *  e1000_acquire_phy - Generic acquire PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Return success if silicon family does not require a semaphore when
+ *  accessing the PHY.
+ **/
+static s32 igb_acquire_phy(struct e1000_hw *hw)
+{
+       if (hw->phy.ops.acquire_phy)
+               return hw->phy.ops.acquire_phy(hw);
+
+       return 0;
+}
+
+/**
+ *  e1000_phy_force_speed_duplex - Generic force PHY speed/duplex
+ *  @hw: pointer to the HW structure
+ *
+ *  When the silicon family has not implemented a forced speed/duplex
+ *  function for the PHY, simply return 0.
+ **/
+s32 igb_phy_force_speed_duplex(struct e1000_hw *hw)
+{
+       if (hw->phy.ops.force_speed_duplex)
+               return hw->phy.ops.force_speed_duplex(hw);
+
+       return 0;
+}
+
+/**
+ *  e1000_phy_init_script_igp3 - Inits the IGP3 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes a Intel Gigabit PHY3 when an EEPROM is not present.
+ **/
+s32 igb_phy_init_script_igp3(struct e1000_hw *hw)
+{
+       hw_dbg(hw, "Running IGP 3 PHY init script\n");
+
+       /* PHY init IGP 3 */
+       /* Enable rise/fall, 10-mode work in class-A */
+       hw->phy.ops.write_phy_reg(hw, 0x2F5B, 0x9018);
+       /* Remove all caps from Replica path filter */
+       hw->phy.ops.write_phy_reg(hw, 0x2F52, 0x0000);
+       /* Bias trimming for ADC, AFE and Driver (Default) */
+       hw->phy.ops.write_phy_reg(hw, 0x2FB1, 0x8B24);
+       /* Increase Hybrid poly bias */
+       hw->phy.ops.write_phy_reg(hw, 0x2FB2, 0xF8F0);
+       /* Add 4% to TX amplitude in Giga mode */
+       hw->phy.ops.write_phy_reg(hw, 0x2010, 0x10B0);
+       /* Disable trimming (TTT) */
+       hw->phy.ops.write_phy_reg(hw, 0x2011, 0x0000);
+       /* Poly DC correction to 94.6% + 2% for all channels */
+       hw->phy.ops.write_phy_reg(hw, 0x20DD, 0x249A);
+       /* ABS DC correction to 95.9% */
+       hw->phy.ops.write_phy_reg(hw, 0x20DE, 0x00D3);
+       /* BG temp curve trim */
+       hw->phy.ops.write_phy_reg(hw, 0x28B4, 0x04CE);
+       /* Increasing ADC OPAMP stage 1 currents to max */
+       hw->phy.ops.write_phy_reg(hw, 0x2F70, 0x29E4);
+       /* Force 1000 ( required for enabling PHY regs configuration) */
+       hw->phy.ops.write_phy_reg(hw, 0x0000, 0x0140);
+       /* Set upd_freq to 6 */
+       hw->phy.ops.write_phy_reg(hw, 0x1F30, 0x1606);
+       /* Disable NPDFE */
+       hw->phy.ops.write_phy_reg(hw, 0x1F31, 0xB814);
+       /* Disable adaptive fixed FFE (Default) */
+       hw->phy.ops.write_phy_reg(hw, 0x1F35, 0x002A);
+       /* Enable FFE hysteresis */
+       hw->phy.ops.write_phy_reg(hw, 0x1F3E, 0x0067);
+       /* Fixed FFE for short cable lengths */
+       hw->phy.ops.write_phy_reg(hw, 0x1F54, 0x0065);
+       /* Fixed FFE for medium cable lengths */
+       hw->phy.ops.write_phy_reg(hw, 0x1F55, 0x002A);
+       /* Fixed FFE for long cable lengths */
+       hw->phy.ops.write_phy_reg(hw, 0x1F56, 0x002A);
+       /* Enable Adaptive Clip Threshold */
+       hw->phy.ops.write_phy_reg(hw, 0x1F72, 0x3FB0);
+       /* AHT reset limit to 1 */
+       hw->phy.ops.write_phy_reg(hw, 0x1F76, 0xC0FF);
+       /* Set AHT master delay to 127 msec */
+       hw->phy.ops.write_phy_reg(hw, 0x1F77, 0x1DEC);
+       /* Set scan bits for AHT */
+       hw->phy.ops.write_phy_reg(hw, 0x1F78, 0xF9EF);
+       /* Set AHT Preset bits */
+       hw->phy.ops.write_phy_reg(hw, 0x1F79, 0x0210);
+       /* Change integ_factor of channel A to 3 */
+       hw->phy.ops.write_phy_reg(hw, 0x1895, 0x0003);
+       /* Change prop_factor of channels BCD to 8 */
+       hw->phy.ops.write_phy_reg(hw, 0x1796, 0x0008);
+       /* Change cg_icount + enable integbp for channels BCD */
+       hw->phy.ops.write_phy_reg(hw, 0x1798, 0xD008);
+       /*
+        * Change cg_icount + enable integbp + change prop_factor_master
+        * to 8 for channel A
+        */
+       hw->phy.ops.write_phy_reg(hw, 0x1898, 0xD918);
+       /* Disable AHT in Slave mode on channel A */
+       hw->phy.ops.write_phy_reg(hw, 0x187A, 0x0800);
+       /*
+        * Enable LPLU and disable AN to 1000 in non-D0a states,
+        * Enable SPD+B2B
+        */
+       hw->phy.ops.write_phy_reg(hw, 0x0019, 0x008D);
+       /* Enable restart AN on an1000_dis change */
+       hw->phy.ops.write_phy_reg(hw, 0x001B, 0x2080);
+       /* Enable wh_fifo read clock in 10/100 modes */
+       hw->phy.ops.write_phy_reg(hw, 0x0014, 0x0045);
+       /* Restart AN, Speed selection is 1000 */
+       hw->phy.ops.write_phy_reg(hw, 0x0000, 0x1340);
+
+       return 0;
+}
+
diff --git a/drivers/net/igb/e1000_phy.h b/drivers/net/igb/e1000_phy.h
new file mode 100644 (file)
index 0000000..8f8fe0a
--- /dev/null
@@ -0,0 +1,98 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_PHY_H_
+#define _E1000_PHY_H_
+
+enum e1000_ms_type {
+       e1000_ms_hw_default = 0,
+       e1000_ms_force_master,
+       e1000_ms_force_slave,
+       e1000_ms_auto
+};
+
+enum e1000_smart_speed {
+       e1000_smart_speed_default = 0,
+       e1000_smart_speed_on,
+       e1000_smart_speed_off
+};
+
+s32  igb_check_downshift(struct e1000_hw *hw);
+s32  igb_check_reset_block(struct e1000_hw *hw);
+s32  igb_copper_link_autoneg(struct e1000_hw *hw);
+s32  igb_phy_force_speed_duplex(struct e1000_hw *hw);
+s32  igb_copper_link_setup_igp(struct e1000_hw *hw);
+s32  igb_copper_link_setup_m88(struct e1000_hw *hw);
+s32  igb_phy_force_speed_duplex_igp(struct e1000_hw *hw);
+s32  igb_phy_force_speed_duplex_m88(struct e1000_hw *hw);
+s32  igb_get_cable_length_m88(struct e1000_hw *hw);
+s32  igb_get_cable_length_igp_2(struct e1000_hw *hw);
+s32  igb_get_phy_id(struct e1000_hw *hw);
+s32  igb_get_phy_info_igp(struct e1000_hw *hw);
+s32  igb_get_phy_info_m88(struct e1000_hw *hw);
+s32  igb_phy_sw_reset(struct e1000_hw *hw);
+s32  igb_phy_hw_reset(struct e1000_hw *hw);
+s32  igb_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  igb_set_d3_lplu_state(struct e1000_hw *hw, bool active);
+s32  igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
+s32  igb_phy_has_link(struct e1000_hw *hw, u32 iterations,
+                               u32 usec_interval, bool *success);
+s32  igb_phy_init_script_igp3(struct e1000_hw *hw);
+
+/* IGP01E1000 Specific Registers */
+#define IGP01E1000_PHY_PORT_CONFIG        0x10 /* Port Config */
+#define IGP01E1000_PHY_PORT_STATUS        0x11 /* Status */
+#define IGP01E1000_PHY_PORT_CTRL          0x12 /* Control */
+#define IGP01E1000_PHY_LINK_HEALTH        0x13 /* PHY Link Health */
+#define IGP02E1000_PHY_POWER_MGMT         0x19 /* Power Management */
+#define IGP01E1000_PHY_PAGE_SELECT        0x1F /* Page Select */
+#define IGP01E1000_PHY_PCS_INIT_REG       0x00B4
+#define IGP01E1000_PHY_POLARITY_MASK      0x0078
+#define IGP01E1000_PSCR_AUTO_MDIX         0x1000
+#define IGP01E1000_PSCR_FORCE_MDI_MDIX    0x2000 /* 0=MDI, 1=MDIX */
+#define IGP01E1000_PSCFR_SMART_SPEED      0x0080
+
+/* Enable flexible speed on link-up */
+#define IGP02E1000_PM_D0_LPLU             0x0002 /* For D0a states */
+#define IGP02E1000_PM_D3_LPLU             0x0004 /* For all other states */
+#define IGP01E1000_PLHR_SS_DOWNGRADE      0x8000
+#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002
+#define IGP01E1000_PSSR_MDIX              0x0008
+#define IGP01E1000_PSSR_SPEED_MASK        0xC000
+#define IGP01E1000_PSSR_SPEED_1000MBPS    0xC000
+#define IGP02E1000_PHY_CHANNEL_NUM        4
+#define IGP02E1000_PHY_AGC_A              0x11B1
+#define IGP02E1000_PHY_AGC_B              0x12B1
+#define IGP02E1000_PHY_AGC_C              0x14B1
+#define IGP02E1000_PHY_AGC_D              0x18B1
+#define IGP02E1000_AGC_LENGTH_SHIFT       9   /* Course - 15:13, Fine - 12:9 */
+#define IGP02E1000_AGC_LENGTH_MASK        0x7F
+#define IGP02E1000_AGC_RANGE              15
+
+#define E1000_CABLE_LENGTH_UNDEFINED      0xFF
+
+#endif
diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h
new file mode 100644 (file)
index 0000000..ff187b7
--- /dev/null
@@ -0,0 +1,270 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_REGS_H_
+#define _E1000_REGS_H_
+
+#define E1000_CTRL     0x00000  /* Device Control - RW */
+#define E1000_STATUS   0x00008  /* Device Status - RO */
+#define E1000_EECD     0x00010  /* EEPROM/Flash Control - RW */
+#define E1000_EERD     0x00014  /* EEPROM Read - RW */
+#define E1000_CTRL_EXT 0x00018  /* Extended Device Control - RW */
+#define E1000_MDIC     0x00020  /* MDI Control - RW */
+#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 */
+#define E1000_FCT      0x00030  /* Flow Control Type - RW */
+#define E1000_CONNSW   0x00034  /* Copper/Fiber switch control - RW */
+#define E1000_VET      0x00038  /* VLAN Ether Type - RW */
+#define E1000_ICR      0x000C0  /* Interrupt Cause Read - R/clr */
+#define E1000_ITR      0x000C4  /* Interrupt Throttling Rate - RW */
+#define E1000_ICS      0x000C8  /* Interrupt Cause Set - WO */
+#define E1000_IMS      0x000D0  /* Interrupt Mask Set - RW */
+#define E1000_IMC      0x000D8  /* Interrupt Mask Clear - WO */
+#define E1000_IAM      0x000E0  /* Interrupt Acknowledge Auto Mask */
+#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 */
+#define E1000_EICR     0x01580  /* Ext. Interrupt Cause Read - R/clr */
+#define E1000_EITR(_n) (0x01680 + (0x4 * (_n)))
+#define E1000_EICS     0x01520  /* Ext. Interrupt Cause Set - W0 */
+#define E1000_EIMS     0x01524  /* Ext. Interrupt Mask Set/Read - RW */
+#define E1000_EIMC     0x01528  /* Ext. Interrupt Mask Clear - WO */
+#define E1000_EIAC     0x0152C  /* Ext. Interrupt Auto Clear - RW */
+#define E1000_EIAM     0x01530  /* Ext. Interrupt Ack Auto Clear Mask - RW */
+#define E1000_TCTL     0x00400  /* TX Control - RW */
+#define E1000_TCTL_EXT 0x00404  /* Extended TX Control - RW */
+#define E1000_TIPG     0x00410  /* TX Inter-packet gap -RW */
+#define E1000_AIT      0x00458  /* Adaptive Interframe Spacing Throttle - RW */
+#define E1000_LEDCTL   0x00E00  /* LED Control - RW */
+#define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
+#define E1000_PBS      0x01008  /* Packet Buffer Size */
+#define E1000_EEMNGCTL 0x01010  /* MNG EEprom Control */
+#define E1000_EEWR     0x0102C  /* EEPROM Write Register - RW */
+#define E1000_I2CCMD   0x01028  /* SFPI2C Command Register - RW */
+#define E1000_FRTIMER  0x01048  /* Free Running Timer - RW */
+#define E1000_TCPTIMER 0x0104C  /* TCP Timer - RW */
+#define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
+#define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
+#define E1000_RDFPCQ(_n)  (0x02430 + (0x4 * (_n)))
+#define E1000_FCRTV    0x02460  /* Flow Control Refresh Timer Value - RW */
+/* Split and Replication RX Control - RW */
+/*
+ * Convenience macros
+ *
+ * Note: "_n" is the queue number of the register to be written to.
+ *
+ * Example usage:
+ * E1000_RDBAL_REG(current_rx_queue)
+ */
+#define E1000_RDBAL(_n)   ((_n) < 4 ? (0x02800 + ((_n) * 0x100)) \
+                                   : (0x0C000 + ((_n) * 0x40)))
+#define E1000_RDBAH(_n)   ((_n) < 4 ? (0x02804 + ((_n) * 0x100)) \
+                                   : (0x0C004 + ((_n) * 0x40)))
+#define E1000_RDLEN(_n)   ((_n) < 4 ? (0x02808 + ((_n) * 0x100)) \
+                                   : (0x0C008 + ((_n) * 0x40)))
+#define E1000_SRRCTL(_n)  ((_n) < 4 ? (0x0280C + ((_n) * 0x100)) \
+                                   : (0x0C00C + ((_n) * 0x40)))
+#define E1000_RDH(_n)     ((_n) < 4 ? (0x02810 + ((_n) * 0x100)) \
+                                   : (0x0C010 + ((_n) * 0x40)))
+#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_TDBAL(_n)   ((_n) < 4 ? (0x03800 + ((_n) * 0x100)) \
+                                   : (0x0E000 + ((_n) * 0x40)))
+#define E1000_TDBAH(_n)   ((_n) < 4 ? (0x03804 + ((_n) * 0x100)) \
+                                   : (0x0E004 + ((_n) * 0x40)))
+#define E1000_TDLEN(_n)   ((_n) < 4 ? (0x03808 + ((_n) * 0x100)) \
+                                   : (0x0E008 + ((_n) * 0x40)))
+#define E1000_TDH(_n)     ((_n) < 4 ? (0x03810 + ((_n) * 0x100)) \
+                                   : (0x0E010 + ((_n) * 0x40)))
+#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_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 */
+#define E1000_TDFPC    0x03430  /* TX Data FIFO Packet Count - RW */
+#define E1000_DTXCTL   0x03590  /* DMA TX Control - RW */
+#define E1000_CRCERRS  0x04000  /* CRC Error Count - R/clr */
+#define E1000_ALGNERRC 0x04004  /* Alignment Error Count - R/clr */
+#define E1000_SYMERRS  0x04008  /* Symbol Error Count - R/clr */
+#define E1000_RXERRC   0x0400C  /* Receive Error Count - R/clr */
+#define E1000_MPC      0x04010  /* Missed Packet Count - R/clr */
+#define E1000_SCC      0x04014  /* Single Collision Count - R/clr */
+#define E1000_ECOL     0x04018  /* Excessive Collision Count - R/clr */
+#define E1000_MCC      0x0401C  /* Multiple Collision Count - R/clr */
+#define E1000_LATECOL  0x04020  /* Late Collision Count - R/clr */
+#define E1000_COLC     0x04028  /* Collision Count - R/clr */
+#define E1000_DC       0x04030  /* Defer Count - R/clr */
+#define E1000_TNCRS    0x04034  /* TX-No CRS - R/clr */
+#define E1000_SEC      0x04038  /* Sequence Error Count - R/clr */
+#define E1000_CEXTERR  0x0403C  /* Carrier Extension Error Count - R/clr */
+#define E1000_RLEC     0x04040  /* Receive Length Error Count - R/clr */
+#define E1000_XONRXC   0x04048  /* XON RX Count - R/clr */
+#define E1000_XONTXC   0x0404C  /* XON TX Count - R/clr */
+#define E1000_XOFFRXC  0x04050  /* XOFF RX Count - R/clr */
+#define E1000_XOFFTXC  0x04054  /* XOFF TX Count - R/clr */
+#define E1000_FCRUC    0x04058  /* Flow Control RX Unsupported Count- R/clr */
+#define E1000_PRC64    0x0405C  /* Packets RX (64 bytes) - R/clr */
+#define E1000_PRC127   0x04060  /* Packets RX (65-127 bytes) - R/clr */
+#define E1000_PRC255   0x04064  /* Packets RX (128-255 bytes) - R/clr */
+#define E1000_PRC511   0x04068  /* Packets RX (255-511 bytes) - R/clr */
+#define E1000_PRC1023  0x0406C  /* Packets RX (512-1023 bytes) - R/clr */
+#define E1000_PRC1522  0x04070  /* Packets RX (1024-1522 bytes) - R/clr */
+#define E1000_GPRC     0x04074  /* Good Packets RX Count - R/clr */
+#define E1000_BPRC     0x04078  /* Broadcast Packets RX Count - R/clr */
+#define E1000_MPRC     0x0407C  /* Multicast Packets RX Count - R/clr */
+#define E1000_GPTC     0x04080  /* Good Packets TX Count - R/clr */
+#define E1000_GORCL    0x04088  /* Good Octets RX Count Low - R/clr */
+#define E1000_GORCH    0x0408C  /* Good Octets RX Count High - R/clr */
+#define E1000_GOTCL    0x04090  /* Good Octets TX Count Low - R/clr */
+#define E1000_GOTCH    0x04094  /* Good Octets TX Count High - R/clr */
+#define E1000_RNBC     0x040A0  /* RX No Buffers Count - R/clr */
+#define E1000_RUC      0x040A4  /* RX Undersize Count - R/clr */
+#define E1000_RFC      0x040A8  /* RX Fragment Count - R/clr */
+#define E1000_ROC      0x040AC  /* RX Oversize Count - R/clr */
+#define E1000_RJC      0x040B0  /* RX Jabber Count - R/clr */
+#define E1000_MGTPRC   0x040B4  /* Management Packets RX Count - R/clr */
+#define E1000_MGTPDC   0x040B8  /* Management Packets Dropped Count - R/clr */
+#define E1000_MGTPTC   0x040BC  /* Management Packets TX Count - R/clr */
+#define E1000_TORL     0x040C0  /* Total Octets RX Low - R/clr */
+#define E1000_TORH     0x040C4  /* Total Octets RX High - R/clr */
+#define E1000_TOTL     0x040C8  /* Total Octets TX Low - R/clr */
+#define E1000_TOTH     0x040CC  /* Total Octets TX High - R/clr */
+#define E1000_TPR      0x040D0  /* Total Packets RX - R/clr */
+#define E1000_TPT      0x040D4  /* Total Packets TX - R/clr */
+#define E1000_PTC64    0x040D8  /* Packets TX (64 bytes) - R/clr */
+#define E1000_PTC127   0x040DC  /* Packets TX (65-127 bytes) - R/clr */
+#define E1000_PTC255   0x040E0  /* Packets TX (128-255 bytes) - R/clr */
+#define E1000_PTC511   0x040E4  /* Packets TX (256-511 bytes) - R/clr */
+#define E1000_PTC1023  0x040E8  /* Packets TX (512-1023 bytes) - R/clr */
+#define E1000_PTC1522  0x040EC  /* Packets TX (1024-1522 Bytes) - R/clr */
+#define E1000_MPTC     0x040F0  /* Multicast Packets TX Count - R/clr */
+#define E1000_BPTC     0x040F4  /* Broadcast Packets TX Count - R/clr */
+#define E1000_TSCTC    0x040F8  /* TCP Segmentation Context TX - R/clr */
+#define E1000_TSCTFC   0x040FC  /* TCP Segmentation Context TX Fail - R/clr */
+#define E1000_IAC      0x04100  /* Interrupt Assertion Count */
+/* Interrupt Cause Rx Packet Timer Expire Count */
+#define E1000_ICRXPTC  0x04104
+/* Interrupt Cause Rx Absolute Timer Expire Count */
+#define E1000_ICRXATC  0x04108
+/* Interrupt Cause Tx Packet Timer Expire Count */
+#define E1000_ICTXPTC  0x0410C
+/* Interrupt Cause Tx Absolute Timer Expire Count */
+#define E1000_ICTXATC  0x04110
+/* Interrupt Cause Tx Queue Empty Count */
+#define E1000_ICTXQEC  0x04118
+/* Interrupt Cause Tx Queue Minimum Threshold Count */
+#define E1000_ICTXQMTC 0x0411C
+/* Interrupt Cause Rx Descriptor Minimum Threshold Count */
+#define E1000_ICRXDMTC 0x04120
+#define E1000_ICRXOC   0x04124  /* Interrupt Cause Receiver Overrun Count */
+#define E1000_PCS_CFG0    0x04200  /* PCS Configuration 0 - RW */
+#define E1000_PCS_LCTL    0x04208  /* PCS Link Control - RW */
+#define E1000_PCS_LSTAT   0x0420C  /* PCS Link Status - RO */
+#define E1000_CBTMPC      0x0402C  /* Circuit Breaker TX Packet Count */
+#define E1000_HTDPMC      0x0403C  /* Host Transmit Discarded Packets */
+#define E1000_CBRMPC      0x040FC  /* Circuit Breaker RX Packet Count */
+#define E1000_RPTHC       0x04104  /* Rx Packets To Host */
+#define E1000_HGPTC       0x04118  /* Host Good Packets TX Count */
+#define E1000_HTCBDPC     0x04124  /* Host TX Circuit Breaker Dropped Count */
+#define E1000_HGORCL      0x04128  /* Host Good Octets Received Count Low */
+#define E1000_HGORCH      0x0412C  /* Host Good Octets Received Count High */
+#define E1000_HGOTCL      0x04130  /* Host Good Octets Transmit Count Low */
+#define E1000_HGOTCH      0x04134  /* Host Good Octets Transmit Count High */
+#define E1000_LENERRS     0x04138  /* Length Errors Count */
+#define E1000_SCVPC       0x04228  /* SerDes/SGMII Code Violation Pkt Count */
+#define E1000_PCS_ANADV   0x04218  /* AN advertisement - RW */
+#define E1000_PCS_LPAB    0x0421C  /* Link Partner Ability - RW */
+#define E1000_PCS_NPTX    0x04220  /* AN Next Page Transmit - RW */
+#define E1000_PCS_LPABNP  0x04224  /* Link Partner Ability Next Page - RW */
+#define E1000_RXCSUM   0x05000  /* RX Checksum Control - RW */
+#define E1000_RLPML    0x05004  /* RX Long Packet Max Length */
+#define E1000_RFCTL    0x05008  /* Receive Filter Control*/
+#define E1000_MTA      0x05200  /* Multicast Table Array - RW Array */
+#define E1000_RA       0x05400  /* Receive Address - RW Array */
+#define E1000_VFTA     0x05600  /* VLAN Filter Table Array - RW Array */
+#define E1000_VMD_CTL  0x0581C  /* VMDq Control - RW */
+#define E1000_WUC      0x05800  /* Wakeup Control - RW */
+#define E1000_WUFC     0x05808  /* Wakeup Filter Control - RW */
+#define E1000_WUS      0x05810  /* Wakeup Status - RO */
+#define E1000_MANC     0x05820  /* Management Control - RW */
+#define E1000_IPAV     0x05838  /* IP Address Valid - RW */
+#define E1000_WUPL     0x05900  /* Wakeup Packet Length - RW */
+#define E1000_HOST_IF  0x08800  /* Host Interface */
+
+#define E1000_MANC2H      0x05860 /* Management Control To Host - RW */
+#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 */
+#define E1000_SCCTL       0x05B4C /* PCIc PLL Configuration Register */
+#define E1000_FACTPS    0x05B30 /* Function Active and Power State to MNG */
+#define E1000_SWSM      0x05B50 /* SW Semaphore */
+#define E1000_FWSM      0x05B54 /* FW Semaphore */
+#define E1000_HICR      0x08F00 /* Host Inteface Control */
+
+/* RSS registers */
+#define E1000_MRQC      0x05818 /* Multiple Receive Control - RW */
+#define E1000_IMIR(_i)      (0x05A80 + ((_i) * 4))  /* Immediate Interrupt */
+#define E1000_IMIREXT(_i)   (0x05AA0 + ((_i) * 4))  /* Immediate Interrupt Ext*/
+#define E1000_IMIRVP    0x05AC0 /* Immediate Interrupt RX VLAN Priority - RW */
+/* MSI-X Allocation Register (_i) - RW */
+#define E1000_MSIXBM(_i)    (0x01600 + ((_i) * 4))
+/* MSI-X Table entry addr low reg 0 - RW */
+#define E1000_MSIXTADD(_i)  (0x0C000 + ((_i) * 0x10))
+/* MSI-X Table entry addr upper reg 0 - RW */
+#define E1000_MSIXTUADD(_i) (0x0C004 + ((_i) * 0x10))
+/* MSI-X Table entry message reg 0 - RW */
+#define E1000_MSIXTMSG(_i)  (0x0C008 + ((_i) * 0x10))
+/* MSI-X Table entry vector ctrl reg 0 - RW */
+#define E1000_MSIXVCTRL(_i) (0x0C00C + ((_i) * 0x10))
+/* Redirection Table - RW Array */
+#define E1000_RETA(_i)  (0x05C00 + ((_i) * 4))
+#define E1000_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* RSS Random Key - RW Array */
+
+#define E1000_REGISTER(a, reg) reg
+
+#define wr32(reg, value) (writel(value, hw->hw_addr + reg))
+#define rd32(reg) (readl(hw->hw_addr + reg))
+#define wrfl() ((void)rd32(E1000_STATUS))
+
+#define array_wr32(reg, offset, value) \
+       (writel(value, hw->hw_addr + reg + ((offset) << 2)))
+#define array_rd32(reg, offset) \
+       (readl(hw->hw_addr + reg + ((offset) << 2)))
+
+#endif
diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h
new file mode 100644 (file)
index 0000000..6b2e7d3
--- /dev/null
@@ -0,0 +1,300 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+
+/* Linux PRO/1000 Ethernet Driver main header file */
+
+#ifndef _IGB_H_
+#define _IGB_H_
+
+#include "e1000_mac.h"
+#include "e1000_82575.h"
+
+struct igb_adapter;
+
+/* Interrupt defines */
+#define IGB_MAX_TX_CLEAN 72
+
+#define IGB_MIN_DYN_ITR 3000
+#define IGB_MAX_DYN_ITR 96000
+#define IGB_START_ITR 6000
+
+#define IGB_DYN_ITR_PACKET_THRESHOLD 2
+#define IGB_DYN_ITR_LENGTH_LOW 200
+#define IGB_DYN_ITR_LENGTH_HIGH 1000
+
+/* TX/RX descriptor defines */
+#define IGB_DEFAULT_TXD                  256
+#define IGB_MIN_TXD                       80
+#define IGB_MAX_TXD                     4096
+
+#define IGB_DEFAULT_RXD                  256
+#define IGB_MIN_RXD                       80
+#define IGB_MAX_RXD                     4096
+
+#define IGB_DEFAULT_ITR                    3 /* dynamic */
+#define IGB_MAX_ITR_USECS              10000
+#define IGB_MIN_ITR_USECS                 10
+
+/* Transmit and receive queues */
+#define IGB_MAX_RX_QUEUES                  4
+
+/* RX descriptor control thresholds.
+ * PTHRESH - MAC will consider prefetch if it has fewer than this number of
+ *           descriptors available in its onboard memory.
+ *           Setting this to 0 disables RX descriptor prefetch.
+ * HTHRESH - MAC will only prefetch if there are at least this many descriptors
+ *           available in host memory.
+ *           If PTHRESH is 0, this should also be 0.
+ * WTHRESH - RX descriptor writeback threshold - MAC will delay writing back
+ *           descriptors until either it has this many to write back, or the
+ *           ITR timer expires.
+ */
+#define IGB_RX_PTHRESH                    16
+#define IGB_RX_HTHRESH                     8
+#define IGB_RX_WTHRESH                     1
+
+/* this is the size past which hardware will drop packets when setting LPE=0 */
+#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
+
+/* Supported Rx Buffer Sizes */
+#define IGB_RXBUFFER_128   128    /* Used for packet split */
+#define IGB_RXBUFFER_256   256    /* Used for packet split */
+#define IGB_RXBUFFER_512   512
+#define IGB_RXBUFFER_1024  1024
+#define IGB_RXBUFFER_2048  2048
+#define IGB_RXBUFFER_4096  4096
+#define IGB_RXBUFFER_8192  8192
+#define IGB_RXBUFFER_16384 16384
+
+/* Packet Buffer allocations */
+
+
+/* How many Tx Descriptors do we need to call netif_wake_queue ? */
+#define IGB_TX_QUEUE_WAKE      16
+/* How many Rx Buffers do we bundle into one write to the hardware ? */
+#define IGB_RX_BUFFER_WRITE    16      /* Must be power of 2 */
+
+#define AUTO_ALL_MODES            0
+#define IGB_EEPROM_APME         0x0400
+
+#ifndef IGB_MASTER_SLAVE
+/* Switch to override PHY master/slave setting */
+#define IGB_MASTER_SLAVE       e1000_ms_hw_default
+#endif
+
+#define IGB_MNG_VLAN_NONE -1
+
+/* wrapper around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer */
+struct igb_buffer {
+       struct sk_buff *skb;
+       dma_addr_t dma;
+       union {
+               /* TX */
+               struct {
+                       unsigned long time_stamp;
+                       u32 length;
+               };
+               /* RX */
+               struct {
+                       struct page *page;
+                       u64 page_dma;
+               };
+       };
+};
+
+struct igb_queue_stats {
+       u64 packets;
+       u64 bytes;
+};
+
+struct igb_ring {
+       struct igb_adapter *adapter; /* backlink */
+       void *desc;                  /* descriptor ring memory */
+       dma_addr_t dma;              /* phys address of the ring */
+       unsigned int size;           /* length of desc. ring in bytes */
+       unsigned int count;          /* number of desc. in the ring */
+       u16 next_to_use;
+       u16 next_to_clean;
+       u16 head;
+       u16 tail;
+       struct igb_buffer *buffer_info; /* array of buffer info structs */
+
+       u32 eims_value;
+       u32 itr_val;
+       u16 itr_register;
+       u16 cpu;
+
+       unsigned int total_bytes;
+       unsigned int total_packets;
+
+       union {
+               /* TX */
+               struct {
+                       spinlock_t tx_clean_lock;
+                       spinlock_t tx_lock;
+                       bool detect_tx_hung;
+               };
+               /* RX */
+               struct {
+                       /* arrays of page information for packet split */
+                       struct sk_buff *pending_skb;
+                       int pending_skb_page;
+                       int no_itr_adjust;
+                       struct igb_queue_stats rx_stats;
+                       struct napi_struct napi;
+               };
+       };
+
+       char name[IFNAMSIZ + 5];
+};
+
+#define IGB_DESC_UNUSED(R) \
+       ((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
+       (R)->next_to_clean - (R)->next_to_use - 1)
+
+#define E1000_RX_DESC_ADV(R, i)            \
+       (&(((union e1000_adv_rx_desc *)((R).desc))[i]))
+#define E1000_TX_DESC_ADV(R, i)            \
+       (&(((union e1000_adv_tx_desc *)((R).desc))[i]))
+#define E1000_TX_CTXTDESC_ADV(R, i)        \
+       (&(((struct e1000_adv_tx_context_desc *)((R).desc))[i]))
+#define E1000_GET_DESC(R, i, type)     (&(((struct type *)((R).desc))[i]))
+#define E1000_TX_DESC(R, i)            E1000_GET_DESC(R, i, e1000_tx_desc)
+#define E1000_RX_DESC(R, i)            E1000_GET_DESC(R, i, e1000_rx_desc)
+
+/* board specific private data structure */
+
+struct igb_adapter {
+       struct timer_list watchdog_timer;
+       struct timer_list phy_info_timer;
+       struct vlan_group *vlgrp;
+       u16 mng_vlan_id;
+       u32 bd_number;
+       u32 rx_buffer_len;
+       u32 wol;
+       u32 en_mng_pt;
+       u16 link_speed;
+       u16 link_duplex;
+       unsigned int total_tx_bytes;
+       unsigned int total_tx_packets;
+       unsigned int total_rx_bytes;
+       unsigned int total_rx_packets;
+       /* Interrupt Throttle Rate */
+       u32 itr;
+       u32 itr_setting;
+       u16 tx_itr;
+       u16 rx_itr;
+       int set_itr;
+
+       struct work_struct reset_task;
+       struct work_struct watchdog_task;
+       bool fc_autoneg;
+       u8  tx_timeout_factor;
+       struct timer_list blink_timer;
+       unsigned long led_status;
+
+       /* TX */
+       struct igb_ring *tx_ring;      /* One per active queue */
+       unsigned int restart_queue;
+       unsigned long tx_queue_len;
+       u32 txd_cmd;
+       u32 gotc;
+       u64 gotc_old;
+       u64 tpt_old;
+       u64 colc_old;
+       u32 tx_timeout_count;
+
+       /* RX */
+       struct igb_ring *rx_ring;      /* One per active queue */
+       int num_tx_queues;
+       int num_rx_queues;
+
+       u64 hw_csum_err;
+       u64 hw_csum_good;
+       u64 rx_hdr_split;
+       u32 alloc_rx_buff_failed;
+       bool rx_csum;
+       u32 gorc;
+       u64 gorc_old;
+       u16 rx_ps_hdr_size;
+       u32 max_frame_size;
+       u32 min_frame_size;
+
+       /* OS defined structs */
+       struct net_device *netdev;
+       struct napi_struct napi;
+       struct pci_dev *pdev;
+       struct net_device_stats net_stats;
+
+       /* structs defined in e1000_hw.h */
+       struct e1000_hw hw;
+       struct e1000_hw_stats stats;
+       struct e1000_phy_info phy_info;
+       struct e1000_phy_stats phy_stats;
+
+       u32 test_icr;
+       struct igb_ring test_tx_ring;
+       struct igb_ring test_rx_ring;
+
+       int msg_enable;
+       struct msix_entry *msix_entries;
+       u32 eims_enable_mask;
+
+       /* to not mess up cache alignment, always add to the bottom */
+       unsigned long state;
+       unsigned int msi_enabled;
+
+       u32 eeprom_wol;
+};
+
+enum e1000_state_t {
+       __IGB_TESTING,
+       __IGB_RESETTING,
+       __IGB_DOWN
+};
+
+enum igb_boards {
+       board_82575,
+};
+
+extern char igb_driver_name[];
+extern char igb_driver_version[];
+
+extern char *igb_get_hw_dev_name(struct e1000_hw *hw);
+extern int igb_up(struct igb_adapter *);
+extern void igb_down(struct igb_adapter *);
+extern void igb_reinit_locked(struct igb_adapter *);
+extern void igb_reset(struct igb_adapter *);
+extern int igb_set_spd_dplx(struct igb_adapter *, u16);
+extern int igb_setup_tx_resources(struct igb_adapter *, struct igb_ring *);
+extern int igb_setup_rx_resources(struct igb_adapter *, struct igb_ring *);
+extern void igb_update_stats(struct igb_adapter *);
+extern void igb_set_ethtool_ops(struct net_device *);
+
+#endif /* _IGB_H_ */
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c
new file mode 100644 (file)
index 0000000..f69721e
--- /dev/null
@@ -0,0 +1,1927 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* ethtool support for igb */
+
+#include <linux/vmalloc.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/if_ether.h>
+#include <linux/ethtool.h>
+
+#include "igb.h"
+
+struct igb_stats {
+       char stat_string[ETH_GSTRING_LEN];
+       int sizeof_stat;
+       int stat_offset;
+};
+
+#define IGB_STAT(m) sizeof(((struct igb_adapter *)0)->m), \
+                     offsetof(struct igb_adapter, m)
+static const struct igb_stats igb_gstrings_stats[] = {
+       { "rx_packets", IGB_STAT(stats.gprc) },
+       { "tx_packets", IGB_STAT(stats.gptc) },
+       { "rx_bytes", IGB_STAT(stats.gorc) },
+       { "tx_bytes", IGB_STAT(stats.gotc) },
+       { "rx_broadcast", IGB_STAT(stats.bprc) },
+       { "tx_broadcast", IGB_STAT(stats.bptc) },
+       { "rx_multicast", IGB_STAT(stats.mprc) },
+       { "tx_multicast", IGB_STAT(stats.mptc) },
+       { "rx_errors", IGB_STAT(net_stats.rx_errors) },
+       { "tx_errors", IGB_STAT(net_stats.tx_errors) },
+       { "tx_dropped", IGB_STAT(net_stats.tx_dropped) },
+       { "multicast", IGB_STAT(stats.mprc) },
+       { "collisions", IGB_STAT(stats.colc) },
+       { "rx_length_errors", IGB_STAT(net_stats.rx_length_errors) },
+       { "rx_over_errors", IGB_STAT(net_stats.rx_over_errors) },
+       { "rx_crc_errors", IGB_STAT(stats.crcerrs) },
+       { "rx_frame_errors", IGB_STAT(net_stats.rx_frame_errors) },
+       { "rx_no_buffer_count", IGB_STAT(stats.rnbc) },
+       { "rx_missed_errors", IGB_STAT(stats.mpc) },
+       { "tx_aborted_errors", IGB_STAT(stats.ecol) },
+       { "tx_carrier_errors", IGB_STAT(stats.tncrs) },
+       { "tx_fifo_errors", IGB_STAT(net_stats.tx_fifo_errors) },
+       { "tx_heartbeat_errors", IGB_STAT(net_stats.tx_heartbeat_errors) },
+       { "tx_window_errors", IGB_STAT(stats.latecol) },
+       { "tx_abort_late_coll", IGB_STAT(stats.latecol) },
+       { "tx_deferred_ok", IGB_STAT(stats.dc) },
+       { "tx_single_coll_ok", IGB_STAT(stats.scc) },
+       { "tx_multi_coll_ok", IGB_STAT(stats.mcc) },
+       { "tx_timeout_count", IGB_STAT(tx_timeout_count) },
+       { "tx_restart_queue", IGB_STAT(restart_queue) },
+       { "rx_long_length_errors", IGB_STAT(stats.roc) },
+       { "rx_short_length_errors", IGB_STAT(stats.ruc) },
+       { "rx_align_errors", IGB_STAT(stats.algnerrc) },
+       { "tx_tcp_seg_good", IGB_STAT(stats.tsctc) },
+       { "tx_tcp_seg_failed", IGB_STAT(stats.tsctfc) },
+       { "rx_flow_control_xon", IGB_STAT(stats.xonrxc) },
+       { "rx_flow_control_xoff", IGB_STAT(stats.xoffrxc) },
+       { "tx_flow_control_xon", IGB_STAT(stats.xontxc) },
+       { "tx_flow_control_xoff", IGB_STAT(stats.xofftxc) },
+       { "rx_long_byte_count", IGB_STAT(stats.gorc) },
+       { "rx_csum_offload_good", IGB_STAT(hw_csum_good) },
+       { "rx_csum_offload_errors", IGB_STAT(hw_csum_err) },
+       { "rx_header_split", IGB_STAT(rx_hdr_split) },
+       { "alloc_rx_buff_failed", IGB_STAT(alloc_rx_buff_failed) },
+       { "tx_smbus", IGB_STAT(stats.mgptc) },
+       { "rx_smbus", IGB_STAT(stats.mgprc) },
+       { "dropped_smbus", IGB_STAT(stats.mgpdc) },
+};
+
+#define IGB_QUEUE_STATS_LEN \
+       ((((((struct igb_adapter *)netdev->priv)->num_rx_queues > 1) ? \
+         ((struct igb_adapter *)netdev->priv)->num_rx_queues : 0) + \
+        (((((struct igb_adapter *)netdev->priv)->num_tx_queues > 1) ? \
+         ((struct igb_adapter *)netdev->priv)->num_tx_queues : 0))) * \
+       (sizeof(struct igb_queue_stats) / sizeof(u64)))
+#define IGB_GLOBAL_STATS_LEN   \
+       sizeof(igb_gstrings_stats) / sizeof(struct igb_stats)
+#define IGB_STATS_LEN (IGB_GLOBAL_STATS_LEN + IGB_QUEUE_STATS_LEN)
+static const char igb_gstrings_test[][ETH_GSTRING_LEN] = {
+       "Register test  (offline)", "Eeprom test    (offline)",
+       "Interrupt test (offline)", "Loopback test  (offline)",
+       "Link test   (on/offline)"
+};
+#define IGB_TEST_LEN sizeof(igb_gstrings_test) / ETH_GSTRING_LEN
+
+static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+
+       if (hw->phy.media_type == e1000_media_type_copper) {
+
+               ecmd->supported = (SUPPORTED_10baseT_Half |
+                                  SUPPORTED_10baseT_Full |
+                                  SUPPORTED_100baseT_Half |
+                                  SUPPORTED_100baseT_Full |
+                                  SUPPORTED_1000baseT_Full|
+                                  SUPPORTED_Autoneg |
+                                  SUPPORTED_TP);
+               ecmd->advertising = ADVERTISED_TP;
+
+               if (hw->mac.autoneg == 1) {
+                       ecmd->advertising |= ADVERTISED_Autoneg;
+                       /* the e1000 autoneg seems to match ethtool nicely */
+                       ecmd->advertising |= hw->phy.autoneg_advertised;
+               }
+
+               ecmd->port = PORT_TP;
+               ecmd->phy_address = hw->phy.addr;
+       } else {
+               ecmd->supported   = (SUPPORTED_1000baseT_Full |
+                                    SUPPORTED_FIBRE |
+                                    SUPPORTED_Autoneg);
+
+               ecmd->advertising = (ADVERTISED_1000baseT_Full |
+                                    ADVERTISED_FIBRE |
+                                    ADVERTISED_Autoneg);
+
+               ecmd->port = PORT_FIBRE;
+       }
+
+       ecmd->transceiver = XCVR_INTERNAL;
+
+       if (rd32(E1000_STATUS) & E1000_STATUS_LU) {
+
+               adapter->hw.mac.ops.get_speed_and_duplex(hw,
+                                       &adapter->link_speed,
+                                       &adapter->link_duplex);
+               ecmd->speed = adapter->link_speed;
+
+               /* unfortunately FULL_DUPLEX != DUPLEX_FULL
+                *          and HALF_DUPLEX != DUPLEX_HALF */
+
+               if (adapter->link_duplex == FULL_DUPLEX)
+                       ecmd->duplex = DUPLEX_FULL;
+               else
+                       ecmd->duplex = DUPLEX_HALF;
+       } else {
+               ecmd->speed = -1;
+               ecmd->duplex = -1;
+       }
+
+       ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) ||
+                        hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+       return 0;
+}
+
+static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+
+       /* When SoL/IDER sessions are active, autoneg/speed/duplex
+        * cannot be changed */
+       if (igb_check_reset_block(hw)) {
+               dev_err(&adapter->pdev->dev, "Cannot change link "
+                       "characteristics when SoL/IDER is active.\n");
+               return -EINVAL;
+       }
+
+       while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
+               msleep(1);
+
+       if (ecmd->autoneg == AUTONEG_ENABLE) {
+               hw->mac.autoneg = 1;
+               if (hw->phy.media_type == e1000_media_type_fiber)
+                       hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full |
+                                                    ADVERTISED_FIBRE |
+                                                    ADVERTISED_Autoneg;
+               else
+                       hw->phy.autoneg_advertised = ecmd->advertising |
+                                                    ADVERTISED_TP |
+                                                    ADVERTISED_Autoneg;
+               ecmd->advertising = hw->phy.autoneg_advertised;
+       } else
+               if (igb_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) {
+                       clear_bit(__IGB_RESETTING, &adapter->state);
+                       return -EINVAL;
+               }
+
+       /* reset the link */
+
+       if (netif_running(adapter->netdev)) {
+               igb_down(adapter);
+               igb_up(adapter);
+       } else
+               igb_reset(adapter);
+
+       clear_bit(__IGB_RESETTING, &adapter->state);
+       return 0;
+}
+
+static void igb_get_pauseparam(struct net_device *netdev,
+                              struct ethtool_pauseparam *pause)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+
+       pause->autoneg =
+               (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
+
+       if (hw->fc.type == e1000_fc_rx_pause)
+               pause->rx_pause = 1;
+       else if (hw->fc.type == e1000_fc_tx_pause)
+               pause->tx_pause = 1;
+       else if (hw->fc.type == e1000_fc_full) {
+               pause->rx_pause = 1;
+               pause->tx_pause = 1;
+       }
+}
+
+static int igb_set_pauseparam(struct net_device *netdev,
+                             struct ethtool_pauseparam *pause)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       int retval = 0;
+
+       adapter->fc_autoneg = pause->autoneg;
+
+       while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
+               msleep(1);
+
+       if (pause->rx_pause && pause->tx_pause)
+               hw->fc.type = e1000_fc_full;
+       else if (pause->rx_pause && !pause->tx_pause)
+               hw->fc.type = e1000_fc_rx_pause;
+       else if (!pause->rx_pause && pause->tx_pause)
+               hw->fc.type = e1000_fc_tx_pause;
+       else if (!pause->rx_pause && !pause->tx_pause)
+               hw->fc.type = e1000_fc_none;
+
+       hw->fc.original_type = hw->fc.type;
+
+       if (adapter->fc_autoneg == AUTONEG_ENABLE) {
+               if (netif_running(adapter->netdev)) {
+                       igb_down(adapter);
+                       igb_up(adapter);
+               } else
+                       igb_reset(adapter);
+       } else
+               retval = ((hw->phy.media_type == e1000_media_type_fiber) ?
+                         igb_setup_link(hw) : igb_force_mac_fc(hw));
+
+       clear_bit(__IGB_RESETTING, &adapter->state);
+       return retval;
+}
+
+static u32 igb_get_rx_csum(struct net_device *netdev)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       return adapter->rx_csum;
+}
+
+static int igb_set_rx_csum(struct net_device *netdev, u32 data)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       adapter->rx_csum = data;
+
+       return 0;
+}
+
+static u32 igb_get_tx_csum(struct net_device *netdev)
+{
+       return (netdev->features & NETIF_F_HW_CSUM) != 0;
+}
+
+static int igb_set_tx_csum(struct net_device *netdev, u32 data)
+{
+       if (data)
+               netdev->features |= NETIF_F_HW_CSUM;
+       else
+               netdev->features &= ~NETIF_F_HW_CSUM;
+
+       return 0;
+}
+
+static int igb_set_tso(struct net_device *netdev, u32 data)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+
+       if (data)
+               netdev->features |= NETIF_F_TSO;
+       else
+               netdev->features &= ~NETIF_F_TSO;
+
+       if (data)
+               netdev->features |= NETIF_F_TSO6;
+       else
+               netdev->features &= ~NETIF_F_TSO6;
+
+       dev_info(&adapter->pdev->dev, "TSO is %s\n",
+                data ? "Enabled" : "Disabled");
+       return 0;
+}
+
+static u32 igb_get_msglevel(struct net_device *netdev)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       return adapter->msg_enable;
+}
+
+static void igb_set_msglevel(struct net_device *netdev, u32 data)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       adapter->msg_enable = data;
+}
+
+static int igb_get_regs_len(struct net_device *netdev)
+{
+#define IGB_REGS_LEN 551
+       return IGB_REGS_LEN * sizeof(u32);
+}
+
+static void igb_get_regs(struct net_device *netdev,
+                        struct ethtool_regs *regs, void *p)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       u32 *regs_buff = p;
+       u8 i;
+
+       memset(p, 0, IGB_REGS_LEN * sizeof(u32));
+
+       regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id;
+
+       /* General Registers */
+       regs_buff[0] = rd32(E1000_CTRL);
+       regs_buff[1] = rd32(E1000_STATUS);
+       regs_buff[2] = rd32(E1000_CTRL_EXT);
+       regs_buff[3] = rd32(E1000_MDIC);
+       regs_buff[4] = rd32(E1000_SCTL);
+       regs_buff[5] = rd32(E1000_CONNSW);
+       regs_buff[6] = rd32(E1000_VET);
+       regs_buff[7] = rd32(E1000_LEDCTL);
+       regs_buff[8] = rd32(E1000_PBA);
+       regs_buff[9] = rd32(E1000_PBS);
+       regs_buff[10] = rd32(E1000_FRTIMER);
+       regs_buff[11] = rd32(E1000_TCPTIMER);
+
+       /* NVM Register */
+       regs_buff[12] = rd32(E1000_EECD);
+
+       /* Interrupt */
+       regs_buff[13] = rd32(E1000_EICR);
+       regs_buff[14] = rd32(E1000_EICS);
+       regs_buff[15] = rd32(E1000_EIMS);
+       regs_buff[16] = rd32(E1000_EIMC);
+       regs_buff[17] = rd32(E1000_EIAC);
+       regs_buff[18] = rd32(E1000_EIAM);
+       regs_buff[19] = rd32(E1000_ICR);
+       regs_buff[20] = rd32(E1000_ICS);
+       regs_buff[21] = rd32(E1000_IMS);
+       regs_buff[22] = rd32(E1000_IMC);
+       regs_buff[23] = rd32(E1000_IAC);
+       regs_buff[24] = rd32(E1000_IAM);
+       regs_buff[25] = rd32(E1000_IMIRVP);
+
+       /* Flow Control */
+       regs_buff[26] = rd32(E1000_FCAL);
+       regs_buff[27] = rd32(E1000_FCAH);
+       regs_buff[28] = rd32(E1000_FCTTV);
+       regs_buff[29] = rd32(E1000_FCRTL);
+       regs_buff[30] = rd32(E1000_FCRTH);
+       regs_buff[31] = rd32(E1000_FCRTV);
+
+       /* Receive */
+       regs_buff[32] = rd32(E1000_RCTL);
+       regs_buff[33] = rd32(E1000_RXCSUM);
+       regs_buff[34] = rd32(E1000_RLPML);
+       regs_buff[35] = rd32(E1000_RFCTL);
+       regs_buff[36] = rd32(E1000_MRQC);
+       regs_buff[37] = rd32(E1000_VMD_CTL);
+
+       /* Transmit */
+       regs_buff[38] = rd32(E1000_TCTL);
+       regs_buff[39] = rd32(E1000_TCTL_EXT);
+       regs_buff[40] = rd32(E1000_TIPG);
+       regs_buff[41] = rd32(E1000_DTXCTL);
+
+       /* Wake Up */
+       regs_buff[42] = rd32(E1000_WUC);
+       regs_buff[43] = rd32(E1000_WUFC);
+       regs_buff[44] = rd32(E1000_WUS);
+       regs_buff[45] = rd32(E1000_IPAV);
+       regs_buff[46] = rd32(E1000_WUPL);
+
+       /* MAC */
+       regs_buff[47] = rd32(E1000_PCS_CFG0);
+       regs_buff[48] = rd32(E1000_PCS_LCTL);
+       regs_buff[49] = rd32(E1000_PCS_LSTAT);
+       regs_buff[50] = rd32(E1000_PCS_ANADV);
+       regs_buff[51] = rd32(E1000_PCS_LPAB);
+       regs_buff[52] = rd32(E1000_PCS_NPTX);
+       regs_buff[53] = rd32(E1000_PCS_LPABNP);
+
+       /* Statistics */
+       regs_buff[54] = adapter->stats.crcerrs;
+       regs_buff[55] = adapter->stats.algnerrc;
+       regs_buff[56] = adapter->stats.symerrs;
+       regs_buff[57] = adapter->stats.rxerrc;
+       regs_buff[58] = adapter->stats.mpc;
+       regs_buff[59] = adapter->stats.scc;
+       regs_buff[60] = adapter->stats.ecol;
+       regs_buff[61] = adapter->stats.mcc;
+       regs_buff[62] = adapter->stats.latecol;
+       regs_buff[63] = adapter->stats.colc;
+       regs_buff[64] = adapter->stats.dc;
+       regs_buff[65] = adapter->stats.tncrs;
+       regs_buff[66] = adapter->stats.sec;
+       regs_buff[67] = adapter->stats.htdpmc;
+       regs_buff[68] = adapter->stats.rlec;
+       regs_buff[69] = adapter->stats.xonrxc;
+       regs_buff[70] = adapter->stats.xontxc;
+       regs_buff[71] = adapter->stats.xoffrxc;
+       regs_buff[72] = adapter->stats.xofftxc;
+       regs_buff[73] = adapter->stats.fcruc;
+       regs_buff[74] = adapter->stats.prc64;
+       regs_buff[75] = adapter->stats.prc127;
+       regs_buff[76] = adapter->stats.prc255;
+       regs_buff[77] = adapter->stats.prc511;
+       regs_buff[78] = adapter->stats.prc1023;
+       regs_buff[79] = adapter->stats.prc1522;
+       regs_buff[80] = adapter->stats.gprc;
+       regs_buff[81] = adapter->stats.bprc;
+       regs_buff[82] = adapter->stats.mprc;
+       regs_buff[83] = adapter->stats.gptc;
+       regs_buff[84] = adapter->stats.gorc;
+       regs_buff[86] = adapter->stats.gotc;
+       regs_buff[88] = adapter->stats.rnbc;
+       regs_buff[89] = adapter->stats.ruc;
+       regs_buff[90] = adapter->stats.rfc;
+       regs_buff[91] = adapter->stats.roc;
+       regs_buff[92] = adapter->stats.rjc;
+       regs_buff[93] = adapter->stats.mgprc;
+       regs_buff[94] = adapter->stats.mgpdc;
+       regs_buff[95] = adapter->stats.mgptc;
+       regs_buff[96] = adapter->stats.tor;
+       regs_buff[98] = adapter->stats.tot;
+       regs_buff[100] = adapter->stats.tpr;
+       regs_buff[101] = adapter->stats.tpt;
+       regs_buff[102] = adapter->stats.ptc64;
+       regs_buff[103] = adapter->stats.ptc127;
+       regs_buff[104] = adapter->stats.ptc255;
+       regs_buff[105] = adapter->stats.ptc511;
+       regs_buff[106] = adapter->stats.ptc1023;
+       regs_buff[107] = adapter->stats.ptc1522;
+       regs_buff[108] = adapter->stats.mptc;
+       regs_buff[109] = adapter->stats.bptc;
+       regs_buff[110] = adapter->stats.tsctc;
+       regs_buff[111] = adapter->stats.iac;
+       regs_buff[112] = adapter->stats.rpthc;
+       regs_buff[113] = adapter->stats.hgptc;
+       regs_buff[114] = adapter->stats.hgorc;
+       regs_buff[116] = adapter->stats.hgotc;
+       regs_buff[118] = adapter->stats.lenerrs;
+       regs_buff[119] = adapter->stats.scvpc;
+       regs_buff[120] = adapter->stats.hrmpc;
+
+       /* These should probably be added to e1000_regs.h instead */
+       #define E1000_PSRTYPE_REG(_i) (0x05480 + ((_i) * 4))
+       #define E1000_RAL(_i)         (0x05400 + ((_i) * 8))
+       #define E1000_RAH(_i)         (0x05404 + ((_i) * 8))
+       #define E1000_IP4AT_REG(_i)   (0x05840 + ((_i) * 8))
+       #define E1000_IP6AT_REG(_i)   (0x05880 + ((_i) * 4))
+       #define E1000_WUPM_REG(_i)    (0x05A00 + ((_i) * 4))
+       #define E1000_FFMT_REG(_i)    (0x09000 + ((_i) * 8))
+       #define E1000_FFVT_REG(_i)    (0x09800 + ((_i) * 8))
+       #define E1000_FFLT_REG(_i)    (0x05F00 + ((_i) * 8))
+
+       for (i = 0; i < 4; i++)
+               regs_buff[121 + i] = rd32(E1000_SRRCTL(i));
+       for (i = 0; i < 4; i++)
+               regs_buff[125 + i] = rd32(E1000_PSRTYPE_REG(i));
+       for (i = 0; i < 4; i++)
+               regs_buff[129 + i] = rd32(E1000_RDBAL(i));
+       for (i = 0; i < 4; i++)
+               regs_buff[133 + i] = rd32(E1000_RDBAH(i));
+       for (i = 0; i < 4; i++)
+               regs_buff[137 + i] = rd32(E1000_RDLEN(i));
+       for (i = 0; i < 4; i++)
+               regs_buff[141 + i] = rd32(E1000_RDH(i));
+       for (i = 0; i < 4; i++)
+               regs_buff[145 + i] = rd32(E1000_RDT(i));
+       for (i = 0; i < 4; i++)
+               regs_buff[149 + i] = rd32(E1000_RXDCTL(i));
+
+       for (i = 0; i < 10; i++)
+               regs_buff[153 + i] = rd32(E1000_EITR(i));
+       for (i = 0; i < 8; i++)
+               regs_buff[163 + i] = rd32(E1000_IMIR(i));
+       for (i = 0; i < 8; i++)
+               regs_buff[171 + i] = rd32(E1000_IMIREXT(i));
+       for (i = 0; i < 16; i++)
+               regs_buff[179 + i] = rd32(E1000_RAL(i));
+       for (i = 0; i < 16; i++)
+               regs_buff[195 + i] = rd32(E1000_RAH(i));
+
+       for (i = 0; i < 4; i++)
+               regs_buff[211 + i] = rd32(E1000_TDBAL(i));
+       for (i = 0; i < 4; i++)
+               regs_buff[215 + i] = rd32(E1000_TDBAH(i));
+       for (i = 0; i < 4; i++)
+               regs_buff[219 + i] = rd32(E1000_TDLEN(i));
+       for (i = 0; i < 4; i++)
+               regs_buff[223 + i] = rd32(E1000_TDH(i));
+       for (i = 0; i < 4; i++)
+               regs_buff[227 + i] = rd32(E1000_TDT(i));
+       for (i = 0; i < 4; i++)
+               regs_buff[231 + i] = rd32(E1000_TXDCTL(i));
+       for (i = 0; i < 4; i++)
+               regs_buff[235 + i] = rd32(E1000_TDWBAL(i));
+       for (i = 0; i < 4; i++)
+               regs_buff[239 + i] = rd32(E1000_TDWBAH(i));
+       for (i = 0; i < 4; i++)
+               regs_buff[243 + i] = rd32(E1000_DCA_TXCTRL(i));
+
+       for (i = 0; i < 4; i++)
+               regs_buff[247 + i] = rd32(E1000_IP4AT_REG(i));
+       for (i = 0; i < 4; i++)
+               regs_buff[251 + i] = rd32(E1000_IP6AT_REG(i));
+       for (i = 0; i < 32; i++)
+               regs_buff[255 + i] = rd32(E1000_WUPM_REG(i));
+       for (i = 0; i < 128; i++)
+               regs_buff[287 + i] = rd32(E1000_FFMT_REG(i));
+       for (i = 0; i < 128; i++)
+               regs_buff[415 + i] = rd32(E1000_FFVT_REG(i));
+       for (i = 0; i < 4; i++)
+               regs_buff[543 + i] = rd32(E1000_FFLT_REG(i));
+
+       regs_buff[547] = rd32(E1000_TDFH);
+       regs_buff[548] = rd32(E1000_TDFT);
+       regs_buff[549] = rd32(E1000_TDFHS);
+       regs_buff[550] = rd32(E1000_TDFPC);
+
+}
+
+static int igb_get_eeprom_len(struct net_device *netdev)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       return adapter->hw.nvm.word_size * 2;
+}
+
+static int igb_get_eeprom(struct net_device *netdev,
+                         struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       u16 *eeprom_buff;
+       int first_word, last_word;
+       int ret_val = 0;
+       u16 i;
+
+       if (eeprom->len == 0)
+               return -EINVAL;
+
+       eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+       first_word = eeprom->offset >> 1;
+       last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+
+       eeprom_buff = kmalloc(sizeof(u16) *
+                       (last_word - first_word + 1), GFP_KERNEL);
+       if (!eeprom_buff)
+               return -ENOMEM;
+
+       if (hw->nvm.type == e1000_nvm_eeprom_spi)
+               ret_val = hw->nvm.ops.read_nvm(hw, first_word,
+                                           last_word - first_word + 1,
+                                           eeprom_buff);
+       else {
+               for (i = 0; i < last_word - first_word + 1; i++) {
+                       ret_val = hw->nvm.ops.read_nvm(hw, first_word + i, 1,
+                                                   &eeprom_buff[i]);
+                       if (ret_val)
+                               break;
+               }
+       }
+
+       /* Device's eeprom is always little-endian, word addressable */
+       for (i = 0; i < last_word - first_word + 1; i++)
+               le16_to_cpus(&eeprom_buff[i]);
+
+       memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1),
+                       eeprom->len);
+       kfree(eeprom_buff);
+
+       return ret_val;
+}
+
+static int igb_set_eeprom(struct net_device *netdev,
+                         struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       u16 *eeprom_buff;
+       void *ptr;
+       int max_len, first_word, last_word, ret_val = 0;
+       u16 i;
+
+       if (eeprom->len == 0)
+               return -EOPNOTSUPP;
+
+       if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))
+               return -EFAULT;
+
+       max_len = hw->nvm.word_size * 2;
+
+       first_word = eeprom->offset >> 1;
+       last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+       eeprom_buff = kmalloc(max_len, GFP_KERNEL);
+       if (!eeprom_buff)
+               return -ENOMEM;
+
+       ptr = (void *)eeprom_buff;
+
+       if (eeprom->offset & 1) {
+               /* need read/modify/write of first changed EEPROM word */
+               /* only the second byte of the word is being modified */
+               ret_val = hw->nvm.ops.read_nvm(hw, first_word, 1,
+                                           &eeprom_buff[0]);
+               ptr++;
+       }
+       if (((eeprom->offset + eeprom->len) & 1) && (ret_val == 0)) {
+               /* need read/modify/write of last changed EEPROM word */
+               /* only the first byte of the word is being modified */
+               ret_val = hw->nvm.ops.read_nvm(hw, last_word, 1,
+                                  &eeprom_buff[last_word - first_word]);
+       }
+
+       /* Device's eeprom is always little-endian, word addressable */
+       for (i = 0; i < last_word - first_word + 1; i++)
+               le16_to_cpus(&eeprom_buff[i]);
+
+       memcpy(ptr, bytes, eeprom->len);
+
+       for (i = 0; i < last_word - first_word + 1; i++)
+               eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]);
+
+       ret_val = hw->nvm.ops.write_nvm(hw, first_word,
+                                    last_word - first_word + 1, eeprom_buff);
+
+       /* Update the checksum over the first part of the EEPROM if needed
+        * and flush shadow RAM for 82573 controllers */
+       if ((ret_val == 0) && ((first_word <= NVM_CHECKSUM_REG)))
+               igb_update_nvm_checksum(hw);
+
+       kfree(eeprom_buff);
+       return ret_val;
+}
+
+static void igb_get_drvinfo(struct net_device *netdev,
+                           struct ethtool_drvinfo *drvinfo)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       char firmware_version[32];
+       u16 eeprom_data;
+
+       strncpy(drvinfo->driver,  igb_driver_name, 32);
+       strncpy(drvinfo->version, igb_driver_version, 32);
+
+       /* EEPROM image version # is reported as firmware version # for
+        * 82575 controllers */
+       adapter->hw.nvm.ops.read_nvm(&adapter->hw, 5, 1, &eeprom_data);
+       sprintf(firmware_version, "%d.%d-%d",
+               (eeprom_data & 0xF000) >> 12,
+               (eeprom_data & 0x0FF0) >> 4,
+               eeprom_data & 0x000F);
+
+       strncpy(drvinfo->fw_version, firmware_version, 32);
+       strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+       drvinfo->n_stats = IGB_STATS_LEN;
+       drvinfo->testinfo_len = IGB_TEST_LEN;
+       drvinfo->regdump_len = igb_get_regs_len(netdev);
+       drvinfo->eedump_len = igb_get_eeprom_len(netdev);
+}
+
+static void igb_get_ringparam(struct net_device *netdev,
+                             struct ethtool_ringparam *ring)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct igb_ring *tx_ring = adapter->tx_ring;
+       struct igb_ring *rx_ring = adapter->rx_ring;
+
+       ring->rx_max_pending = IGB_MAX_RXD;
+       ring->tx_max_pending = IGB_MAX_TXD;
+       ring->rx_mini_max_pending = 0;
+       ring->rx_jumbo_max_pending = 0;
+       ring->rx_pending = rx_ring->count;
+       ring->tx_pending = tx_ring->count;
+       ring->rx_mini_pending = 0;
+       ring->rx_jumbo_pending = 0;
+}
+
+static int igb_set_ringparam(struct net_device *netdev,
+                            struct ethtool_ringparam *ring)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct igb_buffer *old_buf;
+       struct igb_buffer *old_rx_buf;
+       void *old_desc;
+       int i, err;
+       u32 new_rx_count, new_tx_count, old_size;
+       dma_addr_t old_dma;
+
+       if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
+               return -EINVAL;
+
+       new_rx_count = max(ring->rx_pending, (u32)IGB_MIN_RXD);
+       new_rx_count = min(new_rx_count, (u32)IGB_MAX_RXD);
+       new_rx_count = ALIGN(new_rx_count, REQ_RX_DESCRIPTOR_MULTIPLE);
+
+       new_tx_count = max(ring->tx_pending, (u32)IGB_MIN_TXD);
+       new_tx_count = min(new_tx_count, (u32)IGB_MAX_TXD);
+       new_tx_count = ALIGN(new_tx_count, REQ_TX_DESCRIPTOR_MULTIPLE);
+
+       if ((new_tx_count == adapter->tx_ring->count) &&
+           (new_rx_count == adapter->rx_ring->count)) {
+               /* nothing to do */
+               return 0;
+       }
+
+       while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
+               msleep(1);
+
+       if (netif_running(adapter->netdev))
+               igb_down(adapter);
+
+       /*
+        * We can't just free everything and then setup again,
+        * because the ISRs in MSI-X mode get passed pointers
+        * to the tx and rx ring structs.
+        */
+       if (new_tx_count != adapter->tx_ring->count) {
+               for (i = 0; i < adapter->num_tx_queues; i++) {
+                       /* Save existing descriptor ring */
+                       old_buf = adapter->tx_ring[i].buffer_info;
+                       old_desc = adapter->tx_ring[i].desc;
+                       old_size = adapter->tx_ring[i].size;
+                       old_dma = adapter->tx_ring[i].dma;
+                       /* Try to allocate a new one */
+                       adapter->tx_ring[i].buffer_info = NULL;
+                       adapter->tx_ring[i].desc = NULL;
+                       adapter->tx_ring[i].count = new_tx_count;
+                       err = igb_setup_tx_resources(adapter,
+                                               &adapter->tx_ring[i]);
+                       if (err) {
+                               /* Restore the old one so at least
+                                  the adapter still works, even if
+                                  we failed the request */
+                               adapter->tx_ring[i].buffer_info = old_buf;
+                               adapter->tx_ring[i].desc = old_desc;
+                               adapter->tx_ring[i].size = old_size;
+                               adapter->tx_ring[i].dma = old_dma;
+                               goto err_setup;
+                       }
+                       /* Free the old buffer manually */
+                       vfree(old_buf);
+                       pci_free_consistent(adapter->pdev, old_size,
+                                           old_desc, old_dma);
+               }
+       }
+
+       if (new_rx_count != adapter->rx_ring->count) {
+               for (i = 0; i < adapter->num_rx_queues; i++) {
+
+                       old_rx_buf = adapter->rx_ring[i].buffer_info;
+                       old_desc = adapter->rx_ring[i].desc;
+                       old_size = adapter->rx_ring[i].size;
+                       old_dma = adapter->rx_ring[i].dma;
+
+                       adapter->rx_ring[i].buffer_info = NULL;
+                       adapter->rx_ring[i].desc = NULL;
+                       adapter->rx_ring[i].dma = 0;
+                       adapter->rx_ring[i].count = new_rx_count;
+                       err = igb_setup_rx_resources(adapter,
+                                                    &adapter->rx_ring[i]);
+                       if (err) {
+                               adapter->rx_ring[i].buffer_info = old_rx_buf;
+                               adapter->rx_ring[i].desc = old_desc;
+                               adapter->rx_ring[i].size = old_size;
+                               adapter->rx_ring[i].dma = old_dma;
+                               goto err_setup;
+                       }
+
+                       vfree(old_rx_buf);
+                       pci_free_consistent(adapter->pdev, old_size, old_desc,
+                                           old_dma);
+               }
+       }
+
+       err = 0;
+err_setup:
+       if (netif_running(adapter->netdev))
+               igb_up(adapter);
+
+       clear_bit(__IGB_RESETTING, &adapter->state);
+       return err;
+}
+
+/* ethtool register test data */
+struct igb_reg_test {
+       u16 reg;
+       u8  array_len;
+       u8  test_type;
+       u32 mask;
+       u32 write;
+};
+
+/* In the hardware, registers are laid out either singly, in arrays
+ * spaced 0x100 bytes apart, or in contiguous tables.  We assume
+ * most tests take place on arrays or single registers (handled
+ * as a single-element array) and special-case the tables.
+ * Table tests are always pattern tests.
+ *
+ * We also make provision for some required setup steps by specifying
+ * registers to be written without any read-back testing.
+ */
+
+#define PATTERN_TEST   1
+#define SET_READ_TEST  2
+#define WRITE_NO_TEST  3
+#define TABLE32_TEST   4
+#define TABLE64_TEST_LO        5
+#define TABLE64_TEST_HI        6
+
+/* default register test */
+static struct igb_reg_test reg_test_82575[] = {
+       { E1000_FCAL, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { E1000_FCAH, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
+       { E1000_FCT, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
+       { E1000_VET, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { E1000_RDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
+       { E1000_RDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { E1000_RDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
+       /* Enable all four RX queues before testing. */
+       { E1000_RXDCTL(0), 4, WRITE_NO_TEST, 0, E1000_RXDCTL_QUEUE_ENABLE },
+       /* RDH is read-only for 82575, only test RDT. */
+       { E1000_RDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
+       { E1000_RXDCTL(0), 4, WRITE_NO_TEST, 0, 0 },
+       { E1000_FCRTH, 1, PATTERN_TEST, 0x0000FFF0, 0x0000FFF0 },
+       { E1000_FCTTV, 1, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
+       { E1000_TIPG, 1, PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF },
+       { E1000_TDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
+       { E1000_TDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { E1000_TDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
+       { E1000_RCTL, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
+       { E1000_RCTL, 1, SET_READ_TEST, 0x04CFB3FE, 0x003FFFFB },
+       { E1000_RCTL, 1, SET_READ_TEST, 0x04CFB3FE, 0xFFFFFFFF },
+       { E1000_TCTL, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
+       { E1000_TXCW, 1, PATTERN_TEST, 0xC000FFFF, 0x0000FFFF },
+       { E1000_RA, 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF },
+       { E1000_RA, 16, TABLE64_TEST_HI, 0x800FFFFF, 0xFFFFFFFF },
+       { E1000_MTA, 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { 0, 0, 0, 0 }
+};
+
+static bool reg_pattern_test(struct igb_adapter *adapter, u64 *data,
+                            int reg, u32 mask, u32 write)
+{
+       u32 pat, val;
+       u32 _test[] =
+               {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};
+       for (pat = 0; pat < ARRAY_SIZE(_test); pat++) {
+               writel((_test[pat] & write), (adapter->hw.hw_addr + reg));
+               val = readl(adapter->hw.hw_addr + reg);
+               if (val != (_test[pat] & write & mask)) {
+                       dev_err(&adapter->pdev->dev, "pattern test reg %04X "
+                               "failed: got 0x%08X expected 0x%08X\n",
+                               reg, val, (_test[pat] & write & mask));
+                       *data = reg;
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+static bool reg_set_and_check(struct igb_adapter *adapter, u64 *data,
+                             int reg, u32 mask, u32 write)
+{
+       u32 val;
+       writel((write & mask), (adapter->hw.hw_addr + reg));
+       val = readl(adapter->hw.hw_addr + reg);
+       if ((write & mask) != (val & mask)) {
+               dev_err(&adapter->pdev->dev, "set/check reg %04X test failed:"
+                       " got 0x%08X expected 0x%08X\n", reg,
+                       (val & mask), (write & mask));
+               *data = reg;
+               return 1;
+       }
+       return 0;
+}
+
+#define REG_PATTERN_TEST(reg, mask, write) \
+       do { \
+               if (reg_pattern_test(adapter, data, reg, mask, write)) \
+                       return 1; \
+       } while (0)
+
+#define REG_SET_AND_CHECK(reg, mask, write) \
+       do { \
+               if (reg_set_and_check(adapter, data, reg, mask, write)) \
+                       return 1; \
+       } while (0)
+
+static int igb_reg_test(struct igb_adapter *adapter, u64 *data)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       struct igb_reg_test *test;
+       u32 value, before, after;
+       u32 i, toggle;
+
+       toggle = 0x7FFFF3FF;
+       test = reg_test_82575;
+
+       /* Because the status register is such a special case,
+        * we handle it separately from the rest of the register
+        * tests.  Some bits are read-only, some toggle, and some
+        * are writable on newer MACs.
+        */
+       before = rd32(E1000_STATUS);
+       value = (rd32(E1000_STATUS) & toggle);
+       wr32(E1000_STATUS, toggle);
+       after = rd32(E1000_STATUS) & toggle;
+       if (value != after) {
+               dev_err(&adapter->pdev->dev, "failed STATUS register test "
+                       "got: 0x%08X expected: 0x%08X\n", after, value);
+               *data = 1;
+               return 1;
+       }
+       /* restore previous status */
+       wr32(E1000_STATUS, before);
+
+       /* Perform the remainder of the register test, looping through
+        * the test table until we either fail or reach the null entry.
+        */
+       while (test->reg) {
+               for (i = 0; i < test->array_len; i++) {
+                       switch (test->test_type) {
+                       case PATTERN_TEST:
+                               REG_PATTERN_TEST(test->reg + (i * 0x100),
+                                               test->mask,
+                                               test->write);
+                               break;
+                       case SET_READ_TEST:
+                               REG_SET_AND_CHECK(test->reg + (i * 0x100),
+                                               test->mask,
+                                               test->write);
+                               break;
+                       case WRITE_NO_TEST:
+                               writel(test->write,
+                                   (adapter->hw.hw_addr + test->reg)
+                                       + (i * 0x100));
+                               break;
+                       case TABLE32_TEST:
+                               REG_PATTERN_TEST(test->reg + (i * 4),
+                                               test->mask,
+                                               test->write);
+                               break;
+                       case TABLE64_TEST_LO:
+                               REG_PATTERN_TEST(test->reg + (i * 8),
+                                               test->mask,
+                                               test->write);
+                               break;
+                       case TABLE64_TEST_HI:
+                               REG_PATTERN_TEST((test->reg + 4) + (i * 8),
+                                               test->mask,
+                                               test->write);
+                               break;
+                       }
+               }
+               test++;
+       }
+
+       *data = 0;
+       return 0;
+}
+
+static int igb_eeprom_test(struct igb_adapter *adapter, u64 *data)
+{
+       u16 temp;
+       u16 checksum = 0;
+       u16 i;
+
+       *data = 0;
+       /* Read and add up the contents of the EEPROM */
+       for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
+               if ((adapter->hw.nvm.ops.read_nvm(&adapter->hw, i, 1, &temp))
+                   < 0) {
+                       *data = 1;
+                       break;
+               }
+               checksum += temp;
+       }
+
+       /* If Checksum is not Correct return error else test passed */
+       if ((checksum != (u16) NVM_SUM) && !(*data))
+               *data = 2;
+
+       return *data;
+}
+
+static irqreturn_t igb_test_intr(int irq, void *data)
+{
+       struct net_device *netdev = (struct net_device *) data;
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+
+       adapter->test_icr |= rd32(E1000_ICR);
+
+       return IRQ_HANDLED;
+}
+
+static int igb_intr_test(struct igb_adapter *adapter, u64 *data)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       struct net_device *netdev = adapter->netdev;
+       u32 mask, i = 0, shared_int = true;
+       u32 irq = adapter->pdev->irq;
+
+       *data = 0;
+
+       /* Hook up test interrupt handler just for this test */
+       if (adapter->msix_entries) {
+               /* NOTE: we don't test MSI-X interrupts here, yet */
+               return 0;
+       } else if (adapter->msi_enabled) {
+               shared_int = false;
+               if (request_irq(irq, &igb_test_intr, 0, netdev->name, netdev)) {
+                       *data = 1;
+                       return -1;
+               }
+       } else if (!request_irq(irq, &igb_test_intr, IRQF_PROBE_SHARED,
+                               netdev->name, netdev)) {
+               shared_int = false;
+       } else if (request_irq(irq, &igb_test_intr, IRQF_SHARED,
+                netdev->name, netdev)) {
+               *data = 1;
+               return -1;
+       }
+       dev_info(&adapter->pdev->dev, "testing %s interrupt\n",
+               (shared_int ? "shared" : "unshared"));
+
+       /* Disable all the interrupts */
+       wr32(E1000_IMC, 0xFFFFFFFF);
+       msleep(10);
+
+       /* Test each interrupt */
+       for (; i < 10; i++) {
+               /* Interrupt to test */
+               mask = 1 << i;
+
+               if (!shared_int) {
+                       /* Disable the interrupt to be reported in
+                        * the cause register and then force the same
+                        * interrupt and see if one gets posted.  If
+                        * an interrupt was posted to the bus, the
+                        * test failed.
+                        */
+                       adapter->test_icr = 0;
+                       wr32(E1000_IMC, ~mask & 0x00007FFF);
+                       wr32(E1000_ICS, ~mask & 0x00007FFF);
+                       msleep(10);
+
+                       if (adapter->test_icr & mask) {
+                               *data = 3;
+                               break;
+                       }
+               }
+
+               /* Enable the interrupt to be reported in
+                * the cause register and then force the same
+                * interrupt and see if one gets posted.  If
+                * an interrupt was not posted to the bus, the
+                * test failed.
+                */
+               adapter->test_icr = 0;
+               wr32(E1000_IMS, mask);
+               wr32(E1000_ICS, mask);
+               msleep(10);
+
+               if (!(adapter->test_icr & mask)) {
+                       *data = 4;
+                       break;
+               }
+
+               if (!shared_int) {
+                       /* Disable the other interrupts to be reported in
+                        * the cause register and then force the other
+                        * interrupts and see if any get posted.  If
+                        * an interrupt was posted to the bus, the
+                        * test failed.
+                        */
+                       adapter->test_icr = 0;
+                       wr32(E1000_IMC, ~mask & 0x00007FFF);
+                       wr32(E1000_ICS, ~mask & 0x00007FFF);
+                       msleep(10);
+
+                       if (adapter->test_icr) {
+                               *data = 5;
+                               break;
+                       }
+               }
+       }
+
+       /* Disable all the interrupts */
+       wr32(E1000_IMC, 0xFFFFFFFF);
+       msleep(10);
+
+       /* Unhook test interrupt handler */
+       free_irq(irq, netdev);
+
+       return *data;
+}
+
+static void igb_free_desc_rings(struct igb_adapter *adapter)
+{
+       struct igb_ring *tx_ring = &adapter->test_tx_ring;
+       struct igb_ring *rx_ring = &adapter->test_rx_ring;
+       struct pci_dev *pdev = adapter->pdev;
+       int i;
+
+       if (tx_ring->desc && tx_ring->buffer_info) {
+               for (i = 0; i < tx_ring->count; i++) {
+                       struct igb_buffer *buf = &(tx_ring->buffer_info[i]);
+                       if (buf->dma)
+                               pci_unmap_single(pdev, buf->dma, buf->length,
+                                                PCI_DMA_TODEVICE);
+                       if (buf->skb)
+                               dev_kfree_skb(buf->skb);
+               }
+       }
+
+       if (rx_ring->desc && rx_ring->buffer_info) {
+               for (i = 0; i < rx_ring->count; i++) {
+                       struct igb_buffer *buf = &(rx_ring->buffer_info[i]);
+                       if (buf->dma)
+                               pci_unmap_single(pdev, buf->dma,
+                                                IGB_RXBUFFER_2048,
+                                                PCI_DMA_FROMDEVICE);
+                       if (buf->skb)
+                               dev_kfree_skb(buf->skb);
+               }
+       }
+
+       if (tx_ring->desc) {
+               pci_free_consistent(pdev, tx_ring->size, tx_ring->desc,
+                                   tx_ring->dma);
+               tx_ring->desc = NULL;
+       }
+       if (rx_ring->desc) {
+               pci_free_consistent(pdev, rx_ring->size, rx_ring->desc,
+                                   rx_ring->dma);
+               rx_ring->desc = NULL;
+       }
+
+       kfree(tx_ring->buffer_info);
+       tx_ring->buffer_info = NULL;
+       kfree(rx_ring->buffer_info);
+       rx_ring->buffer_info = NULL;
+
+       return;
+}
+
+static int igb_setup_desc_rings(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       struct igb_ring *tx_ring = &adapter->test_tx_ring;
+       struct igb_ring *rx_ring = &adapter->test_rx_ring;
+       struct pci_dev *pdev = adapter->pdev;
+       u32 rctl;
+       int i, ret_val;
+
+       /* Setup Tx descriptor ring and Tx buffers */
+
+       if (!tx_ring->count)
+               tx_ring->count = IGB_DEFAULT_TXD;
+
+       tx_ring->buffer_info = kcalloc(tx_ring->count,
+                                      sizeof(struct igb_buffer),
+                                      GFP_KERNEL);
+       if (!tx_ring->buffer_info) {
+               ret_val = 1;
+               goto err_nomem;
+       }
+
+       tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc);
+       tx_ring->size = ALIGN(tx_ring->size, 4096);
+       tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size,
+                                            &tx_ring->dma);
+       if (!tx_ring->desc) {
+               ret_val = 2;
+               goto err_nomem;
+       }
+       tx_ring->next_to_use = tx_ring->next_to_clean = 0;
+
+       wr32(E1000_TDBAL(0),
+                       ((u64) tx_ring->dma & 0x00000000FFFFFFFF));
+       wr32(E1000_TDBAH(0), ((u64) tx_ring->dma >> 32));
+       wr32(E1000_TDLEN(0),
+                       tx_ring->count * sizeof(struct e1000_tx_desc));
+       wr32(E1000_TDH(0), 0);
+       wr32(E1000_TDT(0), 0);
+       wr32(E1000_TCTL,
+                       E1000_TCTL_PSP | E1000_TCTL_EN |
+                       E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT |
+                       E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT);
+
+       for (i = 0; i < tx_ring->count; i++) {
+               struct e1000_tx_desc *tx_desc = E1000_TX_DESC(*tx_ring, i);
+               struct sk_buff *skb;
+               unsigned int size = 1024;
+
+               skb = alloc_skb(size, GFP_KERNEL);
+               if (!skb) {
+                       ret_val = 3;
+                       goto err_nomem;
+               }
+               skb_put(skb, size);
+               tx_ring->buffer_info[i].skb = skb;
+               tx_ring->buffer_info[i].length = skb->len;
+               tx_ring->buffer_info[i].dma =
+                       pci_map_single(pdev, skb->data, skb->len,
+                                      PCI_DMA_TODEVICE);
+               tx_desc->buffer_addr = cpu_to_le64(tx_ring->buffer_info[i].dma);
+               tx_desc->lower.data = cpu_to_le32(skb->len);
+               tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP |
+                                                  E1000_TXD_CMD_IFCS |
+                                                  E1000_TXD_CMD_RS);
+               tx_desc->upper.data = 0;
+       }
+
+       /* Setup Rx descriptor ring and Rx buffers */
+
+       if (!rx_ring->count)
+               rx_ring->count = IGB_DEFAULT_RXD;
+
+       rx_ring->buffer_info = kcalloc(rx_ring->count,
+                                      sizeof(struct igb_buffer),
+                                      GFP_KERNEL);
+       if (!rx_ring->buffer_info) {
+               ret_val = 4;
+               goto err_nomem;
+       }
+
+       rx_ring->size = rx_ring->count * sizeof(struct e1000_rx_desc);
+       rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size,
+                                            &rx_ring->dma);
+       if (!rx_ring->desc) {
+               ret_val = 5;
+               goto err_nomem;
+       }
+       rx_ring->next_to_use = rx_ring->next_to_clean = 0;
+
+       rctl = rd32(E1000_RCTL);
+       wr32(E1000_RCTL, rctl & ~E1000_RCTL_EN);
+       wr32(E1000_RDBAL(0),
+                       ((u64) rx_ring->dma & 0xFFFFFFFF));
+       wr32(E1000_RDBAH(0),
+                       ((u64) rx_ring->dma >> 32));
+       wr32(E1000_RDLEN(0), rx_ring->size);
+       wr32(E1000_RDH(0), 0);
+       wr32(E1000_RDT(0), 0);
+       rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 |
+               E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
+               (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
+       wr32(E1000_RCTL, rctl);
+       wr32(E1000_SRRCTL(0), 0);
+
+       for (i = 0; i < rx_ring->count; i++) {
+               struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rx_ring, i);
+               struct sk_buff *skb;
+
+               skb = alloc_skb(IGB_RXBUFFER_2048 + NET_IP_ALIGN,
+                               GFP_KERNEL);
+               if (!skb) {
+                       ret_val = 6;
+                       goto err_nomem;
+               }
+               skb_reserve(skb, NET_IP_ALIGN);
+               rx_ring->buffer_info[i].skb = skb;
+               rx_ring->buffer_info[i].dma =
+                       pci_map_single(pdev, skb->data, IGB_RXBUFFER_2048,
+                                      PCI_DMA_FROMDEVICE);
+               rx_desc->buffer_addr = cpu_to_le64(rx_ring->buffer_info[i].dma);
+               memset(skb->data, 0x00, skb->len);
+       }
+
+       return 0;
+
+err_nomem:
+       igb_free_desc_rings(adapter);
+       return ret_val;
+}
+
+static void igb_phy_disable_receiver(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+
+       /* Write out to PHY registers 29 and 30 to disable the Receiver. */
+       hw->phy.ops.write_phy_reg(hw, 29, 0x001F);
+       hw->phy.ops.write_phy_reg(hw, 30, 0x8FFC);
+       hw->phy.ops.write_phy_reg(hw, 29, 0x001A);
+       hw->phy.ops.write_phy_reg(hw, 30, 0x8FF0);
+}
+
+static int igb_integrated_phy_loopback(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 ctrl_reg = 0;
+       u32 stat_reg = 0;
+
+       hw->mac.autoneg = false;
+
+       if (hw->phy.type == e1000_phy_m88) {
+               /* Auto-MDI/MDIX Off */
+               hw->phy.ops.write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808);
+               /* reset to update Auto-MDI/MDIX */
+               hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x9140);
+               /* autoneg off */
+               hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x8140);
+       }
+
+       ctrl_reg = rd32(E1000_CTRL);
+
+       /* force 1000, set loopback */
+       hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x4140);
+
+       /* Now set up the MAC to the same speed/duplex as the PHY. */
+       ctrl_reg = rd32(E1000_CTRL);
+       ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
+       ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+                    E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+                    E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */
+                    E1000_CTRL_FD);     /* Force Duplex to FULL */
+
+       if (hw->phy.media_type == e1000_media_type_copper &&
+           hw->phy.type == e1000_phy_m88)
+               ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */
+       else {
+               /* Set the ILOS bit on the fiber Nic if half duplex link is
+                * detected. */
+               stat_reg = rd32(E1000_STATUS);
+               if ((stat_reg & E1000_STATUS_FD) == 0)
+                       ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU);
+       }
+
+       wr32(E1000_CTRL, ctrl_reg);
+
+       /* Disable the receiver on the PHY so when a cable is plugged in, the
+        * PHY does not begin to autoneg when a cable is reconnected to the NIC.
+        */
+       if (hw->phy.type == e1000_phy_m88)
+               igb_phy_disable_receiver(adapter);
+
+       udelay(500);
+
+       return 0;
+}
+
+static int igb_set_phy_loopback(struct igb_adapter *adapter)
+{
+       return igb_integrated_phy_loopback(adapter);
+}
+
+static int igb_setup_loopback_test(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 rctl;
+
+       if (hw->phy.media_type == e1000_media_type_fiber ||
+           hw->phy.media_type == e1000_media_type_internal_serdes) {
+               rctl = rd32(E1000_RCTL);
+               rctl |= E1000_RCTL_LBM_TCVR;
+               wr32(E1000_RCTL, rctl);
+               return 0;
+       } else if (hw->phy.media_type == e1000_media_type_copper) {
+               return igb_set_phy_loopback(adapter);
+       }
+
+       return 7;
+}
+
+static void igb_loopback_cleanup(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 rctl;
+       u16 phy_reg;
+
+       rctl = rd32(E1000_RCTL);
+       rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC);
+       wr32(E1000_RCTL, rctl);
+
+       hw->mac.autoneg = true;
+       hw->phy.ops.read_phy_reg(hw, PHY_CONTROL, &phy_reg);
+       if (phy_reg & MII_CR_LOOPBACK) {
+               phy_reg &= ~MII_CR_LOOPBACK;
+               hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, phy_reg);
+               igb_phy_sw_reset(hw);
+       }
+}
+
+static void igb_create_lbtest_frame(struct sk_buff *skb,
+                                   unsigned int frame_size)
+{
+       memset(skb->data, 0xFF, frame_size);
+       frame_size &= ~1;
+       memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1);
+       memset(&skb->data[frame_size / 2 + 10], 0xBE, 1);
+       memset(&skb->data[frame_size / 2 + 12], 0xAF, 1);
+}
+
+static int igb_check_lbtest_frame(struct sk_buff *skb, unsigned int frame_size)
+{
+       frame_size &= ~1;
+       if (*(skb->data + 3) == 0xFF)
+               if ((*(skb->data + frame_size / 2 + 10) == 0xBE) &&
+                  (*(skb->data + frame_size / 2 + 12) == 0xAF))
+                       return 0;
+       return 13;
+}
+
+static int igb_run_loopback_test(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       struct igb_ring *tx_ring = &adapter->test_tx_ring;
+       struct igb_ring *rx_ring = &adapter->test_rx_ring;
+       struct pci_dev *pdev = adapter->pdev;
+       int i, j, k, l, lc, good_cnt;
+       int ret_val = 0;
+       unsigned long time;
+
+       wr32(E1000_RDT(0), rx_ring->count - 1);
+
+       /* Calculate the loop count based on the largest descriptor ring
+        * The idea is to wrap the largest ring a number of times using 64
+        * send/receive pairs during each loop
+        */
+
+       if (rx_ring->count <= tx_ring->count)
+               lc = ((tx_ring->count / 64) * 2) + 1;
+       else
+               lc = ((rx_ring->count / 64) * 2) + 1;
+
+       k = l = 0;
+       for (j = 0; j <= lc; j++) { /* loop count loop */
+               for (i = 0; i < 64; i++) { /* send the packets */
+                       igb_create_lbtest_frame(tx_ring->buffer_info[k].skb,
+                                               1024);
+                       pci_dma_sync_single_for_device(pdev,
+                               tx_ring->buffer_info[k].dma,
+                               tx_ring->buffer_info[k].length,
+                               PCI_DMA_TODEVICE);
+                       k++;
+                       if (k == tx_ring->count)
+                               k = 0;
+               }
+               wr32(E1000_TDT(0), k);
+               msleep(200);
+               time = jiffies; /* set the start time for the receive */
+               good_cnt = 0;
+               do { /* receive the sent packets */
+                       pci_dma_sync_single_for_cpu(pdev,
+                                       rx_ring->buffer_info[l].dma,
+                                       IGB_RXBUFFER_2048,
+                                       PCI_DMA_FROMDEVICE);
+
+                       ret_val = igb_check_lbtest_frame(
+                                            rx_ring->buffer_info[l].skb, 1024);
+                       if (!ret_val)
+                               good_cnt++;
+                       l++;
+                       if (l == rx_ring->count)
+                               l = 0;
+                       /* time + 20 msecs (200 msecs on 2.4) is more than
+                        * enough time to complete the receives, if it's
+                        * exceeded, break and error off
+                        */
+               } while (good_cnt < 64 && jiffies < (time + 20));
+               if (good_cnt != 64) {
+                       ret_val = 13; /* ret_val is the same as mis-compare */
+                       break;
+               }
+               if (jiffies >= (time + 20)) {
+                       ret_val = 14; /* error code for time out error */
+                       break;
+               }
+       } /* end loop count loop */
+       return ret_val;
+}
+
+static int igb_loopback_test(struct igb_adapter *adapter, u64 *data)
+{
+       /* PHY loopback cannot be performed if SoL/IDER
+        * sessions are active */
+       if (igb_check_reset_block(&adapter->hw)) {
+               dev_err(&adapter->pdev->dev,
+                       "Cannot do PHY loopback test "
+                       "when SoL/IDER is active.\n");
+               *data = 0;
+               goto out;
+       }
+       *data = igb_setup_desc_rings(adapter);
+       if (*data)
+               goto out;
+       *data = igb_setup_loopback_test(adapter);
+       if (*data)
+               goto err_loopback;
+       *data = igb_run_loopback_test(adapter);
+       igb_loopback_cleanup(adapter);
+
+err_loopback:
+       igb_free_desc_rings(adapter);
+out:
+       return *data;
+}
+
+static int igb_link_test(struct igb_adapter *adapter, u64 *data)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       *data = 0;
+       if (hw->phy.media_type == e1000_media_type_internal_serdes) {
+               int i = 0;
+               hw->mac.serdes_has_link = false;
+
+               /* On some blade server designs, link establishment
+                * could take as long as 2-3 minutes */
+               do {
+                       hw->mac.ops.check_for_link(&adapter->hw);
+                       if (hw->mac.serdes_has_link)
+                               return *data;
+                       msleep(20);
+               } while (i++ < 3750);
+
+               *data = 1;
+       } else {
+               hw->mac.ops.check_for_link(&adapter->hw);
+               if (hw->mac.autoneg)
+                       msleep(4000);
+
+               if (!(rd32(E1000_STATUS) &
+                     E1000_STATUS_LU))
+                       *data = 1;
+       }
+       return *data;
+}
+
+static void igb_diag_test(struct net_device *netdev,
+                         struct ethtool_test *eth_test, u64 *data)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       u16 autoneg_advertised;
+       u8 forced_speed_duplex, autoneg;
+       bool if_running = netif_running(netdev);
+
+       set_bit(__IGB_TESTING, &adapter->state);
+       if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
+               /* Offline tests */
+
+               /* save speed, duplex, autoneg settings */
+               autoneg_advertised = adapter->hw.phy.autoneg_advertised;
+               forced_speed_duplex = adapter->hw.mac.forced_speed_duplex;
+               autoneg = adapter->hw.mac.autoneg;
+
+               dev_info(&adapter->pdev->dev, "offline testing starting\n");
+
+               /* Link test performed before hardware reset so autoneg doesn't
+                * interfere with test result */
+               if (igb_link_test(adapter, &data[4]))
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
+
+               if (if_running)
+                       /* indicate we're in test mode */
+                       dev_close(netdev);
+               else
+                       igb_reset(adapter);
+
+               if (igb_reg_test(adapter, &data[0]))
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
+
+               igb_reset(adapter);
+               if (igb_eeprom_test(adapter, &data[1]))
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
+
+               igb_reset(adapter);
+               if (igb_intr_test(adapter, &data[2]))
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
+
+               igb_reset(adapter);
+               if (igb_loopback_test(adapter, &data[3]))
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
+
+               /* restore speed, duplex, autoneg settings */
+               adapter->hw.phy.autoneg_advertised = autoneg_advertised;
+               adapter->hw.mac.forced_speed_duplex = forced_speed_duplex;
+               adapter->hw.mac.autoneg = autoneg;
+
+               /* force this routine to wait until autoneg complete/timeout */
+               adapter->hw.phy.autoneg_wait_to_complete = true;
+               igb_reset(adapter);
+               adapter->hw.phy.autoneg_wait_to_complete = false;
+
+               clear_bit(__IGB_TESTING, &adapter->state);
+               if (if_running)
+                       dev_open(netdev);
+       } else {
+               dev_info(&adapter->pdev->dev, "online testing starting\n");
+               /* Online tests */
+               if (igb_link_test(adapter, &data[4]))
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
+
+               /* Online tests aren't run; pass by default */
+               data[0] = 0;
+               data[1] = 0;
+               data[2] = 0;
+               data[3] = 0;
+
+               clear_bit(__IGB_TESTING, &adapter->state);
+       }
+       msleep_interruptible(4 * 1000);
+}
+
+static int igb_wol_exclusion(struct igb_adapter *adapter,
+                            struct ethtool_wolinfo *wol)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       int retval = 1; /* fail by default */
+
+       switch (hw->device_id) {
+       case E1000_DEV_ID_82575GB_QUAD_COPPER:
+               /* WoL not supported */
+               wol->supported = 0;
+               break;
+       case E1000_DEV_ID_82575EB_FIBER_SERDES:
+               /* Wake events not supported on port B */
+               if (rd32(E1000_STATUS) & E1000_STATUS_FUNC_1) {
+                       wol->supported = 0;
+                       break;
+               }
+               /* return success for non excluded adapter ports */
+               retval = 0;
+               break;
+       default:
+               /* dual port cards only support WoL on port A from now on
+                * unless it was enabled in the eeprom for port B
+                * so exclude FUNC_1 ports from having WoL enabled */
+               if (rd32(E1000_STATUS) & E1000_STATUS_FUNC_1 &&
+                   !adapter->eeprom_wol) {
+                       wol->supported = 0;
+                       break;
+               }
+
+               retval = 0;
+       }
+
+       return retval;
+}
+
+static void igb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+
+       wol->supported = WAKE_UCAST | WAKE_MCAST |
+                        WAKE_BCAST | WAKE_MAGIC;
+       wol->wolopts = 0;
+
+       /* this function will set ->supported = 0 and return 1 if wol is not
+        * supported by this hardware */
+       if (igb_wol_exclusion(adapter, wol))
+               return;
+
+       /* apply any specific unsupported masks here */
+       switch (adapter->hw.device_id) {
+       default:
+               break;
+       }
+
+       if (adapter->wol & E1000_WUFC_EX)
+               wol->wolopts |= WAKE_UCAST;
+       if (adapter->wol & E1000_WUFC_MC)
+               wol->wolopts |= WAKE_MCAST;
+       if (adapter->wol & E1000_WUFC_BC)
+               wol->wolopts |= WAKE_BCAST;
+       if (adapter->wol & E1000_WUFC_MAG)
+               wol->wolopts |= WAKE_MAGIC;
+
+       return;
+}
+
+static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+
+       if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
+               return -EOPNOTSUPP;
+
+       if (igb_wol_exclusion(adapter, wol))
+               return wol->wolopts ? -EOPNOTSUPP : 0;
+
+       switch (hw->device_id) {
+       default:
+               break;
+       }
+
+       /* these settings will always override what we currently have */
+       adapter->wol = 0;
+
+       if (wol->wolopts & WAKE_UCAST)
+               adapter->wol |= E1000_WUFC_EX;
+       if (wol->wolopts & WAKE_MCAST)
+               adapter->wol |= E1000_WUFC_MC;
+       if (wol->wolopts & WAKE_BCAST)
+               adapter->wol |= E1000_WUFC_BC;
+       if (wol->wolopts & WAKE_MAGIC)
+               adapter->wol |= E1000_WUFC_MAG;
+
+       return 0;
+}
+
+/* toggle LED 4 times per second = 2 "blinks" per second */
+#define IGB_ID_INTERVAL                (HZ/4)
+
+/* bit defines for adapter->led_status */
+#define IGB_LED_ON             0
+
+static int igb_phys_id(struct net_device *netdev, u32 data)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+
+       if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
+               data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
+
+       igb_blink_led(hw);
+       msleep_interruptible(data * 1000);
+
+       igb_led_off(hw);
+       clear_bit(IGB_LED_ON, &adapter->led_status);
+       igb_cleanup_led(hw);
+
+       return 0;
+}
+
+static int igb_set_coalesce(struct net_device *netdev,
+                           struct ethtool_coalesce *ec)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+
+       if ((ec->rx_coalesce_usecs > IGB_MAX_ITR_USECS) ||
+           ((ec->rx_coalesce_usecs > 3) &&
+            (ec->rx_coalesce_usecs < IGB_MIN_ITR_USECS)) ||
+           (ec->rx_coalesce_usecs == 2))
+               return -EINVAL;
+
+       /* convert to rate of irq's per second */
+       if (ec->rx_coalesce_usecs <= 3)
+               adapter->itr_setting = ec->rx_coalesce_usecs;
+       else
+               adapter->itr_setting = (1000000 / ec->rx_coalesce_usecs);
+
+       if (netif_running(netdev))
+               igb_reinit_locked(adapter);
+
+       return 0;
+}
+
+static int igb_get_coalesce(struct net_device *netdev,
+                           struct ethtool_coalesce *ec)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+
+       if (adapter->itr_setting <= 3)
+               ec->rx_coalesce_usecs = adapter->itr_setting;
+       else
+               ec->rx_coalesce_usecs = 1000000 / adapter->itr_setting;
+
+       return 0;
+}
+
+
+static int igb_nway_reset(struct net_device *netdev)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       if (netif_running(netdev))
+               igb_reinit_locked(adapter);
+       return 0;
+}
+
+static int igb_get_sset_count(struct net_device *netdev, int sset)
+{
+       switch (sset) {
+       case ETH_SS_STATS:
+               return IGB_STATS_LEN;
+       case ETH_SS_TEST:
+               return IGB_TEST_LEN;
+       default:
+               return -ENOTSUPP;
+       }
+}
+
+static void igb_get_ethtool_stats(struct net_device *netdev,
+                                 struct ethtool_stats *stats, u64 *data)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       u64 *queue_stat;
+       int stat_count = sizeof(struct igb_queue_stats) / sizeof(u64);
+       int j;
+       int i;
+
+       igb_update_stats(adapter);
+       for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) {
+               char *p = (char *)adapter+igb_gstrings_stats[i].stat_offset;
+               data[i] = (igb_gstrings_stats[i].sizeof_stat ==
+                       sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+       }
+       for (j = 0; j < adapter->num_rx_queues; j++) {
+               int k;
+               queue_stat = (u64 *)&adapter->rx_ring[j].rx_stats;
+               for (k = 0; k < stat_count; k++)
+                       data[i + k] = queue_stat[k];
+               i += k;
+       }
+}
+
+static void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       u8 *p = data;
+       int i;
+
+       switch (stringset) {
+       case ETH_SS_TEST:
+               memcpy(data, *igb_gstrings_test,
+                       IGB_TEST_LEN*ETH_GSTRING_LEN);
+               break;
+       case ETH_SS_STATS:
+               for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) {
+                       memcpy(p, igb_gstrings_stats[i].stat_string,
+                              ETH_GSTRING_LEN);
+                       p += ETH_GSTRING_LEN;
+               }
+               for (i = 0; i < adapter->num_tx_queues; i++) {
+                       sprintf(p, "tx_queue_%u_packets", i);
+                       p += ETH_GSTRING_LEN;
+                       sprintf(p, "tx_queue_%u_bytes", i);
+                       p += ETH_GSTRING_LEN;
+               }
+               for (i = 0; i < adapter->num_rx_queues; i++) {
+                       sprintf(p, "rx_queue_%u_packets", i);
+                       p += ETH_GSTRING_LEN;
+                       sprintf(p, "rx_queue_%u_bytes", i);
+                       p += ETH_GSTRING_LEN;
+               }
+/*             BUG_ON(p - data != IGB_STATS_LEN * ETH_GSTRING_LEN); */
+               break;
+       }
+}
+
+static struct ethtool_ops igb_ethtool_ops = {
+       .get_settings           = igb_get_settings,
+       .set_settings           = igb_set_settings,
+       .get_drvinfo            = igb_get_drvinfo,
+       .get_regs_len           = igb_get_regs_len,
+       .get_regs               = igb_get_regs,
+       .get_wol                = igb_get_wol,
+       .set_wol                = igb_set_wol,
+       .get_msglevel           = igb_get_msglevel,
+       .set_msglevel           = igb_set_msglevel,
+       .nway_reset             = igb_nway_reset,
+       .get_link               = ethtool_op_get_link,
+       .get_eeprom_len         = igb_get_eeprom_len,
+       .get_eeprom             = igb_get_eeprom,
+       .set_eeprom             = igb_set_eeprom,
+       .get_ringparam          = igb_get_ringparam,
+       .set_ringparam          = igb_set_ringparam,
+       .get_pauseparam         = igb_get_pauseparam,
+       .set_pauseparam         = igb_set_pauseparam,
+       .get_rx_csum            = igb_get_rx_csum,
+       .set_rx_csum            = igb_set_rx_csum,
+       .get_tx_csum            = igb_get_tx_csum,
+       .set_tx_csum            = igb_set_tx_csum,
+       .get_sg                 = ethtool_op_get_sg,
+       .set_sg                 = ethtool_op_set_sg,
+       .get_tso                = ethtool_op_get_tso,
+       .set_tso                = igb_set_tso,
+       .self_test              = igb_diag_test,
+       .get_strings            = igb_get_strings,
+       .phys_id                = igb_phys_id,
+       .get_sset_count         = igb_get_sset_count,
+       .get_ethtool_stats      = igb_get_ethtool_stats,
+       .get_coalesce           = igb_get_coalesce,
+       .set_coalesce           = igb_set_coalesce,
+};
+
+void igb_set_ethtool_ops(struct net_device *netdev)
+{
+       SET_ETHTOOL_OPS(netdev, &igb_ethtool_ops);
+}
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
new file mode 100644 (file)
index 0000000..f3c144d
--- /dev/null
@@ -0,0 +1,4138 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <linux/netdevice.h>
+#include <linux/tcp.h>
+#include <linux/ipv6.h>
+#include <net/checksum.h>
+#include <net/ip6_checksum.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/if_ether.h>
+
+#include "igb.h"
+
+#define DRV_VERSION "1.0.8-k2"
+char igb_driver_name[] = "igb";
+char igb_driver_version[] = DRV_VERSION;
+static const char igb_driver_string[] =
+                               "Intel(R) Gigabit Ethernet Network Driver";
+static const char igb_copyright[] = "Copyright (c) 2007 Intel Corporation.";
+
+
+static const struct e1000_info *igb_info_tbl[] = {
+       [board_82575] = &e1000_82575_info,
+};
+
+static struct pci_device_id igb_pci_tbl[] = {
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_COPPER), board_82575 },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_FIBER_SERDES), board_82575 },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575GB_QUAD_COPPER), board_82575 },
+       /* required last entry */
+       {0, }
+};
+
+MODULE_DEVICE_TABLE(pci, igb_pci_tbl);
+
+void igb_reset(struct igb_adapter *);
+static int igb_setup_all_tx_resources(struct igb_adapter *);
+static int igb_setup_all_rx_resources(struct igb_adapter *);
+static void igb_free_all_tx_resources(struct igb_adapter *);
+static void igb_free_all_rx_resources(struct igb_adapter *);
+static void igb_free_tx_resources(struct igb_adapter *, struct igb_ring *);
+static void igb_free_rx_resources(struct igb_adapter *, struct igb_ring *);
+void igb_update_stats(struct igb_adapter *);
+static int igb_probe(struct pci_dev *, const struct pci_device_id *);
+static void __devexit igb_remove(struct pci_dev *pdev);
+static int igb_sw_init(struct igb_adapter *);
+static int igb_open(struct net_device *);
+static int igb_close(struct net_device *);
+static void igb_configure_tx(struct igb_adapter *);
+static void igb_configure_rx(struct igb_adapter *);
+static void igb_setup_rctl(struct igb_adapter *);
+static void igb_clean_all_tx_rings(struct igb_adapter *);
+static void igb_clean_all_rx_rings(struct igb_adapter *);
+static void igb_clean_tx_ring(struct igb_adapter *, struct igb_ring *);
+static void igb_clean_rx_ring(struct igb_adapter *, struct igb_ring *);
+static void igb_set_multi(struct net_device *);
+static void igb_update_phy_info(unsigned long);
+static void igb_watchdog(unsigned long);
+static void igb_watchdog_task(struct work_struct *);
+static int igb_xmit_frame_ring_adv(struct sk_buff *, struct net_device *,
+                                 struct igb_ring *);
+static int igb_xmit_frame_adv(struct sk_buff *skb, struct net_device *);
+static struct net_device_stats *igb_get_stats(struct net_device *);
+static int igb_change_mtu(struct net_device *, int);
+static int igb_set_mac(struct net_device *, void *);
+static irqreturn_t igb_intr(int irq, void *);
+static irqreturn_t igb_intr_msi(int irq, void *);
+static irqreturn_t igb_msix_other(int irq, void *);
+static irqreturn_t igb_msix_rx(int irq, void *);
+static irqreturn_t igb_msix_tx(int irq, void *);
+static int igb_clean_rx_ring_msix(struct napi_struct *, int);
+static bool igb_clean_tx_irq(struct igb_adapter *, struct igb_ring *);
+static int igb_clean(struct napi_struct *, int);
+static bool igb_clean_rx_irq_adv(struct igb_adapter *,
+                                struct igb_ring *, int *, int);
+static void igb_alloc_rx_buffers_adv(struct igb_adapter *,
+                                    struct igb_ring *, int);
+static int igb_ioctl(struct net_device *, struct ifreq *, int cmd);
+static void igb_tx_timeout(struct net_device *);
+static void igb_reset_task(struct work_struct *);
+static void igb_vlan_rx_register(struct net_device *, struct vlan_group *);
+static void igb_vlan_rx_add_vid(struct net_device *, u16);
+static void igb_vlan_rx_kill_vid(struct net_device *, u16);
+static void igb_restore_vlan(struct igb_adapter *);
+
+static int igb_suspend(struct pci_dev *, pm_message_t);
+#ifdef CONFIG_PM
+static int igb_resume(struct pci_dev *);
+#endif
+static void igb_shutdown(struct pci_dev *);
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/* for netdump / net console */
+static void igb_netpoll(struct net_device *);
+#endif
+
+static pci_ers_result_t igb_io_error_detected(struct pci_dev *,
+                    pci_channel_state_t);
+static pci_ers_result_t igb_io_slot_reset(struct pci_dev *);
+static void igb_io_resume(struct pci_dev *);
+
+static struct pci_error_handlers igb_err_handler = {
+       .error_detected = igb_io_error_detected,
+       .slot_reset = igb_io_slot_reset,
+       .resume = igb_io_resume,
+};
+
+
+static struct pci_driver igb_driver = {
+       .name     = igb_driver_name,
+       .id_table = igb_pci_tbl,
+       .probe    = igb_probe,
+       .remove   = __devexit_p(igb_remove),
+#ifdef CONFIG_PM
+       /* Power Managment Hooks */
+       .suspend  = igb_suspend,
+       .resume   = igb_resume,
+#endif
+       .shutdown = igb_shutdown,
+       .err_handler = &igb_err_handler
+};
+
+MODULE_AUTHOR("Intel Corporation, <e1000-devel@lists.sourceforge.net>");
+MODULE_DESCRIPTION("Intel(R) Gigabit Ethernet Network Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+#ifdef DEBUG
+/**
+ * igb_get_hw_dev_name - return device name string
+ * used by hardware layer to print debugging information
+ **/
+char *igb_get_hw_dev_name(struct e1000_hw *hw)
+{
+       struct igb_adapter *adapter = hw->back;
+       return adapter->netdev->name;
+}
+#endif
+
+/**
+ * igb_init_module - Driver Registration Routine
+ *
+ * igb_init_module is the first routine called when the driver is
+ * loaded. All it does is register with the PCI subsystem.
+ **/
+static int __init igb_init_module(void)
+{
+       int ret;
+       printk(KERN_INFO "%s - version %s\n",
+              igb_driver_string, igb_driver_version);
+
+       printk(KERN_INFO "%s\n", igb_copyright);
+
+       ret = pci_register_driver(&igb_driver);
+       return ret;
+}
+
+module_init(igb_init_module);
+
+/**
+ * igb_exit_module - Driver Exit Cleanup Routine
+ *
+ * igb_exit_module is called just before the driver is removed
+ * from memory.
+ **/
+static void __exit igb_exit_module(void)
+{
+       pci_unregister_driver(&igb_driver);
+}
+
+module_exit(igb_exit_module);
+
+/**
+ * igb_alloc_queues - Allocate memory for all rings
+ * @adapter: board private structure to initialize
+ *
+ * We allocate one ring per queue at run-time since we don't know the
+ * number of queues at compile-time.
+ **/
+static int igb_alloc_queues(struct igb_adapter *adapter)
+{
+       int i;
+
+       adapter->tx_ring = kcalloc(adapter->num_tx_queues,
+                                  sizeof(struct igb_ring), GFP_KERNEL);
+       if (!adapter->tx_ring)
+               return -ENOMEM;
+
+       adapter->rx_ring = kcalloc(adapter->num_rx_queues,
+                                  sizeof(struct igb_ring), GFP_KERNEL);
+       if (!adapter->rx_ring) {
+               kfree(adapter->tx_ring);
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < adapter->num_rx_queues; i++) {
+               struct igb_ring *ring = &(adapter->rx_ring[i]);
+               ring->adapter = adapter;
+               ring->itr_register = E1000_ITR;
+
+               if (!ring->napi.poll)
+                       netif_napi_add(adapter->netdev, &ring->napi, igb_clean,
+                                      adapter->napi.weight /
+                                      adapter->num_rx_queues);
+       }
+       return 0;
+}
+
+#define IGB_N0_QUEUE -1
+static void igb_assign_vector(struct igb_adapter *adapter, int rx_queue,
+                             int tx_queue, int msix_vector)
+{
+       u32 msixbm = 0;
+       struct e1000_hw *hw = &adapter->hw;
+               /* The 82575 assigns vectors using a bitmask, which matches the
+                  bitmask for the EICR/EIMS/EIMC registers.  To assign one
+                  or more queues to a vector, we write the appropriate bits
+                  into the MSIXBM register for that vector. */
+               if (rx_queue > IGB_N0_QUEUE) {
+                       msixbm = E1000_EICR_RX_QUEUE0 << rx_queue;
+                       adapter->rx_ring[rx_queue].eims_value = msixbm;
+               }
+               if (tx_queue > IGB_N0_QUEUE) {
+                       msixbm |= E1000_EICR_TX_QUEUE0 << tx_queue;
+                       adapter->tx_ring[tx_queue].eims_value =
+                                 E1000_EICR_TX_QUEUE0 << tx_queue;
+               }
+               array_wr32(E1000_MSIXBM(0), msix_vector, msixbm);
+}
+
+/**
+ * igb_configure_msix - Configure MSI-X hardware
+ *
+ * igb_configure_msix sets up the hardware to properly
+ * generate MSI-X interrupts.
+ **/
+static void igb_configure_msix(struct igb_adapter *adapter)
+{
+       u32 tmp;
+       int i, vector = 0;
+       struct e1000_hw *hw = &adapter->hw;
+
+       adapter->eims_enable_mask = 0;
+
+       for (i = 0; i < adapter->num_tx_queues; i++) {
+               struct igb_ring *tx_ring = &adapter->tx_ring[i];
+               igb_assign_vector(adapter, IGB_N0_QUEUE, i, vector++);
+               adapter->eims_enable_mask |= tx_ring->eims_value;
+               if (tx_ring->itr_val)
+                       writel(1000000000 / (tx_ring->itr_val * 256),
+                              hw->hw_addr + tx_ring->itr_register);
+               else
+                       writel(1, hw->hw_addr + tx_ring->itr_register);
+       }
+
+       for (i = 0; i < adapter->num_rx_queues; i++) {
+               struct igb_ring *rx_ring = &adapter->rx_ring[i];
+               igb_assign_vector(adapter, i, IGB_N0_QUEUE, vector++);
+               adapter->eims_enable_mask |= rx_ring->eims_value;
+               if (rx_ring->itr_val)
+                       writel(1000000000 / (rx_ring->itr_val * 256),
+                              hw->hw_addr + rx_ring->itr_register);
+               else
+                       writel(1, hw->hw_addr + rx_ring->itr_register);
+       }
+
+
+       /* set vector for other causes, i.e. link changes */
+               array_wr32(E1000_MSIXBM(0), vector++,
+                                     E1000_EIMS_OTHER);
+
+               /* disable IAM for ICR interrupt bits */
+               wr32(E1000_IAM, 0);
+
+               tmp = rd32(E1000_CTRL_EXT);
+               /* enable MSI-X PBA support*/
+               tmp |= E1000_CTRL_EXT_PBA_CLR;
+
+               /* Auto-Mask interrupts upon ICR read. */
+               tmp |= E1000_CTRL_EXT_EIAME;
+               tmp |= E1000_CTRL_EXT_IRCA;
+
+               wr32(E1000_CTRL_EXT, tmp);
+               adapter->eims_enable_mask |= E1000_EIMS_OTHER;
+
+       wrfl();
+}
+
+/**
+ * igb_request_msix - Initialize MSI-X interrupts
+ *
+ * igb_request_msix allocates MSI-X vectors and requests interrupts from the
+ * kernel.
+ **/
+static int igb_request_msix(struct igb_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       int i, err = 0, vector = 0;
+
+       vector = 0;
+
+       for (i = 0; i < adapter->num_tx_queues; i++) {
+               struct igb_ring *ring = &(adapter->tx_ring[i]);
+               sprintf(ring->name, "%s-tx%d", netdev->name, i);
+               err = request_irq(adapter->msix_entries[vector].vector,
+                                 &igb_msix_tx, 0, ring->name,
+                                 &(adapter->tx_ring[i]));
+               if (err)
+                       goto out;
+               ring->itr_register = E1000_EITR(0) + (vector << 2);
+               ring->itr_val = adapter->itr;
+               vector++;
+       }
+       for (i = 0; i < adapter->num_rx_queues; i++) {
+               struct igb_ring *ring = &(adapter->rx_ring[i]);
+               if (strlen(netdev->name) < (IFNAMSIZ - 5))
+                       sprintf(ring->name, "%s-rx%d", netdev->name, i);
+               else
+                       memcpy(ring->name, netdev->name, IFNAMSIZ);
+               err = request_irq(adapter->msix_entries[vector].vector,
+                                 &igb_msix_rx, 0, ring->name,
+                                 &(adapter->rx_ring[i]));
+               if (err)
+                       goto out;
+               ring->itr_register = E1000_EITR(0) + (vector << 2);
+               ring->itr_val = adapter->itr;
+               vector++;
+       }
+
+       err = request_irq(adapter->msix_entries[vector].vector,
+                         &igb_msix_other, 0, netdev->name, netdev);
+       if (err)
+               goto out;
+
+       adapter->napi.poll = igb_clean_rx_ring_msix;
+       for (i = 0; i < adapter->num_rx_queues; i++)
+               adapter->rx_ring[i].napi.poll = adapter->napi.poll;
+       igb_configure_msix(adapter);
+       return 0;
+out:
+       return err;
+}
+
+static void igb_reset_interrupt_capability(struct igb_adapter *adapter)
+{
+       if (adapter->msix_entries) {
+               pci_disable_msix(adapter->pdev);
+               kfree(adapter->msix_entries);
+               adapter->msix_entries = NULL;
+       } else if (adapter->msi_enabled)
+               pci_disable_msi(adapter->pdev);
+       return;
+}
+
+
+/**
+ * igb_set_interrupt_capability - set MSI or MSI-X if supported
+ *
+ * Attempt to configure interrupts using the best available
+ * capabilities of the hardware and kernel.
+ **/
+static void igb_set_interrupt_capability(struct igb_adapter *adapter)
+{
+       int err;
+       int numvecs, i;
+
+       numvecs = adapter->num_tx_queues + adapter->num_rx_queues + 1;
+       adapter->msix_entries = kcalloc(numvecs, sizeof(struct msix_entry),
+                                       GFP_KERNEL);
+       if (!adapter->msix_entries)
+               goto msi_only;
+
+       for (i = 0; i < numvecs; i++)
+               adapter->msix_entries[i].entry = i;
+
+       err = pci_enable_msix(adapter->pdev,
+                             adapter->msix_entries,
+                             numvecs);
+       if (err == 0)
+               return;
+
+       igb_reset_interrupt_capability(adapter);
+
+       /* If we can't do MSI-X, try MSI */
+msi_only:
+       adapter->num_rx_queues = 1;
+       if (!pci_enable_msi(adapter->pdev))
+               adapter->msi_enabled = 1;
+       return;
+}
+
+/**
+ * igb_request_irq - initialize interrupts
+ *
+ * Attempts to configure interrupts using the best available
+ * capabilities of the hardware and kernel.
+ **/
+static int igb_request_irq(struct igb_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       struct e1000_hw *hw = &adapter->hw;
+       int err = 0;
+
+       if (adapter->msix_entries) {
+               err = igb_request_msix(adapter);
+               if (!err) {
+                       struct e1000_hw *hw = &adapter->hw;
+                       /* enable IAM, auto-mask,
+                        * DO NOT USE EIAME or IAME in legacy mode */
+                       wr32(E1000_IAM, IMS_ENABLE_MASK);
+                       goto request_done;
+               }
+               /* fall back to MSI */
+               igb_reset_interrupt_capability(adapter);
+               if (!pci_enable_msi(adapter->pdev))
+                       adapter->msi_enabled = 1;
+               igb_free_all_tx_resources(adapter);
+               igb_free_all_rx_resources(adapter);
+               adapter->num_rx_queues = 1;
+               igb_alloc_queues(adapter);
+       }
+       if (adapter->msi_enabled) {
+               err = request_irq(adapter->pdev->irq, &igb_intr_msi, 0,
+                                 netdev->name, netdev);
+               if (!err)
+                       goto request_done;
+               /* fall back to legacy interrupts */
+               igb_reset_interrupt_capability(adapter);
+               adapter->msi_enabled = 0;
+       }
+
+       err = request_irq(adapter->pdev->irq, &igb_intr, IRQF_SHARED,
+                         netdev->name, netdev);
+
+       if (err) {
+               dev_err(&adapter->pdev->dev, "Error %d getting interrupt\n",
+                       err);
+               goto request_done;
+       }
+
+       /* enable IAM, auto-mask */
+       wr32(E1000_IAM, IMS_ENABLE_MASK);
+
+request_done:
+       return err;
+}
+
+static void igb_free_irq(struct igb_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+
+       if (adapter->msix_entries) {
+               int vector = 0, i;
+
+               for (i = 0; i < adapter->num_tx_queues; i++)
+                       free_irq(adapter->msix_entries[vector++].vector,
+                               &(adapter->tx_ring[i]));
+               for (i = 0; i < adapter->num_rx_queues; i++)
+                       free_irq(adapter->msix_entries[vector++].vector,
+                               &(adapter->rx_ring[i]));
+
+               free_irq(adapter->msix_entries[vector++].vector, netdev);
+               return;
+       }
+
+       free_irq(adapter->pdev->irq, netdev);
+}
+
+/**
+ * igb_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ **/
+static void igb_irq_disable(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+
+       if (adapter->msix_entries) {
+               wr32(E1000_EIMC, ~0);
+               wr32(E1000_EIAC, 0);
+       }
+       wr32(E1000_IMC, ~0);
+       wrfl();
+       synchronize_irq(adapter->pdev->irq);
+}
+
+/**
+ * igb_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ **/
+static void igb_irq_enable(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+
+       if (adapter->msix_entries) {
+               wr32(E1000_EIMS,
+                               adapter->eims_enable_mask);
+               wr32(E1000_EIAC,
+                               adapter->eims_enable_mask);
+               wr32(E1000_IMS, E1000_IMS_LSC);
+       } else
+       wr32(E1000_IMS, IMS_ENABLE_MASK);
+}
+
+static void igb_update_mng_vlan(struct igb_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       u16 vid = adapter->hw.mng_cookie.vlan_id;
+       u16 old_vid = adapter->mng_vlan_id;
+       if (adapter->vlgrp) {
+               if (!vlan_group_get_device(adapter->vlgrp, vid)) {
+                       if (adapter->hw.mng_cookie.status &
+                               E1000_MNG_DHCP_COOKIE_STATUS_VLAN) {
+                               igb_vlan_rx_add_vid(netdev, vid);
+                               adapter->mng_vlan_id = vid;
+                       } else
+                               adapter->mng_vlan_id = IGB_MNG_VLAN_NONE;
+
+                       if ((old_vid != (u16)IGB_MNG_VLAN_NONE) &&
+                                       (vid != old_vid) &&
+                           !vlan_group_get_device(adapter->vlgrp, old_vid))
+                               igb_vlan_rx_kill_vid(netdev, old_vid);
+               } else
+                       adapter->mng_vlan_id = vid;
+       }
+}
+
+/**
+ * igb_release_hw_control - release control of the h/w to f/w
+ * @adapter: address of board private structure
+ *
+ * igb_release_hw_control resets CTRL_EXT:DRV_LOAD bit.
+ * For ASF and Pass Through versions of f/w this means that the
+ * driver is no longer loaded.
+ *
+ **/
+static void igb_release_hw_control(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 ctrl_ext;
+
+       /* Let firmware take over control of h/w */
+       ctrl_ext = rd32(E1000_CTRL_EXT);
+       wr32(E1000_CTRL_EXT,
+                       ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD);
+}
+
+
+/**
+ * igb_get_hw_control - get control of the h/w from f/w
+ * @adapter: address of board private structure
+ *
+ * igb_get_hw_control sets CTRL_EXT:DRV_LOAD bit.
+ * For ASF and Pass Through versions of f/w this means that
+ * the driver is loaded.
+ *
+ **/
+static void igb_get_hw_control(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 ctrl_ext;
+
+       /* Let firmware know the driver has taken over */
+       ctrl_ext = rd32(E1000_CTRL_EXT);
+       wr32(E1000_CTRL_EXT,
+                       ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
+}
+
+static void igb_init_manageability(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+
+       if (adapter->en_mng_pt) {
+               u32 manc2h = rd32(E1000_MANC2H);
+               u32 manc = rd32(E1000_MANC);
+
+               /* disable hardware interception of ARP */
+               manc &= ~(E1000_MANC_ARP_EN);
+
+               /* enable receiving management packets to the host */
+               /* this will probably generate destination unreachable messages
+                * from the host OS, but the packets will be handled on SMBUS */
+               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;
+               wr32(E1000_MANC2H, manc2h);
+
+               wr32(E1000_MANC, manc);
+       }
+}
+
+static void igb_release_manageability(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+
+       if (adapter->en_mng_pt) {
+               u32 manc = rd32(E1000_MANC);
+
+               /* re-enable hardware interception of ARP */
+               manc |= E1000_MANC_ARP_EN;
+               manc &= ~E1000_MANC_EN_MNG2HOST;
+
+               /* don't explicitly have to mess with MANC2H since
+                * MANC has an enable disable that gates MANC2H */
+
+               /* XXX stop the hardware watchdog ? */
+               wr32(E1000_MANC, manc);
+       }
+}
+
+/**
+ * igb_configure - configure the hardware for RX and TX
+ * @adapter: private board structure
+ **/
+static void igb_configure(struct igb_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       int i;
+
+       igb_get_hw_control(adapter);
+       igb_set_multi(netdev);
+
+       igb_restore_vlan(adapter);
+       igb_init_manageability(adapter);
+
+       igb_configure_tx(adapter);
+       igb_setup_rctl(adapter);
+       igb_configure_rx(adapter);
+       /* call IGB_DESC_UNUSED which always leaves
+        * at least 1 descriptor unused to make sure
+        * next_to_use != next_to_clean */
+       for (i = 0; i < adapter->num_rx_queues; i++) {
+               struct igb_ring *ring = &adapter->rx_ring[i];
+               igb_alloc_rx_buffers_adv(adapter, ring, IGB_DESC_UNUSED(ring));
+       }
+
+
+       adapter->tx_queue_len = netdev->tx_queue_len;
+}
+
+
+/**
+ * igb_up - Open the interface and prepare it to handle traffic
+ * @adapter: board private structure
+ **/
+
+int igb_up(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       int i;
+
+       /* hardware has been reset, we need to reload some things */
+       igb_configure(adapter);
+
+       clear_bit(__IGB_DOWN, &adapter->state);
+
+       napi_enable(&adapter->napi);
+
+       if (adapter->msix_entries) {
+               for (i = 0; i < adapter->num_rx_queues; i++)
+                       napi_enable(&adapter->rx_ring[i].napi);
+               igb_configure_msix(adapter);
+       }
+
+       /* Clear any pending interrupts. */
+       rd32(E1000_ICR);
+       igb_irq_enable(adapter);
+
+       /* Fire a link change interrupt to start the watchdog. */
+       wr32(E1000_ICS, E1000_ICS_LSC);
+       return 0;
+}
+
+void igb_down(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       struct net_device *netdev = adapter->netdev;
+       u32 tctl, rctl;
+       int i;
+
+       /* signal that we're down so the interrupt handler does not
+        * reschedule our watchdog timer */
+       set_bit(__IGB_DOWN, &adapter->state);
+
+       /* disable receives in the hardware */
+       rctl = rd32(E1000_RCTL);
+       wr32(E1000_RCTL, rctl & ~E1000_RCTL_EN);
+       /* flush and sleep below */
+
+       netif_stop_queue(netdev);
+
+       /* disable transmits in the hardware */
+       tctl = rd32(E1000_TCTL);
+       tctl &= ~E1000_TCTL_EN;
+       wr32(E1000_TCTL, tctl);
+       /* flush both disables and wait for them to finish */
+       wrfl();
+       msleep(10);
+
+       napi_disable(&adapter->napi);
+
+       if (adapter->msix_entries)
+               for (i = 0; i < adapter->num_rx_queues; i++)
+                       napi_disable(&adapter->rx_ring[i].napi);
+       igb_irq_disable(adapter);
+
+       del_timer_sync(&adapter->watchdog_timer);
+       del_timer_sync(&adapter->phy_info_timer);
+
+       netdev->tx_queue_len = adapter->tx_queue_len;
+       netif_carrier_off(netdev);
+       adapter->link_speed = 0;
+       adapter->link_duplex = 0;
+
+       igb_reset(adapter);
+       igb_clean_all_tx_rings(adapter);
+       igb_clean_all_rx_rings(adapter);
+}
+
+void igb_reinit_locked(struct igb_adapter *adapter)
+{
+       WARN_ON(in_interrupt());
+       while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
+               msleep(1);
+       igb_down(adapter);
+       igb_up(adapter);
+       clear_bit(__IGB_RESETTING, &adapter->state);
+}
+
+void igb_reset(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       struct e1000_fc_info *fc = &adapter->hw.fc;
+       u32 pba = 0, tx_space, min_tx_space, min_rx_space;
+       u16 hwm;
+
+       /* Repartition Pba for greater than 9k mtu
+        * To take effect CTRL.RST is required.
+        */
+       pba = E1000_PBA_34K;
+
+       if (adapter->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN) {
+               /* adjust PBA for jumbo frames */
+               wr32(E1000_PBA, pba);
+
+               /* To maintain wire speed transmits, the Tx FIFO should be
+                * large enough to accommodate two full transmit packets,
+                * rounded up to the next 1KB and expressed in KB.  Likewise,
+                * the Rx FIFO should be large enough to accommodate at least
+                * one full receive packet and is similarly rounded up and
+                * expressed in KB. */
+               pba = rd32(E1000_PBA);
+               /* upper 16 bits has Tx packet buffer allocation size in KB */
+               tx_space = pba >> 16;
+               /* lower 16 bits has Rx packet buffer allocation size in KB */
+               pba &= 0xffff;
+               /* the tx fifo also stores 16 bytes of information about the tx
+                * but don't include ethernet FCS because hardware appends it */
+               min_tx_space = (adapter->max_frame_size +
+                               sizeof(struct e1000_tx_desc) -
+                               ETH_FCS_LEN) * 2;
+               min_tx_space = ALIGN(min_tx_space, 1024);
+               min_tx_space >>= 10;
+               /* software strips receive CRC, so leave room for it */
+               min_rx_space = adapter->max_frame_size;
+               min_rx_space = ALIGN(min_rx_space, 1024);
+               min_rx_space >>= 10;
+
+               /* If current Tx allocation is less than the min Tx FIFO size,
+                * and the min Tx FIFO size is less than the current Rx FIFO
+                * allocation, take space away from current Rx allocation */
+               if (tx_space < min_tx_space &&
+                   ((min_tx_space - tx_space) < pba)) {
+                       pba = pba - (min_tx_space - tx_space);
+
+                       /* if short on rx space, rx wins and must trump tx
+                        * adjustment */
+                       if (pba < min_rx_space)
+                               pba = min_rx_space;
+               }
+       }
+       wr32(E1000_PBA, pba);
+
+       /* flow control settings */
+       /* The high water mark must be low enough to fit one full frame
+        * (or the size used for early receive) above it in the Rx FIFO.
+        * Set it to the lower of:
+        * - 90% of the Rx FIFO size, or
+        * - the full Rx FIFO size minus one full frame */
+       hwm = min(((pba << 10) * 9 / 10),
+                 ((pba << 10) - adapter->max_frame_size));
+
+       fc->high_water = hwm & 0xFFF8;  /* 8-byte granularity */
+       fc->low_water = fc->high_water - 8;
+       fc->pause_time = 0xFFFF;
+       fc->send_xon = 1;
+       fc->type = fc->original_type;
+
+       /* Allow time for pending master requests to run */
+       adapter->hw.mac.ops.reset_hw(&adapter->hw);
+       wr32(E1000_WUC, 0);
+
+       if (adapter->hw.mac.ops.init_hw(&adapter->hw))
+               dev_err(&adapter->pdev->dev, "Hardware Error\n");
+
+       igb_update_mng_vlan(adapter);
+
+       /* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */
+       wr32(E1000_VET, ETHERNET_IEEE_VLAN_TYPE);
+
+       igb_reset_adaptive(&adapter->hw);
+       adapter->hw.phy.ops.get_phy_info(&adapter->hw);
+       igb_release_manageability(adapter);
+}
+
+/**
+ * igb_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in igb_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * igb_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ **/
+static int __devinit igb_probe(struct pci_dev *pdev,
+                              const struct pci_device_id *ent)
+{
+       struct net_device *netdev;
+       struct igb_adapter *adapter;
+       struct e1000_hw *hw;
+       const struct e1000_info *ei = igb_info_tbl[ent->driver_data];
+       unsigned long mmio_start, mmio_len;
+       static int cards_found;
+       int i, err, pci_using_dac;
+       u16 eeprom_data = 0;
+       u16 eeprom_apme_mask = IGB_EEPROM_APME;
+       u32 part_num;
+
+       err = pci_enable_device(pdev);
+       if (err)
+               return err;
+
+       pci_using_dac = 0;
+       err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+       if (!err) {
+               err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+               if (!err)
+                       pci_using_dac = 1;
+       } else {
+               err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+               if (err) {
+                       err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+                       if (err) {
+                               dev_err(&pdev->dev, "No usable DMA "
+                                       "configuration, aborting\n");
+                               goto err_dma;
+                       }
+               }
+       }
+
+       err = pci_request_regions(pdev, igb_driver_name);
+       if (err)
+               goto err_pci_reg;
+
+       pci_set_master(pdev);
+
+       err = -ENOMEM;
+       netdev = alloc_etherdev(sizeof(struct igb_adapter));
+       if (!netdev)
+               goto err_alloc_etherdev;
+
+       SET_NETDEV_DEV(netdev, &pdev->dev);
+
+       pci_set_drvdata(pdev, netdev);
+       adapter = netdev_priv(netdev);
+       adapter->netdev = netdev;
+       adapter->pdev = pdev;
+       hw = &adapter->hw;
+       hw->back = adapter;
+       adapter->msg_enable = NETIF_MSG_DRV | NETIF_MSG_PROBE;
+
+       mmio_start = pci_resource_start(pdev, 0);
+       mmio_len = pci_resource_len(pdev, 0);
+
+       err = -EIO;
+       adapter->hw.hw_addr = ioremap(mmio_start, mmio_len);
+       if (!adapter->hw.hw_addr)
+               goto err_ioremap;
+
+       netdev->open = &igb_open;
+       netdev->stop = &igb_close;
+       netdev->get_stats = &igb_get_stats;
+       netdev->set_multicast_list = &igb_set_multi;
+       netdev->set_mac_address = &igb_set_mac;
+       netdev->change_mtu = &igb_change_mtu;
+       netdev->do_ioctl = &igb_ioctl;
+       igb_set_ethtool_ops(netdev);
+       netdev->tx_timeout = &igb_tx_timeout;
+       netdev->watchdog_timeo = 5 * HZ;
+       netif_napi_add(netdev, &adapter->napi, igb_clean, 64);
+       netdev->vlan_rx_register = igb_vlan_rx_register;
+       netdev->vlan_rx_add_vid = igb_vlan_rx_add_vid;
+       netdev->vlan_rx_kill_vid = igb_vlan_rx_kill_vid;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       netdev->poll_controller = igb_netpoll;
+#endif
+       netdev->hard_start_xmit = &igb_xmit_frame_adv;
+
+       strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
+
+       netdev->mem_start = mmio_start;
+       netdev->mem_end = mmio_start + mmio_len;
+
+       adapter->bd_number = cards_found;
+
+       /* PCI config space info */
+       hw->vendor_id = pdev->vendor;
+       hw->device_id = pdev->device;
+       hw->revision_id = pdev->revision;
+       hw->subsystem_vendor_id = pdev->subsystem_vendor;
+       hw->subsystem_device_id = pdev->subsystem_device;
+
+       /* setup the private structure */
+       hw->back = adapter;
+       /* Copy the default MAC, PHY and NVM function pointers */
+       memcpy(&hw->mac.ops, ei->mac_ops, sizeof(hw->mac.ops));
+       memcpy(&hw->phy.ops, ei->phy_ops, sizeof(hw->phy.ops));
+       memcpy(&hw->nvm.ops, ei->nvm_ops, sizeof(hw->nvm.ops));
+       /* Initialize skew-specific constants */
+       err = ei->get_invariants(hw);
+       if (err)
+               goto err_hw_init;
+
+       err = igb_sw_init(adapter);
+       if (err)
+               goto err_sw_init;
+
+       igb_get_bus_info_pcie(hw);
+
+       hw->phy.autoneg_wait_to_complete = false;
+       hw->mac.adaptive_ifs = true;
+
+       /* Copper options */
+       if (hw->phy.media_type == e1000_media_type_copper) {
+               hw->phy.mdix = AUTO_ALL_MODES;
+               hw->phy.disable_polarity_correction = false;
+               hw->phy.ms_type = e1000_ms_hw_default;
+       }
+
+       if (igb_check_reset_block(hw))
+               dev_info(&pdev->dev,
+                       "PHY reset is blocked due to SOL/IDER session.\n");
+
+       netdev->features = NETIF_F_SG |
+                          NETIF_F_HW_CSUM |
+                          NETIF_F_HW_VLAN_TX |
+                          NETIF_F_HW_VLAN_RX |
+                          NETIF_F_HW_VLAN_FILTER;
+
+       netdev->features |= NETIF_F_TSO;
+
+       netdev->features |= NETIF_F_TSO6;
+       if (pci_using_dac)
+               netdev->features |= NETIF_F_HIGHDMA;
+
+       netdev->features |= NETIF_F_LLTX;
+       adapter->en_mng_pt = igb_enable_mng_pass_thru(&adapter->hw);
+
+       /* before reading the NVM, reset the controller to put the device in a
+        * known good starting state */
+       hw->mac.ops.reset_hw(hw);
+
+       /* make sure the NVM is good */
+       if (igb_validate_nvm_checksum(hw) < 0) {
+               dev_err(&pdev->dev, "The NVM Checksum Is Not Valid\n");
+               err = -EIO;
+               goto err_eeprom;
+       }
+
+       /* copy the MAC address out of the NVM */
+       if (hw->mac.ops.read_mac_addr(hw))
+               dev_err(&pdev->dev, "NVM Read Error\n");
+
+       memcpy(netdev->dev_addr, hw->mac.addr, netdev->addr_len);
+       memcpy(netdev->perm_addr, hw->mac.addr, netdev->addr_len);
+
+       if (!is_valid_ether_addr(netdev->perm_addr)) {
+               dev_err(&pdev->dev, "Invalid MAC Address\n");
+               err = -EIO;
+               goto err_eeprom;
+       }
+
+       init_timer(&adapter->watchdog_timer);
+       adapter->watchdog_timer.function = &igb_watchdog;
+       adapter->watchdog_timer.data = (unsigned long) adapter;
+
+       init_timer(&adapter->phy_info_timer);
+       adapter->phy_info_timer.function = &igb_update_phy_info;
+       adapter->phy_info_timer.data = (unsigned long) adapter;
+
+       INIT_WORK(&adapter->reset_task, igb_reset_task);
+       INIT_WORK(&adapter->watchdog_task, igb_watchdog_task);
+
+       /* Initialize link & ring properties that are user-changeable */
+       adapter->tx_ring->count = 256;
+       for (i = 0; i < adapter->num_tx_queues; i++)
+               adapter->tx_ring[i].count = adapter->tx_ring->count;
+       adapter->rx_ring->count = 256;
+       for (i = 0; i < adapter->num_rx_queues; i++)
+               adapter->rx_ring[i].count = adapter->rx_ring->count;
+
+       adapter->fc_autoneg = true;
+       hw->mac.autoneg = true;
+       hw->phy.autoneg_advertised = 0x2f;
+
+       hw->fc.original_type = e1000_fc_default;
+       hw->fc.type = e1000_fc_default;
+
+       adapter->itr_setting = 3;
+       adapter->itr = IGB_START_ITR;
+
+       igb_validate_mdi_setting(hw);
+
+       adapter->rx_csum = 1;
+
+       /* Initial Wake on LAN setting If APM wake is enabled in the EEPROM,
+        * enable the ACPI Magic Packet filter
+        */
+
+       if (hw->bus.func == 0 ||
+           hw->device_id == E1000_DEV_ID_82575EB_COPPER)
+               hw->nvm.ops.read_nvm(hw, NVM_INIT_CONTROL3_PORT_A, 1,
+                                    &eeprom_data);
+
+       if (eeprom_data & eeprom_apme_mask)
+               adapter->eeprom_wol |= E1000_WUFC_MAG;
+
+       /* now that we have the eeprom settings, apply the special cases where
+        * the eeprom may be wrong or the board simply won't support wake on
+        * lan on a particular port */
+       switch (pdev->device) {
+       case E1000_DEV_ID_82575GB_QUAD_COPPER:
+               adapter->eeprom_wol = 0;
+               break;
+       case E1000_DEV_ID_82575EB_FIBER_SERDES:
+               /* Wake events only supported on port A for dual fiber
+                * regardless of eeprom setting */
+               if (rd32(E1000_STATUS) & E1000_STATUS_FUNC_1)
+                       adapter->eeprom_wol = 0;
+               break;
+       }
+
+       /* initialize the wol settings based on the eeprom settings */
+       adapter->wol = adapter->eeprom_wol;
+
+       /* reset the hardware with the new settings */
+       igb_reset(adapter);
+
+       /* let the f/w know that the h/w is now under the control of the
+        * driver. */
+       igb_get_hw_control(adapter);
+
+       /* tell the stack to leave us alone until igb_open() is called */
+       netif_carrier_off(netdev);
+       netif_stop_queue(netdev);
+
+       strcpy(netdev->name, "eth%d");
+       err = register_netdev(netdev);
+       if (err)
+               goto err_register;
+
+       dev_info(&pdev->dev, "Intel(R) Gigabit Ethernet Network Connection\n");
+       /* print bus type/speed/width info */
+       dev_info(&pdev->dev,
+                "%s: (PCIe:%s:%s) %02x:%02x:%02x:%02x:%02x:%02x\n",
+                netdev->name,
+                ((hw->bus.speed == e1000_bus_speed_2500)
+                 ? "2.5Gb/s" : "unknown"),
+                ((hw->bus.width == e1000_bus_width_pcie_x4)
+                 ? "Width x4" : (hw->bus.width == e1000_bus_width_pcie_x1)
+                 ? "Width x1" : "unknown"),
+                netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
+                netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
+
+       igb_read_part_num(hw, &part_num);
+       dev_info(&pdev->dev, "%s: PBA No: %06x-%03x\n", netdev->name,
+               (part_num >> 8), (part_num & 0xff));
+
+       dev_info(&pdev->dev,
+               "Using %s interrupts. %d rx queue(s), %d tx queue(s)\n",
+               adapter->msix_entries ? "MSI-X" :
+               adapter->msi_enabled ? "MSI" : "legacy",
+               adapter->num_rx_queues, adapter->num_tx_queues);
+
+       cards_found++;
+       return 0;
+
+err_register:
+       igb_release_hw_control(adapter);
+err_eeprom:
+       if (!igb_check_reset_block(hw))
+               hw->phy.ops.reset_phy(hw);
+
+       if (hw->flash_address)
+               iounmap(hw->flash_address);
+
+       igb_remove_device(hw);
+       kfree(adapter->tx_ring);
+       kfree(adapter->rx_ring);
+err_sw_init:
+err_hw_init:
+       iounmap(hw->hw_addr);
+err_ioremap:
+       free_netdev(netdev);
+err_alloc_etherdev:
+       pci_release_regions(pdev);
+err_pci_reg:
+err_dma:
+       pci_disable_device(pdev);
+       return err;
+}
+
+/**
+ * igb_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * igb_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.  The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ **/
+static void __devexit igb_remove(struct pci_dev *pdev)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct igb_adapter *adapter = netdev_priv(netdev);
+
+       /* flush_scheduled work may reschedule our watchdog task, so
+        * explicitly disable watchdog tasks from being rescheduled  */
+       set_bit(__IGB_DOWN, &adapter->state);
+       del_timer_sync(&adapter->watchdog_timer);
+       del_timer_sync(&adapter->phy_info_timer);
+
+       flush_scheduled_work();
+
+
+       igb_release_manageability(adapter);
+
+       /* Release control of h/w to f/w.  If f/w is AMT enabled, this
+        * would have already happened in close and is redundant. */
+       igb_release_hw_control(adapter);
+
+       unregister_netdev(netdev);
+
+       if (!igb_check_reset_block(&adapter->hw))
+               adapter->hw.phy.ops.reset_phy(&adapter->hw);
+
+       igb_remove_device(&adapter->hw);
+       igb_reset_interrupt_capability(adapter);
+
+       kfree(adapter->tx_ring);
+       kfree(adapter->rx_ring);
+
+       iounmap(adapter->hw.hw_addr);
+       if (adapter->hw.flash_address)
+               iounmap(adapter->hw.flash_address);
+       pci_release_regions(pdev);
+
+       free_netdev(netdev);
+
+       pci_disable_device(pdev);
+}
+
+/**
+ * igb_sw_init - Initialize general software structures (struct igb_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * igb_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ **/
+static int __devinit igb_sw_init(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       struct net_device *netdev = adapter->netdev;
+       struct pci_dev *pdev = adapter->pdev;
+
+       pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
+
+       adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
+       adapter->rx_ps_hdr_size = 0; /* disable packet split */
+       adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+       adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
+
+       /* Number of supported queues. */
+       /* Having more queues than CPUs doesn't make sense. */
+       adapter->num_tx_queues = 1;
+       adapter->num_rx_queues = min(IGB_MAX_RX_QUEUES, num_online_cpus());
+
+       igb_set_interrupt_capability(adapter);
+
+       if (igb_alloc_queues(adapter)) {
+               dev_err(&pdev->dev, "Unable to allocate memory for queues\n");
+               return -ENOMEM;
+       }
+
+       /* Explicitly disable IRQ since the NIC can be in any state. */
+       igb_irq_disable(adapter);
+
+       set_bit(__IGB_DOWN, &adapter->state);
+       return 0;
+}
+
+/**
+ * igb_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP).  At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ **/
+static int igb_open(struct net_device *netdev)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       int err;
+       int i;
+
+       /* disallow open during test */
+       if (test_bit(__IGB_TESTING, &adapter->state))
+               return -EBUSY;
+
+       /* allocate transmit descriptors */
+       err = igb_setup_all_tx_resources(adapter);
+       if (err)
+               goto err_setup_tx;
+
+       /* allocate receive descriptors */
+       err = igb_setup_all_rx_resources(adapter);
+       if (err)
+               goto err_setup_rx;
+
+       /* e1000_power_up_phy(adapter); */
+
+       adapter->mng_vlan_id = IGB_MNG_VLAN_NONE;
+       if ((adapter->hw.mng_cookie.status &
+            E1000_MNG_DHCP_COOKIE_STATUS_VLAN))
+               igb_update_mng_vlan(adapter);
+
+       /* before we allocate an interrupt, we must be ready to handle it.
+        * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt
+        * as soon as we call pci_request_irq, so we have to setup our
+        * clean_rx handler before we do so.  */
+       igb_configure(adapter);
+
+       err = igb_request_irq(adapter);
+       if (err)
+               goto err_req_irq;
+
+       /* From here on the code is the same as igb_up() */
+       clear_bit(__IGB_DOWN, &adapter->state);
+
+       napi_enable(&adapter->napi);
+       if (adapter->msix_entries)
+               for (i = 0; i < adapter->num_rx_queues; i++)
+                       napi_enable(&adapter->rx_ring[i].napi);
+
+       igb_irq_enable(adapter);
+
+       /* Clear any pending interrupts. */
+       rd32(E1000_ICR);
+       /* Fire a link status change interrupt to start the watchdog. */
+       wr32(E1000_ICS, E1000_ICS_LSC);
+
+       return 0;
+
+err_req_irq:
+       igb_release_hw_control(adapter);
+       /* e1000_power_down_phy(adapter); */
+       igb_free_all_rx_resources(adapter);
+err_setup_rx:
+       igb_free_all_tx_resources(adapter);
+err_setup_tx:
+       igb_reset(adapter);
+
+       return err;
+}
+
+/**
+ * igb_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS.  The hardware is still under the driver's control, but
+ * needs to be disabled.  A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ **/
+static int igb_close(struct net_device *netdev)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+
+       WARN_ON(test_bit(__IGB_RESETTING, &adapter->state));
+       igb_down(adapter);
+
+       igb_free_irq(adapter);
+
+       igb_free_all_tx_resources(adapter);
+       igb_free_all_rx_resources(adapter);
+
+       /* kill manageability vlan ID if supported, but not if a vlan with
+        * the same ID is registered on the host OS (let 8021q kill it) */
+       if ((adapter->hw.mng_cookie.status &
+                         E1000_MNG_DHCP_COOKIE_STATUS_VLAN) &&
+            !(adapter->vlgrp &&
+              vlan_group_get_device(adapter->vlgrp, adapter->mng_vlan_id)))
+               igb_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
+
+       return 0;
+}
+
+/**
+ * igb_setup_tx_resources - allocate Tx resources (Descriptors)
+ * @adapter: board private structure
+ * @tx_ring: tx descriptor ring (for a specific queue) to setup
+ *
+ * Return 0 on success, negative on failure
+ **/
+
+int igb_setup_tx_resources(struct igb_adapter *adapter,
+                          struct igb_ring *tx_ring)
+{
+       struct pci_dev *pdev = adapter->pdev;
+       int size;
+
+       size = sizeof(struct igb_buffer) * tx_ring->count;
+       tx_ring->buffer_info = vmalloc(size);
+       if (!tx_ring->buffer_info)
+               goto err;
+       memset(tx_ring->buffer_info, 0, size);
+
+       /* round up to nearest 4K */
+       tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc)
+                       + sizeof(u32);
+       tx_ring->size = ALIGN(tx_ring->size, 4096);
+
+       tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size,
+                                            &tx_ring->dma);
+
+       if (!tx_ring->desc)
+               goto err;
+
+       tx_ring->adapter = adapter;
+       tx_ring->next_to_use = 0;
+       tx_ring->next_to_clean = 0;
+       spin_lock_init(&tx_ring->tx_clean_lock);
+       spin_lock_init(&tx_ring->tx_lock);
+       return 0;
+
+err:
+       vfree(tx_ring->buffer_info);
+       dev_err(&adapter->pdev->dev,
+               "Unable to allocate memory for the transmit descriptor ring\n");
+       return -ENOMEM;
+}
+
+/**
+ * igb_setup_all_tx_resources - wrapper to allocate Tx resources
+ *                               (Descriptors) for all queues
+ * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
+ **/
+static int igb_setup_all_tx_resources(struct igb_adapter *adapter)
+{
+       int i, err = 0;
+
+       for (i = 0; i < adapter->num_tx_queues; i++) {
+               err = igb_setup_tx_resources(adapter, &adapter->tx_ring[i]);
+               if (err) {
+                       dev_err(&adapter->pdev->dev,
+                               "Allocation for Tx Queue %u failed\n", i);
+                       for (i--; i >= 0; i--)
+                               igb_free_tx_resources(adapter,
+                                                       &adapter->tx_ring[i]);
+                       break;
+               }
+       }
+
+       return err;
+}
+
+/**
+ * igb_configure_tx - Configure transmit Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx unit of the MAC after a reset.
+ **/
+static void igb_configure_tx(struct igb_adapter *adapter)
+{
+       u64 tdba, tdwba;
+       struct e1000_hw *hw = &adapter->hw;
+       u32 tctl;
+       u32 txdctl, txctrl;
+       int i;
+
+       for (i = 0; i < adapter->num_tx_queues; i++) {
+               struct igb_ring *ring = &(adapter->tx_ring[i]);
+
+               wr32(E1000_TDLEN(i),
+                               ring->count * sizeof(struct e1000_tx_desc));
+               tdba = ring->dma;
+               wr32(E1000_TDBAL(i),
+                               tdba & 0x00000000ffffffffULL);
+               wr32(E1000_TDBAH(i), tdba >> 32);
+
+               tdwba = ring->dma + ring->count * sizeof(struct e1000_tx_desc);
+               tdwba |= 1; /* enable head wb */
+               wr32(E1000_TDWBAL(i),
+                               tdwba & 0x00000000ffffffffULL);
+               wr32(E1000_TDWBAH(i), tdwba >> 32);
+
+               ring->head = E1000_TDH(i);
+               ring->tail = E1000_TDT(i);
+               writel(0, hw->hw_addr + ring->tail);
+               writel(0, hw->hw_addr + ring->head);
+               txdctl = rd32(E1000_TXDCTL(i));
+               txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+               wr32(E1000_TXDCTL(i), txdctl);
+
+               /* Turn off Relaxed Ordering on head write-backs.  The
+                * writebacks MUST be delivered in order or it will
+                * completely screw up our bookeeping.
+                */
+               txctrl = rd32(E1000_DCA_TXCTRL(i));
+               txctrl &= ~E1000_DCA_TXCTRL_TX_WB_RO_EN;
+               wr32(E1000_DCA_TXCTRL(i), txctrl);
+       }
+
+
+
+       /* Use the default values for the Tx Inter Packet Gap (IPG) timer */
+
+       /* Program the Transmit Control Register */
+
+       tctl = rd32(E1000_TCTL);
+       tctl &= ~E1000_TCTL_CT;
+       tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC |
+               (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
+
+       igb_config_collision_dist(hw);
+
+       /* Setup Transmit Descriptor Settings for eop descriptor */
+       adapter->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_RS;
+
+       /* Enable transmits */
+       tctl |= E1000_TCTL_EN;
+
+       wr32(E1000_TCTL, tctl);
+}
+
+/**
+ * igb_setup_rx_resources - allocate Rx resources (Descriptors)
+ * @adapter: board private structure
+ * @rx_ring:    rx descriptor ring (for a specific queue) to setup
+ *
+ * Returns 0 on success, negative on failure
+ **/
+
+int igb_setup_rx_resources(struct igb_adapter *adapter,
+                          struct igb_ring *rx_ring)
+{
+       struct pci_dev *pdev = adapter->pdev;
+       int size, desc_len;
+
+       size = sizeof(struct igb_buffer) * rx_ring->count;
+       rx_ring->buffer_info = vmalloc(size);
+       if (!rx_ring->buffer_info)
+               goto err;
+       memset(rx_ring->buffer_info, 0, size);
+
+       desc_len = sizeof(union e1000_adv_rx_desc);
+
+       /* Round up to nearest 4K */
+       rx_ring->size = rx_ring->count * desc_len;
+       rx_ring->size = ALIGN(rx_ring->size, 4096);
+
+       rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size,
+                                            &rx_ring->dma);
+
+       if (!rx_ring->desc)
+               goto err;
+
+       rx_ring->next_to_clean = 0;
+       rx_ring->next_to_use = 0;
+       rx_ring->pending_skb = NULL;
+
+       rx_ring->adapter = adapter;
+       /* FIXME: do we want to setup ring->napi->poll here? */
+       rx_ring->napi.poll = adapter->napi.poll;
+
+       return 0;
+
+err:
+       vfree(rx_ring->buffer_info);
+       dev_err(&adapter->pdev->dev, "Unable to allocate memory for "
+               "the receive descriptor ring\n");
+       return -ENOMEM;
+}
+
+/**
+ * igb_setup_all_rx_resources - wrapper to allocate Rx resources
+ *                               (Descriptors) for all queues
+ * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
+ **/
+static int igb_setup_all_rx_resources(struct igb_adapter *adapter)
+{
+       int i, err = 0;
+
+       for (i = 0; i < adapter->num_rx_queues; i++) {
+               err = igb_setup_rx_resources(adapter, &adapter->rx_ring[i]);
+               if (err) {
+                       dev_err(&adapter->pdev->dev,
+                               "Allocation for Rx Queue %u failed\n", i);
+                       for (i--; i >= 0; i--)
+                               igb_free_rx_resources(adapter,
+                                                       &adapter->rx_ring[i]);
+                       break;
+               }
+       }
+
+       return err;
+}
+
+/**
+ * igb_setup_rctl - configure the receive control registers
+ * @adapter: Board private structure
+ **/
+static void igb_setup_rctl(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 rctl;
+       u32 srrctl = 0;
+       int i;
+
+       rctl = rd32(E1000_RCTL);
+
+       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);
+
+       /* disable the stripping of CRC because it breaks
+        * BMC firmware connected over SMBUS
+       rctl |= E1000_RCTL_SECRC;
+       */
+
+       rctl &= ~E1000_RCTL_SBP;
+
+       if (adapter->netdev->mtu <= ETH_DATA_LEN)
+               rctl &= ~E1000_RCTL_LPE;
+       else
+               rctl |= E1000_RCTL_LPE;
+       if (adapter->rx_buffer_len <= IGB_RXBUFFER_2048) {
+               /* Setup buffer sizes */
+               rctl &= ~E1000_RCTL_SZ_4096;
+               rctl |= E1000_RCTL_BSEX;
+               switch (adapter->rx_buffer_len) {
+               case IGB_RXBUFFER_256:
+                       rctl |= E1000_RCTL_SZ_256;
+                       rctl &= ~E1000_RCTL_BSEX;
+                       break;
+               case IGB_RXBUFFER_512:
+                       rctl |= E1000_RCTL_SZ_512;
+                       rctl &= ~E1000_RCTL_BSEX;
+                       break;
+               case IGB_RXBUFFER_1024:
+                       rctl |= E1000_RCTL_SZ_1024;
+                       rctl &= ~E1000_RCTL_BSEX;
+                       break;
+               case IGB_RXBUFFER_2048:
+               default:
+                       rctl |= E1000_RCTL_SZ_2048;
+                       rctl &= ~E1000_RCTL_BSEX;
+                       break;
+               case IGB_RXBUFFER_4096:
+                       rctl |= E1000_RCTL_SZ_4096;
+                       break;
+               case IGB_RXBUFFER_8192:
+                       rctl |= E1000_RCTL_SZ_8192;
+                       break;
+               case IGB_RXBUFFER_16384:
+                       rctl |= E1000_RCTL_SZ_16384;
+                       break;
+               }
+       } else {
+               rctl &= ~E1000_RCTL_BSEX;
+               srrctl = adapter->rx_buffer_len >> E1000_SRRCTL_BSIZEPKT_SHIFT;
+       }
+
+       /* 82575 and greater support packet-split where the protocol
+        * header is placed in skb->data and the packet data is
+        * placed in pages hanging off of skb_shinfo(skb)->nr_frags.
+        * In the case of a non-split, skb->data is linearly filled,
+        * followed by the page buffers.  Therefore, skb->data is
+        * sized to hold the largest protocol header.
+        */
+       /* allocations using alloc_page take too long for regular MTU
+        * so only enable packet split for jumbo frames */
+       if (rctl & E1000_RCTL_LPE) {
+               adapter->rx_ps_hdr_size = IGB_RXBUFFER_128;
+               srrctl = adapter->rx_ps_hdr_size <<
+                        E1000_SRRCTL_BSIZEHDRSIZE_SHIFT;
+               /* buffer size is ALWAYS one page */
+               srrctl |= PAGE_SIZE >> E1000_SRRCTL_BSIZEPKT_SHIFT;
+               srrctl |= E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS;
+       } else {
+               adapter->rx_ps_hdr_size = 0;
+               srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF;
+       }
+
+       for (i = 0; i < adapter->num_rx_queues; i++)
+               wr32(E1000_SRRCTL(i), srrctl);
+
+       wr32(E1000_RCTL, rctl);
+}
+
+/**
+ * igb_configure_rx - Configure receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ **/
+static void igb_configure_rx(struct igb_adapter *adapter)
+{
+       u64 rdba;
+       struct e1000_hw *hw = &adapter->hw;
+       u32 rctl, rxcsum;
+       u32 rxdctl;
+       int i;
+
+       /* disable receives while setting up the descriptors */
+       rctl = rd32(E1000_RCTL);
+       wr32(E1000_RCTL, rctl & ~E1000_RCTL_EN);
+       wrfl();
+       mdelay(10);
+
+       if (adapter->itr_setting > 3)
+               wr32(E1000_ITR,
+                               1000000000 / (adapter->itr * 256));
+
+       /* Setup the HW Rx Head and Tail Descriptor Pointers and
+        * the Base and Length of the Rx Descriptor Ring */
+       for (i = 0; i < adapter->num_rx_queues; i++) {
+               struct igb_ring *ring = &(adapter->rx_ring[i]);
+               rdba = ring->dma;
+               wr32(E1000_RDBAL(i),
+                               rdba & 0x00000000ffffffffULL);
+               wr32(E1000_RDBAH(i), rdba >> 32);
+               wr32(E1000_RDLEN(i),
+                              ring->count * sizeof(union e1000_adv_rx_desc));
+
+               ring->head = E1000_RDH(i);
+               ring->tail = E1000_RDT(i);
+               writel(0, hw->hw_addr + ring->tail);
+               writel(0, hw->hw_addr + ring->head);
+
+               rxdctl = rd32(E1000_RXDCTL(i));
+               rxdctl |= E1000_RXDCTL_QUEUE_ENABLE;
+               rxdctl &= 0xFFF00000;
+               rxdctl |= IGB_RX_PTHRESH;
+               rxdctl |= IGB_RX_HTHRESH << 8;
+               rxdctl |= IGB_RX_WTHRESH << 16;
+               wr32(E1000_RXDCTL(i), rxdctl);
+       }
+
+       if (adapter->num_rx_queues > 1) {
+               u32 random[10];
+               u32 mrqc;
+               u32 j, shift;
+               union e1000_reta {
+                       u32 dword;
+                       u8  bytes[4];
+               } reta;
+
+               get_random_bytes(&random[0], 40);
+
+               shift = 6;
+               for (j = 0; j < (32 * 4); j++) {
+                       reta.bytes[j & 3] =
+                               (j % adapter->num_rx_queues) << shift;
+                       if ((j & 3) == 3)
+                               writel(reta.dword,
+                                      hw->hw_addr + E1000_RETA(0) + (j & ~3));
+               }
+               mrqc = E1000_MRQC_ENABLE_RSS_4Q;
+
+               /* Fill out hash function seeds */
+               for (j = 0; j < 10; j++)
+                       array_wr32(E1000_RSSRK(0), j, random[j]);
+
+               mrqc |= (E1000_MRQC_RSS_FIELD_IPV4 |
+                        E1000_MRQC_RSS_FIELD_IPV4_TCP);
+               mrqc |= (E1000_MRQC_RSS_FIELD_IPV6 |
+                        E1000_MRQC_RSS_FIELD_IPV6_TCP);
+               mrqc |= (E1000_MRQC_RSS_FIELD_IPV4_UDP |
+                        E1000_MRQC_RSS_FIELD_IPV6_UDP);
+               mrqc |= (E1000_MRQC_RSS_FIELD_IPV6_UDP_EX |
+                        E1000_MRQC_RSS_FIELD_IPV6_TCP_EX);
+
+
+               wr32(E1000_MRQC, mrqc);
+
+               /* Multiqueue and raw packet checksumming are mutually
+                * exclusive.  Note that this not the same as TCP/IP
+                * checksumming, which works fine. */
+               rxcsum = rd32(E1000_RXCSUM);
+               rxcsum |= E1000_RXCSUM_PCSD;
+               wr32(E1000_RXCSUM, rxcsum);
+       } else {
+               /* Enable Receive Checksum Offload for TCP and UDP */
+               rxcsum = rd32(E1000_RXCSUM);
+               if (adapter->rx_csum) {
+                       rxcsum |= E1000_RXCSUM_TUOFL;
+
+                       /* Enable IPv4 payload checksum for UDP fragments
+                        * Must be used in conjunction with packet-split. */
+                       if (adapter->rx_ps_hdr_size)
+                               rxcsum |= E1000_RXCSUM_IPPCSE;
+               } else {
+                       rxcsum &= ~E1000_RXCSUM_TUOFL;
+                       /* don't need to clear IPPCSE as it defaults to 0 */
+               }
+               wr32(E1000_RXCSUM, rxcsum);
+       }
+
+       if (adapter->vlgrp)
+               wr32(E1000_RLPML,
+                               adapter->max_frame_size + VLAN_TAG_SIZE);
+       else
+               wr32(E1000_RLPML, adapter->max_frame_size);
+
+       /* Enable Receives */
+       wr32(E1000_RCTL, rctl);
+}
+
+/**
+ * igb_free_tx_resources - Free Tx Resources per Queue
+ * @adapter: board private structure
+ * @tx_ring: Tx descriptor ring for a specific queue
+ *
+ * Free all transmit software resources
+ **/
+static void igb_free_tx_resources(struct igb_adapter *adapter,
+                                 struct igb_ring *tx_ring)
+{
+       struct pci_dev *pdev = adapter->pdev;
+
+       igb_clean_tx_ring(adapter, tx_ring);
+
+       vfree(tx_ring->buffer_info);
+       tx_ring->buffer_info = NULL;
+
+       pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, tx_ring->dma);
+
+       tx_ring->desc = NULL;
+}
+
+/**
+ * igb_free_all_tx_resources - Free Tx Resources for All Queues
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ **/
+static void igb_free_all_tx_resources(struct igb_adapter *adapter)
+{
+       int i;
+
+       for (i = 0; i < adapter->num_tx_queues; i++)
+               igb_free_tx_resources(adapter, &adapter->tx_ring[i]);
+}
+
+static void igb_unmap_and_free_tx_resource(struct igb_adapter *adapter,
+                                          struct igb_buffer *buffer_info)
+{
+       if (buffer_info->dma) {
+               pci_unmap_page(adapter->pdev,
+                               buffer_info->dma,
+                               buffer_info->length,
+                               PCI_DMA_TODEVICE);
+               buffer_info->dma = 0;
+       }
+       if (buffer_info->skb) {
+               dev_kfree_skb_any(buffer_info->skb);
+               buffer_info->skb = NULL;
+       }
+       buffer_info->time_stamp = 0;
+       /* buffer_info must be completely set up in the transmit path */
+}
+
+/**
+ * igb_clean_tx_ring - Free Tx Buffers
+ * @adapter: board private structure
+ * @tx_ring: ring to be cleaned
+ **/
+static void igb_clean_tx_ring(struct igb_adapter *adapter,
+                             struct igb_ring *tx_ring)
+{
+       struct igb_buffer *buffer_info;
+       unsigned long size;
+       unsigned int i;
+
+       if (!tx_ring->buffer_info)
+               return;
+       /* Free all the Tx ring sk_buffs */
+
+       for (i = 0; i < tx_ring->count; i++) {
+               buffer_info = &tx_ring->buffer_info[i];
+               igb_unmap_and_free_tx_resource(adapter, buffer_info);
+       }
+
+       size = sizeof(struct igb_buffer) * tx_ring->count;
+       memset(tx_ring->buffer_info, 0, size);
+
+       /* Zero out the descriptor ring */
+
+       memset(tx_ring->desc, 0, tx_ring->size);
+
+       tx_ring->next_to_use = 0;
+       tx_ring->next_to_clean = 0;
+
+       writel(0, adapter->hw.hw_addr + tx_ring->head);
+       writel(0, adapter->hw.hw_addr + tx_ring->tail);
+}
+
+/**
+ * igb_clean_all_tx_rings - Free Tx Buffers for all queues
+ * @adapter: board private structure
+ **/
+static void igb_clean_all_tx_rings(struct igb_adapter *adapter)
+{
+       int i;
+
+       for (i = 0; i < adapter->num_tx_queues; i++)
+               igb_clean_tx_ring(adapter, &adapter->tx_ring[i]);
+}
+
+/**
+ * igb_free_rx_resources - Free Rx Resources
+ * @adapter: board private structure
+ * @rx_ring: ring to clean the resources from
+ *
+ * Free all receive software resources
+ **/
+static void igb_free_rx_resources(struct igb_adapter *adapter,
+                                 struct igb_ring *rx_ring)
+{
+       struct pci_dev *pdev = adapter->pdev;
+
+       igb_clean_rx_ring(adapter, rx_ring);
+
+       vfree(rx_ring->buffer_info);
+       rx_ring->buffer_info = NULL;
+
+       pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma);
+
+       rx_ring->desc = NULL;
+}
+
+/**
+ * igb_free_all_rx_resources - Free Rx Resources for All Queues
+ * @adapter: board private structure
+ *
+ * Free all receive software resources
+ **/
+static void igb_free_all_rx_resources(struct igb_adapter *adapter)
+{
+       int i;
+
+       for (i = 0; i < adapter->num_rx_queues; i++)
+               igb_free_rx_resources(adapter, &adapter->rx_ring[i]);
+}
+
+/**
+ * igb_clean_rx_ring - Free Rx Buffers per Queue
+ * @adapter: board private structure
+ * @rx_ring: ring to free buffers from
+ **/
+static void igb_clean_rx_ring(struct igb_adapter *adapter,
+                             struct igb_ring *rx_ring)
+{
+       struct igb_buffer *buffer_info;
+       struct pci_dev *pdev = adapter->pdev;
+       unsigned long size;
+       unsigned int i;
+
+       if (!rx_ring->buffer_info)
+               return;
+       /* Free all the Rx ring sk_buffs */
+       for (i = 0; i < rx_ring->count; i++) {
+               buffer_info = &rx_ring->buffer_info[i];
+               if (buffer_info->dma) {
+                       if (adapter->rx_ps_hdr_size)
+                               pci_unmap_single(pdev, buffer_info->dma,
+                                                adapter->rx_ps_hdr_size,
+                                                PCI_DMA_FROMDEVICE);
+                       else
+                               pci_unmap_single(pdev, buffer_info->dma,
+                                                adapter->rx_buffer_len,
+                                                PCI_DMA_FROMDEVICE);
+                       buffer_info->dma = 0;
+               }
+
+               if (buffer_info->skb) {
+                       dev_kfree_skb(buffer_info->skb);
+                       buffer_info->skb = NULL;
+               }
+               if (buffer_info->page) {
+                       pci_unmap_page(pdev, buffer_info->page_dma,
+                                      PAGE_SIZE, PCI_DMA_FROMDEVICE);
+                       put_page(buffer_info->page);
+                       buffer_info->page = NULL;
+                       buffer_info->page_dma = 0;
+               }
+       }
+
+       /* there also may be some cached data from a chained receive */
+       if (rx_ring->pending_skb) {
+               dev_kfree_skb(rx_ring->pending_skb);
+               rx_ring->pending_skb = NULL;
+       }
+
+       size = sizeof(struct igb_buffer) * rx_ring->count;
+       memset(rx_ring->buffer_info, 0, size);
+
+       /* Zero out the descriptor ring */
+       memset(rx_ring->desc, 0, rx_ring->size);
+
+       rx_ring->next_to_clean = 0;
+       rx_ring->next_to_use = 0;
+
+       writel(0, adapter->hw.hw_addr + rx_ring->head);
+       writel(0, adapter->hw.hw_addr + rx_ring->tail);
+}
+
+/**
+ * igb_clean_all_rx_rings - Free Rx Buffers for all queues
+ * @adapter: board private structure
+ **/
+static void igb_clean_all_rx_rings(struct igb_adapter *adapter)
+{
+       int i;
+
+       for (i = 0; i < adapter->num_rx_queues; i++)
+               igb_clean_rx_ring(adapter, &adapter->rx_ring[i]);
+}
+
+/**
+ * igb_set_mac - Change the Ethernet Address of the NIC
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int igb_set_mac(struct net_device *netdev, void *p)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct sockaddr *addr = p;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+       memcpy(adapter->hw.mac.addr, addr->sa_data, netdev->addr_len);
+
+       adapter->hw.mac.ops.rar_set(&adapter->hw, adapter->hw.mac.addr, 0);
+
+       return 0;
+}
+
+/**
+ * igb_set_multi - Multicast and Promiscuous mode set
+ * @netdev: network interface device structure
+ *
+ * The set_multi entry point is called whenever the multicast address
+ * list or the network interface flags are updated.  This routine is
+ * responsible for configuring the hardware for proper multicast,
+ * promiscuous mode, and all-multi behavior.
+ **/
+static void igb_set_multi(struct net_device *netdev)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       struct e1000_mac_info *mac = &hw->mac;
+       struct dev_mc_list *mc_ptr;
+       u8  *mta_list;
+       u32 rctl;
+       int i;
+
+       /* Check for Promiscuous and All Multicast modes */
+
+       rctl = rd32(E1000_RCTL);
+
+       if (netdev->flags & IFF_PROMISC)
+               rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
+       else if (netdev->flags & IFF_ALLMULTI) {
+               rctl |= E1000_RCTL_MPE;
+               rctl &= ~E1000_RCTL_UPE;
+       } else
+               rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE);
+
+       wr32(E1000_RCTL, rctl);
+
+       if (!netdev->mc_count) {
+               /* nothing to program, so clear mc list */
+               igb_update_mc_addr_list(hw, NULL, 0, 1,
+                                         mac->rar_entry_count);
+               return;
+       }
+
+       mta_list = kzalloc(netdev->mc_count * 6, GFP_ATOMIC);
+       if (!mta_list)
+               return;
+
+       /* The shared function expects a packed array of only addresses. */
+       mc_ptr = netdev->mc_list;
+
+       for (i = 0; i < netdev->mc_count; i++) {
+               if (!mc_ptr)
+                       break;
+               memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr, ETH_ALEN);
+               mc_ptr = mc_ptr->next;
+       }
+       igb_update_mc_addr_list(hw, mta_list, i, 1, mac->rar_entry_count);
+       kfree(mta_list);
+}
+
+/* Need to wait a few seconds after link up to get diagnostic information from
+ * the phy */
+static void igb_update_phy_info(unsigned long data)
+{
+       struct igb_adapter *adapter = (struct igb_adapter *) data;
+       adapter->hw.phy.ops.get_phy_info(&adapter->hw);
+}
+
+/**
+ * igb_watchdog - Timer Call-back
+ * @data: pointer to adapter cast into an unsigned long
+ **/
+static void igb_watchdog(unsigned long data)
+{
+       struct igb_adapter *adapter = (struct igb_adapter *)data;
+       /* Do the rest outside of interrupt context */
+       schedule_work(&adapter->watchdog_task);
+}
+
+static void igb_watchdog_task(struct work_struct *work)
+{
+       struct igb_adapter *adapter = container_of(work,
+                                       struct igb_adapter, watchdog_task);
+       struct e1000_hw *hw = &adapter->hw;
+
+       struct net_device *netdev = adapter->netdev;
+       struct igb_ring *tx_ring = adapter->tx_ring;
+       struct e1000_mac_info *mac = &adapter->hw.mac;
+       u32 link;
+       s32 ret_val;
+
+       if ((netif_carrier_ok(netdev)) &&
+           (rd32(E1000_STATUS) & E1000_STATUS_LU))
+               goto link_up;
+
+       ret_val = hw->mac.ops.check_for_link(&adapter->hw);
+       if ((ret_val == E1000_ERR_PHY) &&
+           (hw->phy.type == e1000_phy_igp_3) &&
+           (rd32(E1000_CTRL) &
+            E1000_PHY_CTRL_GBE_DISABLE))
+               dev_info(&adapter->pdev->dev,
+                        "Gigabit has been disabled, downgrading speed\n");
+
+       if ((hw->phy.media_type == e1000_media_type_internal_serdes) &&
+           !(rd32(E1000_TXCW) & E1000_TXCW_ANE))
+               link = mac->serdes_has_link;
+       else
+               link = rd32(E1000_STATUS) &
+                                     E1000_STATUS_LU;
+
+       if (link) {
+               if (!netif_carrier_ok(netdev)) {
+                       u32 ctrl;
+                       hw->mac.ops.get_speed_and_duplex(&adapter->hw,
+                                                  &adapter->link_speed,
+                                                  &adapter->link_duplex);
+
+                       ctrl = rd32(E1000_CTRL);
+                       dev_info(&adapter->pdev->dev,
+                                "NIC Link is Up %d Mbps %s, "
+                                "Flow Control: %s\n",
+                                adapter->link_speed,
+                                adapter->link_duplex == FULL_DUPLEX ?
+                                "Full Duplex" : "Half Duplex",
+                                ((ctrl & E1000_CTRL_TFCE) && (ctrl &
+                                E1000_CTRL_RFCE)) ? "RX/TX" : ((ctrl &
+                                E1000_CTRL_RFCE) ? "RX" : ((ctrl &
+                                E1000_CTRL_TFCE) ? "TX" : "None")));
+
+                       /* tweak tx_queue_len according to speed/duplex and
+                        * adjust the timeout factor */
+                       netdev->tx_queue_len = adapter->tx_queue_len;
+                       adapter->tx_timeout_factor = 1;
+                       switch (adapter->link_speed) {
+                       case SPEED_10:
+                               netdev->tx_queue_len = 10;
+                               adapter->tx_timeout_factor = 14;
+                               break;
+                       case SPEED_100:
+                               netdev->tx_queue_len = 100;
+                               /* maybe add some timeout factor ? */
+                               break;
+                       }
+
+                       netif_carrier_on(netdev);
+                       netif_wake_queue(netdev);
+
+                       if (!test_bit(__IGB_DOWN, &adapter->state))
+                               mod_timer(&adapter->phy_info_timer,
+                                         round_jiffies(jiffies + 2 * HZ));
+               }
+       } else {
+               if (netif_carrier_ok(netdev)) {
+                       adapter->link_speed = 0;
+                       adapter->link_duplex = 0;
+                       dev_info(&adapter->pdev->dev, "NIC Link is Down\n");
+                       netif_carrier_off(netdev);
+                       netif_stop_queue(netdev);
+                       if (!test_bit(__IGB_DOWN, &adapter->state))
+                               mod_timer(&adapter->phy_info_timer,
+                                         round_jiffies(jiffies + 2 * HZ));
+               }
+       }
+
+link_up:
+       igb_update_stats(adapter);
+
+       mac->tx_packet_delta = adapter->stats.tpt - adapter->tpt_old;
+       adapter->tpt_old = adapter->stats.tpt;
+       mac->collision_delta = adapter->stats.colc - adapter->colc_old;
+       adapter->colc_old = adapter->stats.colc;
+
+       adapter->gorc = adapter->stats.gorc - adapter->gorc_old;
+       adapter->gorc_old = adapter->stats.gorc;
+       adapter->gotc = adapter->stats.gotc - adapter->gotc_old;
+       adapter->gotc_old = adapter->stats.gotc;
+
+       igb_update_adaptive(&adapter->hw);
+
+       if (!netif_carrier_ok(netdev)) {
+               if (IGB_DESC_UNUSED(tx_ring) + 1 < tx_ring->count) {
+                       /* We've lost link, so the controller stops DMA,
+                        * but we've got queued Tx work that's never going
+                        * to get done, so reset controller to flush Tx.
+                        * (Do the reset outside of interrupt context). */
+                       adapter->tx_timeout_count++;
+                       schedule_work(&adapter->reset_task);
+               }
+       }
+
+       /* Cause software interrupt to ensure rx ring is cleaned */
+       wr32(E1000_ICS, E1000_ICS_RXDMT0);
+
+       /* Force detection of hung controller every watchdog period */
+       tx_ring->detect_tx_hung = true;
+
+       /* Reset the timer */
+       if (!test_bit(__IGB_DOWN, &adapter->state))
+               mod_timer(&adapter->watchdog_timer,
+                         round_jiffies(jiffies + 2 * HZ));
+}
+
+enum latency_range {
+       lowest_latency = 0,
+       low_latency = 1,
+       bulk_latency = 2,
+       latency_invalid = 255
+};
+
+
+static void igb_lower_rx_eitr(struct igb_adapter *adapter,
+                             struct igb_ring *rx_ring)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       int new_val;
+
+       new_val = rx_ring->itr_val / 2;
+       if (new_val < IGB_MIN_DYN_ITR)
+               new_val = IGB_MIN_DYN_ITR;
+
+       if (new_val != rx_ring->itr_val) {
+               rx_ring->itr_val = new_val;
+               wr32(rx_ring->itr_register,
+                               1000000000 / (new_val * 256));
+       }
+}
+
+static void igb_raise_rx_eitr(struct igb_adapter *adapter,
+                             struct igb_ring *rx_ring)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       int new_val;
+
+       new_val = rx_ring->itr_val * 2;
+       if (new_val > IGB_MAX_DYN_ITR)
+               new_val = IGB_MAX_DYN_ITR;
+
+       if (new_val != rx_ring->itr_val) {
+               rx_ring->itr_val = new_val;
+               wr32(rx_ring->itr_register,
+                               1000000000 / (new_val * 256));
+       }
+}
+
+/**
+ * igb_update_itr - update the dynamic ITR value based on statistics
+ *      Stores a new ITR value based on packets and byte
+ *      counts during the last interrupt.  The advantage of per interrupt
+ *      computation is faster updates and more accurate ITR for the current
+ *      traffic pattern.  Constants in this function were computed
+ *      based on theoretical maximum wire speed and thresholds were set based
+ *      on testing data as well as attempting to minimize response time
+ *      while increasing bulk throughput.
+ *      this functionality is controlled by the InterruptThrottleRate module
+ *      parameter (see igb_param.c)
+ *      NOTE:  These calculations are only valid when operating in a single-
+ *             queue environment.
+ * @adapter: pointer to adapter
+ * @itr_setting: current adapter->itr
+ * @packets: the number of packets during this measurement interval
+ * @bytes: the number of bytes during this measurement interval
+ **/
+static unsigned int igb_update_itr(struct igb_adapter *adapter, u16 itr_setting,
+                                  int packets, int bytes)
+{
+       unsigned int retval = itr_setting;
+
+       if (packets == 0)
+               goto update_itr_done;
+
+       switch (itr_setting) {
+       case lowest_latency:
+               /* handle TSO and jumbo frames */
+               if (bytes/packets > 8000)
+                       retval = bulk_latency;
+               else if ((packets < 5) && (bytes > 512))
+                       retval = low_latency;
+               break;
+       case low_latency:  /* 50 usec aka 20000 ints/s */
+               if (bytes > 10000) {
+                       /* this if handles the TSO accounting */
+                       if (bytes/packets > 8000) {
+                               retval = bulk_latency;
+                       } else if ((packets < 10) || ((bytes/packets) > 1200)) {
+                               retval = bulk_latency;
+                       } else if ((packets > 35)) {
+                               retval = lowest_latency;
+                       }
+               } else if (bytes/packets > 2000) {
+                       retval = bulk_latency;
+               } else if (packets <= 2 && bytes < 512) {
+                       retval = lowest_latency;
+               }
+               break;
+       case bulk_latency: /* 250 usec aka 4000 ints/s */
+               if (bytes > 25000) {
+                       if (packets > 35)
+                               retval = low_latency;
+               } else if (bytes < 6000) {
+                       retval = low_latency;
+               }
+               break;
+       }
+
+update_itr_done:
+       return retval;
+}
+
+static void igb_set_itr(struct igb_adapter *adapter, u16 itr_register,
+                       int rx_only)
+{
+       u16 current_itr;
+       u32 new_itr = adapter->itr;
+
+       /* for non-gigabit speeds, just fix the interrupt rate at 4000 */
+       if (adapter->link_speed != SPEED_1000) {
+               current_itr = 0;
+               new_itr = 4000;
+               goto set_itr_now;
+       }
+
+       adapter->rx_itr = igb_update_itr(adapter,
+                                   adapter->rx_itr,
+                                   adapter->rx_ring->total_packets,
+                                   adapter->rx_ring->total_bytes);
+       /* conservative mode (itr 3) eliminates the lowest_latency setting */
+       if (adapter->itr_setting == 3 && adapter->rx_itr == lowest_latency)
+               adapter->rx_itr = low_latency;
+
+       if (!rx_only) {
+               adapter->tx_itr = igb_update_itr(adapter,
+                                           adapter->tx_itr,
+                                           adapter->tx_ring->total_packets,
+                                           adapter->tx_ring->total_bytes);
+               /* conservative mode (itr 3) eliminates the
+                * lowest_latency setting */
+               if (adapter->itr_setting == 3 &&
+                   adapter->tx_itr == lowest_latency)
+                       adapter->tx_itr = low_latency;
+
+               current_itr = max(adapter->rx_itr, adapter->tx_itr);
+       } else {
+               current_itr = adapter->rx_itr;
+       }
+
+       switch (current_itr) {
+       /* counts and packets in update_itr are dependent on these numbers */
+       case lowest_latency:
+               new_itr = 70000;
+               break;
+       case low_latency:
+               new_itr = 20000; /* aka hwitr = ~200 */
+               break;
+       case bulk_latency:
+               new_itr = 4000;
+               break;
+       default:
+               break;
+       }
+
+set_itr_now:
+       if (new_itr != adapter->itr) {
+               /* this attempts to bias the interrupt rate towards Bulk
+                * by adding intermediate steps when interrupt rate is
+                * increasing */
+               new_itr = new_itr > adapter->itr ?
+                            min(adapter->itr + (new_itr >> 2), new_itr) :
+                            new_itr;
+               /* Don't write the value here; it resets the adapter's
+                * internal timer, and causes us to delay far longer than
+                * we should between interrupts.  Instead, we write the ITR
+                * value at the beginning of the next interrupt so the timing
+                * ends up being correct.
+                */
+               adapter->itr = new_itr;
+               adapter->set_itr = 1;
+       }
+
+       return;
+}
+
+
+#define IGB_TX_FLAGS_CSUM              0x00000001
+#define IGB_TX_FLAGS_VLAN              0x00000002
+#define IGB_TX_FLAGS_TSO               0x00000004
+#define IGB_TX_FLAGS_IPV4              0x00000008
+#define IGB_TX_FLAGS_VLAN_MASK 0xffff0000
+#define IGB_TX_FLAGS_VLAN_SHIFT        16
+
+static inline int igb_tso_adv(struct igb_adapter *adapter,
+                             struct igb_ring *tx_ring,
+                             struct sk_buff *skb, u32 tx_flags, u8 *hdr_len)
+{
+       struct e1000_adv_tx_context_desc *context_desc;
+       unsigned int i;
+       int err;
+       struct igb_buffer *buffer_info;
+       u32 info = 0, tu_cmd = 0;
+       u32 mss_l4len_idx, l4len;
+       *hdr_len = 0;
+
+       if (skb_header_cloned(skb)) {
+               err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+               if (err)
+                       return err;
+       }
+
+       l4len = tcp_hdrlen(skb);
+       *hdr_len += l4len;
+
+       if (skb->protocol == htons(ETH_P_IP)) {
+               struct iphdr *iph = ip_hdr(skb);
+               iph->tot_len = 0;
+               iph->check = 0;
+               tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
+                                                        iph->daddr, 0,
+                                                        IPPROTO_TCP,
+                                                        0);
+       } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) {
+               ipv6_hdr(skb)->payload_len = 0;
+               tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+                                                      &ipv6_hdr(skb)->daddr,
+                                                      0, IPPROTO_TCP, 0);
+       }
+
+       i = tx_ring->next_to_use;
+
+       buffer_info = &tx_ring->buffer_info[i];
+       context_desc = E1000_TX_CTXTDESC_ADV(*tx_ring, i);
+       /* VLAN MACLEN IPLEN */
+       if (tx_flags & IGB_TX_FLAGS_VLAN)
+               info |= (tx_flags & IGB_TX_FLAGS_VLAN_MASK);
+       info |= (skb_network_offset(skb) << E1000_ADVTXD_MACLEN_SHIFT);
+       *hdr_len += skb_network_offset(skb);
+       info |= skb_network_header_len(skb);
+       *hdr_len += skb_network_header_len(skb);
+       context_desc->vlan_macip_lens = cpu_to_le32(info);
+
+       /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */
+       tu_cmd |= (E1000_TXD_CMD_DEXT | E1000_ADVTXD_DTYP_CTXT);
+
+       if (skb->protocol == htons(ETH_P_IP))
+               tu_cmd |= E1000_ADVTXD_TUCMD_IPV4;
+       tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
+
+       context_desc->type_tucmd_mlhl = cpu_to_le32(tu_cmd);
+
+       /* MSS L4LEN IDX */
+       mss_l4len_idx = (skb_shinfo(skb)->gso_size << E1000_ADVTXD_MSS_SHIFT);
+       mss_l4len_idx |= (l4len << E1000_ADVTXD_L4LEN_SHIFT);
+
+       /* Context index must be unique per ring.  Luckily, so is the interrupt
+        * mask value. */
+       mss_l4len_idx |= tx_ring->eims_value >> 4;
+
+       context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx);
+       context_desc->seqnum_seed = 0;
+
+       buffer_info->time_stamp = jiffies;
+       buffer_info->dma = 0;
+       i++;
+       if (i == tx_ring->count)
+               i = 0;
+
+       tx_ring->next_to_use = i;
+
+       return true;
+}
+
+static inline bool igb_tx_csum_adv(struct igb_adapter *adapter,
+                                       struct igb_ring *tx_ring,
+                                       struct sk_buff *skb, u32 tx_flags)
+{
+       struct e1000_adv_tx_context_desc *context_desc;
+       unsigned int i;
+       struct igb_buffer *buffer_info;
+       u32 info = 0, tu_cmd = 0;
+
+       if ((skb->ip_summed == CHECKSUM_PARTIAL) ||
+           (tx_flags & IGB_TX_FLAGS_VLAN)) {
+               i = tx_ring->next_to_use;
+               buffer_info = &tx_ring->buffer_info[i];
+               context_desc = E1000_TX_CTXTDESC_ADV(*tx_ring, i);
+
+               if (tx_flags & IGB_TX_FLAGS_VLAN)
+                       info |= (tx_flags & IGB_TX_FLAGS_VLAN_MASK);
+               info |= (skb_network_offset(skb) << E1000_ADVTXD_MACLEN_SHIFT);
+               if (skb->ip_summed == CHECKSUM_PARTIAL)
+                       info |= skb_network_header_len(skb);
+
+               context_desc->vlan_macip_lens = cpu_to_le32(info);
+
+               tu_cmd |= (E1000_TXD_CMD_DEXT | E1000_ADVTXD_DTYP_CTXT);
+
+               if (skb->ip_summed == CHECKSUM_PARTIAL) {
+                       if (skb->protocol == htons(ETH_P_IP))
+                               tu_cmd |= E1000_ADVTXD_TUCMD_IPV4;
+                       if (skb->sk && (skb->sk->sk_protocol == IPPROTO_TCP))
+                               tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
+               }
+
+               context_desc->type_tucmd_mlhl = cpu_to_le32(tu_cmd);
+               context_desc->seqnum_seed = 0;
+               context_desc->mss_l4len_idx =
+                                         cpu_to_le32(tx_ring->eims_value >> 4);
+
+               buffer_info->time_stamp = jiffies;
+               buffer_info->dma = 0;
+
+               i++;
+               if (i == tx_ring->count)
+                       i = 0;
+               tx_ring->next_to_use = i;
+
+               return true;
+       }
+
+
+       return false;
+}
+
+#define IGB_MAX_TXD_PWR        16
+#define IGB_MAX_DATA_PER_TXD   (1<<IGB_MAX_TXD_PWR)
+
+static inline int igb_tx_map_adv(struct igb_adapter *adapter,
+                                struct igb_ring *tx_ring,
+                                struct sk_buff *skb)
+{
+       struct igb_buffer *buffer_info;
+       unsigned int len = skb_headlen(skb);
+       unsigned int count = 0, i;
+       unsigned int f;
+
+       i = tx_ring->next_to_use;
+
+       buffer_info = &tx_ring->buffer_info[i];
+       BUG_ON(len >= IGB_MAX_DATA_PER_TXD);
+       buffer_info->length = len;
+       /* set time_stamp *before* dma to help avoid a possible race */
+       buffer_info->time_stamp = jiffies;
+       buffer_info->dma = pci_map_single(adapter->pdev, skb->data, len,
+                                         PCI_DMA_TODEVICE);
+       count++;
+       i++;
+       if (i == tx_ring->count)
+               i = 0;
+
+       for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
+               struct skb_frag_struct *frag;
+
+               frag = &skb_shinfo(skb)->frags[f];
+               len = frag->size;
+
+               buffer_info = &tx_ring->buffer_info[i];
+               BUG_ON(len >= IGB_MAX_DATA_PER_TXD);
+               buffer_info->length = len;
+               buffer_info->time_stamp = jiffies;
+               buffer_info->dma = pci_map_page(adapter->pdev,
+                                               frag->page,
+                                               frag->page_offset,
+                                               len,
+                                               PCI_DMA_TODEVICE);
+
+               count++;
+               i++;
+               if (i == tx_ring->count)
+                       i = 0;
+       }
+
+       i = (i == 0) ? tx_ring->count - 1 : i - 1;
+       tx_ring->buffer_info[i].skb = skb;
+
+       return count;
+}
+
+static inline void igb_tx_queue_adv(struct igb_adapter *adapter,
+                                   struct igb_ring *tx_ring,
+                                   int tx_flags, int count, u32 paylen,
+                                   u8 hdr_len)
+{
+       union e1000_adv_tx_desc *tx_desc = NULL;
+       struct igb_buffer *buffer_info;
+       u32 olinfo_status = 0, cmd_type_len;
+       unsigned int i;
+
+       cmd_type_len = (E1000_ADVTXD_DTYP_DATA | E1000_ADVTXD_DCMD_IFCS |
+                       E1000_ADVTXD_DCMD_DEXT);
+
+       if (tx_flags & IGB_TX_FLAGS_VLAN)
+               cmd_type_len |= E1000_ADVTXD_DCMD_VLE;
+
+       if (tx_flags & IGB_TX_FLAGS_TSO) {
+               cmd_type_len |= E1000_ADVTXD_DCMD_TSE;
+
+               /* insert tcp checksum */
+               olinfo_status |= E1000_TXD_POPTS_TXSM << 8;
+
+               /* insert ip checksum */
+               if (tx_flags & IGB_TX_FLAGS_IPV4)
+                       olinfo_status |= E1000_TXD_POPTS_IXSM << 8;
+
+       } else if (tx_flags & IGB_TX_FLAGS_CSUM) {
+               olinfo_status |= E1000_TXD_POPTS_TXSM << 8;
+       }
+
+       if (tx_flags & (IGB_TX_FLAGS_CSUM | IGB_TX_FLAGS_TSO |
+                       IGB_TX_FLAGS_VLAN))
+               olinfo_status |= tx_ring->eims_value >> 4;
+
+       olinfo_status |= ((paylen - hdr_len) << E1000_ADVTXD_PAYLEN_SHIFT);
+
+       i = tx_ring->next_to_use;
+       while (count--) {
+               buffer_info = &tx_ring->buffer_info[i];
+               tx_desc = E1000_TX_DESC_ADV(*tx_ring, i);
+               tx_desc->read.buffer_addr = cpu_to_le64(buffer_info->dma);
+               tx_desc->read.cmd_type_len =
+                       cpu_to_le32(cmd_type_len | buffer_info->length);
+               tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
+               i++;
+               if (i == tx_ring->count)
+                       i = 0;
+       }
+
+       tx_desc->read.cmd_type_len |= cpu_to_le32(adapter->txd_cmd);
+       /* Force memory writes to complete before letting h/w
+        * know there are new descriptors to fetch.  (Only
+        * applicable for weak-ordered memory model archs,
+        * such as IA-64). */
+       wmb();
+
+       tx_ring->next_to_use = i;
+       writel(i, adapter->hw.hw_addr + tx_ring->tail);
+       /* we need this if more than one processor can write to our tail
+        * at a time, it syncronizes IO on IA64/Altix systems */
+       mmiowb();
+}
+
+static int __igb_maybe_stop_tx(struct net_device *netdev,
+                              struct igb_ring *tx_ring, int size)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+
+       netif_stop_queue(netdev);
+       /* Herbert's original patch had:
+        *  smp_mb__after_netif_stop_queue();
+        * but since that doesn't exist yet, just open code it. */
+       smp_mb();
+
+       /* We need to check again in a case another CPU has just
+        * made room available. */
+       if (IGB_DESC_UNUSED(tx_ring) < size)
+               return -EBUSY;
+
+       /* A reprieve! */
+       netif_start_queue(netdev);
+       ++adapter->restart_queue;
+       return 0;
+}
+
+static int igb_maybe_stop_tx(struct net_device *netdev,
+                            struct igb_ring *tx_ring, int size)
+{
+       if (IGB_DESC_UNUSED(tx_ring) >= size)
+               return 0;
+       return __igb_maybe_stop_tx(netdev, tx_ring, size);
+}
+
+#define TXD_USE_COUNT(S) (((S) >> (IGB_MAX_TXD_PWR)) + 1)
+
+static int igb_xmit_frame_ring_adv(struct sk_buff *skb,
+                                  struct net_device *netdev,
+                                  struct igb_ring *tx_ring)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       unsigned int tx_flags = 0;
+       unsigned int len;
+       unsigned long irq_flags;
+       u8 hdr_len = 0;
+       int tso = 0;
+
+       len = skb_headlen(skb);
+
+       if (test_bit(__IGB_DOWN, &adapter->state)) {
+               dev_kfree_skb_any(skb);
+               return NETDEV_TX_OK;
+       }
+
+       if (skb->len <= 0) {
+               dev_kfree_skb_any(skb);
+               return NETDEV_TX_OK;
+       }
+
+       if (!spin_trylock_irqsave(&tx_ring->tx_lock, irq_flags))
+               /* Collision - tell upper layer to requeue */
+               return NETDEV_TX_LOCKED;
+
+       /* need: 1 descriptor per page,
+        *       + 2 desc gap to keep tail from touching head,
+        *       + 1 desc for skb->data,
+        *       + 1 desc for context descriptor,
+        * otherwise try next time */
+       if (igb_maybe_stop_tx(netdev, tx_ring, skb_shinfo(skb)->nr_frags + 4)) {
+               /* this is a hard error */
+               spin_unlock_irqrestore(&tx_ring->tx_lock, irq_flags);
+               return NETDEV_TX_BUSY;
+       }
+
+       if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
+               tx_flags |= IGB_TX_FLAGS_VLAN;
+               tx_flags |= (vlan_tx_tag_get(skb) << IGB_TX_FLAGS_VLAN_SHIFT);
+       }
+
+       tso = skb_is_gso(skb) ? igb_tso_adv(adapter, tx_ring, skb, tx_flags,
+                                             &hdr_len) : 0;
+
+       if (tso < 0) {
+               dev_kfree_skb_any(skb);
+               spin_unlock_irqrestore(&tx_ring->tx_lock, irq_flags);
+               return NETDEV_TX_OK;
+       }
+
+       if (tso)
+               tx_flags |= IGB_TX_FLAGS_TSO;
+       else if (igb_tx_csum_adv(adapter, tx_ring, skb, tx_flags))
+                       if (skb->ip_summed == CHECKSUM_PARTIAL)
+                               tx_flags |= IGB_TX_FLAGS_CSUM;
+
+       if (skb->protocol == htons(ETH_P_IP))
+               tx_flags |= IGB_TX_FLAGS_IPV4;
+
+       igb_tx_queue_adv(adapter, tx_ring, tx_flags,
+                        igb_tx_map_adv(adapter, tx_ring, skb),
+                        skb->len, hdr_len);
+
+       netdev->trans_start = jiffies;
+
+       /* Make sure there is space in the ring for the next send. */
+       igb_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 4);
+
+       spin_unlock_irqrestore(&tx_ring->tx_lock, irq_flags);
+       return NETDEV_TX_OK;
+}
+
+static int igb_xmit_frame_adv(struct sk_buff *skb, struct net_device *netdev)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct igb_ring *tx_ring = &adapter->tx_ring[0];
+
+       /* This goes back to the question of how to logically map a tx queue
+        * to a flow.  Right now, performance is impacted slightly negatively
+        * if using multiple tx queues.  If the stack breaks away from a
+        * single qdisc implementation, we can look at this again. */
+       return (igb_xmit_frame_ring_adv(skb, netdev, tx_ring));
+}
+
+/**
+ * igb_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ **/
+static void igb_tx_timeout(struct net_device *netdev)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+
+       /* Do the reset outside of interrupt context */
+       adapter->tx_timeout_count++;
+       schedule_work(&adapter->reset_task);
+       wr32(E1000_EICS, adapter->eims_enable_mask &
+               ~(E1000_EIMS_TCP_TIMER | E1000_EIMS_OTHER));
+}
+
+static void igb_reset_task(struct work_struct *work)
+{
+       struct igb_adapter *adapter;
+       adapter = container_of(work, struct igb_adapter, reset_task);
+
+       igb_reinit_locked(adapter);
+}
+
+/**
+ * igb_get_stats - Get System Network Statistics
+ * @netdev: network interface device structure
+ *
+ * Returns the address of the device statistics structure.
+ * The statistics are actually updated from the timer callback.
+ **/
+static struct net_device_stats *
+igb_get_stats(struct net_device *netdev)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+
+       /* only return the current stats */
+       return &adapter->net_stats;
+}
+
+/**
+ * igb_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int igb_change_mtu(struct net_device *netdev, int new_mtu)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
+
+       if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) ||
+           (max_frame > MAX_JUMBO_FRAME_SIZE)) {
+               dev_err(&adapter->pdev->dev, "Invalid MTU setting\n");
+               return -EINVAL;
+       }
+
+#define MAX_STD_JUMBO_FRAME_SIZE 9234
+       if (max_frame > MAX_STD_JUMBO_FRAME_SIZE) {
+               dev_err(&adapter->pdev->dev, "MTU > 9216 not supported.\n");
+               return -EINVAL;
+       }
+
+       while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
+               msleep(1);
+       /* igb_down has a dependency on max_frame_size */
+       adapter->max_frame_size = max_frame;
+       if (netif_running(netdev))
+               igb_down(adapter);
+
+       /* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN
+        * means we reserve 2 more, this pushes us to allocate from the next
+        * larger slab size.
+        * i.e. RXBUFFER_2048 --> size-4096 slab
+        */
+
+       if (max_frame <= IGB_RXBUFFER_256)
+               adapter->rx_buffer_len = IGB_RXBUFFER_256;
+       else if (max_frame <= IGB_RXBUFFER_512)
+               adapter->rx_buffer_len = IGB_RXBUFFER_512;
+       else if (max_frame <= IGB_RXBUFFER_1024)
+               adapter->rx_buffer_len = IGB_RXBUFFER_1024;
+       else if (max_frame <= IGB_RXBUFFER_2048)
+               adapter->rx_buffer_len = IGB_RXBUFFER_2048;
+       else
+               adapter->rx_buffer_len = IGB_RXBUFFER_4096;
+       /* adjust allocation if LPE protects us, and we aren't using SBP */
+       if ((max_frame == ETH_FRAME_LEN + ETH_FCS_LEN) ||
+            (max_frame == MAXIMUM_ETHERNET_VLAN_SIZE))
+               adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
+
+       dev_info(&adapter->pdev->dev, "changing MTU from %d to %d\n",
+                netdev->mtu, new_mtu);
+       netdev->mtu = new_mtu;
+
+       if (netif_running(netdev))
+               igb_up(adapter);
+       else
+               igb_reset(adapter);
+
+       clear_bit(__IGB_RESETTING, &adapter->state);
+
+       return 0;
+}
+
+/**
+ * igb_update_stats - Update the board statistics counters
+ * @adapter: board private structure
+ **/
+
+void igb_update_stats(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       struct pci_dev *pdev = adapter->pdev;
+       u16 phy_tmp;
+
+#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF
+
+       /*
+        * Prevent stats update while adapter is being reset, or if the pci
+        * connection is down.
+        */
+       if (adapter->link_speed == 0)
+               return;
+       if (pci_channel_offline(pdev))
+               return;
+
+       adapter->stats.crcerrs += rd32(E1000_CRCERRS);
+       adapter->stats.gprc += rd32(E1000_GPRC);
+       adapter->stats.gorc += rd32(E1000_GORCL);
+       rd32(E1000_GORCH); /* clear GORCL */
+       adapter->stats.bprc += rd32(E1000_BPRC);
+       adapter->stats.mprc += rd32(E1000_MPRC);
+       adapter->stats.roc += rd32(E1000_ROC);
+
+       adapter->stats.prc64 += rd32(E1000_PRC64);
+       adapter->stats.prc127 += rd32(E1000_PRC127);
+       adapter->stats.prc255 += rd32(E1000_PRC255);
+       adapter->stats.prc511 += rd32(E1000_PRC511);
+       adapter->stats.prc1023 += rd32(E1000_PRC1023);
+       adapter->stats.prc1522 += rd32(E1000_PRC1522);
+       adapter->stats.symerrs += rd32(E1000_SYMERRS);
+       adapter->stats.sec += rd32(E1000_SEC);
+
+       adapter->stats.mpc += rd32(E1000_MPC);
+       adapter->stats.scc += rd32(E1000_SCC);
+       adapter->stats.ecol += rd32(E1000_ECOL);
+       adapter->stats.mcc += rd32(E1000_MCC);
+       adapter->stats.latecol += rd32(E1000_LATECOL);
+       adapter->stats.dc += rd32(E1000_DC);
+       adapter->stats.rlec += rd32(E1000_RLEC);
+       adapter->stats.xonrxc += rd32(E1000_XONRXC);
+       adapter->stats.xontxc += rd32(E1000_XONTXC);
+       adapter->stats.xoffrxc += rd32(E1000_XOFFRXC);
+       adapter->stats.xofftxc += rd32(E1000_XOFFTXC);
+       adapter->stats.fcruc += rd32(E1000_FCRUC);
+       adapter->stats.gptc += rd32(E1000_GPTC);
+       adapter->stats.gotc += rd32(E1000_GOTCL);
+       rd32(E1000_GOTCH); /* clear GOTCL */
+       adapter->stats.rnbc += rd32(E1000_RNBC);
+       adapter->stats.ruc += rd32(E1000_RUC);
+       adapter->stats.rfc += rd32(E1000_RFC);
+       adapter->stats.rjc += rd32(E1000_RJC);
+       adapter->stats.tor += rd32(E1000_TORH);
+       adapter->stats.tot += rd32(E1000_TOTH);
+       adapter->stats.tpr += rd32(E1000_TPR);
+
+       adapter->stats.ptc64 += rd32(E1000_PTC64);
+       adapter->stats.ptc127 += rd32(E1000_PTC127);
+       adapter->stats.ptc255 += rd32(E1000_PTC255);
+       adapter->stats.ptc511 += rd32(E1000_PTC511);
+       adapter->stats.ptc1023 += rd32(E1000_PTC1023);
+       adapter->stats.ptc1522 += rd32(E1000_PTC1522);
+
+       adapter->stats.mptc += rd32(E1000_MPTC);
+       adapter->stats.bptc += rd32(E1000_BPTC);
+
+       /* used for adaptive IFS */
+
+       hw->mac.tx_packet_delta = rd32(E1000_TPT);
+       adapter->stats.tpt += hw->mac.tx_packet_delta;
+       hw->mac.collision_delta = rd32(E1000_COLC);
+       adapter->stats.colc += hw->mac.collision_delta;
+
+       adapter->stats.algnerrc += rd32(E1000_ALGNERRC);
+       adapter->stats.rxerrc += rd32(E1000_RXERRC);
+       adapter->stats.tncrs += rd32(E1000_TNCRS);
+       adapter->stats.tsctc += rd32(E1000_TSCTC);
+       adapter->stats.tsctfc += rd32(E1000_TSCTFC);
+
+       adapter->stats.iac += rd32(E1000_IAC);
+       adapter->stats.icrxoc += rd32(E1000_ICRXOC);
+       adapter->stats.icrxptc += rd32(E1000_ICRXPTC);
+       adapter->stats.icrxatc += rd32(E1000_ICRXATC);
+       adapter->stats.ictxptc += rd32(E1000_ICTXPTC);
+       adapter->stats.ictxatc += rd32(E1000_ICTXATC);
+       adapter->stats.ictxqec += rd32(E1000_ICTXQEC);
+       adapter->stats.ictxqmtc += rd32(E1000_ICTXQMTC);
+       adapter->stats.icrxdmtc += rd32(E1000_ICRXDMTC);
+
+       /* Fill out the OS statistics structure */
+       adapter->net_stats.multicast = adapter->stats.mprc;
+       adapter->net_stats.collisions = adapter->stats.colc;
+
+       /* Rx Errors */
+
+       /* RLEC on some newer hardware can be incorrect so build
+       * our own version based on RUC and ROC */
+       adapter->net_stats.rx_errors = adapter->stats.rxerrc +
+               adapter->stats.crcerrs + adapter->stats.algnerrc +
+               adapter->stats.ruc + adapter->stats.roc +
+               adapter->stats.cexterr;
+       adapter->net_stats.rx_length_errors = adapter->stats.ruc +
+                                             adapter->stats.roc;
+       adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs;
+       adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc;
+       adapter->net_stats.rx_missed_errors = adapter->stats.mpc;
+
+       /* Tx Errors */
+       adapter->net_stats.tx_errors = adapter->stats.ecol +
+                                      adapter->stats.latecol;
+       adapter->net_stats.tx_aborted_errors = adapter->stats.ecol;
+       adapter->net_stats.tx_window_errors = adapter->stats.latecol;
+       adapter->net_stats.tx_carrier_errors = adapter->stats.tncrs;
+
+       /* Tx Dropped needs to be maintained elsewhere */
+
+       /* Phy Stats */
+       if (hw->phy.media_type == e1000_media_type_copper) {
+               if ((adapter->link_speed == SPEED_1000) &&
+                  (!hw->phy.ops.read_phy_reg(hw, PHY_1000T_STATUS,
+                                             &phy_tmp))) {
+                       phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK;
+                       adapter->phy_stats.idle_errors += phy_tmp;
+               }
+       }
+
+       /* Management Stats */
+       adapter->stats.mgptc += rd32(E1000_MGTPTC);
+       adapter->stats.mgprc += rd32(E1000_MGTPRC);
+       adapter->stats.mgpdc += rd32(E1000_MGTPDC);
+}
+
+
+static irqreturn_t igb_msix_other(int irq, void *data)
+{
+       struct net_device *netdev = data;
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       u32 eicr;
+       /* disable interrupts from the "other" bit, avoid re-entry */
+       wr32(E1000_EIMC, E1000_EIMS_OTHER);
+
+       eicr = rd32(E1000_EICR);
+
+       if (eicr & E1000_EIMS_OTHER) {
+               u32 icr = rd32(E1000_ICR);
+               /* reading ICR causes bit 31 of EICR to be cleared */
+               if (!(icr & E1000_ICR_LSC))
+                       goto no_link_interrupt;
+               hw->mac.get_link_status = 1;
+               /* guard against interrupt when we're going down */
+               if (!test_bit(__IGB_DOWN, &adapter->state))
+                       mod_timer(&adapter->watchdog_timer, jiffies + 1);
+       }
+
+no_link_interrupt:
+       wr32(E1000_IMS, E1000_IMS_LSC);
+       wr32(E1000_EIMS, E1000_EIMS_OTHER);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t igb_msix_tx(int irq, void *data)
+{
+       struct igb_ring *tx_ring = data;
+       struct igb_adapter *adapter = tx_ring->adapter;
+       struct e1000_hw *hw = &adapter->hw;
+
+       if (!tx_ring->itr_val)
+               wr32(E1000_EIMC, tx_ring->eims_value);
+
+       tx_ring->total_bytes = 0;
+       tx_ring->total_packets = 0;
+       if (!igb_clean_tx_irq(adapter, tx_ring))
+               /* Ring was not completely cleaned, so fire another interrupt */
+               wr32(E1000_EICS, tx_ring->eims_value);
+
+       if (!tx_ring->itr_val)
+               wr32(E1000_EIMS, tx_ring->eims_value);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t igb_msix_rx(int irq, void *data)
+{
+       struct igb_ring *rx_ring = data;
+       struct igb_adapter *adapter = rx_ring->adapter;
+       struct e1000_hw *hw = &adapter->hw;
+
+       if (!rx_ring->itr_val)
+               wr32(E1000_EIMC, rx_ring->eims_value);
+
+       if (netif_rx_schedule_prep(adapter->netdev, &rx_ring->napi)) {
+               rx_ring->total_bytes = 0;
+               rx_ring->total_packets = 0;
+               rx_ring->no_itr_adjust = 0;
+               __netif_rx_schedule(adapter->netdev, &rx_ring->napi);
+       } else {
+               if (!rx_ring->no_itr_adjust) {
+                       igb_lower_rx_eitr(adapter, rx_ring);
+                       rx_ring->no_itr_adjust = 1;
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
+
+/**
+ * igb_intr_msi - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ **/
+static irqreturn_t igb_intr_msi(int irq, void *data)
+{
+       struct net_device *netdev = data;
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct napi_struct *napi = &adapter->napi;
+       struct e1000_hw *hw = &adapter->hw;
+       /* read ICR disables interrupts using IAM */
+       u32 icr = rd32(E1000_ICR);
+
+       /* Write the ITR value calculated at the end of the
+        * previous interrupt.
+        */
+       if (adapter->set_itr) {
+               wr32(E1000_ITR,
+                       1000000000 / (adapter->itr * 256));
+               adapter->set_itr = 0;
+       }
+
+       /* read ICR disables interrupts using IAM */
+       if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+               hw->mac.get_link_status = 1;
+               if (!test_bit(__IGB_DOWN, &adapter->state))
+                       mod_timer(&adapter->watchdog_timer, jiffies + 1);
+       }
+
+       if (netif_rx_schedule_prep(netdev, napi)) {
+               adapter->tx_ring->total_bytes = 0;
+               adapter->tx_ring->total_packets = 0;
+               adapter->rx_ring->total_bytes = 0;
+               adapter->rx_ring->total_packets = 0;
+               __netif_rx_schedule(netdev, napi);
+       }
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * igb_intr - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ **/
+static irqreturn_t igb_intr(int irq, void *data)
+{
+       struct net_device *netdev = data;
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct napi_struct *napi = &adapter->napi;
+       struct e1000_hw *hw = &adapter->hw;
+       /* Interrupt Auto-Mask...upon reading ICR, interrupts are masked.  No
+        * need for the IMC write */
+       u32 icr = rd32(E1000_ICR);
+       u32 eicr = 0;
+       if (!icr)
+               return IRQ_NONE;  /* Not our interrupt */
+
+       /* Write the ITR value calculated at the end of the
+        * previous interrupt.
+        */
+       if (adapter->set_itr) {
+               wr32(E1000_ITR,
+                       1000000000 / (adapter->itr * 256));
+               adapter->set_itr = 0;
+       }
+
+       /* IMS will not auto-mask if INT_ASSERTED is not set, and if it is
+        * not set, then the adapter didn't send an interrupt */
+       if (!(icr & E1000_ICR_INT_ASSERTED))
+               return IRQ_NONE;
+
+       eicr = rd32(E1000_EICR);
+
+       if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+               hw->mac.get_link_status = 1;
+               /* guard against interrupt when we're going down */
+               if (!test_bit(__IGB_DOWN, &adapter->state))
+                       mod_timer(&adapter->watchdog_timer, jiffies + 1);
+       }
+
+       if (netif_rx_schedule_prep(netdev, napi)) {
+               adapter->tx_ring->total_bytes = 0;
+               adapter->rx_ring->total_bytes = 0;
+               adapter->tx_ring->total_packets = 0;
+               adapter->rx_ring->total_packets = 0;
+               __netif_rx_schedule(netdev, napi);
+       }
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * igb_clean - NAPI Rx polling callback
+ * @adapter: board private structure
+ **/
+static int igb_clean(struct napi_struct *napi, int budget)
+{
+       struct igb_adapter *adapter = container_of(napi, struct igb_adapter,
+                                                  napi);
+       struct net_device *netdev = adapter->netdev;
+       int tx_clean_complete = 1, work_done = 0;
+       int i;
+
+       /* Must NOT use netdev_priv macro here. */
+       adapter = netdev->priv;
+
+       /* Keep link state information with original netdev */
+       if (!netif_carrier_ok(netdev))
+               goto quit_polling;
+
+       /* igb_clean is called per-cpu.  This lock protects tx_ring[i] from
+        * being cleaned by multiple cpus simultaneously.  A failure obtaining
+        * the lock means tx_ring[i] is currently being cleaned anyway. */
+       for (i = 0; i < adapter->num_tx_queues; i++) {
+               if (spin_trylock(&adapter->tx_ring[i].tx_clean_lock)) {
+                       tx_clean_complete &= igb_clean_tx_irq(adapter,
+                                                       &adapter->tx_ring[i]);
+                       spin_unlock(&adapter->tx_ring[i].tx_clean_lock);
+               }
+       }
+
+       for (i = 0; i < adapter->num_rx_queues; i++)
+               igb_clean_rx_irq_adv(adapter, &adapter->rx_ring[i], &work_done,
+                                    adapter->rx_ring[i].napi.weight);
+
+       /* If no Tx and not enough Rx work done, exit the polling mode */
+       if ((tx_clean_complete && (work_done < budget)) ||
+           !netif_running(netdev)) {
+quit_polling:
+               if (adapter->itr_setting & 3)
+                       igb_set_itr(adapter, E1000_ITR, false);
+               netif_rx_complete(netdev, napi);
+               if (!test_bit(__IGB_DOWN, &adapter->state))
+                       igb_irq_enable(adapter);
+               return 0;
+       }
+
+       return 1;
+}
+
+static int igb_clean_rx_ring_msix(struct napi_struct *napi, int budget)
+{
+       struct igb_ring *rx_ring = container_of(napi, struct igb_ring, napi);
+       struct igb_adapter *adapter = rx_ring->adapter;
+       struct e1000_hw *hw = &adapter->hw;
+       struct net_device *netdev = adapter->netdev;
+       int work_done = 0;
+
+       /* Keep link state information with original netdev */
+       if (!netif_carrier_ok(netdev))
+               goto quit_polling;
+
+       igb_clean_rx_irq_adv(adapter, rx_ring, &work_done, budget);
+
+
+       /* If not enough Rx work done, exit the polling mode */
+       if ((work_done == 0) || !netif_running(netdev)) {
+quit_polling:
+               netif_rx_complete(netdev, napi);
+
+               wr32(E1000_EIMS, rx_ring->eims_value);
+               if ((adapter->itr_setting & 3) && !rx_ring->no_itr_adjust &&
+                   (rx_ring->total_packets > IGB_DYN_ITR_PACKET_THRESHOLD)) {
+                       int mean_size = rx_ring->total_bytes /
+                                       rx_ring->total_packets;
+                       if (mean_size < IGB_DYN_ITR_LENGTH_LOW)
+                               igb_raise_rx_eitr(adapter, rx_ring);
+                       else if (mean_size > IGB_DYN_ITR_LENGTH_HIGH)
+                               igb_lower_rx_eitr(adapter, rx_ring);
+               }
+               return 0;
+       }
+
+       return 1;
+}
+/**
+ * igb_clean_tx_irq - Reclaim resources after transmit completes
+ * @adapter: board private structure
+ * returns true if ring is completely cleaned
+ **/
+static bool igb_clean_tx_irq(struct igb_adapter *adapter,
+                                 struct igb_ring *tx_ring)
+{
+       struct net_device *netdev = adapter->netdev;
+       struct e1000_hw *hw = &adapter->hw;
+       struct e1000_tx_desc *tx_desc;
+       struct igb_buffer *buffer_info;
+       struct sk_buff *skb;
+       unsigned int i;
+       u32 head, oldhead;
+       unsigned int count = 0;
+       bool cleaned = false;
+       bool retval = true;
+       unsigned int total_bytes = 0, total_packets = 0;
+
+       rmb();
+       head = *(volatile u32 *)((struct e1000_tx_desc *)tx_ring->desc
+                                + tx_ring->count);
+       head = le32_to_cpu(head);
+       i = tx_ring->next_to_clean;
+       while (1) {
+               while (i != head) {
+                       cleaned = true;
+                       tx_desc = E1000_TX_DESC(*tx_ring, i);
+                       buffer_info = &tx_ring->buffer_info[i];
+                       skb = buffer_info->skb;
+
+                       if (skb) {
+                               unsigned int segs, bytecount;
+                               /* gso_segs is currently only valid for tcp */
+                               segs = skb_shinfo(skb)->gso_segs ?: 1;
+                               /* multiply data chunks by size of headers */
+                               bytecount = ((segs - 1) * skb_headlen(skb)) +
+                                           skb->len;
+                               total_packets += segs;
+                               total_bytes += bytecount;
+                       }
+
+                       igb_unmap_and_free_tx_resource(adapter, buffer_info);
+                       tx_desc->upper.data = 0;
+
+                       i++;
+                       if (i == tx_ring->count)
+                               i = 0;
+
+                       count++;
+                       if (count == IGB_MAX_TX_CLEAN) {
+                               retval = false;
+                               goto done_cleaning;
+                       }
+               }
+               oldhead = head;
+               rmb();
+               head = *(volatile u32 *)((struct e1000_tx_desc *)tx_ring->desc
+                                        + tx_ring->count);
+               head = le32_to_cpu(head);
+               if (head == oldhead)
+                       goto done_cleaning;
+       }  /* while (1) */
+
+done_cleaning:
+       tx_ring->next_to_clean = i;
+
+       if (unlikely(cleaned &&
+                    netif_carrier_ok(netdev) &&
+                    IGB_DESC_UNUSED(tx_ring) >= IGB_TX_QUEUE_WAKE)) {
+               /* Make sure that anybody stopping the queue after this
+                * sees the new next_to_clean.
+                */
+               smp_mb();
+               if (netif_queue_stopped(netdev) &&
+                   !(test_bit(__IGB_DOWN, &adapter->state))) {
+                       netif_wake_queue(netdev);
+                       ++adapter->restart_queue;
+               }
+       }
+
+       if (tx_ring->detect_tx_hung) {
+               /* Detect a transmit hang in hardware, this serializes the
+                * check with the clearing of time_stamp and movement of i */
+               tx_ring->detect_tx_hung = false;
+               if (tx_ring->buffer_info[i].time_stamp &&
+                   time_after(jiffies, tx_ring->buffer_info[i].time_stamp +
+                              (adapter->tx_timeout_factor * HZ))
+                   && !(rd32(E1000_STATUS) &
+                        E1000_STATUS_TXOFF)) {
+
+                       tx_desc = E1000_TX_DESC(*tx_ring, i);
+                       /* detected Tx unit hang */
+                       dev_err(&adapter->pdev->dev,
+                               "Detected Tx Unit Hang\n"
+                               "  Tx Queue             <%lu>\n"
+                               "  TDH                  <%x>\n"
+                               "  TDT                  <%x>\n"
+                               "  next_to_use          <%x>\n"
+                               "  next_to_clean        <%x>\n"
+                               "  head (WB)            <%x>\n"
+                               "buffer_info[next_to_clean]\n"
+                               "  time_stamp           <%lx>\n"
+                               "  jiffies              <%lx>\n"
+                               "  desc.status          <%x>\n",
+                               (unsigned long)((tx_ring - adapter->tx_ring) /
+                                       sizeof(struct igb_ring)),
+                               readl(adapter->hw.hw_addr + tx_ring->head),
+                               readl(adapter->hw.hw_addr + tx_ring->tail),
+                               tx_ring->next_to_use,
+                               tx_ring->next_to_clean,
+                               head,
+                               tx_ring->buffer_info[i].time_stamp,
+                               jiffies,
+                               tx_desc->upper.fields.status);
+                       netif_stop_queue(netdev);
+               }
+       }
+       tx_ring->total_bytes += total_bytes;
+       tx_ring->total_packets += total_packets;
+       adapter->net_stats.tx_bytes += total_bytes;
+       adapter->net_stats.tx_packets += total_packets;
+       return retval;
+}
+
+
+/**
+ * igb_receive_skb - helper function to handle rx indications
+ * @adapter: board private structure
+ * @status: descriptor status field as written by hardware
+ * @vlan: descriptor vlan field as written by hardware (no le/be conversion)
+ * @skb: pointer to sk_buff to be indicated to stack
+ **/
+static void igb_receive_skb(struct igb_adapter *adapter, u8 status, u16 vlan,
+                           struct sk_buff *skb)
+{
+       if (adapter->vlgrp && (status & E1000_RXD_STAT_VP))
+               vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
+                                        le16_to_cpu(vlan) &
+                                        E1000_RXD_SPC_VLAN_MASK);
+       else
+               netif_receive_skb(skb);
+}
+
+
+static inline void igb_rx_checksum_adv(struct igb_adapter *adapter,
+                                      u32 status_err, struct sk_buff *skb)
+{
+       skb->ip_summed = CHECKSUM_NONE;
+
+       /* Ignore Checksum bit is set or checksum is disabled through ethtool */
+       if ((status_err & E1000_RXD_STAT_IXSM) || !adapter->rx_csum)
+               return;
+       /* TCP/UDP checksum error bit is set */
+       if (status_err &
+           (E1000_RXDEXT_STATERR_TCPE | E1000_RXDEXT_STATERR_IPE)) {
+               /* let the stack verify checksum errors */
+               adapter->hw_csum_err++;
+               return;
+       }
+       /* It must be a TCP or UDP packet with a valid checksum */
+       if (status_err & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS))
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+       adapter->hw_csum_good++;
+}
+
+static bool igb_clean_rx_irq_adv(struct igb_adapter *adapter,
+                                     struct igb_ring *rx_ring,
+                                     int *work_done, int budget)
+{
+       struct net_device *netdev = adapter->netdev;
+       struct pci_dev *pdev = adapter->pdev;
+       union e1000_adv_rx_desc *rx_desc , *next_rxd;
+       struct igb_buffer *buffer_info , *next_buffer;
+       struct sk_buff *skb;
+       unsigned int i, j;
+       u32 length, hlen, staterr;
+       bool cleaned = false;
+       int cleaned_count = 0;
+       unsigned int total_bytes = 0, total_packets = 0;
+
+       i = rx_ring->next_to_clean;
+       rx_desc = E1000_RX_DESC_ADV(*rx_ring, i);
+       staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+
+       while (staterr & E1000_RXD_STAT_DD) {
+               if (*work_done >= budget)
+                       break;
+               (*work_done)++;
+               buffer_info = &rx_ring->buffer_info[i];
+
+               /* HW will not DMA in data larger than the given buffer, even
+                * if it parses the (NFS, of course) header to be larger.  In
+                * that case, it fills the header buffer and spills the rest
+                * into the page.
+                */
+               hlen = le16_to_cpu((rx_desc->wb.lower.lo_dword.hdr_info &
+                 E1000_RXDADV_HDRBUFLEN_MASK) >> E1000_RXDADV_HDRBUFLEN_SHIFT);
+               if (hlen > adapter->rx_ps_hdr_size)
+                       hlen = adapter->rx_ps_hdr_size;
+
+               length = le16_to_cpu(rx_desc->wb.upper.length);
+               cleaned = true;
+               cleaned_count++;
+
+               if (rx_ring->pending_skb != NULL) {
+                       skb = rx_ring->pending_skb;
+                       rx_ring->pending_skb = NULL;
+                       j = rx_ring->pending_skb_page;
+               } else {
+                       skb = buffer_info->skb;
+                       prefetch(skb->data - NET_IP_ALIGN);
+                       buffer_info->skb = NULL;
+                       if (hlen) {
+                               pci_unmap_single(pdev, buffer_info->dma,
+                                                adapter->rx_ps_hdr_size +
+                                                  NET_IP_ALIGN,
+                                                PCI_DMA_FROMDEVICE);
+                               skb_put(skb, hlen);
+                       } else {
+                               pci_unmap_single(pdev, buffer_info->dma,
+                                                adapter->rx_buffer_len +
+                                                  NET_IP_ALIGN,
+                                                PCI_DMA_FROMDEVICE);
+                               skb_put(skb, length);
+                               goto send_up;
+                       }
+                       j = 0;
+               }
+
+               while (length) {
+                       pci_unmap_page(pdev, buffer_info->page_dma,
+                               PAGE_SIZE, PCI_DMA_FROMDEVICE);
+                       buffer_info->page_dma = 0;
+                       skb_fill_page_desc(skb, j, buffer_info->page,
+                                               0, length);
+                       buffer_info->page = NULL;
+
+                       skb->len += length;
+                       skb->data_len += length;
+                       skb->truesize += length;
+                       rx_desc->wb.upper.status_error = 0;
+                       if (staterr & E1000_RXD_STAT_EOP)
+                               break;
+
+                       j++;
+                       cleaned_count++;
+                       i++;
+                       if (i == rx_ring->count)
+                               i = 0;
+
+                       buffer_info = &rx_ring->buffer_info[i];
+                       rx_desc = E1000_RX_DESC_ADV(*rx_ring, i);
+                       staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+                       length = le16_to_cpu(rx_desc->wb.upper.length);
+                       if (!(staterr & E1000_RXD_STAT_DD)) {
+                               rx_ring->pending_skb = skb;
+                               rx_ring->pending_skb_page = j;
+                               goto out;
+                       }
+               }
+send_up:
+               pskb_trim(skb, skb->len - 4);
+               i++;
+               if (i == rx_ring->count)
+                       i = 0;
+               next_rxd = E1000_RX_DESC_ADV(*rx_ring, i);
+               prefetch(next_rxd);
+               next_buffer = &rx_ring->buffer_info[i];
+
+               if (staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) {
+                       dev_kfree_skb_irq(skb);
+                       goto next_desc;
+               }
+               rx_ring->no_itr_adjust |= (staterr & E1000_RXD_STAT_DYNINT);
+
+               total_bytes += skb->len;
+               total_packets++;
+
+               igb_rx_checksum_adv(adapter, staterr, skb);
+
+               skb->protocol = eth_type_trans(skb, netdev);
+
+               igb_receive_skb(adapter, staterr, rx_desc->wb.upper.vlan, skb);
+
+               netdev->last_rx = jiffies;
+
+next_desc:
+               rx_desc->wb.upper.status_error = 0;
+
+               /* return some buffers to hardware, one at a time is too slow */
+               if (cleaned_count >= IGB_RX_BUFFER_WRITE) {
+                       igb_alloc_rx_buffers_adv(adapter, rx_ring,
+                                                cleaned_count);
+                       cleaned_count = 0;
+               }
+
+               /* use prefetched values */
+               rx_desc = next_rxd;
+               buffer_info = next_buffer;
+
+               staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+       }
+out:
+       rx_ring->next_to_clean = i;
+       cleaned_count = IGB_DESC_UNUSED(rx_ring);
+
+       if (cleaned_count)
+               igb_alloc_rx_buffers_adv(adapter, rx_ring, cleaned_count);
+
+       rx_ring->total_packets += total_packets;
+       rx_ring->total_bytes += total_bytes;
+       rx_ring->rx_stats.packets += total_packets;
+       rx_ring->rx_stats.bytes += total_bytes;
+       adapter->net_stats.rx_bytes += total_bytes;
+       adapter->net_stats.rx_packets += total_packets;
+       return cleaned;
+}
+
+
+/**
+ * igb_alloc_rx_buffers_adv - Replace used receive buffers; packet split
+ * @adapter: address of board private structure
+ **/
+static void igb_alloc_rx_buffers_adv(struct igb_adapter *adapter,
+                                    struct igb_ring *rx_ring,
+                                    int cleaned_count)
+{
+       struct net_device *netdev = adapter->netdev;
+       struct pci_dev *pdev = adapter->pdev;
+       union e1000_adv_rx_desc *rx_desc;
+       struct igb_buffer *buffer_info;
+       struct sk_buff *skb;
+       unsigned int i;
+
+       i = rx_ring->next_to_use;
+       buffer_info = &rx_ring->buffer_info[i];
+
+       while (cleaned_count--) {
+               rx_desc = E1000_RX_DESC_ADV(*rx_ring, i);
+
+               if (adapter->rx_ps_hdr_size && !buffer_info->page) {
+                       buffer_info->page = alloc_page(GFP_ATOMIC);
+                       if (!buffer_info->page) {
+                               adapter->alloc_rx_buff_failed++;
+                               goto no_buffers;
+                       }
+                       buffer_info->page_dma =
+                               pci_map_page(pdev,
+                                            buffer_info->page,
+                                            0, PAGE_SIZE,
+                                            PCI_DMA_FROMDEVICE);
+               }
+
+               if (!buffer_info->skb) {
+                       int bufsz;
+
+                       if (adapter->rx_ps_hdr_size)
+                               bufsz = adapter->rx_ps_hdr_size;
+                       else
+                               bufsz = adapter->rx_buffer_len;
+                       bufsz += NET_IP_ALIGN;
+                       skb = netdev_alloc_skb(netdev, bufsz);
+
+                       if (!skb) {
+                               adapter->alloc_rx_buff_failed++;
+                               goto no_buffers;
+                       }
+
+                       /* Make buffer alignment 2 beyond a 16 byte boundary
+                        * this will result in a 16 byte aligned IP header after
+                        * the 14 byte MAC header is removed
+                        */
+                       skb_reserve(skb, NET_IP_ALIGN);
+
+                       buffer_info->skb = skb;
+                       buffer_info->dma = pci_map_single(pdev, skb->data,
+                                                         bufsz,
+                                                         PCI_DMA_FROMDEVICE);
+
+               }
+               /* Refresh the desc even if buffer_addrs didn't change because
+                * each write-back erases this info. */
+               if (adapter->rx_ps_hdr_size) {
+                       rx_desc->read.pkt_addr =
+                            cpu_to_le64(buffer_info->page_dma);
+                       rx_desc->read.hdr_addr = cpu_to_le64(buffer_info->dma);
+               } else {
+                       rx_desc->read.pkt_addr =
+                            cpu_to_le64(buffer_info->dma);
+                       rx_desc->read.hdr_addr = 0;
+               }
+
+               i++;
+               if (i == rx_ring->count)
+                       i = 0;
+               buffer_info = &rx_ring->buffer_info[i];
+       }
+
+no_buffers:
+       if (rx_ring->next_to_use != i) {
+               rx_ring->next_to_use = i;
+               if (i == 0)
+                       i = (rx_ring->count - 1);
+               else
+                       i--;
+
+               /* Force memory writes to complete before letting h/w
+                * know there are new descriptors to fetch.  (Only
+                * applicable for weak-ordered memory model archs,
+                * such as IA-64). */
+               wmb();
+               writel(i, adapter->hw.hw_addr + rx_ring->tail);
+       }
+}
+
+/**
+ * igb_mii_ioctl -
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ **/
+static int igb_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct mii_ioctl_data *data = if_mii(ifr);
+
+       if (adapter->hw.phy.media_type != e1000_media_type_copper)
+               return -EOPNOTSUPP;
+
+       switch (cmd) {
+       case SIOCGMIIPHY:
+               data->phy_id = adapter->hw.phy.addr;
+               break;
+       case SIOCGMIIREG:
+               if (!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+               if (adapter->hw.phy.ops.read_phy_reg(&adapter->hw,
+                                                    data->reg_num
+                                                    & 0x1F, &data->val_out))
+                       return -EIO;
+               break;
+       case SIOCSMIIREG:
+       default:
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
+/**
+ * igb_ioctl -
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ **/
+static int igb_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+       switch (cmd) {
+       case SIOCGMIIPHY:
+       case SIOCGMIIREG:
+       case SIOCSMIIREG:
+               return igb_mii_ioctl(netdev, ifr, cmd);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static void igb_vlan_rx_register(struct net_device *netdev,
+                                struct vlan_group *grp)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       u32 ctrl, rctl;
+
+       igb_irq_disable(adapter);
+       adapter->vlgrp = grp;
+
+       if (grp) {
+               /* enable VLAN tag insert/strip */
+               ctrl = rd32(E1000_CTRL);
+               ctrl |= E1000_CTRL_VME;
+               wr32(E1000_CTRL, ctrl);
+
+               /* enable VLAN receive filtering */
+               rctl = rd32(E1000_RCTL);
+               rctl |= E1000_RCTL_VFE;
+               rctl &= ~E1000_RCTL_CFIEN;
+               wr32(E1000_RCTL, rctl);
+               igb_update_mng_vlan(adapter);
+               wr32(E1000_RLPML,
+                               adapter->max_frame_size + VLAN_TAG_SIZE);
+       } else {
+               /* disable VLAN tag insert/strip */
+               ctrl = rd32(E1000_CTRL);
+               ctrl &= ~E1000_CTRL_VME;
+               wr32(E1000_CTRL, ctrl);
+
+               /* disable VLAN filtering */
+               rctl = rd32(E1000_RCTL);
+               rctl &= ~E1000_RCTL_VFE;
+               wr32(E1000_RCTL, rctl);
+               if (adapter->mng_vlan_id != (u16)IGB_MNG_VLAN_NONE) {
+                       igb_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
+                       adapter->mng_vlan_id = IGB_MNG_VLAN_NONE;
+               }
+               wr32(E1000_RLPML,
+                               adapter->max_frame_size);
+       }
+
+       if (!test_bit(__IGB_DOWN, &adapter->state))
+               igb_irq_enable(adapter);
+}
+
+static void igb_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       u32 vfta, index;
+
+       if ((adapter->hw.mng_cookie.status &
+            E1000_MNG_DHCP_COOKIE_STATUS_VLAN) &&
+           (vid == adapter->mng_vlan_id))
+               return;
+       /* add VID to filter table */
+       index = (vid >> 5) & 0x7F;
+       vfta = array_rd32(E1000_VFTA, index);
+       vfta |= (1 << (vid & 0x1F));
+       igb_write_vfta(&adapter->hw, index, vfta);
+}
+
+static void igb_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       u32 vfta, index;
+
+       igb_irq_disable(adapter);
+       vlan_group_set_device(adapter->vlgrp, vid, NULL);
+
+       if (!test_bit(__IGB_DOWN, &adapter->state))
+               igb_irq_enable(adapter);
+
+       if ((adapter->hw.mng_cookie.status &
+            E1000_MNG_DHCP_COOKIE_STATUS_VLAN) &&
+           (vid == adapter->mng_vlan_id)) {
+               /* release control to f/w */
+               igb_release_hw_control(adapter);
+               return;
+       }
+
+       /* remove VID from filter table */
+       index = (vid >> 5) & 0x7F;
+       vfta = array_rd32(E1000_VFTA, index);
+       vfta &= ~(1 << (vid & 0x1F));
+       igb_write_vfta(&adapter->hw, index, vfta);
+}
+
+static void igb_restore_vlan(struct igb_adapter *adapter)
+{
+       igb_vlan_rx_register(adapter->netdev, adapter->vlgrp);
+
+       if (adapter->vlgrp) {
+               u16 vid;
+               for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+                       if (!vlan_group_get_device(adapter->vlgrp, vid))
+                               continue;
+                       igb_vlan_rx_add_vid(adapter->netdev, vid);
+               }
+       }
+}
+
+int igb_set_spd_dplx(struct igb_adapter *adapter, u16 spddplx)
+{
+       struct e1000_mac_info *mac = &adapter->hw.mac;
+
+       mac->autoneg = 0;
+
+       /* Fiber NICs only allow 1000 gbps Full duplex */
+       if ((adapter->hw.phy.media_type == e1000_media_type_fiber) &&
+               spddplx != (SPEED_1000 + DUPLEX_FULL)) {
+               dev_err(&adapter->pdev->dev,
+                       "Unsupported Speed/Duplex configuration\n");
+               return -EINVAL;
+       }
+
+       switch (spddplx) {
+       case SPEED_10 + DUPLEX_HALF:
+               mac->forced_speed_duplex = ADVERTISE_10_HALF;
+               break;
+       case SPEED_10 + DUPLEX_FULL:
+               mac->forced_speed_duplex = ADVERTISE_10_FULL;
+               break;
+       case SPEED_100 + DUPLEX_HALF:
+               mac->forced_speed_duplex = ADVERTISE_100_HALF;
+               break;
+       case SPEED_100 + DUPLEX_FULL:
+               mac->forced_speed_duplex = ADVERTISE_100_FULL;
+               break;
+       case SPEED_1000 + DUPLEX_FULL:
+               mac->autoneg = 1;
+               adapter->hw.phy.autoneg_advertised = ADVERTISE_1000_FULL;
+               break;
+       case SPEED_1000 + DUPLEX_HALF: /* not supported */
+       default:
+               dev_err(&adapter->pdev->dev,
+                       "Unsupported Speed/Duplex configuration\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+
+static int igb_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       u32 ctrl, ctrl_ext, rctl, status;
+       u32 wufc = adapter->wol;
+#ifdef CONFIG_PM
+       int retval = 0;
+#endif
+
+       netif_device_detach(netdev);
+
+       if (netif_running(netdev)) {
+               WARN_ON(test_bit(__IGB_RESETTING, &adapter->state));
+               igb_down(adapter);
+               igb_free_irq(adapter);
+       }
+
+#ifdef CONFIG_PM
+       retval = pci_save_state(pdev);
+       if (retval)
+               return retval;
+#endif
+
+       status = rd32(E1000_STATUS);
+       if (status & E1000_STATUS_LU)
+               wufc &= ~E1000_WUFC_LNKC;
+
+       if (wufc) {
+               igb_setup_rctl(adapter);
+               igb_set_multi(netdev);
+
+               /* turn on all-multi mode if wake on multicast is enabled */
+               if (wufc & E1000_WUFC_MC) {
+                       rctl = rd32(E1000_RCTL);
+                       rctl |= E1000_RCTL_MPE;
+                       wr32(E1000_RCTL, rctl);
+               }
+
+               ctrl = rd32(E1000_CTRL);
+               /* advertise wake from D3Cold */
+               #define E1000_CTRL_ADVD3WUC 0x00100000
+               /* phy power management enable */
+               #define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000
+               ctrl |= E1000_CTRL_ADVD3WUC;
+               wr32(E1000_CTRL, ctrl);
+
+               if (adapter->hw.phy.media_type == e1000_media_type_fiber ||
+                  adapter->hw.phy.media_type ==
+                                       e1000_media_type_internal_serdes) {
+                       /* keep the laser running in D3 */
+                       ctrl_ext = rd32(E1000_CTRL_EXT);
+                       ctrl_ext |= E1000_CTRL_EXT_SDP7_DATA;
+                       wr32(E1000_CTRL_EXT, ctrl_ext);
+               }
+
+               /* Allow time for pending master requests to run */
+               igb_disable_pcie_master(&adapter->hw);
+
+               wr32(E1000_WUC, E1000_WUC_PME_EN);
+               wr32(E1000_WUFC, wufc);
+               pci_enable_wake(pdev, PCI_D3hot, 1);
+               pci_enable_wake(pdev, PCI_D3cold, 1);
+       } else {
+               wr32(E1000_WUC, 0);
+               wr32(E1000_WUFC, 0);
+               pci_enable_wake(pdev, PCI_D3hot, 0);
+               pci_enable_wake(pdev, PCI_D3cold, 0);
+       }
+
+       igb_release_manageability(adapter);
+
+       /* make sure adapter isn't asleep if manageability is enabled */
+       if (adapter->en_mng_pt) {
+               pci_enable_wake(pdev, PCI_D3hot, 1);
+               pci_enable_wake(pdev, PCI_D3cold, 1);
+       }
+
+       /* Release control of h/w to f/w.  If f/w is AMT enabled, this
+        * would have already happened in close and is redundant. */
+       igb_release_hw_control(adapter);
+
+       pci_disable_device(pdev);
+
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int igb_resume(struct pci_dev *pdev)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       u32 err;
+
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
+       err = pci_enable_device(pdev);
+       if (err) {
+               dev_err(&pdev->dev,
+                       "igb: Cannot enable PCI device from suspend\n");
+               return err;
+       }
+       pci_set_master(pdev);
+
+       pci_enable_wake(pdev, PCI_D3hot, 0);
+       pci_enable_wake(pdev, PCI_D3cold, 0);
+
+       if (netif_running(netdev)) {
+               err = igb_request_irq(adapter);
+               if (err)
+                       return err;
+       }
+
+       /* e1000_power_up_phy(adapter); */
+
+       igb_reset(adapter);
+       wr32(E1000_WUS, ~0);
+
+       igb_init_manageability(adapter);
+
+       if (netif_running(netdev))
+               igb_up(adapter);
+
+       netif_device_attach(netdev);
+
+       /* let the f/w know that the h/w is now under the control of the
+        * driver. */
+       igb_get_hw_control(adapter);
+
+       return 0;
+}
+#endif
+
+static void igb_shutdown(struct pci_dev *pdev)
+{
+       igb_suspend(pdev, PMSG_SUSPEND);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+static void igb_netpoll(struct net_device *netdev)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       int i;
+       int work_done = 0;
+
+       igb_irq_disable(adapter);
+       for (i = 0; i < adapter->num_tx_queues; i++)
+               igb_clean_tx_irq(adapter, &adapter->tx_ring[i]);
+
+       for (i = 0; i < adapter->num_rx_queues; i++)
+               igb_clean_rx_irq_adv(adapter, &adapter->rx_ring[i],
+                                    &work_done,
+                                    adapter->rx_ring[i].napi.weight);
+
+       igb_irq_enable(adapter);
+}
+#endif /* CONFIG_NET_POLL_CONTROLLER */
+
+/**
+ * igb_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci connection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t igb_io_error_detected(struct pci_dev *pdev,
+                                             pci_channel_state_t state)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct igb_adapter *adapter = netdev_priv(netdev);
+
+       netif_device_detach(netdev);
+
+       if (netif_running(netdev))
+               igb_down(adapter);
+       pci_disable_device(pdev);
+
+       /* Request a slot slot reset. */
+       return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * igb_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot. Implementation
+ * resembles the first-half of the igb_resume routine.
+ */
+static pci_ers_result_t igb_io_slot_reset(struct pci_dev *pdev)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+
+       if (pci_enable_device(pdev)) {
+               dev_err(&pdev->dev,
+                       "Cannot re-enable PCI device after reset.\n");
+               return PCI_ERS_RESULT_DISCONNECT;
+       }
+       pci_set_master(pdev);
+
+       pci_enable_wake(pdev, PCI_D3hot, 0);
+       pci_enable_wake(pdev, PCI_D3cold, 0);
+
+       igb_reset(adapter);
+       wr32(E1000_WUS, ~0);
+
+       return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * igb_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells us that
+ * its OK to resume normal operation. Implementation resembles the
+ * second-half of the igb_resume routine.
+ */
+static void igb_io_resume(struct pci_dev *pdev)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct igb_adapter *adapter = netdev_priv(netdev);
+
+       igb_init_manageability(adapter);
+
+       if (netif_running(netdev)) {
+               if (igb_up(adapter)) {
+                       dev_err(&pdev->dev, "igb_up failed after reset\n");
+                       return;
+               }
+       }
+
+       netif_device_attach(netdev);
+
+       /* let the f/w know that the h/w is now under the control of the
+        * driver. */
+       igb_get_hw_control(adapter);
+
+}
+
+/* igb_main.c */