Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / net / e100.c
index a98e843..31ac001 100644 (file)
@@ -1,25 +1,25 @@
 /*******************************************************************************
 
 /*******************************************************************************
 
-  
-  Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
-  
-  This program is free software; you can redistribute it and/or modify it 
-  under the terms of the GNU General Public License as published by the Free 
-  Software Foundation; either version 2 of the License, or (at your option) 
+
+  Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by the Free
+  Software Foundation; either version 2 of the License, or (at your option)
   any later version.
   any later version.
-  
-  This program is distributed in the hope that 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 
+
+  This program is distributed in the hope that 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.
   more details.
-  
+
   You should have received a copy of the GNU General Public License along with
   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., 59 
+  this program; if not, write to the Free Software Foundation, Inc., 59
   Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-  
+
   The full GNU General Public License is included in this distribution in the
   file called LICENSE.
   The full GNU General Public License is included in this distribution in the
   file called LICENSE.
-  
+
   Contact Information:
   Linux NICS <linux.nics@intel.com>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
   Contact Information:
   Linux NICS <linux.nics@intel.com>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
@@ -87,9 +87,8 @@
  *     cb_to_use is the next CB to use for queuing a command; cb_to_clean
  *     is the next CB to check for completion; cb_to_send is the first
  *     CB to start on in case of a previous failure to resume.  CB clean
  *     cb_to_use is the next CB to use for queuing a command; cb_to_clean
  *     is the next CB to check for completion; cb_to_send is the first
  *     CB to start on in case of a previous failure to resume.  CB clean
- *     up happens in interrupt context in response to a CU interrupt, or
- *     in dev->poll in the case where NAPI is enabled.  cbs_avail keeps
- *     track of number of free CB resources available.
+ *     up happens in interrupt context in response to a CU interrupt.
+ *     cbs_avail keeps track of number of free CB resources available.
  *
  *     Hardware padding of short packets to minimum packet size is
  *     enabled.  82557 pads with 7Eh, while the later controllers pad
  *
  *     Hardware padding of short packets to minimum packet size is
  *     enabled.  82557 pads with 7Eh, while the later controllers pad
  *     replacement RFDs cannot be allocated, or the RU goes non-active,
  *     the RU must be restarted.  Frame arrival generates an interrupt,
  *     and Rx indication and re-allocation happen in the same context,
  *     replacement RFDs cannot be allocated, or the RU goes non-active,
  *     the RU must be restarted.  Frame arrival generates an interrupt,
  *     and Rx indication and re-allocation happen in the same context,
- *     therefore no locking is required.  If NAPI is enabled, this work
- *     happens in dev->poll.  A software-generated interrupt is gen-
- *     erated from the watchdog to recover from a failed allocation
+ *     therefore no locking is required.  A software-generated interrupt
+ *     is generated from the watchdog to recover from a failed allocation
  *     senario where all Rx resources have been indicated and none re-
  *     placed.
  *
  *     senario where all Rx resources have been indicated and none re-
  *     placed.
  *
  *     supported.  Tx Scatter/Gather is not supported.  Jumbo Frames is
  *     not supported (hardware limitation).
  *
  *     supported.  Tx Scatter/Gather is not supported.  Jumbo Frames is
  *     not supported (hardware limitation).
  *
- *     NAPI support is enabled with CONFIG_E100_NAPI.
- *
  *     MagicPacket(tm) WoL support is enabled/disabled via ethtool.
  *
  *     Thanks to JC (jchapman@katalix.com) for helping with
  *     MagicPacket(tm) WoL support is enabled/disabled via ethtool.
  *
  *     Thanks to JC (jchapman@katalix.com) for helping with
  *     TODO:
  *     o several entry points race with dev->close
  *     o check for tx-no-resources/stop Q races with tx clean/wake Q
  *     TODO:
  *     o several entry points race with dev->close
  *     o check for tx-no-resources/stop Q races with tx clean/wake Q
+ *
+ *     FIXES:
+ * 2005/12/02 - Michael O'Donnell <Michael.ODonnell at stratus dot com>
+ *     - Stratus87247: protect MDI control register manipulations
  */
 
 #include <linux/config.h>
  */
 
 #include <linux/config.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/mii.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/mii.h>
 
 
 #define DRV_NAME               "e100"
 
 
 #define DRV_NAME               "e100"
-#define DRV_VERSION            "3.0.17"
+#define DRV_EXT                "-NAPI"
+#define DRV_VERSION            "3.5.10-k2"DRV_EXT
 #define DRV_DESCRIPTION                "Intel(R) PRO/100 Network Driver"
 #define DRV_DESCRIPTION                "Intel(R) PRO/100 Network Driver"
-#define DRV_COPYRIGHT          "Copyright(c) 1999-2004 Intel Corporation"
+#define DRV_COPYRIGHT          "Copyright(c) 1999-2005 Intel Corporation"
 #define PFX                    DRV_NAME ": "
 
 #define E100_WATCHDOG_PERIOD   (2 * HZ)
 #define PFX                    DRV_NAME ": "
 
 #define E100_WATCHDOG_PERIOD   (2 * HZ)
 MODULE_DESCRIPTION(DRV_DESCRIPTION);
 MODULE_AUTHOR(DRV_COPYRIGHT);
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION(DRV_DESCRIPTION);
 MODULE_AUTHOR(DRV_COPYRIGHT);
 MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
 
 static int debug = 3;
 module_param(debug, int, 0);
 
 static int debug = 3;
 module_param(debug, int, 0);
@@ -201,6 +204,9 @@ static struct pci_device_id e100_id_table[] = {
        INTEL_8255X_ETHERNET_DEVICE(0x1053, 5),
        INTEL_8255X_ETHERNET_DEVICE(0x1054, 5),
        INTEL_8255X_ETHERNET_DEVICE(0x1055, 5),
        INTEL_8255X_ETHERNET_DEVICE(0x1053, 5),
        INTEL_8255X_ETHERNET_DEVICE(0x1054, 5),
        INTEL_8255X_ETHERNET_DEVICE(0x1055, 5),
+       INTEL_8255X_ETHERNET_DEVICE(0x1056, 5),
+       INTEL_8255X_ETHERNET_DEVICE(0x1057, 5),
+       INTEL_8255X_ETHERNET_DEVICE(0x1059, 0),
        INTEL_8255X_ETHERNET_DEVICE(0x1064, 6),
        INTEL_8255X_ETHERNET_DEVICE(0x1065, 6),
        INTEL_8255X_ETHERNET_DEVICE(0x1066, 6),
        INTEL_8255X_ETHERNET_DEVICE(0x1064, 6),
        INTEL_8255X_ETHERNET_DEVICE(0x1065, 6),
        INTEL_8255X_ETHERNET_DEVICE(0x1066, 6),
@@ -209,12 +215,17 @@ static struct pci_device_id e100_id_table[] = {
        INTEL_8255X_ETHERNET_DEVICE(0x1069, 6),
        INTEL_8255X_ETHERNET_DEVICE(0x106A, 6),
        INTEL_8255X_ETHERNET_DEVICE(0x106B, 6),
        INTEL_8255X_ETHERNET_DEVICE(0x1069, 6),
        INTEL_8255X_ETHERNET_DEVICE(0x106A, 6),
        INTEL_8255X_ETHERNET_DEVICE(0x106B, 6),
-       INTEL_8255X_ETHERNET_DEVICE(0x1059, 0),
+       INTEL_8255X_ETHERNET_DEVICE(0x1091, 7),
+       INTEL_8255X_ETHERNET_DEVICE(0x1092, 7),
+       INTEL_8255X_ETHERNET_DEVICE(0x1093, 7),
+       INTEL_8255X_ETHERNET_DEVICE(0x1094, 7),
+       INTEL_8255X_ETHERNET_DEVICE(0x1095, 7),
        INTEL_8255X_ETHERNET_DEVICE(0x1209, 0),
        INTEL_8255X_ETHERNET_DEVICE(0x1229, 0),
        INTEL_8255X_ETHERNET_DEVICE(0x2449, 2),
        INTEL_8255X_ETHERNET_DEVICE(0x2459, 2),
        INTEL_8255X_ETHERNET_DEVICE(0x245D, 2),
        INTEL_8255X_ETHERNET_DEVICE(0x1209, 0),
        INTEL_8255X_ETHERNET_DEVICE(0x1229, 0),
        INTEL_8255X_ETHERNET_DEVICE(0x2449, 2),
        INTEL_8255X_ETHERNET_DEVICE(0x2459, 2),
        INTEL_8255X_ETHERNET_DEVICE(0x245D, 2),
+       INTEL_8255X_ETHERNET_DEVICE(0x27DC, 7),
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, e100_id_table);
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, e100_id_table);
@@ -242,6 +253,7 @@ enum phy {
        phy_nsc_tx   = 0x5C002000,
        phy_82562_et = 0x033002A8,
        phy_82562_em = 0x032002A8,
        phy_nsc_tx   = 0x5C002000,
        phy_82562_et = 0x033002A8,
        phy_82562_em = 0x032002A8,
+       phy_82562_ek = 0x031002A8,
        phy_82562_eh = 0x017002A8,
        phy_unknown  = 0xFFFFFFFF,
 };
        phy_82562_eh = 0x017002A8,
        phy_unknown  = 0xFFFFFFFF,
 };
@@ -268,6 +280,12 @@ enum scb_status {
        rus_mask         = 0x3C,
 };
 
        rus_mask         = 0x3C,
 };
 
+enum ru_state  {
+       RU_SUSPENDED = 0,
+       RU_RUNNING       = 1,
+       RU_UNINITIALIZED = -1,
+};
+
 enum scb_stat_ack {
        stat_ack_not_ours    = 0x00,
        stat_ack_sw_gen      = 0x04,
 enum scb_stat_ack {
        stat_ack_not_ours    = 0x00,
        stat_ack_sw_gen      = 0x04,
@@ -302,7 +320,7 @@ enum cuc_dump {
        cuc_dump_complete       = 0x0000A005,
        cuc_dump_reset_complete = 0x0000A007,
 };
        cuc_dump_complete       = 0x0000A005,
        cuc_dump_reset_complete = 0x0000A007,
 };
-               
+
 enum port {
        software_reset  = 0x0000,
        selftest        = 0x0001,
 enum port {
        software_reset  = 0x0000,
        selftest        = 0x0001,
@@ -330,11 +348,16 @@ enum eeprom_op {
 };
 
 enum eeprom_offsets {
 };
 
 enum eeprom_offsets {
+       eeprom_cnfg_mdix  = 0x03,
        eeprom_id         = 0x0A,
        eeprom_config_asf = 0x0D,
        eeprom_smbus_addr = 0x90,
 };
 
        eeprom_id         = 0x0A,
        eeprom_config_asf = 0x0D,
        eeprom_smbus_addr = 0x90,
 };
 
+enum eeprom_cnfg_mdix {
+       eeprom_mdix_enabled = 0x0080,
+};
+
 enum eeprom_id {
        eeprom_id_wol = 0x0020,
 };
 enum eeprom_id {
        eeprom_id_wol = 0x0020,
 };
@@ -350,10 +373,12 @@ enum cb_status {
 };
 
 enum cb_command {
 };
 
 enum cb_command {
+       cb_nop    = 0x0000,
        cb_iaaddr = 0x0001,
        cb_config = 0x0002,
        cb_multi  = 0x0003,
        cb_tx     = 0x0004,
        cb_iaaddr = 0x0001,
        cb_config = 0x0002,
        cb_multi  = 0x0003,
        cb_tx     = 0x0004,
+       cb_ucode  = 0x0005,
        cb_dump   = 0x0006,
        cb_tx_sf  = 0x0008,
        cb_cid    = 0x1f00,
        cb_dump   = 0x0006,
        cb_tx_sf  = 0x0008,
        cb_cid    = 0x1f00,
@@ -428,12 +453,14 @@ struct multi {
 };
 
 /* Important: keep total struct u32-aligned */
 };
 
 /* Important: keep total struct u32-aligned */
+#define UCODE_SIZE                     134
 struct cb {
        u16 status;
        u16 command;
        u32 link;
        union {
                u8 iaaddr[ETH_ALEN];
 struct cb {
        u16 status;
        u16 command;
        u32 link;
        union {
                u8 iaaddr[ETH_ALEN];
+               u32 ucode[UCODE_SIZE];
                struct config config;
                struct multi multi;
                struct {
                struct config config;
                struct multi multi;
                struct {
@@ -500,11 +527,11 @@ struct nic {
        struct rx *rx_to_use;
        struct rx *rx_to_clean;
        struct rfd blank_rfd;
        struct rx *rx_to_use;
        struct rx *rx_to_clean;
        struct rfd blank_rfd;
-       int ru_running;
+       enum ru_state ru_running;
 
        spinlock_t cb_lock                      ____cacheline_aligned;
        spinlock_t cmd_lock;
 
        spinlock_t cb_lock                      ____cacheline_aligned;
        spinlock_t cmd_lock;
-       struct csr *csr;
+       struct csr __iomem *csr;
        enum scb_cmd_lo cuc_cmd;
        unsigned int cbs_avail;
        struct cb *cbs;
        enum scb_cmd_lo cuc_cmd;
        unsigned int cbs_avail;
        struct cb *cbs;
@@ -529,6 +556,7 @@ struct nic {
        struct timer_list watchdog;
        struct timer_list blink_timer;
        struct mii_if_info mii;
        struct timer_list watchdog;
        struct timer_list blink_timer;
        struct mii_if_info mii;
+       struct work_struct tx_timeout_task;
        enum loopback loopback;
 
        struct mem *mem;
        enum loopback loopback;
 
        struct mem *mem;
@@ -548,12 +576,13 @@ struct nic {
        u32 rx_fc_pause;
        u32 rx_fc_unsupported;
        u32 rx_tco_frames;
        u32 rx_fc_pause;
        u32 rx_fc_unsupported;
        u32 rx_tco_frames;
+       u32 rx_over_length_errors;
 
        u8 rev_id;
        u16 leds;
        u16 eeprom_wc;
        u16 eeprom[256];
 
        u8 rev_id;
        u16 leds;
        u16 eeprom_wc;
        u16 eeprom[256];
-       u32 pm_state[16];
+       spinlock_t mdio_lock;
 };
 
 static inline void e100_write_flush(struct nic *nic)
 };
 
 static inline void e100_write_flush(struct nic *nic)
@@ -563,16 +592,24 @@ static inline void e100_write_flush(struct nic *nic)
        (void)readb(&nic->csr->scb.status);
 }
 
        (void)readb(&nic->csr->scb.status);
 }
 
-static inline void e100_enable_irq(struct nic *nic)
+static void e100_enable_irq(struct nic *nic)
 {
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&nic->cmd_lock, flags);
        writeb(irq_mask_none, &nic->csr->scb.cmd_hi);
        e100_write_flush(nic);
        writeb(irq_mask_none, &nic->csr->scb.cmd_hi);
        e100_write_flush(nic);
+       spin_unlock_irqrestore(&nic->cmd_lock, flags);
 }
 
 }
 
-static inline void e100_disable_irq(struct nic *nic)
+static void e100_disable_irq(struct nic *nic)
 {
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&nic->cmd_lock, flags);
        writeb(irq_mask_all, &nic->csr->scb.cmd_hi);
        e100_write_flush(nic);
        writeb(irq_mask_all, &nic->csr->scb.cmd_hi);
        e100_write_flush(nic);
+       spin_unlock_irqrestore(&nic->cmd_lock, flags);
 }
 
 static void e100_hw_reset(struct nic *nic)
 }
 
 static void e100_hw_reset(struct nic *nic)
@@ -586,16 +623,6 @@ static void e100_hw_reset(struct nic *nic)
        writel(software_reset, &nic->csr->port);
        e100_write_flush(nic); udelay(20);
 
        writel(software_reset, &nic->csr->port);
        e100_write_flush(nic); udelay(20);
 
-       /* TCO workaround - 82559 and greater */
-       if(nic->mac >= mac_82559_D101M) {
-               /* Issue a redundant CU load base without setting
-                * general pointer, and without waiting for scb to
-                * clear.  This gets us into post-driver.  Finally,
-                * wait 20 msec for reset to take effect. */
-               writeb(cuc_load_base, &nic->csr->scb.cmd_lo);
-               mdelay(20);
-       }
-
        /* Mask off our interrupt line - it's unmasked after reset */
        e100_disable_irq(nic);
 }
        /* Mask off our interrupt line - it's unmasked after reset */
        e100_disable_irq(nic);
 }
@@ -613,8 +640,7 @@ static int e100_self_test(struct nic *nic)
        writel(selftest | dma_addr, &nic->csr->port);
        e100_write_flush(nic);
        /* Wait 10 msec for self-test to complete */
        writel(selftest | dma_addr, &nic->csr->port);
        e100_write_flush(nic);
        /* Wait 10 msec for self-test to complete */
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       schedule_timeout(HZ / 100 + 1);
+       msleep(10);
 
        /* Interrupts are enabled after self-test */
        e100_disable_irq(nic);
 
        /* Interrupts are enabled after self-test */
        e100_disable_irq(nic);
@@ -641,7 +667,8 @@ static void e100_eeprom_write(struct nic *nic, u16 addr_len, u16 addr, u16 data)
 
        /* Three cmds: write/erase enable, write data, write/erase disable */
        cmd_addr_data[0] = op_ewen << (addr_len - 2);
 
        /* Three cmds: write/erase enable, write data, write/erase disable */
        cmd_addr_data[0] = op_ewen << (addr_len - 2);
-       cmd_addr_data[1] = (((op_write << addr_len) | addr) << 16) | data;
+       cmd_addr_data[1] = (((op_write << addr_len) | addr) << 16) |
+               cpu_to_le16(data);
        cmd_addr_data[2] = op_ewds << (addr_len - 2);
 
        /* Bit-bang cmds to write word to eeprom */
        cmd_addr_data[2] = op_ewds << (addr_len - 2);
 
        /* Bit-bang cmds to write word to eeprom */
@@ -661,14 +688,12 @@ static void e100_eeprom_write(struct nic *nic, u16 addr_len, u16 addr, u16 data)
                        e100_write_flush(nic); udelay(4);
                }
                /* Wait 10 msec for cmd to complete */
                        e100_write_flush(nic); udelay(4);
                }
                /* Wait 10 msec for cmd to complete */
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(HZ / 100 + 1);
+               msleep(10);
 
                /* Chip deselect */
                writeb(0, &nic->csr->eeprom_ctrl_lo);
                e100_write_flush(nic); udelay(4);
        }
 
                /* Chip deselect */
                writeb(0, &nic->csr->eeprom_ctrl_lo);
                e100_write_flush(nic); udelay(4);
        }
-
 };
 
 /* General technique stolen from the eepro100 driver - very clever */
 };
 
 /* General technique stolen from the eepro100 driver - very clever */
@@ -690,10 +715,10 @@ static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr)
                ctrl = (cmd_addr_data & (1 << i)) ? eecs | eedi : eecs;
                writeb(ctrl, &nic->csr->eeprom_ctrl_lo);
                e100_write_flush(nic); udelay(4);
                ctrl = (cmd_addr_data & (1 << i)) ? eecs | eedi : eecs;
                writeb(ctrl, &nic->csr->eeprom_ctrl_lo);
                e100_write_flush(nic); udelay(4);
-               
+
                writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
                e100_write_flush(nic); udelay(4);
                writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
                e100_write_flush(nic); udelay(4);
-               
+
                /* Eeprom drives a dummy zero to EEDO after receiving
                 * complete address.  Use this to adjust addr_len. */
                ctrl = readb(&nic->csr->eeprom_ctrl_lo);
                /* Eeprom drives a dummy zero to EEDO after receiving
                 * complete address.  Use this to adjust addr_len. */
                ctrl = readb(&nic->csr->eeprom_ctrl_lo);
@@ -701,7 +726,7 @@ static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr)
                        *addr_len -= (i - 16);
                        i = 17;
                }
                        *addr_len -= (i - 16);
                        i = 17;
                }
-               
+
                data = (data << 1) | (ctrl & eedo ? 1 : 0);
        }
 
                data = (data << 1) | (ctrl & eedo ? 1 : 0);
        }
 
@@ -709,7 +734,7 @@ static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr)
        writeb(0, &nic->csr->eeprom_ctrl_lo);
        e100_write_flush(nic); udelay(4);
 
        writeb(0, &nic->csr->eeprom_ctrl_lo);
        e100_write_flush(nic); udelay(4);
 
-       return data;
+       return le16_to_cpu(data);
 };
 
 /* Load entire EEPROM image into driver cache and validate checksum */
 };
 
 /* Load entire EEPROM image into driver cache and validate checksum */
@@ -724,12 +749,12 @@ static int e100_eeprom_load(struct nic *nic)
        for(addr = 0; addr < nic->eeprom_wc; addr++) {
                nic->eeprom[addr] = e100_eeprom_read(nic, &addr_len, addr);
                if(addr < nic->eeprom_wc - 1)
        for(addr = 0; addr < nic->eeprom_wc; addr++) {
                nic->eeprom[addr] = e100_eeprom_read(nic, &addr_len, addr);
                if(addr < nic->eeprom_wc - 1)
-                       checksum += nic->eeprom[addr];
+                       checksum += cpu_to_le16(nic->eeprom[addr]);
        }
 
        /* The checksum, stored in the last word, is calculated such that
         * the sum of words should be 0xBABA */
        }
 
        /* The checksum, stored in the last word, is calculated such that
         * the sum of words should be 0xBABA */
-       checksum = 0xBABA - checksum;
+       checksum = le16_to_cpu(0xBABA - checksum);
        if(checksum != nic->eeprom[nic->eeprom_wc - 1]) {
                DPRINTK(PROBE, ERR, "EEPROM corrupted\n");
                return -EAGAIN;
        if(checksum != nic->eeprom[nic->eeprom_wc - 1]) {
                DPRINTK(PROBE, ERR, "EEPROM corrupted\n");
                return -EAGAIN;
@@ -756,15 +781,17 @@ static int e100_eeprom_save(struct nic *nic, u16 start, u16 count)
        /* The checksum, stored in the last word, is calculated such that
         * the sum of words should be 0xBABA */
        for(addr = 0; addr < nic->eeprom_wc - 1; addr++)
        /* The checksum, stored in the last word, is calculated such that
         * the sum of words should be 0xBABA */
        for(addr = 0; addr < nic->eeprom_wc - 1; addr++)
-               checksum += nic->eeprom[addr];
-       nic->eeprom[nic->eeprom_wc - 1] = 0xBABA - checksum;
-       e100_eeprom_write(nic, addr_len, nic->eeprom_wc - 1, 0xBABA - checksum);
+               checksum += cpu_to_le16(nic->eeprom[addr]);
+       nic->eeprom[nic->eeprom_wc - 1] = le16_to_cpu(0xBABA - checksum);
+       e100_eeprom_write(nic, addr_len, nic->eeprom_wc - 1,
+               nic->eeprom[nic->eeprom_wc - 1]);
 
        return 0;
 }
 
 
        return 0;
 }
 
-#define E100_WAIT_SCB_TIMEOUT 40
-static inline int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr)
+#define E100_WAIT_SCB_TIMEOUT 20000 /* we might have to wait 100ms!!! */
+#define E100_WAIT_SCB_FAST 20       /* delay like the old code */
+static int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr)
 {
        unsigned long flags;
        unsigned int i;
 {
        unsigned long flags;
        unsigned int i;
@@ -777,7 +804,7 @@ static inline int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr)
                if(likely(!readb(&nic->csr->scb.cmd_lo)))
                        break;
                cpu_relax();
                if(likely(!readb(&nic->csr->scb.cmd_lo)))
                        break;
                cpu_relax();
-               if(unlikely(i > (E100_WAIT_SCB_TIMEOUT >> 1)))
+               if(unlikely(i > E100_WAIT_SCB_FAST))
                        udelay(5);
        }
        if(unlikely(i == E100_WAIT_SCB_TIMEOUT)) {
                        udelay(5);
        }
        if(unlikely(i == E100_WAIT_SCB_TIMEOUT)) {
@@ -795,7 +822,7 @@ err_unlock:
        return err;
 }
 
        return err;
 }
 
-static inline int e100_exec_cb(struct nic *nic, struct sk_buff *skb,
+static int e100_exec_cb(struct nic *nic, struct sk_buff *skb,
        void (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *))
 {
        struct cb *cb;
        void (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *))
 {
        struct cb *cb;
@@ -826,13 +853,17 @@ static inline int e100_exec_cb(struct nic *nic, struct sk_buff *skb,
        cb->prev->command &= cpu_to_le16(~cb_s);
 
        while(nic->cb_to_send != nic->cb_to_use) {
        cb->prev->command &= cpu_to_le16(~cb_s);
 
        while(nic->cb_to_send != nic->cb_to_use) {
-               if(unlikely((err = e100_exec_cmd(nic, nic->cuc_cmd,
-                       nic->cb_to_send->dma_addr)))) {
+               if(unlikely(e100_exec_cmd(nic, nic->cuc_cmd,
+                       nic->cb_to_send->dma_addr))) {
                        /* Ok, here's where things get sticky.  It's
                         * possible that we can't schedule the command
                         * because the controller is too busy, so
                         * let's just queue the command and try again
                         * when another command is scheduled. */
                        /* Ok, here's where things get sticky.  It's
                         * possible that we can't schedule the command
                         * because the controller is too busy, so
                         * let's just queue the command and try again
                         * when another command is scheduled. */
+                       if(err == -ENOSPC) {
+                               //request a reset
+                               schedule_work(&nic->tx_timeout_task);
+                       }
                        break;
                } else {
                        nic->cuc_cmd = cuc_resume;
                        break;
                } else {
                        nic->cuc_cmd = cuc_resume;
@@ -850,15 +881,35 @@ static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data)
 {
        u32 data_out = 0;
        unsigned int i;
 {
        u32 data_out = 0;
        unsigned int i;
+       unsigned long flags;
+
 
 
+       /*
+        * Stratus87247: we shouldn't be writing the MDI control
+        * register until the Ready bit shows True.  Also, since
+        * manipulation of the MDI control registers is a multi-step
+        * procedure it should be done under lock.
+        */
+       spin_lock_irqsave(&nic->mdio_lock, flags);
+       for (i = 100; i; --i) {
+               if (readl(&nic->csr->mdi_ctrl) & mdi_ready)
+                       break;
+               udelay(20);
+       }
+       if (unlikely(!i)) {
+               printk("e100.mdio_ctrl(%s) won't go Ready\n",
+                       nic->netdev->name );
+               spin_unlock_irqrestore(&nic->mdio_lock, flags);
+               return 0;               /* No way to indicate timeout error */
+       }
        writel((reg << 16) | (addr << 21) | dir | data, &nic->csr->mdi_ctrl);
 
        writel((reg << 16) | (addr << 21) | dir | data, &nic->csr->mdi_ctrl);
 
-       for(i = 0; i < 100; i++) {
+       for (i = 0; i < 100; i++) {
                udelay(20);
                udelay(20);
-               if((data_out = readl(&nic->csr->mdi_ctrl)) & mdi_ready)
+               if ((data_out = readl(&nic->csr->mdi_ctrl)) & mdi_ready)
                        break;
        }
                        break;
        }
-
+       spin_unlock_irqrestore(&nic->mdio_lock, flags);
        DPRINTK(HW, DEBUG,
                "%s:addr=%d, reg=%d, data_in=0x%04X, data_out=0x%04X\n",
                dir == mdi_read ? "READ" : "WRITE", addr, reg, data, data_out);
        DPRINTK(HW, DEBUG,
                "%s:addr=%d, reg=%d, data_in=0x%04X, data_out=0x%04X\n",
                dir == mdi_read ? "READ" : "WRITE", addr, reg, data, data_out);
@@ -867,18 +918,18 @@ static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data)
 
 static int mdio_read(struct net_device *netdev, int addr, int reg)
 {
 
 static int mdio_read(struct net_device *netdev, int addr, int reg)
 {
-       return mdio_ctrl(netdev->priv, addr, mdi_read, reg, 0);
+       return mdio_ctrl(netdev_priv(netdev), addr, mdi_read, reg, 0);
 }
 
 static void mdio_write(struct net_device *netdev, int addr, int reg, int data)
 {
 }
 
 static void mdio_write(struct net_device *netdev, int addr, int reg, int data)
 {
-       mdio_ctrl(netdev->priv, addr, mdi_write, reg, data);
+       mdio_ctrl(netdev_priv(netdev), addr, mdi_write, reg, data);
 }
 
 static void e100_get_defaults(struct nic *nic)
 {
 }
 
 static void e100_get_defaults(struct nic *nic)
 {
-       struct param_range rfds = { .min = 64, .max = 256, .count = 64 };
-       struct param_range cbs  = { .min = 64, .max = 256, .count = 64 };
+       struct param_range rfds = { .min = 16, .max = 256, .count = 256 };
+       struct param_range cbs  = { .min = 64, .max = 256, .count = 128 };
 
        pci_read_config_byte(nic->pdev, PCI_REVISION_ID, &nic->rev_id);
        /* MAC type is encoded as rev ID; exception: ICH is treated as 82559 */
 
        pci_read_config_byte(nic->pdev, PCI_REVISION_ID, &nic->rev_id);
        /* MAC type is encoded as rev ID; exception: ICH is treated as 82559 */
@@ -892,8 +943,9 @@ static void e100_get_defaults(struct nic *nic)
        /* Quadwords to DMA into FIFO before starting frame transmit */
        nic->tx_threshold = 0xE0;
 
        /* Quadwords to DMA into FIFO before starting frame transmit */
        nic->tx_threshold = 0xE0;
 
-       nic->tx_command = cpu_to_le16(cb_tx | cb_i | cb_tx_sf |
-               ((nic->mac >= mac_82558_D101_A4) ? cb_cid : 0));
+       /* no interrupt for every tx completion, delay = 256us if not 557*/
+       nic->tx_command = cpu_to_le16(cb_tx | cb_tx_sf |
+               ((nic->mac >= mac_82558_D101_A4) ? cb_cid : cb_i));
 
        /* Template for a freshly allocated RFD */
        nic->blank_rfd.command = cpu_to_le16(cb_el);
 
        /* Template for a freshly allocated RFD */
        nic->blank_rfd.command = cpu_to_le16(cb_el);
@@ -957,7 +1009,8 @@ static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb)
        if(nic->flags & multicast_all)
                config->multicast_all = 0x1;            /* 1=accept, 0=no */
 
        if(nic->flags & multicast_all)
                config->multicast_all = 0x1;            /* 1=accept, 0=no */
 
-       if(!(nic->flags & wol_magic))
+       /* disable WoL when up */
+       if(netif_running(nic->netdev) || !(nic->flags & wol_magic))
                config->magic_packet_disable = 0x1;     /* 1=off, 0=on */
 
        if(nic->mac >= mac_82558_D101_A4) {
                config->magic_packet_disable = 0x1;     /* 1=off, 0=on */
 
        if(nic->mac >= mac_82558_D101_A4) {
@@ -979,6 +1032,300 @@ static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb)
                c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]);
 }
 
                c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]);
 }
 
+/********************************************************/
+/*  Micro code for 8086:1229 Rev 8                      */
+/********************************************************/
+
+/*  Parameter values for the D101M B-step  */
+#define D101M_CPUSAVER_TIMER_DWORD             78
+#define D101M_CPUSAVER_BUNDLE_DWORD            65
+#define D101M_CPUSAVER_MIN_SIZE_DWORD          126
+
+#define D101M_B_RCVBUNDLE_UCODE \
+{\
+0x00550215, 0xFFFF0437, 0xFFFFFFFF, 0x06A70789, 0xFFFFFFFF, 0x0558FFFF, \
+0x000C0001, 0x00101312, 0x000C0008, 0x00380216, \
+0x0010009C, 0x00204056, 0x002380CC, 0x00380056, \
+0x0010009C, 0x00244C0B, 0x00000800, 0x00124818, \
+0x00380438, 0x00000000, 0x00140000, 0x00380555, \
+0x00308000, 0x00100662, 0x00100561, 0x000E0408, \
+0x00134861, 0x000C0002, 0x00103093, 0x00308000, \
+0x00100624, 0x00100561, 0x000E0408, 0x00100861, \
+0x000C007E, 0x00222C21, 0x000C0002, 0x00103093, \
+0x00380C7A, 0x00080000, 0x00103090, 0x00380C7A, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0010009C, 0x00244C2D, 0x00010004, 0x00041000, \
+0x003A0437, 0x00044010, 0x0038078A, 0x00000000, \
+0x00100099, 0x00206C7A, 0x0010009C, 0x00244C48, \
+0x00130824, 0x000C0001, 0x00101213, 0x00260C75, \
+0x00041000, 0x00010004, 0x00130826, 0x000C0006, \
+0x002206A8, 0x0013C926, 0x00101313, 0x003806A8, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00080600, 0x00101B10, 0x00050004, 0x00100826, \
+0x00101210, 0x00380C34, 0x00000000, 0x00000000, \
+0x0021155B, 0x00100099, 0x00206559, 0x0010009C, \
+0x00244559, 0x00130836, 0x000C0000, 0x00220C62, \
+0x000C0001, 0x00101B13, 0x00229C0E, 0x00210C0E, \
+0x00226C0E, 0x00216C0E, 0x0022FC0E, 0x00215C0E, \
+0x00214C0E, 0x00380555, 0x00010004, 0x00041000, \
+0x00278C67, 0x00040800, 0x00018100, 0x003A0437, \
+0x00130826, 0x000C0001, 0x00220559, 0x00101313, \
+0x00380559, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00130831, 0x0010090B, 0x00124813, \
+0x000CFF80, 0x002606AB, 0x00041000, 0x00010004, \
+0x003806A8, 0x00000000, 0x00000000, 0x00000000, \
+}
+
+/********************************************************/
+/*  Micro code for 8086:1229 Rev 9                      */
+/********************************************************/
+
+/*  Parameter values for the D101S  */
+#define D101S_CPUSAVER_TIMER_DWORD             78
+#define D101S_CPUSAVER_BUNDLE_DWORD            67
+#define D101S_CPUSAVER_MIN_SIZE_DWORD          128
+
+#define D101S_RCVBUNDLE_UCODE \
+{\
+0x00550242, 0xFFFF047E, 0xFFFFFFFF, 0x06FF0818, 0xFFFFFFFF, 0x05A6FFFF, \
+0x000C0001, 0x00101312, 0x000C0008, 0x00380243, \
+0x0010009C, 0x00204056, 0x002380D0, 0x00380056, \
+0x0010009C, 0x00244F8B, 0x00000800, 0x00124818, \
+0x0038047F, 0x00000000, 0x00140000, 0x003805A3, \
+0x00308000, 0x00100610, 0x00100561, 0x000E0408, \
+0x00134861, 0x000C0002, 0x00103093, 0x00308000, \
+0x00100624, 0x00100561, 0x000E0408, 0x00100861, \
+0x000C007E, 0x00222FA1, 0x000C0002, 0x00103093, \
+0x00380F90, 0x00080000, 0x00103090, 0x00380F90, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0010009C, 0x00244FAD, 0x00010004, 0x00041000, \
+0x003A047E, 0x00044010, 0x00380819, 0x00000000, \
+0x00100099, 0x00206FFD, 0x0010009A, 0x0020AFFD, \
+0x0010009C, 0x00244FC8, 0x00130824, 0x000C0001, \
+0x00101213, 0x00260FF7, 0x00041000, 0x00010004, \
+0x00130826, 0x000C0006, 0x00220700, 0x0013C926, \
+0x00101313, 0x00380700, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00080600, 0x00101B10, 0x00050004, 0x00100826, \
+0x00101210, 0x00380FB6, 0x00000000, 0x00000000, \
+0x002115A9, 0x00100099, 0x002065A7, 0x0010009A, \
+0x0020A5A7, 0x0010009C, 0x002445A7, 0x00130836, \
+0x000C0000, 0x00220FE4, 0x000C0001, 0x00101B13, \
+0x00229F8E, 0x00210F8E, 0x00226F8E, 0x00216F8E, \
+0x0022FF8E, 0x00215F8E, 0x00214F8E, 0x003805A3, \
+0x00010004, 0x00041000, 0x00278FE9, 0x00040800, \
+0x00018100, 0x003A047E, 0x00130826, 0x000C0001, \
+0x002205A7, 0x00101313, 0x003805A7, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00130831, \
+0x0010090B, 0x00124813, 0x000CFF80, 0x00260703, \
+0x00041000, 0x00010004, 0x00380700  \
+}
+
+/********************************************************/
+/*  Micro code for the 8086:1229 Rev F/10               */
+/********************************************************/
+
+/*  Parameter values for the D102 E-step  */
+#define D102_E_CPUSAVER_TIMER_DWORD            42
+#define D102_E_CPUSAVER_BUNDLE_DWORD           54
+#define D102_E_CPUSAVER_MIN_SIZE_DWORD         46
+
+#define     D102_E_RCVBUNDLE_UCODE \
+{\
+0x007D028F, 0x0E4204F9, 0x14ED0C85, 0x14FA14E9, 0x0EF70E36, 0x1FFF1FFF, \
+0x00E014B9, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014BD, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014D5, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014C1, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014C8, 0x00000000, 0x00000000, 0x00000000, \
+0x00200600, 0x00E014EE, 0x00000000, 0x00000000, \
+0x0030FF80, 0x00940E46, 0x00038200, 0x00102000, \
+0x00E00E43, 0x00000000, 0x00000000, 0x00000000, \
+0x00300006, 0x00E014FB, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00906E41, 0x00800E3C, 0x00E00E39, 0x00000000, \
+0x00906EFD, 0x00900EFD, 0x00E00EF8, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+}
+
+static void e100_setup_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb)
+{
+/* *INDENT-OFF* */
+       static struct {
+               u32 ucode[UCODE_SIZE + 1];
+               u8 mac;
+               u8 timer_dword;
+               u8 bundle_dword;
+               u8 min_size_dword;
+       } ucode_opts[] = {
+               { D101M_B_RCVBUNDLE_UCODE,
+                 mac_82559_D101M,
+                 D101M_CPUSAVER_TIMER_DWORD,
+                 D101M_CPUSAVER_BUNDLE_DWORD,
+                 D101M_CPUSAVER_MIN_SIZE_DWORD },
+               { D101S_RCVBUNDLE_UCODE,
+                 mac_82559_D101S,
+                 D101S_CPUSAVER_TIMER_DWORD,
+                 D101S_CPUSAVER_BUNDLE_DWORD,
+                 D101S_CPUSAVER_MIN_SIZE_DWORD },
+               { D102_E_RCVBUNDLE_UCODE,
+                 mac_82551_F,
+                 D102_E_CPUSAVER_TIMER_DWORD,
+                 D102_E_CPUSAVER_BUNDLE_DWORD,
+                 D102_E_CPUSAVER_MIN_SIZE_DWORD },
+               { D102_E_RCVBUNDLE_UCODE,
+                 mac_82551_10,
+                 D102_E_CPUSAVER_TIMER_DWORD,
+                 D102_E_CPUSAVER_BUNDLE_DWORD,
+                 D102_E_CPUSAVER_MIN_SIZE_DWORD },
+               { {0}, 0, 0, 0, 0}
+       }, *opts;
+/* *INDENT-ON* */
+
+/*************************************************************************
+*  CPUSaver parameters
+*
+*  All CPUSaver parameters are 16-bit literals that are part of a
+*  "move immediate value" instruction.  By changing the value of
+*  the literal in the instruction before the code is loaded, the
+*  driver can change the algorithm.
+*
+*  INTDELAY - This loads the dead-man timer with its inital value.
+*    When this timer expires the interrupt is asserted, and the
+*    timer is reset each time a new packet is received.  (see
+*    BUNDLEMAX below to set the limit on number of chained packets)
+*    The current default is 0x600 or 1536.  Experiments show that
+*    the value should probably stay within the 0x200 - 0x1000.
+*
+*  BUNDLEMAX -
+*    This sets the maximum number of frames that will be bundled.  In
+*    some situations, such as the TCP windowing algorithm, it may be
+*    better to limit the growth of the bundle size than let it go as
+*    high as it can, because that could cause too much added latency.
+*    The default is six, because this is the number of packets in the
+*    default TCP window size.  A value of 1 would make CPUSaver indicate
+*    an interrupt for every frame received.  If you do not want to put
+*    a limit on the bundle size, set this value to xFFFF.
+*
+*  BUNDLESMALL -
+*    This contains a bit-mask describing the minimum size frame that
+*    will be bundled.  The default masks the lower 7 bits, which means
+*    that any frame less than 128 bytes in length will not be bundled,
+*    but will instead immediately generate an interrupt.  This does
+*    not affect the current bundle in any way.  Any frame that is 128
+*    bytes or large will be bundled normally.  This feature is meant
+*    to provide immediate indication of ACK frames in a TCP environment.
+*    Customers were seeing poor performance when a machine with CPUSaver
+*    enabled was sending but not receiving.  The delay introduced when
+*    the ACKs were received was enough to reduce total throughput, because
+*    the sender would sit idle until the ACK was finally seen.
+*
+*    The current default is 0xFF80, which masks out the lower 7 bits.
+*    This means that any frame which is x7F (127) bytes or smaller
+*    will cause an immediate interrupt.  Because this value must be a
+*    bit mask, there are only a few valid values that can be used.  To
+*    turn this feature off, the driver can write the value xFFFF to the
+*    lower word of this instruction (in the same way that the other
+*    parameters are used).  Likewise, a value of 0xF800 (2047) would
+*    cause an interrupt to be generated for every frame, because all
+*    standard Ethernet frames are <= 2047 bytes in length.
+*************************************************************************/
+
+/* if you wish to disable the ucode functionality, while maintaining the
+ * workarounds it provides, set the following defines to:
+ * BUNDLESMALL 0
+ * BUNDLEMAX 1
+ * INTDELAY 1
+ */
+#define BUNDLESMALL 1
+#define BUNDLEMAX (u16)6
+#define INTDELAY (u16)1536 /* 0x600 */
+
+       /* do not load u-code for ICH devices */
+       if (nic->flags & ich)
+               goto noloaducode;
+
+       /* Search for ucode match against h/w rev_id */
+       for (opts = ucode_opts; opts->mac; opts++) {
+               int i;
+               u32 *ucode = opts->ucode;
+               if (nic->mac != opts->mac)
+                       continue;
+
+               /* Insert user-tunable settings */
+               ucode[opts->timer_dword] &= 0xFFFF0000;
+               ucode[opts->timer_dword] |= INTDELAY;
+               ucode[opts->bundle_dword] &= 0xFFFF0000;
+               ucode[opts->bundle_dword] |= BUNDLEMAX;
+               ucode[opts->min_size_dword] &= 0xFFFF0000;
+               ucode[opts->min_size_dword] |= (BUNDLESMALL) ? 0xFFFF : 0xFF80;
+
+               for (i = 0; i < UCODE_SIZE; i++)
+                       cb->u.ucode[i] = cpu_to_le32(ucode[i]);
+               cb->command = cpu_to_le16(cb_ucode | cb_el);
+               return;
+       }
+
+noloaducode:
+       cb->command = cpu_to_le16(cb_nop | cb_el);
+}
+
+static inline int e100_exec_cb_wait(struct nic *nic, struct sk_buff *skb,
+       void (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *))
+{
+       int err = 0, counter = 50;
+       struct cb *cb = nic->cb_to_clean;
+
+       if ((err = e100_exec_cb(nic, NULL, e100_setup_ucode)))
+               DPRINTK(PROBE,ERR, "ucode cmd failed with error %d\n", err);
+
+       /* must restart cuc */
+       nic->cuc_cmd = cuc_start;
+
+       /* wait for completion */
+       e100_write_flush(nic);
+       udelay(10);
+
+       /* wait for possibly (ouch) 500ms */
+       while (!(cb->status & cpu_to_le16(cb_complete))) {
+               msleep(10);
+               if (!--counter) break;
+       }
+
+       /* ack any interupts, something could have been set */
+       writeb(~0, &nic->csr->scb.stat_ack);
+
+       /* if the command failed, or is not OK, notify and return */
+       if (!counter || !(cb->status & cpu_to_le16(cb_ok))) {
+               DPRINTK(PROBE,ERR, "ucode load failed\n");
+               err = -EPERM;
+       }
+
+       return err;
+}
+
 static void e100_setup_iaaddr(struct nic *nic, struct cb *cb,
        struct sk_buff *skb)
 {
 static void e100_setup_iaaddr(struct nic *nic, struct cb *cb,
        struct sk_buff *skb)
 {
@@ -1044,10 +1391,17 @@ static int e100_phy_init(struct nic *nic)
                mdio_write(netdev, nic->mii.phy_id, MII_NSC_CONG, cong);
        }
 
                mdio_write(netdev, nic->mii.phy_id, MII_NSC_CONG, cong);
        }
 
-       if(nic->mac >= mac_82550_D102)
-               /* enable/disable MDI/MDI-X auto-switching */
-               mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG,
-                       nic->mii.force_media ? 0 : NCONFIG_AUTO_SWITCH);
+       if((nic->mac >= mac_82550_D102) || ((nic->flags & ich) &&
+          (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000))) {
+               /* enable/disable MDI/MDI-X auto-switching.
+                  MDI/MDI-X auto-switching is disabled for 82551ER/QM chips */
+               if((nic->mac == mac_82551_E) || (nic->mac == mac_82551_F) ||
+                  (nic->mac == mac_82551_10) || (nic->mii.force_media) ||
+                  !(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))
+                       mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, 0);
+               else
+                       mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, NCONFIG_AUTO_SWITCH);
+       }
 
        return 0;
 }
 
        return 0;
 }
@@ -1068,6 +1422,8 @@ static int e100_hw_init(struct nic *nic)
                return err;
        if((err = e100_exec_cmd(nic, ruc_load_base, 0)))
                return err;
                return err;
        if((err = e100_exec_cmd(nic, ruc_load_base, 0)))
                return err;
+       if ((err = e100_exec_cb_wait(nic, NULL, e100_setup_ucode)))
+               return err;
        if((err = e100_exec_cb(nic, NULL, e100_configure)))
                return err;
        if((err = e100_exec_cb(nic, NULL, e100_setup_iaaddr)))
        if((err = e100_exec_cb(nic, NULL, e100_configure)))
                return err;
        if((err = e100_exec_cb(nic, NULL, e100_setup_iaaddr)))
@@ -1098,7 +1454,7 @@ static void e100_multi(struct nic *nic, struct cb *cb, struct sk_buff *skb)
 
 static void e100_set_multicast_list(struct net_device *netdev)
 {
 
 static void e100_set_multicast_list(struct net_device *netdev)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
 
        DPRINTK(HW, DEBUG, "mc_count=%d, flags=0x%04X\n",
                netdev->mc_count, netdev->flags);
 
        DPRINTK(HW, DEBUG, "mc_count=%d, flags=0x%04X\n",
                netdev->mc_count, netdev->flags);
@@ -1141,11 +1497,13 @@ static void e100_update_stats(struct nic *nic)
                ns->collisions += nic->tx_collisions;
                ns->tx_errors += le32_to_cpu(s->tx_max_collisions) +
                        le32_to_cpu(s->tx_lost_crs);
                ns->collisions += nic->tx_collisions;
                ns->tx_errors += le32_to_cpu(s->tx_max_collisions) +
                        le32_to_cpu(s->tx_lost_crs);
-               ns->rx_dropped += le32_to_cpu(s->rx_resource_errors);
-               ns->rx_length_errors += le32_to_cpu(s->rx_short_frame_errors);
+               ns->rx_length_errors += le32_to_cpu(s->rx_short_frame_errors) +
+                       nic->rx_over_length_errors;
                ns->rx_crc_errors += le32_to_cpu(s->rx_crc_errors);
                ns->rx_frame_errors += le32_to_cpu(s->rx_alignment_errors);
                ns->rx_crc_errors += le32_to_cpu(s->rx_crc_errors);
                ns->rx_frame_errors += le32_to_cpu(s->rx_alignment_errors);
+               ns->rx_over_errors += le32_to_cpu(s->rx_overrun_errors);
                ns->rx_fifo_errors += le32_to_cpu(s->rx_overrun_errors);
                ns->rx_fifo_errors += le32_to_cpu(s->rx_overrun_errors);
+               ns->rx_missed_errors += le32_to_cpu(s->rx_resource_errors);
                ns->rx_errors += le32_to_cpu(s->rx_crc_errors) +
                        le32_to_cpu(s->rx_alignment_errors) +
                        le32_to_cpu(s->rx_short_frame_errors) +
                ns->rx_errors += le32_to_cpu(s->rx_crc_errors) +
                        le32_to_cpu(s->rx_alignment_errors) +
                        le32_to_cpu(s->rx_short_frame_errors) +
@@ -1169,7 +1527,9 @@ static void e100_update_stats(struct nic *nic)
                }
        }
 
                }
        }
 
-       e100_exec_cmd(nic, cuc_dump_reset, 0);
+
+       if(e100_exec_cmd(nic, cuc_dump_reset, 0))
+               DPRINTK(TX_ERR, DEBUG, "exec cuc_dump_reset failed\n");
 }
 
 static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex)
 }
 
 static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex)
@@ -1216,9 +1576,14 @@ static void e100_watchdog(unsigned long data)
        mii_check_link(&nic->mii);
 
        /* Software generated interrupt to recover from (rare) Rx
        mii_check_link(&nic->mii);
 
        /* Software generated interrupt to recover from (rare) Rx
-        * allocation failure */
-       writeb(irq_sw_gen, &nic->csr->scb.cmd_hi);
+        * allocation failure.
+        * Unfortunately have to use a spinlock to not re-enable interrupts
+        * accidentally, due to hardware that shares a register between the
+        * interrupt mask bit and the SW Interrupt generation bit */
+       spin_lock_irq(&nic->cmd_lock);
+       writeb(readb(&nic->csr->scb.cmd_hi) | irq_sw_gen,&nic->csr->scb.cmd_hi);
        e100_write_flush(nic);
        e100_write_flush(nic);
+       spin_unlock_irq(&nic->cmd_lock);
 
        e100_update_stats(nic);
        e100_adjust_adaptive_ifs(nic, cmd.speed, cmd.duplex);
 
        e100_update_stats(nic);
        e100_adjust_adaptive_ifs(nic, cmd.speed, cmd.duplex);
@@ -1236,29 +1601,34 @@ static void e100_watchdog(unsigned long data)
        mod_timer(&nic->watchdog, jiffies + E100_WATCHDOG_PERIOD);
 }
 
        mod_timer(&nic->watchdog, jiffies + E100_WATCHDOG_PERIOD);
 }
 
-static inline void e100_xmit_prepare(struct nic *nic, struct cb *cb,
+static void e100_xmit_prepare(struct nic *nic, struct cb *cb,
        struct sk_buff *skb)
 {
        cb->command = nic->tx_command;
        struct sk_buff *skb)
 {
        cb->command = nic->tx_command;
+       /* interrupt every 16 packets regardless of delay */
+       if((nic->cbs_avail & ~15) == nic->cbs_avail)
+               cb->command |= cpu_to_le16(cb_i);
        cb->u.tcb.tbd_array = cb->dma_addr + offsetof(struct cb, u.tcb.tbd);
        cb->u.tcb.tcb_byte_count = 0;
        cb->u.tcb.threshold = nic->tx_threshold;
        cb->u.tcb.tbd_count = 1;
        cb->u.tcb.tbd.buf_addr = cpu_to_le32(pci_map_single(nic->pdev,
                skb->data, skb->len, PCI_DMA_TODEVICE));
        cb->u.tcb.tbd_array = cb->dma_addr + offsetof(struct cb, u.tcb.tbd);
        cb->u.tcb.tcb_byte_count = 0;
        cb->u.tcb.threshold = nic->tx_threshold;
        cb->u.tcb.tbd_count = 1;
        cb->u.tcb.tbd.buf_addr = cpu_to_le32(pci_map_single(nic->pdev,
                skb->data, skb->len, PCI_DMA_TODEVICE));
+       /* check for mapping failure? */
        cb->u.tcb.tbd.size = cpu_to_le16(skb->len);
 }
 
 static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 {
        cb->u.tcb.tbd.size = cpu_to_le16(skb->len);
 }
 
 static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
        int err;
 
        if(nic->flags & ich_10h_workaround) {
                /* SW workaround for ICH[x] 10Mbps/half duplex Tx hang.
                   Issue a NOP command followed by a 1us delay before
                   issuing the Tx command. */
        int err;
 
        if(nic->flags & ich_10h_workaround) {
                /* SW workaround for ICH[x] 10Mbps/half duplex Tx hang.
                   Issue a NOP command followed by a 1us delay before
                   issuing the Tx command. */
-               e100_exec_cmd(nic, cuc_nop, 0);
+               if(e100_exec_cmd(nic, cuc_nop, 0))
+                       DPRINTK(TX_ERR, DEBUG, "exec cuc_nop failed\n");
                udelay(1);
        }
 
                udelay(1);
        }
 
@@ -1267,6 +1637,7 @@ static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        switch(err) {
        case -ENOSPC:
                /* We queued the skb, but now we're out of space. */
        switch(err) {
        case -ENOSPC:
                /* We queued the skb, but now we're out of space. */
+               DPRINTK(TX_ERR, DEBUG, "No space for CB\n");
                netif_stop_queue(netdev);
                break;
        case -ENOMEM:
                netif_stop_queue(netdev);
                break;
        case -ENOMEM:
@@ -1280,7 +1651,7 @@ static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        return 0;
 }
 
        return 0;
 }
 
-static inline int e100_tx_clean(struct nic *nic)
+static int e100_tx_clean(struct nic *nic)
 {
        struct cb *cb;
        int tx_cleaned = 0;
 {
        struct cb *cb;
        int tx_cleaned = 0;
@@ -1322,7 +1693,7 @@ static inline int e100_tx_clean(struct nic *nic)
 static void e100_clean_cbs(struct nic *nic)
 {
        if(nic->cbs) {
 static void e100_clean_cbs(struct nic *nic)
 {
        if(nic->cbs) {
-               while(nic->cb_to_clean != nic->cb_to_use) {
+               while(nic->cbs_avail != nic->params.cbs.count) {
                        struct cb *cb = nic->cb_to_clean;
                        if(cb->skb) {
                                pci_unmap_single(nic->pdev,
                        struct cb *cb = nic->cb_to_clean;
                        if(cb->skb) {
                                pci_unmap_single(nic->pdev,
@@ -1332,8 +1703,8 @@ static void e100_clean_cbs(struct nic *nic)
                                dev_kfree_skb(cb->skb);
                        }
                        nic->cb_to_clean = nic->cb_to_clean->next;
                                dev_kfree_skb(cb->skb);
                        }
                        nic->cb_to_clean = nic->cb_to_clean->next;
+                       nic->cbs_avail++;
                }
                }
-               nic->cbs_avail = nic->params.cbs.count;
                pci_free_consistent(nic->pdev,
                        sizeof(struct cb) * nic->params.cbs.count,
                        nic->cbs, nic->cbs_dma_addr);
                pci_free_consistent(nic->pdev,
                        sizeof(struct cb) * nic->params.cbs.count,
                        nic->cbs, nic->cbs_dma_addr);
@@ -1375,29 +1746,40 @@ static int e100_alloc_cbs(struct nic *nic)
        return 0;
 }
 
        return 0;
 }
 
-static inline void e100_start_receiver(struct nic *nic)
+static inline void e100_start_receiver(struct nic *nic, struct rx *rx)
 {
 {
+       if(!nic->rxs) return;
+       if(RU_SUSPENDED != nic->ru_running) return;
+
+       /* handle init time starts */
+       if(!rx) rx = nic->rxs;
+
        /* (Re)start RU if suspended or idle and RFA is non-NULL */
        /* (Re)start RU if suspended or idle and RFA is non-NULL */
-       if(!nic->ru_running && nic->rx_to_clean->skb) {
-               e100_exec_cmd(nic, ruc_start, nic->rx_to_clean->dma_addr);
-               nic->ru_running = 1;
+       if(rx->skb) {
+               e100_exec_cmd(nic, ruc_start, rx->dma_addr);
+               nic->ru_running = RU_RUNNING;
        }
 }
 
 #define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN)
        }
 }
 
 #define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN)
-static inline int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
+static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
 {
 {
-       unsigned int rx_offset = 2; /* u32 align protocol headers */
-
-       if(!(rx->skb = dev_alloc_skb(RFD_BUF_LEN + rx_offset)))
+       if(!(rx->skb = dev_alloc_skb(RFD_BUF_LEN + NET_IP_ALIGN)))
                return -ENOMEM;
 
                return -ENOMEM;
 
-       /* Align, init, and map the RFA. */
+       /* Align, init, and map the RFD. */
        rx->skb->dev = nic->netdev;
        rx->skb->dev = nic->netdev;
-       skb_reserve(rx->skb, rx_offset);
+       skb_reserve(rx->skb, NET_IP_ALIGN);
        memcpy(rx->skb->data, &nic->blank_rfd, sizeof(struct rfd));
        rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data,
        memcpy(rx->skb->data, &nic->blank_rfd, sizeof(struct rfd));
        rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data,
-               RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
+               RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL);
+
+       if(pci_dma_mapping_error(rx->dma_addr)) {
+               dev_kfree_skb_any(rx->skb);
+               rx->skb = NULL;
+               rx->dma_addr = 0;
+               return -ENOMEM;
+       }
 
        /* Link the RFD to end of RFA by linking previous RFD to
         * this one, and clearing EL bit of previous.  */
 
        /* Link the RFD to end of RFA by linking previous RFD to
         * this one, and clearing EL bit of previous.  */
@@ -1408,13 +1790,13 @@ static inline int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
                wmb();
                prev_rfd->command &= ~cpu_to_le16(cb_el);
                pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr,
                wmb();
                prev_rfd->command &= ~cpu_to_le16(cb_el);
                pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr,
-                                              sizeof(struct rfd), PCI_DMA_TODEVICE);
+                       sizeof(struct rfd), PCI_DMA_TODEVICE);
        }
 
        return 0;
 }
 
        }
 
        return 0;
 }
 
-static inline int e100_rx_indicate(struct nic *nic, struct rx *rx,
+static int e100_rx_indicate(struct nic *nic, struct rx *rx,
        unsigned int *work_done, unsigned int work_to_do)
 {
        struct sk_buff *skb = rx->skb;
        unsigned int *work_done, unsigned int work_to_do)
 {
        struct sk_buff *skb = rx->skb;
@@ -1426,14 +1808,14 @@ static inline int e100_rx_indicate(struct nic *nic, struct rx *rx,
 
        /* Need to sync before taking a peek at cb_complete bit */
        pci_dma_sync_single_for_cpu(nic->pdev, rx->dma_addr,
 
        /* Need to sync before taking a peek at cb_complete bit */
        pci_dma_sync_single_for_cpu(nic->pdev, rx->dma_addr,
-                                   sizeof(struct rfd), PCI_DMA_FROMDEVICE);
+               sizeof(struct rfd), PCI_DMA_FROMDEVICE);
        rfd_status = le16_to_cpu(rfd->status);
 
        DPRINTK(RX_STATUS, DEBUG, "status=0x%04X\n", rfd_status);
 
        /* If data isn't ready, nothing to indicate */
        if(unlikely(!(rfd_status & cb_complete)))
        rfd_status = le16_to_cpu(rfd->status);
 
        DPRINTK(RX_STATUS, DEBUG, "status=0x%04X\n", rfd_status);
 
        /* If data isn't ready, nothing to indicate */
        if(unlikely(!(rfd_status & cb_complete)))
-                       return -EAGAIN;
+               return -ENODATA;
 
        /* Get actual data size */
        actual_size = le16_to_cpu(rfd->actual_size) & 0x3FFF;
 
        /* Get actual data size */
        actual_size = le16_to_cpu(rfd->actual_size) & 0x3FFF;
@@ -1442,7 +1824,11 @@ static inline int e100_rx_indicate(struct nic *nic, struct rx *rx,
 
        /* Get data */
        pci_unmap_single(nic->pdev, rx->dma_addr,
 
        /* Get data */
        pci_unmap_single(nic->pdev, rx->dma_addr,
-                        RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
+               RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
+
+       /* this allows for a fast restart without re-enabling interrupts */
+       if(le16_to_cpu(rfd->command) & cb_el)
+               nic->ru_running = RU_SUSPENDED;
 
        /* Pull off the RFD and put the actual data (minus eth hdr) */
        skb_reserve(skb, sizeof(struct rfd));
 
        /* Pull off the RFD and put the actual data (minus eth hdr) */
        skb_reserve(skb, sizeof(struct rfd));
@@ -1451,22 +1837,16 @@ static inline int e100_rx_indicate(struct nic *nic, struct rx *rx,
 
        if(unlikely(!(rfd_status & cb_ok))) {
                /* Don't indicate if hardware indicates errors */
 
        if(unlikely(!(rfd_status & cb_ok))) {
                /* Don't indicate if hardware indicates errors */
-               nic->net_stats.rx_dropped++;
                dev_kfree_skb_any(skb);
                dev_kfree_skb_any(skb);
-       } else if(actual_size > nic->netdev->mtu + VLAN_ETH_HLEN) {
+       } else if(actual_size > ETH_DATA_LEN + VLAN_ETH_HLEN) {
                /* Don't indicate oversized frames */
                /* Don't indicate oversized frames */
-               nic->net_stats.rx_over_errors++;
-               nic->net_stats.rx_dropped++;
+               nic->rx_over_length_errors++;
                dev_kfree_skb_any(skb);
        } else {
                nic->net_stats.rx_packets++;
                nic->net_stats.rx_bytes += actual_size;
                nic->netdev->last_rx = jiffies;
                dev_kfree_skb_any(skb);
        } else {
                nic->net_stats.rx_packets++;
                nic->net_stats.rx_bytes += actual_size;
                nic->netdev->last_rx = jiffies;
-#ifdef CONFIG_E100_NAPI
                netif_receive_skb(skb);
                netif_receive_skb(skb);
-#else
-               netif_rx(skb);
-#endif
                if(work_done)
                        (*work_done)++;
        }
                if(work_done)
                        (*work_done)++;
        }
@@ -1476,24 +1856,49 @@ static inline int e100_rx_indicate(struct nic *nic, struct rx *rx,
        return 0;
 }
 
        return 0;
 }
 
-static inline void e100_rx_clean(struct nic *nic, unsigned int *work_done,
+static void e100_rx_clean(struct nic *nic, unsigned int *work_done,
        unsigned int work_to_do)
 {
        struct rx *rx;
        unsigned int work_to_do)
 {
        struct rx *rx;
+       int restart_required = 0;
+       struct rx *rx_to_start = NULL;
+
+       /* are we already rnr? then pay attention!!! this ensures that
+        * the state machine progression never allows a start with a
+        * partially cleaned list, avoiding a race between hardware
+        * and rx_to_clean when in NAPI mode */
+       if(RU_SUSPENDED == nic->ru_running)
+               restart_required = 1;
 
        /* Indicate newly arrived packets */
        for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) {
 
        /* Indicate newly arrived packets */
        for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) {
-               if(e100_rx_indicate(nic, rx, work_done, work_to_do))
+               int err = e100_rx_indicate(nic, rx, work_done, work_to_do);
+               if(-EAGAIN == err) {
+                       /* hit quota so have more work to do, restart once
+                        * cleanup is complete */
+                       restart_required = 0;
+                       break;
+               } else if(-ENODATA == err)
                        break; /* No more to clean */
        }
 
                        break; /* No more to clean */
        }
 
+       /* save our starting point as the place we'll restart the receiver */
+       if(restart_required)
+               rx_to_start = nic->rx_to_clean;
+
        /* Alloc new skbs to refill list */
        for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) {
                if(unlikely(e100_rx_alloc_skb(nic, rx)))
                        break; /* Better luck next time (see watchdog) */
        }
 
        /* Alloc new skbs to refill list */
        for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) {
                if(unlikely(e100_rx_alloc_skb(nic, rx)))
                        break; /* Better luck next time (see watchdog) */
        }
 
-       e100_start_receiver(nic);
+       if(restart_required) {
+               // ack the rnr?
+               writeb(stat_ack_rnr, &nic->csr->scb.stat_ack);
+               e100_start_receiver(nic, rx_to_start);
+               if(work_done)
+                       (*work_done)++;
+       }
 }
 
 static void e100_rx_clean_list(struct nic *nic)
 }
 
 static void e100_rx_clean_list(struct nic *nic)
@@ -1501,6 +1906,8 @@ static void e100_rx_clean_list(struct nic *nic)
        struct rx *rx;
        unsigned int i, count = nic->params.rfds.count;
 
        struct rx *rx;
        unsigned int i, count = nic->params.rfds.count;
 
+       nic->ru_running = RU_UNINITIALIZED;
+
        if(nic->rxs) {
                for(rx = nic->rxs, i = 0; i < count; rx++, i++) {
                        if(rx->skb) {
        if(nic->rxs) {
                for(rx = nic->rxs, i = 0; i < count; rx++, i++) {
                        if(rx->skb) {
@@ -1514,7 +1921,6 @@ static void e100_rx_clean_list(struct nic *nic)
        }
 
        nic->rx_to_use = nic->rx_to_clean = NULL;
        }
 
        nic->rx_to_use = nic->rx_to_clean = NULL;
-       nic->ru_running = 0;
 }
 
 static int e100_rx_alloc_list(struct nic *nic)
 }
 
 static int e100_rx_alloc_list(struct nic *nic)
@@ -1523,6 +1929,7 @@ static int e100_rx_alloc_list(struct nic *nic)
        unsigned int i, count = nic->params.rfds.count;
 
        nic->rx_to_use = nic->rx_to_clean = NULL;
        unsigned int i, count = nic->params.rfds.count;
 
        nic->rx_to_use = nic->rx_to_clean = NULL;
+       nic->ru_running = RU_UNINITIALIZED;
 
        if(!(nic->rxs = kmalloc(sizeof(struct rx) * count, GFP_ATOMIC)))
                return -ENOMEM;
 
        if(!(nic->rxs = kmalloc(sizeof(struct rx) * count, GFP_ATOMIC)))
                return -ENOMEM;
@@ -1538,6 +1945,7 @@ static int e100_rx_alloc_list(struct nic *nic)
        }
 
        nic->rx_to_use = nic->rx_to_clean = nic->rxs;
        }
 
        nic->rx_to_use = nic->rx_to_clean = nic->rxs;
+       nic->ru_running = RU_SUSPENDED;
 
        return 0;
 }
 
        return 0;
 }
@@ -1545,7 +1953,7 @@ static int e100_rx_alloc_list(struct nic *nic)
 static irqreturn_t e100_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
        struct net_device *netdev = dev_id;
 static irqreturn_t e100_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
        struct net_device *netdev = dev_id;
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
        u8 stat_ack = readb(&nic->csr->scb.stat_ack);
 
        DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\n", stat_ack);
        u8 stat_ack = readb(&nic->csr->scb.stat_ack);
 
        DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\n", stat_ack);
@@ -1559,25 +1967,19 @@ static irqreturn_t e100_intr(int irq, void *dev_id, struct pt_regs *regs)
 
        /* We hit Receive No Resource (RNR); restart RU after cleaning */
        if(stat_ack & stat_ack_rnr)
 
        /* We hit Receive No Resource (RNR); restart RU after cleaning */
        if(stat_ack & stat_ack_rnr)
-               nic->ru_running = 0;
+               nic->ru_running = RU_SUSPENDED;
 
 
-#ifdef CONFIG_E100_NAPI
-       e100_disable_irq(nic);
-       netif_rx_schedule(netdev);
-#else
-       if(stat_ack & stat_ack_rx)
-               e100_rx_clean(nic, NULL, 0);
-       if(stat_ack & stat_ack_tx)
-               e100_tx_clean(nic);
-#endif
+       if(likely(netif_rx_schedule_prep(netdev))) {
+               e100_disable_irq(nic);
+               __netif_rx_schedule(netdev);
+       }
 
        return IRQ_HANDLED;
 }
 
 
        return IRQ_HANDLED;
 }
 
-#ifdef CONFIG_E100_NAPI
 static int e100_poll(struct net_device *netdev, int *budget)
 {
 static int e100_poll(struct net_device *netdev, int *budget)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
        unsigned int work_to_do = min(netdev->quota, *budget);
        unsigned int work_done = 0;
        int tx_cleaned;
        unsigned int work_to_do = min(netdev->quota, *budget);
        unsigned int work_done = 0;
        int tx_cleaned;
@@ -1597,27 +1999,28 @@ static int e100_poll(struct net_device *netdev, int *budget)
 
        return 1;
 }
 
        return 1;
 }
-#endif
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void e100_netpoll(struct net_device *netdev)
 {
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void e100_netpoll(struct net_device *netdev)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
+
        e100_disable_irq(nic);
        e100_intr(nic->pdev->irq, netdev, NULL);
        e100_disable_irq(nic);
        e100_intr(nic->pdev->irq, netdev, NULL);
+       e100_tx_clean(nic);
        e100_enable_irq(nic);
 }
 #endif
 
 static struct net_device_stats *e100_get_stats(struct net_device *netdev)
 {
        e100_enable_irq(nic);
 }
 #endif
 
 static struct net_device_stats *e100_get_stats(struct net_device *netdev)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
        return &nic->net_stats;
 }
 
 static int e100_set_mac_address(struct net_device *netdev, void *p)
 {
        return &nic->net_stats;
 }
 
 static int e100_set_mac_address(struct net_device *netdev, void *p)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
        struct sockaddr *addr = p;
 
        if (!is_valid_ether_addr(addr->sa_data))
        struct sockaddr *addr = p;
 
        if (!is_valid_ether_addr(addr->sa_data))
@@ -1637,14 +2040,16 @@ static int e100_change_mtu(struct net_device *netdev, int new_mtu)
        return 0;
 }
 
        return 0;
 }
 
+#ifdef CONFIG_PM
 static int e100_asf(struct nic *nic)
 {
        /* ASF can be enabled from eeprom */
 static int e100_asf(struct nic *nic)
 {
        /* ASF can be enabled from eeprom */
-       return((nic->pdev->device >= 0x1050) && (nic->pdev->device <= 0x1055) &&
+       return((nic->pdev->device >= 0x1050) && (nic->pdev->device <= 0x1057) &&
           (nic->eeprom[eeprom_config_asf] & eeprom_asf) &&
           !(nic->eeprom[eeprom_config_asf] & eeprom_gcl) &&
           ((nic->eeprom[eeprom_smbus_addr] & 0xFF) != 0xFE));
 }
           (nic->eeprom[eeprom_config_asf] & eeprom_asf) &&
           !(nic->eeprom[eeprom_config_asf] & eeprom_gcl) &&
           ((nic->eeprom[eeprom_smbus_addr] & 0xFF) != 0xFE));
 }
+#endif
 
 static int e100_up(struct nic *nic)
 {
 
 static int e100_up(struct nic *nic)
 {
@@ -1657,18 +2062,20 @@ static int e100_up(struct nic *nic)
        if((err = e100_hw_init(nic)))
                goto err_clean_cbs;
        e100_set_multicast_list(nic->netdev);
        if((err = e100_hw_init(nic)))
                goto err_clean_cbs;
        e100_set_multicast_list(nic->netdev);
-       e100_start_receiver(nic);
-       netif_start_queue(nic->netdev);
+       e100_start_receiver(nic, NULL);
        mod_timer(&nic->watchdog, jiffies);
        if((err = request_irq(nic->pdev->irq, e100_intr, SA_SHIRQ,
                nic->netdev->name, nic->netdev)))
                goto err_no_irq;
        mod_timer(&nic->watchdog, jiffies);
        if((err = request_irq(nic->pdev->irq, e100_intr, SA_SHIRQ,
                nic->netdev->name, nic->netdev)))
                goto err_no_irq;
+       netif_wake_queue(nic->netdev);
+       netif_poll_enable(nic->netdev);
+       /* enable ints _after_ enabling poll, preventing a race between
+        * disable ints+schedule */
        e100_enable_irq(nic);
        return 0;
 
 err_no_irq:
        del_timer_sync(&nic->watchdog);
        e100_enable_irq(nic);
        return 0;
 
 err_no_irq:
        del_timer_sync(&nic->watchdog);
-       netif_stop_queue(nic->netdev);
 err_clean_cbs:
        e100_clean_cbs(nic);
 err_rx_clean_list:
 err_clean_cbs:
        e100_clean_cbs(nic);
 err_rx_clean_list:
@@ -1678,23 +2085,34 @@ err_rx_clean_list:
 
 static void e100_down(struct nic *nic)
 {
 
 static void e100_down(struct nic *nic)
 {
+       /* wait here for poll to complete */
+       netif_poll_disable(nic->netdev);
+       netif_stop_queue(nic->netdev);
        e100_hw_reset(nic);
        free_irq(nic->pdev->irq, nic->netdev);
        del_timer_sync(&nic->watchdog);
        netif_carrier_off(nic->netdev);
        e100_hw_reset(nic);
        free_irq(nic->pdev->irq, nic->netdev);
        del_timer_sync(&nic->watchdog);
        netif_carrier_off(nic->netdev);
-       netif_stop_queue(nic->netdev);
        e100_clean_cbs(nic);
        e100_rx_clean_list(nic);
 }
 
 static void e100_tx_timeout(struct net_device *netdev)
 {
        e100_clean_cbs(nic);
        e100_rx_clean_list(nic);
 }
 
 static void e100_tx_timeout(struct net_device *netdev)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
+
+       /* Reset outside of interrupt context, to avoid request_irq
+        * in interrupt context */
+       schedule_work(&nic->tx_timeout_task);
+}
+
+static void e100_tx_timeout_task(struct net_device *netdev)
+{
+       struct nic *nic = netdev_priv(netdev);
 
        DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n",
                readb(&nic->csr->scb.status));
 
        DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n",
                readb(&nic->csr->scb.status));
-       e100_down(netdev->priv);
-       e100_up(netdev->priv);
+       e100_down(netdev_priv(netdev));
+       e100_up(netdev_priv(netdev));
 }
 
 static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode)
 }
 
 static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode)
@@ -1724,7 +2142,7 @@ static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode)
                mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR,
                        BMCR_LOOPBACK);
 
                mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR,
                        BMCR_LOOPBACK);
 
-       e100_start_receiver(nic);
+       e100_start_receiver(nic, NULL);
 
        if(!(skb = dev_alloc_skb(ETH_DATA_LEN))) {
                err = -ENOMEM;
 
        if(!(skb = dev_alloc_skb(ETH_DATA_LEN))) {
                err = -ENOMEM;
@@ -1734,18 +2152,20 @@ static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode)
        memset(skb->data, 0xFF, ETH_DATA_LEN);
        e100_xmit_frame(skb, nic->netdev);
 
        memset(skb->data, 0xFF, ETH_DATA_LEN);
        e100_xmit_frame(skb, nic->netdev);
 
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       schedule_timeout(HZ / 100 + 1);
+       msleep(10);
+
+       pci_dma_sync_single_for_cpu(nic->pdev, nic->rx_to_clean->dma_addr,
+                       RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
 
        if(memcmp(nic->rx_to_clean->skb->data + sizeof(struct rfd),
           skb->data, ETH_DATA_LEN))
 
        if(memcmp(nic->rx_to_clean->skb->data + sizeof(struct rfd),
           skb->data, ETH_DATA_LEN))
-                       err = -EAGAIN;
+               err = -EAGAIN;
 
 err_loopback_none:
        mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR, 0);
        nic->loopback = lb_none;
 
 err_loopback_none:
        mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR, 0);
        nic->loopback = lb_none;
-       e100_hw_init(nic);
        e100_clean_cbs(nic);
        e100_clean_cbs(nic);
+       e100_hw_reset(nic);
 err_clean_rx:
        e100_rx_clean_list(nic);
        return err;
 err_clean_rx:
        e100_rx_clean_list(nic);
        return err;
@@ -1770,13 +2190,13 @@ static void e100_blink_led(unsigned long data)
 
 static int e100_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
 {
 
 static int e100_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
        return mii_ethtool_gset(&nic->mii, cmd);
 }
 
 static int e100_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
 {
        return mii_ethtool_gset(&nic->mii, cmd);
 }
 
 static int e100_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
        int err;
 
        mdio_write(netdev, nic->mii.phy_id, MII_BMCR, BMCR_RESET);
        int err;
 
        mdio_write(netdev, nic->mii.phy_id, MII_BMCR, BMCR_RESET);
@@ -1789,7 +2209,7 @@ static int e100_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
 static void e100_get_drvinfo(struct net_device *netdev,
        struct ethtool_drvinfo *info)
 {
 static void e100_get_drvinfo(struct net_device *netdev,
        struct ethtool_drvinfo *info)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
        strcpy(info->driver, DRV_NAME);
        strcpy(info->version, DRV_VERSION);
        strcpy(info->fw_version, "N/A");
        strcpy(info->driver, DRV_NAME);
        strcpy(info->version, DRV_VERSION);
        strcpy(info->fw_version, "N/A");
@@ -1798,7 +2218,7 @@ static void e100_get_drvinfo(struct net_device *netdev,
 
 static int e100_get_regs_len(struct net_device *netdev)
 {
 
 static int e100_get_regs_len(struct net_device *netdev)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
 #define E100_PHY_REGS          0x1C
 #define E100_REGS_LEN          1 + E100_PHY_REGS + \
        sizeof(nic->mem->dump_buf) / sizeof(u32)
 #define E100_PHY_REGS          0x1C
 #define E100_REGS_LEN          1 + E100_PHY_REGS + \
        sizeof(nic->mem->dump_buf) / sizeof(u32)
@@ -1808,7 +2228,7 @@ static int e100_get_regs_len(struct net_device *netdev)
 static void e100_get_regs(struct net_device *netdev,
        struct ethtool_regs *regs, void *p)
 {
 static void e100_get_regs(struct net_device *netdev,
        struct ethtool_regs *regs, void *p)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
        u32 *buff = p;
        int i;
 
        u32 *buff = p;
        int i;
 
@@ -1821,22 +2241,21 @@ static void e100_get_regs(struct net_device *netdev,
                        mdio_read(netdev, nic->mii.phy_id, i);
        memset(nic->mem->dump_buf, 0, sizeof(nic->mem->dump_buf));
        e100_exec_cb(nic, NULL, e100_dump);
                        mdio_read(netdev, nic->mii.phy_id, i);
        memset(nic->mem->dump_buf, 0, sizeof(nic->mem->dump_buf));
        e100_exec_cb(nic, NULL, e100_dump);
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       schedule_timeout(HZ / 100 + 1);
+       msleep(10);
        memcpy(&buff[2 + E100_PHY_REGS], nic->mem->dump_buf,
                sizeof(nic->mem->dump_buf));
 }
 
 static void e100_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
 {
        memcpy(&buff[2 + E100_PHY_REGS], nic->mem->dump_buf,
                sizeof(nic->mem->dump_buf));
 }
 
 static void e100_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
        wol->supported = (nic->mac >= mac_82558_D101_A4) ?  WAKE_MAGIC : 0;
        wol->wolopts = (nic->flags & wol_magic) ? WAKE_MAGIC : 0;
 }
 
 static int e100_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
 {
        wol->supported = (nic->mac >= mac_82558_D101_A4) ?  WAKE_MAGIC : 0;
        wol->wolopts = (nic->flags & wol_magic) ? WAKE_MAGIC : 0;
 }
 
 static int e100_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
 
        if(wol->wolopts != WAKE_MAGIC && wol->wolopts != 0)
                return -EOPNOTSUPP;
 
        if(wol->wolopts != WAKE_MAGIC && wol->wolopts != 0)
                return -EOPNOTSUPP;
@@ -1846,7 +2265,6 @@ static int e100_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
        else
                nic->flags &= ~wol_magic;
 
        else
                nic->flags &= ~wol_magic;
 
-       pci_enable_wake(nic->pdev, 0, nic->flags & (wol_magic | e100_asf(nic)));
        e100_exec_cb(nic, NULL, e100_configure);
 
        return 0;
        e100_exec_cb(nic, NULL, e100_configure);
 
        return 0;
@@ -1854,31 +2272,31 @@ static int e100_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
 
 static u32 e100_get_msglevel(struct net_device *netdev)
 {
 
 static u32 e100_get_msglevel(struct net_device *netdev)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
        return nic->msg_enable;
 }
 
 static void e100_set_msglevel(struct net_device *netdev, u32 value)
 {
        return nic->msg_enable;
 }
 
 static void e100_set_msglevel(struct net_device *netdev, u32 value)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
        nic->msg_enable = value;
 }
 
 static int e100_nway_reset(struct net_device *netdev)
 {
        nic->msg_enable = value;
 }
 
 static int e100_nway_reset(struct net_device *netdev)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
        return mii_nway_restart(&nic->mii);
 }
 
 static u32 e100_get_link(struct net_device *netdev)
 {
        return mii_nway_restart(&nic->mii);
 }
 
 static u32 e100_get_link(struct net_device *netdev)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
        return mii_link_ok(&nic->mii);
 }
 
 static int e100_get_eeprom_len(struct net_device *netdev)
 {
        return mii_link_ok(&nic->mii);
 }
 
 static int e100_get_eeprom_len(struct net_device *netdev)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
        return nic->eeprom_wc << 1;
 }
 
        return nic->eeprom_wc << 1;
 }
 
@@ -1886,7 +2304,7 @@ static int e100_get_eeprom_len(struct net_device *netdev)
 static int e100_get_eeprom(struct net_device *netdev,
        struct ethtool_eeprom *eeprom, u8 *bytes)
 {
 static int e100_get_eeprom(struct net_device *netdev,
        struct ethtool_eeprom *eeprom, u8 *bytes)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
 
        eeprom->magic = E100_EEPROM_MAGIC;
        memcpy(bytes, &((u8 *)nic->eeprom)[eeprom->offset], eeprom->len);
 
        eeprom->magic = E100_EEPROM_MAGIC;
        memcpy(bytes, &((u8 *)nic->eeprom)[eeprom->offset], eeprom->len);
@@ -1897,10 +2315,11 @@ static int e100_get_eeprom(struct net_device *netdev,
 static int e100_set_eeprom(struct net_device *netdev,
        struct ethtool_eeprom *eeprom, u8 *bytes)
 {
 static int e100_set_eeprom(struct net_device *netdev,
        struct ethtool_eeprom *eeprom, u8 *bytes)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
 
        if(eeprom->magic != E100_EEPROM_MAGIC)
                return -EINVAL;
 
        if(eeprom->magic != E100_EEPROM_MAGIC)
                return -EINVAL;
+
        memcpy(&((u8 *)nic->eeprom)[eeprom->offset], bytes, eeprom->len);
 
        return e100_eeprom_save(nic, eeprom->offset >> 1,
        memcpy(&((u8 *)nic->eeprom)[eeprom->offset], bytes, eeprom->len);
 
        return e100_eeprom_save(nic, eeprom->offset >> 1,
@@ -1910,7 +2329,7 @@ static int e100_set_eeprom(struct net_device *netdev,
 static void e100_get_ringparam(struct net_device *netdev,
        struct ethtool_ringparam *ring)
 {
 static void e100_get_ringparam(struct net_device *netdev,
        struct ethtool_ringparam *ring)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
        struct param_range *rfds = &nic->params.rfds;
        struct param_range *cbs = &nic->params.cbs;
 
        struct param_range *rfds = &nic->params.rfds;
        struct param_range *cbs = &nic->params.cbs;
 
@@ -1927,16 +2346,21 @@ static void e100_get_ringparam(struct net_device *netdev,
 static int e100_set_ringparam(struct net_device *netdev,
        struct ethtool_ringparam *ring)
 {
 static int e100_set_ringparam(struct net_device *netdev,
        struct ethtool_ringparam *ring)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
        struct param_range *rfds = &nic->params.rfds;
        struct param_range *cbs = &nic->params.cbs;
 
        struct param_range *rfds = &nic->params.rfds;
        struct param_range *cbs = &nic->params.cbs;
 
+       if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
+               return -EINVAL;
+
        if(netif_running(netdev))
                e100_down(nic);
        rfds->count = max(ring->rx_pending, rfds->min);
        rfds->count = min(rfds->count, rfds->max);
        cbs->count = max(ring->tx_pending, cbs->min);
        cbs->count = min(cbs->count, cbs->max);
        if(netif_running(netdev))
                e100_down(nic);
        rfds->count = max(ring->rx_pending, rfds->min);
        rfds->count = min(rfds->count, rfds->max);
        cbs->count = max(ring->tx_pending, cbs->min);
        cbs->count = min(cbs->count, cbs->max);
+       DPRINTK(DRV, INFO, "Ring Param settings: rx: %d, tx %d\n",
+               rfds->count, cbs->count);
        if(netif_running(netdev))
                e100_up(nic);
 
        if(netif_running(netdev))
                e100_up(nic);
 
@@ -1960,34 +2384,44 @@ static int e100_diag_test_count(struct net_device *netdev)
 static void e100_diag_test(struct net_device *netdev,
        struct ethtool_test *test, u64 *data)
 {
 static void e100_diag_test(struct net_device *netdev,
        struct ethtool_test *test, u64 *data)
 {
-       struct nic *nic = netdev->priv;
-       int i;
+       struct ethtool_cmd cmd;
+       struct nic *nic = netdev_priv(netdev);
+       int i, err;
 
        memset(data, 0, E100_TEST_LEN * sizeof(u64));
        data[0] = !mii_link_ok(&nic->mii);
        data[1] = e100_eeprom_load(nic);
        if(test->flags & ETH_TEST_FL_OFFLINE) {
 
        memset(data, 0, E100_TEST_LEN * sizeof(u64));
        data[0] = !mii_link_ok(&nic->mii);
        data[1] = e100_eeprom_load(nic);
        if(test->flags & ETH_TEST_FL_OFFLINE) {
+
+               /* save speed, duplex & autoneg settings */
+               err = mii_ethtool_gset(&nic->mii, &cmd);
+
                if(netif_running(netdev))
                        e100_down(nic);
                data[2] = e100_self_test(nic);
                data[3] = e100_loopback_test(nic, lb_mac);
                data[4] = e100_loopback_test(nic, lb_phy);
                if(netif_running(netdev))
                        e100_down(nic);
                data[2] = e100_self_test(nic);
                data[3] = e100_loopback_test(nic, lb_mac);
                data[4] = e100_loopback_test(nic, lb_phy);
+
+               /* restore speed, duplex & autoneg settings */
+               err = mii_ethtool_sset(&nic->mii, &cmd);
+
                if(netif_running(netdev))
                        e100_up(nic);
        }
        for(i = 0; i < E100_TEST_LEN; i++)
                test->flags |= data[i] ? ETH_TEST_FL_FAILED : 0;
                if(netif_running(netdev))
                        e100_up(nic);
        }
        for(i = 0; i < E100_TEST_LEN; i++)
                test->flags |= data[i] ? ETH_TEST_FL_FAILED : 0;
+
+       msleep_interruptible(4 * 1000);
 }
 
 static int e100_phys_id(struct net_device *netdev, u32 data)
 {
 }
 
 static int e100_phys_id(struct net_device *netdev, u32 data)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
 
        if(!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
                data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
        mod_timer(&nic->blink_timer, jiffies);
 
        if(!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
                data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
        mod_timer(&nic->blink_timer, jiffies);
-       set_current_state(TASK_INTERRUPTIBLE);
-       schedule_timeout(data * HZ);
+       msleep_interruptible(data * 1000);
        del_timer_sync(&nic->blink_timer);
        mdio_write(netdev, nic->mii.phy_id, MII_LED_CONTROL, 0);
 
        del_timer_sync(&nic->blink_timer);
        mdio_write(netdev, nic->mii.phy_id, MII_LED_CONTROL, 0);
 
@@ -2017,7 +2451,7 @@ static int e100_get_stats_count(struct net_device *netdev)
 static void e100_get_ethtool_stats(struct net_device *netdev,
        struct ethtool_stats *stats, u64 *data)
 {
 static void e100_get_ethtool_stats(struct net_device *netdev,
        struct ethtool_stats *stats, u64 *data)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
        int i;
 
        for(i = 0; i < E100_NET_STATS_LEN; i++)
        int i;
 
        for(i = 0; i < E100_NET_STATS_LEN; i++)
@@ -2068,14 +2502,14 @@ static struct ethtool_ops e100_ethtool_ops = {
        .phys_id                = e100_phys_id,
        .get_stats_count        = e100_get_stats_count,
        .get_ethtool_stats      = e100_get_ethtool_stats,
        .phys_id                = e100_phys_id,
        .get_stats_count        = e100_get_stats_count,
        .get_ethtool_stats      = e100_get_ethtool_stats,
+       .get_perm_addr          = ethtool_op_get_perm_addr,
 };
 
 static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
 {
 };
 
 static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
 {
-       struct nic *nic = netdev->priv;
-       struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&ifr->ifr_data;
+       struct nic *nic = netdev_priv(netdev);
 
 
-       return generic_mii_ioctl(&nic->mii, mii, cmd, NULL);
+       return generic_mii_ioctl(&nic->mii, if_mii(ifr), cmd, NULL);
 }
 
 static int e100_alloc(struct nic *nic)
 }
 
 static int e100_alloc(struct nic *nic)
@@ -2096,7 +2530,7 @@ static void e100_free(struct nic *nic)
 
 static int e100_open(struct net_device *netdev)
 {
 
 static int e100_open(struct net_device *netdev)
 {
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
        int err = 0;
 
        netif_carrier_off(netdev);
        int err = 0;
 
        netif_carrier_off(netdev);
@@ -2107,7 +2541,7 @@ static int e100_open(struct net_device *netdev)
 
 static int e100_close(struct net_device *netdev)
 {
 
 static int e100_close(struct net_device *netdev)
 {
-       e100_down(netdev->priv);
+       e100_down(netdev_priv(netdev));
        return 0;
 }
 
        return 0;
 }
 
@@ -2135,15 +2569,14 @@ static int __devinit e100_probe(struct pci_dev *pdev,
        SET_ETHTOOL_OPS(netdev, &e100_ethtool_ops);
        netdev->tx_timeout = e100_tx_timeout;
        netdev->watchdog_timeo = E100_WATCHDOG_PERIOD;
        SET_ETHTOOL_OPS(netdev, &e100_ethtool_ops);
        netdev->tx_timeout = e100_tx_timeout;
        netdev->watchdog_timeo = E100_WATCHDOG_PERIOD;
-#ifdef CONFIG_E100_NAPI
        netdev->poll = e100_poll;
        netdev->weight = E100_NAPI_WEIGHT;
        netdev->poll = e100_poll;
        netdev->weight = E100_NAPI_WEIGHT;
-#endif
 #ifdef CONFIG_NET_POLL_CONTROLLER
        netdev->poll_controller = e100_netpoll;
 #endif
 #ifdef CONFIG_NET_POLL_CONTROLLER
        netdev->poll_controller = e100_netpoll;
 #endif
+       strcpy(netdev->name, pci_name(pdev));
 
 
-       nic = netdev->priv;
+       nic = netdev_priv(netdev);
        nic->netdev = netdev;
        nic->pdev = pdev;
        nic->msg_enable = (1 << debug) - 1;
        nic->netdev = netdev;
        nic->pdev = pdev;
        nic->msg_enable = (1 << debug) - 1;
@@ -2166,9 +2599,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
                goto err_out_disable_pdev;
        }
 
                goto err_out_disable_pdev;
        }
 
-       pci_set_master(pdev);
-
-       if((err = pci_set_dma_mask(pdev, 0xFFFFFFFFULL))) {
+       if((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) {
                DPRINTK(PROBE, ERR, "No usable DMA configuration, aborting.\n");
                goto err_out_free_res;
        }
                DPRINTK(PROBE, ERR, "No usable DMA configuration, aborting.\n");
                goto err_out_free_res;
        }
@@ -2188,8 +2619,19 @@ static int __devinit e100_probe(struct pci_dev *pdev,
        else
                nic->flags &= ~ich;
 
        else
                nic->flags &= ~ich;
 
+       e100_get_defaults(nic);
+
+       /* locks must be initialized before calling hw_reset */
        spin_lock_init(&nic->cb_lock);
        spin_lock_init(&nic->cmd_lock);
        spin_lock_init(&nic->cb_lock);
        spin_lock_init(&nic->cmd_lock);
+       spin_lock_init(&nic->mdio_lock);
+
+       /* Reset the device before pci_set_master() in case device is in some
+        * funky state and has an interrupt pending - hint: we don't have the
+        * interrupt handler registered yet. */
+       e100_hw_reset(nic);
+
+       pci_set_master(pdev);
 
        init_timer(&nic->watchdog);
        nic->watchdog.function = e100_watchdog;
 
        init_timer(&nic->watchdog);
        nic->watchdog.function = e100_watchdog;
@@ -2198,21 +2640,22 @@ static int __devinit e100_probe(struct pci_dev *pdev,
        nic->blink_timer.function = e100_blink_led;
        nic->blink_timer.data = (unsigned long)nic;
 
        nic->blink_timer.function = e100_blink_led;
        nic->blink_timer.data = (unsigned long)nic;
 
+       INIT_WORK(&nic->tx_timeout_task,
+               (void (*)(void *))e100_tx_timeout_task, netdev);
+
        if((err = e100_alloc(nic))) {
                DPRINTK(PROBE, ERR, "Cannot alloc driver memory, aborting.\n");
                goto err_out_iounmap;
        }
 
        if((err = e100_alloc(nic))) {
                DPRINTK(PROBE, ERR, "Cannot alloc driver memory, aborting.\n");
                goto err_out_iounmap;
        }
 
-       e100_get_defaults(nic);
-       e100_hw_reset(nic);
-       e100_phy_init(nic);
-
        if((err = e100_eeprom_load(nic)))
                goto err_out_free;
        if((err = e100_eeprom_load(nic)))
                goto err_out_free;
-       ((u16 *)netdev->dev_addr)[0] = le16_to_cpu(nic->eeprom[0]);
-       ((u16 *)netdev->dev_addr)[1] = le16_to_cpu(nic->eeprom[1]);
-       ((u16 *)netdev->dev_addr)[2] = le16_to_cpu(nic->eeprom[2]);
-       if(!is_valid_ether_addr(netdev->dev_addr)) {
+
+       e100_phy_init(nic);
+
+       memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN);
+       memcpy(netdev->perm_addr, nic->eeprom, ETH_ALEN);
+       if(!is_valid_ether_addr(netdev->perm_addr)) {
                DPRINTK(PROBE, ERR, "Invalid MAC address from "
                        "EEPROM, aborting.\n");
                err = -EAGAIN;
                DPRINTK(PROBE, ERR, "Invalid MAC address from "
                        "EEPROM, aborting.\n");
                err = -EAGAIN;
@@ -2224,8 +2667,12 @@ static int __devinit e100_probe(struct pci_dev *pdev,
           (nic->eeprom[eeprom_id] & eeprom_id_wol))
                nic->flags |= wol_magic;
 
           (nic->eeprom[eeprom_id] & eeprom_id_wol))
                nic->flags |= wol_magic;
 
-       pci_enable_wake(pdev, 0, nic->flags & (wol_magic | e100_asf(nic)));
+       /* ack any pending wake events, disable PME */
+       err = pci_enable_wake(pdev, 0, 0);
+       if (err)
+               DPRINTK(PROBE, ERR, "Error clearing wake event\n");
 
 
+       strcpy(netdev->name, "eth%d");
        if((err = register_netdev(netdev))) {
                DPRINTK(PROBE, ERR, "Cannot register net device, aborting.\n");
                goto err_out_free;
        if((err = register_netdev(netdev))) {
                DPRINTK(PROBE, ERR, "Cannot register net device, aborting.\n");
                goto err_out_free;
@@ -2258,7 +2705,7 @@ static void __devexit e100_remove(struct pci_dev *pdev)
        struct net_device *netdev = pci_get_drvdata(pdev);
 
        if(netdev) {
        struct net_device *netdev = pci_get_drvdata(pdev);
 
        if(netdev) {
-               struct nic *nic = netdev->priv;
+               struct nic *nic = netdev_priv(netdev);
                unregister_netdev(netdev);
                e100_free(nic);
                iounmap(nic->csr);
                unregister_netdev(netdev);
                e100_free(nic);
                iounmap(nic->csr);
@@ -2270,20 +2717,26 @@ static void __devexit e100_remove(struct pci_dev *pdev)
 }
 
 #ifdef CONFIG_PM
 }
 
 #ifdef CONFIG_PM
-static int e100_suspend(struct pci_dev *pdev, u32 state)
+static int e100_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
-       struct nic *nic = netdev->priv;
+       struct nic *nic = netdev_priv(netdev);
+       int retval;
 
        if(netif_running(netdev))
                e100_down(nic);
        e100_hw_reset(nic);
        netif_device_detach(netdev);
 
 
        if(netif_running(netdev))
                e100_down(nic);
        e100_hw_reset(nic);
        netif_device_detach(netdev);
 
-       pci_save_state(pdev, nic->pm_state);
-       pci_enable_wake(pdev, state, nic->flags & (wol_magic | e100_asf(nic)));
+       pci_save_state(pdev);
+       retval = pci_enable_wake(pdev, pci_choose_state(pdev, state),
+                                nic->flags & (wol_magic | e100_asf(nic)));
+       if (retval)
+               DPRINTK(PROBE,ERR, "Error enabling wake\n");
        pci_disable_device(pdev);
        pci_disable_device(pdev);
-       pci_set_power_state(pdev, state);
+       retval = pci_set_power_state(pdev, pci_choose_state(pdev, state));
+       if (retval)
+               DPRINTK(PROBE,ERR, "Error %d setting power state\n", retval);
 
        return 0;
 }
 
        return 0;
 }
@@ -2291,11 +2744,17 @@ static int e100_suspend(struct pci_dev *pdev, u32 state)
 static int e100_resume(struct pci_dev *pdev)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
 static int e100_resume(struct pci_dev *pdev)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
-       struct nic *nic = netdev->priv;
-
-       pci_set_power_state(pdev, 0);
-       pci_restore_state(pdev, nic->pm_state);
-       e100_hw_init(nic);
+       struct nic *nic = netdev_priv(netdev);
+       int retval;
+
+       retval = pci_set_power_state(pdev, PCI_D0);
+       if (retval)
+               DPRINTK(PROBE,ERR, "Error waking adapter\n");
+       pci_restore_state(pdev);
+       /* ack any pending wake events, disable PME */
+       retval = pci_enable_wake(pdev, 0, 0);
+       if (retval)
+               DPRINTK(PROBE,ERR, "Error clearing wake events\n");
 
        netif_device_attach(netdev);
        if(netif_running(netdev))
 
        netif_device_attach(netdev);
        if(netif_running(netdev))
@@ -2305,6 +2764,23 @@ static int e100_resume(struct pci_dev *pdev)
 }
 #endif
 
 }
 #endif
 
+
+static void e100_shutdown(struct pci_dev *pdev)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct nic *nic = netdev_priv(netdev);
+       int retval;
+
+#ifdef CONFIG_PM
+       retval = pci_enable_wake(pdev, 0, nic->flags & (wol_magic | e100_asf(nic)));
+#else
+       retval = pci_enable_wake(pdev, 0, nic->flags & (wol_magic));
+#endif
+       if (retval)
+               DPRINTK(PROBE,ERR, "Error enabling wake\n");
+}
+
+
 static struct pci_driver e100_driver = {
        .name =         DRV_NAME,
        .id_table =     e100_id_table,
 static struct pci_driver e100_driver = {
        .name =         DRV_NAME,
        .id_table =     e100_id_table,
@@ -2314,6 +2790,7 @@ static struct pci_driver e100_driver = {
        .suspend =      e100_suspend,
        .resume =       e100_resume,
 #endif
        .suspend =      e100_suspend,
        .resume =       e100_resume,
 #endif
+       .shutdown =     e100_shutdown,
 };
 
 static int __init e100_init_module(void)
 };
 
 static int __init e100_init_module(void)
@@ -2322,7 +2799,7 @@ static int __init e100_init_module(void)
                printk(KERN_INFO PFX "%s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
                printk(KERN_INFO PFX "%s\n", DRV_COPYRIGHT);
        }
                printk(KERN_INFO PFX "%s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
                printk(KERN_INFO PFX "%s\n", DRV_COPYRIGHT);
        }
-        return pci_module_init(&e100_driver);
+       return pci_module_init(&e100_driver);
 }
 
 static void __exit e100_cleanup_module(void)
 }
 
 static void __exit e100_cleanup_module(void)