vserver 1.9.5.x5
[linux-2.6.git] / drivers / net / 3c59x.c
index a450864..b22ed57 100644 (file)
@@ -238,12 +238,6 @@ static int vortex_debug = VORTEX_DEBUG;
 static int vortex_debug = 1;
 #endif
 
-#ifndef __OPTIMIZE__
-#error You must compile this file with the correct options!
-#error See the last lines of the source file.
-#error You must compile this driver with "-O".
-#endif
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -263,8 +257,8 @@ static int vortex_debug = 1;
 #include <linux/ethtool.h>
 #include <linux/highmem.h>
 #include <linux/eisa.h>
+#include <linux/bitops.h>
 #include <asm/irq.h>                   /* For NR_IRQS only. */
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
@@ -283,37 +277,8 @@ MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("3Com 3c59x/3c9xx ethernet driver "
                                        DRV_VERSION " " DRV_RELDATE);
 MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
 
-MODULE_PARM(debug, "i");
-MODULE_PARM(global_options, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(global_full_duplex, "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(hw_checksums, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(flow_ctrl, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(global_enable_wol, "i");
-MODULE_PARM(enable_wol, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(compaq_ioaddr, "i");
-MODULE_PARM(compaq_irq, "i");
-MODULE_PARM(compaq_device_id, "i");
-MODULE_PARM(watchdog, "i");
-MODULE_PARM_DESC(debug, "3c59x debug level (0-6)");
-MODULE_PARM_DESC(options, "3c59x: Bits 0-3: media type, bit 4: bus mastering, bit 9: full duplex");
-MODULE_PARM_DESC(global_options, "3c59x: same as options, but applies to all NICs if options is unset");
-MODULE_PARM_DESC(full_duplex, "3c59x full duplex setting(s) (1)");
-MODULE_PARM_DESC(global_full_duplex, "3c59x: same as full_duplex, but applies to all NICs if options is unset");
-MODULE_PARM_DESC(hw_checksums, "3c59x Hardware checksum checking by adapter(s) (0-1)");
-MODULE_PARM_DESC(flow_ctrl, "3c59x 802.3x flow control usage (PAUSE only) (0-1)");
-MODULE_PARM_DESC(enable_wol, "3c59x: Turn on Wake-on-LAN for adapter(s) (0-1)");
-MODULE_PARM_DESC(global_enable_wol, "3c59x: same as enable_wol, but applies to all NICs if options is unset");
-MODULE_PARM_DESC(rx_copybreak, "3c59x copy breakpoint for copy-only-tiny-frames");
-MODULE_PARM_DESC(max_interrupt_work, "3c59x maximum events handled per interrupt");
-MODULE_PARM_DESC(compaq_ioaddr, "3c59x PCI I/O base address (Compaq BIOS problem workaround)");
-MODULE_PARM_DESC(compaq_irq, "3c59x PCI IRQ number (Compaq BIOS problem workaround)");
-MODULE_PARM_DESC(compaq_device_id, "3c59x PCI device ID (Compaq BIOS problem workaround)");
-MODULE_PARM_DESC(watchdog, "3c59x transmit timeout in milliseconds");
 
 /* Operational parameter that usually are not changed. */
 
@@ -422,7 +387,7 @@ enum {      IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, IS_TORNADO=8,
        HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100,
        INVERT_MII_PWR=0x200, INVERT_LED_PWR=0x400, MAX_COLLISION_RESET=0x800,
        EEPROM_OFFSET=0x1000, HAS_HWCKSM=0x2000, WNO_XCVR_PWR=0x4000,
-       EXTRA_PREAMBLE=0x8000, };
+       EXTRA_PREAMBLE=0x8000, EEPROM_RESET=0x10000, };
 
 enum vortex_chips {
        CH_3C590 = 0,
@@ -446,6 +411,7 @@ enum vortex_chips {
        CH_3C905B_2,
        CH_3C905B_FX,
        CH_3C905C,
+       CH_3C9202,
        CH_3C980,
        CH_3C9805,
 
@@ -496,9 +462,9 @@ static struct vortex_chip_info {
        {"3c595 Vortex 100base-MII",
         PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
        {"3c900 Boomerang 10baseT",
-        PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
+        PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, },
        {"3c900 Boomerang 10Mbps Combo",
-        PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
+        PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, },
        {"3c900 Cyclone 10Mbps TPO",                                            /* AKPM: from Don's 0.99M */
         PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
        {"3c900 Cyclone 10Mbps Combo",
@@ -509,9 +475,9 @@ static struct vortex_chip_info {
        {"3c900B-FL Cyclone 10base-FL",
         PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
        {"3c905 Boomerang 100baseTx",
-        PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, },
+        PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, },
        {"3c905 Boomerang 100baseT4",
-        PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, },
+        PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, },
        {"3c905B Cyclone 100baseTx",
         PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
 
@@ -520,12 +486,14 @@ static struct vortex_chip_info {
        {"3c905B-FX Cyclone 100baseFx",
         PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
        {"3c905C Tornado",
-        PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
+       PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
+       {"3c920B-EMB-WNM (ATI Radeon 9100 IGP)",
+        PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_MII|HAS_HWCKSM, 128, },
        {"3c980 Cyclone",
         PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
+
        {"3c980C Python-T",
         PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
-
        {"3cSOHO100-TX Hurricane",
         PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
        {"3c555 Laptop Hurricane",
@@ -536,9 +504,9 @@ static struct vortex_chip_info {
        {"3c556B Laptop Hurricane",
         PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR|
                                        WNO_XCVR_PWR|HAS_HWCKSM, 128, },
+
        {"3c575 [Megahertz] 10/100 LAN  CardBus",
        PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
-
        {"3c575 Boomerang CardBus",
         PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
        {"3CCFE575BT Cyclone CardBus",
@@ -550,10 +518,10 @@ static struct vortex_chip_info {
        {"3CCFE656 Cyclone CardBus",
         PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
                                                                        INVERT_LED_PWR|HAS_HWCKSM, 128, },
+
        {"3CCFEM656B Cyclone+Winmodem CardBus",
         PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
                                                                        INVERT_LED_PWR|HAS_HWCKSM, 128, },
-
        {"3CXFEM656C Tornado+Winmodem CardBus",                 /* From pcmcia-cs-3.1.5 */
         PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
                                                                        MAX_COLLISION_RESET|HAS_HWCKSM, 128, },
@@ -563,15 +531,15 @@ static struct vortex_chip_info {
         PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
        {"3c982 Hydra Dual Port A",
         PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, },
+
        {"3c982 Hydra Dual Port B",
         PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, },
-
        {"3c905B-T4",
         PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
        {"3c920B-EMB-WNM Tornado",
         PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
 
-       {0,}, /* 0 terminated list. */
+       {NULL,}, /* NULL terminated list. */
 };
 
 
@@ -597,6 +565,7 @@ static struct pci_device_id vortex_pci_tbl[] = {
        { 0x10B7, 0x9058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_2 },
        { 0x10B7, 0x905A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_FX },
        { 0x10B7, 0x9200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905C },
+       { 0x10B7, 0x9202, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C9202 },
        { 0x10B7, 0x9800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C980 },
        { 0x10B7, 0x9805, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C9805 },
 
@@ -697,7 +666,7 @@ enum Window2 {                      /* Window 2. */
        Wn2_ResetOptions=12,
 };
 enum Window3 {                 /* Window 3: MAC/config bits. */
-       Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8,
+       Wn3_Config=0, Wn3_MaxPktSize=4, Wn3_MAC_Ctrl=6, Wn3_Options=8,
 };
 
 #define BFEXT(value, offset, bitcount)  \
@@ -725,7 +694,8 @@ enum Win4_Media_bits {
        Media_LnkBeat = 0x0800,
 };
 enum Window7 {                                 /* Window 7: Bus Master control. */
-       Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12,
+       Wn7_MasterAddr = 0, Wn7_VlanEtherType=4, Wn7_MasterLen = 6,
+       Wn7_MasterStatus = 12,
 };
 /* Boomerang bus master control registers. */
 enum MasterCtrl {
@@ -782,6 +752,12 @@ enum tx_desc_status {
 /* Chip features we care about in vp->capabilities, read from the EEPROM. */
 enum ChipCaps { CapBusMaster=0x20, CapPwrMgmt=0x2000 };
 
+struct vortex_extra_stats {
+        unsigned long tx_deferred;
+        unsigned long tx_multiple_collisions;
+        unsigned long rx_bad_ssd;
+};
+
 struct vortex_private {
        /* The Rx and Tx rings should be quad-word-aligned. */
        struct boom_rx_desc* rx_ring;
@@ -793,13 +769,14 @@ struct vortex_private {
        struct sk_buff* tx_skbuff[TX_RING_SIZE];
        unsigned int cur_rx, cur_tx;            /* The next free ring entry */
        unsigned int dirty_rx, dirty_tx;        /* The ring entries to be free()ed. */
-       struct net_device_stats stats;
+       struct net_device_stats stats;          /* Generic stats */
+       struct vortex_extra_stats xstats;       /* NIC-specific extra stats */
        struct sk_buff *tx_skb;                         /* Packet being eaten by bus master ctrl.  */
        dma_addr_t tx_skb_dma;                          /* Allocated DMA address for bus master ctrl DMA.   */
 
        /* PCI configuration space information. */
        struct device *gendev;
-       char *cb_fn_base;                                       /* CardBus function status addr space. */
+       char __iomem *cb_fn_base;               /* CardBus function status addr space. */
 
        /* Some values here only for performance evaluation and path-coverage */
        int rx_nocopy, rx_copy, queued_packet, rx_csumhits;
@@ -818,10 +795,11 @@ struct vortex_private {
                partner_flow_ctrl:1,                    /* Partner supports flow control */
                has_nway:1,
                enable_wol:1,                                   /* Wake-on-LAN is enabled */
-               pm_state_valid:1,                               /* power_state[] has sane contents */
+               pm_state_valid:1,                               /* pci_dev->saved_config_space has sane contents */
                open:1,
                medialock:1,
-               must_free_region:1;                             /* Flag: if zero, Cardbus owns the I/O region */
+               must_free_region:1,                             /* Flag: if zero, Cardbus owns the I/O region */
+               large_frames:1;                 /* accept large frames */
        int drv_flags;
        u16 status_enable;
        u16 intr_enable;
@@ -833,8 +811,7 @@ struct vortex_private {
                                                                                 * bale from the ISR */
        u16 io_size;                                            /* Size of PCI region (for release_region) */
        spinlock_t lock;                                        /* Serialise access to device & its vortex_private */
-       spinlock_t mdio_lock;                           /* Serialise access to mdio hardware */
-       u32 power_state[16];
+       struct mii_if_info mii;                         /* MII lib hooks/info */
 };
 
 #ifdef CONFIG_PCI
@@ -881,10 +858,21 @@ static struct media_table {
   { "Default",  0,                     0xFF, XCVR_10baseT, 10000},
 };
 
+static struct {
+       const char str[ETH_GSTRING_LEN];
+} ethtool_stats_keys[] = {
+       { "tx_deferred" },
+       { "tx_multiple_collisions" },
+       { "rx_bad_ssd" },
+};
+
+/* number of ETHTOOL_GSTATS u64's */
+#define VORTEX_NUM_STATS     3
+
 static int vortex_probe1(struct device *gendev, long ioaddr, int irq,
                                   int chip_idx, int card_idx);
 static void vortex_up(struct net_device *dev);
-static void vortex_down(struct net_device *dev);
+static void vortex_down(struct net_device *dev, int final);
 static int vortex_open(struct net_device *dev);
 static void mdio_sync(long ioaddr, int bits);
 static int mdio_read(struct net_device *dev, int phy_id, int location);
@@ -902,10 +890,14 @@ static void dump_tx_ring(struct net_device *dev);
 static void update_stats(long ioaddr, struct net_device *dev);
 static struct net_device_stats *vortex_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
+#ifdef CONFIG_PCI
 static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+#endif
 static void vortex_tx_timeout(struct net_device *dev);
 static void acpi_set_WOL(struct net_device *dev);
 static struct ethtool_ops vortex_ethtool_ops;
+static void set_8021q_mode(struct net_device *dev, int enable);
+
 \f
 /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
 /* Option count limit only -- unlimited interfaces are supported. */
@@ -927,10 +919,41 @@ static struct net_device *compaq_net_device;
 
 static int vortex_cards_found;
 
+module_param(debug, int, 0);
+module_param(global_options, int, 0);
+module_param_array(options, int, NULL, 0);
+module_param(global_full_duplex, int, 0);
+module_param_array(full_duplex, int, NULL, 0);
+module_param_array(hw_checksums, int, NULL, 0);
+module_param_array(flow_ctrl, int, NULL, 0);
+module_param(global_enable_wol, int, 0);
+module_param_array(enable_wol, int, NULL, 0);
+module_param(rx_copybreak, int, 0);
+module_param(max_interrupt_work, int, 0);
+module_param(compaq_ioaddr, int, 0);
+module_param(compaq_irq, int, 0);
+module_param(compaq_device_id, int, 0);
+module_param(watchdog, int, 0);
+MODULE_PARM_DESC(debug, "3c59x debug level (0-6)");
+MODULE_PARM_DESC(options, "3c59x: Bits 0-3: media type, bit 4: bus mastering, bit 9: full duplex");
+MODULE_PARM_DESC(global_options, "3c59x: same as options, but applies to all NICs if options is unset");
+MODULE_PARM_DESC(full_duplex, "3c59x full duplex setting(s) (1)");
+MODULE_PARM_DESC(global_full_duplex, "3c59x: same as full_duplex, but applies to all NICs if options is unset");
+MODULE_PARM_DESC(hw_checksums, "3c59x Hardware checksum checking by adapter(s) (0-1)");
+MODULE_PARM_DESC(flow_ctrl, "3c59x 802.3x flow control usage (PAUSE only) (0-1)");
+MODULE_PARM_DESC(enable_wol, "3c59x: Turn on Wake-on-LAN for adapter(s) (0-1)");
+MODULE_PARM_DESC(global_enable_wol, "3c59x: same as enable_wol, but applies to all NICs if options is unset");
+MODULE_PARM_DESC(rx_copybreak, "3c59x copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(max_interrupt_work, "3c59x maximum events handled per interrupt");
+MODULE_PARM_DESC(compaq_ioaddr, "3c59x PCI I/O base address (Compaq BIOS problem workaround)");
+MODULE_PARM_DESC(compaq_irq, "3c59x PCI IRQ number (Compaq BIOS problem workaround)");
+MODULE_PARM_DESC(compaq_device_id, "3c59x PCI device ID (Compaq BIOS problem workaround)");
+MODULE_PARM_DESC(watchdog, "3c59x transmit timeout in milliseconds");
+
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void poll_vortex(struct net_device *dev)
 {
-       struct vortex_private *vp = (struct vortex_private *)dev->priv;
+       struct vortex_private *vp = netdev_priv(dev);
        unsigned long flags;
        local_save_flags(flags);
        local_irq_disable();
@@ -948,7 +971,7 @@ static int vortex_suspend (struct pci_dev *pdev, u32 state)
        if (dev && dev->priv) {
                if (netif_running(dev)) {
                        netif_device_detach(dev);
-                       vortex_down(dev);
+                       vortex_down(dev, 1);
                }
        }
        return 0;
@@ -1071,14 +1094,20 @@ static int __devinit vortex_init_one (struct pci_dev *pdev,
        int rc;
 
        /* wake up and enable device */         
-       if (pci_enable_device (pdev)) {
-               rc = -EIO;
-       } else {
-               rc = vortex_probe1 (&pdev->dev, pci_resource_start (pdev, 0),
-                                                       pdev->irq, ent->driver_data, vortex_cards_found);
-               if (rc == 0)
-                       vortex_cards_found++;
+       rc = pci_enable_device (pdev);
+       if (rc < 0)
+               goto out;
+
+       rc = vortex_probe1 (&pdev->dev, pci_resource_start (pdev, 0),
+                                               pdev->irq, ent->driver_data, vortex_cards_found);
+       if (rc < 0) {
+               pci_disable_device (pdev);
+               goto out;
        }
+
+       vortex_cards_found++;
+
+out:
        return rc;
 }
 
@@ -1166,6 +1195,7 @@ static int __devinit vortex_probe1(struct device *gendev,
        dev->base_addr = ioaddr;
        dev->irq = irq;
        dev->mtu = mtu;
+       vp->large_frames = mtu > 1500;
        vp->drv_flags = vci->drv_flags;
        vp->has_nway = (vci->drv_flags & HAS_NWAY) ? 1 : 0;
        vp->io_size = vci->io_size;
@@ -1206,8 +1236,12 @@ static int __devinit vortex_probe1(struct device *gendev,
        }
 
        spin_lock_init(&vp->lock);
-       spin_lock_init(&vp->mdio_lock);
        vp->gendev = gendev;
+       vp->mii.dev = dev;
+       vp->mii.mdio_read = mdio_read;
+       vp->mii.mdio_write = mdio_write;
+       vp->mii.phy_id_mask = 0x1f;
+       vp->mii.reg_num_mask = 0x1f;
 
        /* Makes sure rings are at least 16 byte aligned. */
        vp->rx_ring = pci_alloc_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE
@@ -1292,6 +1326,13 @@ static int __devinit vortex_probe1(struct device *gendev,
                for (i = 0; i < 6; i++)
                        printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
        }
+       /* Unfortunately an all zero eeprom passes the checksum and this
+          gets found in the wild in failure cases. Crypto is hard 8) */
+       if (!is_valid_ether_addr(dev->dev_addr)) {
+               retval = -EINVAL;
+               printk(KERN_ERR "*** EEPROM MAC address is invalid.\n");
+               goto free_ring; /* With every pack */
+       }
        EL3WINDOW(2);
        for (i = 0; i < 6; i++)
                outb(dev->dev_addr[i], ioaddr + i);
@@ -1435,6 +1476,7 @@ static int __devinit vortex_probe1(struct device *gendev,
                                mdio_write(dev, vp->phys[0], 4, vp->advertising);
                        }
                }
+               vp->mii.phy_id = vp->phys[0];
        }
 
        if (vp->capabilities & CapBusMaster) {
@@ -1470,7 +1512,9 @@ static int __devinit vortex_probe1(struct device *gendev,
 
        dev->stop = vortex_close;
        dev->get_stats = vortex_get_stats;
+#ifdef CONFIG_PCI
        dev->do_ioctl = vortex_ioctl;
+#endif
        dev->ethtool_ops = &vortex_ethtool_ops;
        dev->set_multicast_list = set_rx_mode;
        dev->tx_timeout = vortex_tx_timeout;
@@ -1478,9 +1522,9 @@ static int __devinit vortex_probe1(struct device *gendev,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        dev->poll_controller = poll_vortex; 
 #endif
-       if (pdev && vp->enable_wol) {
+       if (pdev) {
                vp->pm_state_valid = 1;
-               pci_save_state(VORTEX_PCI(vp), vp->power_state);
+               pci_save_state(VORTEX_PCI(vp));
                acpi_set_WOL(dev);
        }
        retval = register_netdev(dev);
@@ -1535,9 +1579,10 @@ vortex_up(struct net_device *dev)
        unsigned int config;
        int i;
 
-       if (VORTEX_PCI(vp) && vp->enable_wol) {
-               pci_set_power_state(VORTEX_PCI(vp), 0); /* Go active */
-               pci_restore_state(VORTEX_PCI(vp), vp->power_state);
+       if (VORTEX_PCI(vp)) {
+               pci_set_power_state(VORTEX_PCI(vp), PCI_D0);    /* Go active */
+               pci_restore_state(VORTEX_PCI(vp));
+               pci_enable_device(VORTEX_PCI(vp));
        }
 
        /* Before initializing select the active media port. */
@@ -1618,7 +1663,7 @@ vortex_up(struct net_device *dev)
 
        /* Set the full-duplex bit. */
        outw(   ((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) |
-                       (dev->mtu > 1500 ? 0x40 : 0) |
+                       (vp->large_frames ? 0x40 : 0) |
                        ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0),
                        ioaddr + Wn3_MAC_Ctrl);
 
@@ -1697,11 +1742,13 @@ vortex_up(struct net_device *dev)
                for (i = 0; i < RX_RING_SIZE; i++)      /* AKPM: this is done in vortex_open, too */
                        vp->rx_ring[i].status = 0;
                for (i = 0; i < TX_RING_SIZE; i++)
-                       vp->tx_skbuff[i] = 0;
+                       vp->tx_skbuff[i] = NULL;
                outl(0, ioaddr + DownListPtr);
        }
        /* Set receiver mode: presumably accept b-case and phys addr only. */
        set_rx_mode(dev);
+       /* enable 802.1q tagged frames */
+       set_8021q_mode(dev, 1);
        outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
 
 //     issue_and_wait(dev, SetTxStart|0x07ff);
@@ -1762,7 +1809,7 @@ vortex_open(struct net_device *dev)
                        for (j = 0; j < i; j++) {
                                if (vp->rx_skbuff[j]) {
                                        dev_kfree_skb(vp->rx_skbuff[j]);
-                                       vp->rx_skbuff[j] = 0;
+                                       vp->rx_skbuff[j] = NULL;
                                }
                        }
                        retval = -ENOMEM;
@@ -1823,6 +1870,7 @@ vortex_timer(unsigned long data)
                break;
        case XCVR_MII: case XCVR_NWAY:
                {
+                       spin_lock_bh(&vp->lock);
                        mii_status = mdio_read(dev, vp->phys[0], 1);
                        ok = 1;
                        if (vortex_debug > 2)
@@ -1844,7 +1892,7 @@ vortex_timer(unsigned long data)
                                                /* Set the full-duplex bit. */
                                                EL3WINDOW(3);
                                                outw(   (vp->full_duplex ? 0x20 : 0) |
-                                                               (dev->mtu > 1500 ? 0x40 : 0) |
+                                                               (vp->large_frames ? 0x40 : 0) |
                                                                ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0),
                                                                ioaddr + Wn3_MAC_Ctrl);
                                                if (vortex_debug > 1)
@@ -1856,6 +1904,7 @@ vortex_timer(unsigned long data)
                        } else {
                                netif_carrier_off(dev);
                        }
+                       spin_unlock_bh(&vp->lock);
                }
                break;
          default:                                      /* Other media types handled by Tx timeouts. */
@@ -1940,9 +1989,9 @@ static void vortex_tx_timeout(struct net_device *dev)
                        unsigned long flags;
                        local_irq_save(flags);
                        if (vp->full_bus_master_tx)
-                               boomerang_interrupt(dev->irq, dev, 0);
+                               boomerang_interrupt(dev->irq, dev, NULL);
                        else
-                               vortex_interrupt(dev->irq, dev, 0);
+                               vortex_interrupt(dev->irq, dev, NULL);
                        local_irq_restore(flags);
                }
        }
@@ -2059,7 +2108,8 @@ vortex_error(struct net_device *dev, int status)
                                printk(KERN_ERR "%s: PCI bus error, bus status %8.8x\n", dev->name, bus_status);
 
                        /* In this case, blow the card away */
-                       vortex_down(dev);
+                       /* Must not enter D3 or we can't legally issue the reset! */
+                       vortex_down(dev, 0);
                        issue_and_wait(dev, TotalReset | 0xff);
                        vortex_up(dev);         /* AKPM: bug.  vortex_up() assumes that the rx ring is full. It may not be. */
                } else if (fifo_diag & 0x0400)
@@ -2069,6 +2119,8 @@ vortex_error(struct net_device *dev, int status)
                        issue_and_wait(dev, RxReset|0x07);
                        /* Set the Rx filter to the current state. */
                        set_rx_mode(dev);
+                       /* enable 802.1q VLAN tagged frames */
+                       set_8021q_mode(dev, 1);
                        outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
                        outw(AckIntr | HostError, ioaddr + EL3_CMD);
                }
@@ -2420,7 +2472,7 @@ boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                                                le32_to_cpu(vp->tx_ring[entry].addr), skb->len, PCI_DMA_TODEVICE);
 #endif
                                        dev_kfree_skb_irq(skb);
-                                       vp->tx_skbuff[entry] = 0;
+                                       vp->tx_skbuff[entry] = NULL;
                                } else {
                                        printk(KERN_DEBUG "boomerang_interrupt: no skb!\n");
                                }
@@ -2656,7 +2708,7 @@ rx_oom_timer(unsigned long arg)
 }
 
 static void
-vortex_down(struct net_device *dev)
+vortex_down(struct net_device *dev, int final_down)
 {
        struct vortex_private *vp = netdev_priv(dev);
        long ioaddr = dev->base_addr;
@@ -2673,6 +2725,9 @@ vortex_down(struct net_device *dev)
        outw(RxDisable, ioaddr + EL3_CMD);
        outw(TxDisable, ioaddr + EL3_CMD);
 
+       /* Disable receiving 802.1q tagged frames */
+       set_8021q_mode(dev, 0);
+
        if (dev->if_port == XCVR_10base2)
                /* Turn off thinnet power.  Green! */
                outw(StopCoax, ioaddr + EL3_CMD);
@@ -2685,8 +2740,8 @@ vortex_down(struct net_device *dev)
        if (vp->full_bus_master_tx)
                outl(0, ioaddr + DownListPtr);
 
-       if (VORTEX_PCI(vp) && vp->enable_wol) {
-               pci_save_state(VORTEX_PCI(vp), vp->power_state);
+       if (final_down && VORTEX_PCI(vp)) {
+               pci_save_state(VORTEX_PCI(vp));
                acpi_set_WOL(dev);
        }
 }
@@ -2699,7 +2754,7 @@ vortex_close(struct net_device *dev)
        int i;
 
        if (netif_device_present(dev))
-               vortex_down(dev);
+               vortex_down(dev, 1);
 
        if (vortex_debug > 1) {
                printk(KERN_DEBUG"%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
@@ -2725,7 +2780,7 @@ vortex_close(struct net_device *dev)
                                pci_unmap_single(       VORTEX_PCI(vp), le32_to_cpu(vp->rx_ring[i].addr),
                                                                        PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
                                dev_kfree_skb(vp->rx_skbuff[i]);
-                               vp->rx_skbuff[i] = 0;
+                               vp->rx_skbuff[i] = NULL;
                        }
        }
        if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */
@@ -2744,7 +2799,7 @@ vortex_close(struct net_device *dev)
                                pci_unmap_single(VORTEX_PCI(vp), le32_to_cpu(vp->tx_ring[i].addr), skb->len, PCI_DMA_TODEVICE);
 #endif
                                dev_kfree_skb(skb);
-                               vp->tx_skbuff[i] = 0;
+                               vp->tx_skbuff[i] = NULL;
                        }
                }
        }
@@ -2818,23 +2873,23 @@ static void update_stats(long ioaddr, struct net_device *dev)
        /* Switch to the stats window, and read everything. */
        EL3WINDOW(6);
        vp->stats.tx_carrier_errors             += inb(ioaddr + 0);
-       vp->stats.tx_heartbeat_errors   += inb(ioaddr + 1);
-       /* Multiple collisions. */              inb(ioaddr + 2);
+       vp->stats.tx_heartbeat_errors           += inb(ioaddr + 1);
        vp->stats.collisions                    += inb(ioaddr + 3);
        vp->stats.tx_window_errors              += inb(ioaddr + 4);
        vp->stats.rx_fifo_errors                += inb(ioaddr + 5);
        vp->stats.tx_packets                    += inb(ioaddr + 6);
        vp->stats.tx_packets                    += (inb(ioaddr + 9)&0x30) << 4;
-       /* Rx packets   */                              inb(ioaddr + 7);   /* Must read to clear */
-       /* Tx deferrals */                              inb(ioaddr + 8);
+       /* Rx packets   */                      inb(ioaddr + 7);   /* Must read to clear */
        /* Don't bother with register 9, an extension of registers 6&7.
           If we do use the 6&7 values the atomic update assumption above
           is invalid. */
-       vp->stats.rx_bytes += inw(ioaddr + 10);
-       vp->stats.tx_bytes += inw(ioaddr + 12);
-       /* New: On the Vortex we must also clear the BadSSD counter. */
+       vp->stats.rx_bytes                      += inw(ioaddr + 10);
+       vp->stats.tx_bytes                      += inw(ioaddr + 12);
+       /* Extra stats for get_ethtool_stats() */
+       vp->xstats.tx_multiple_collisions       += inb(ioaddr + 2);
+       vp->xstats.tx_deferred                  += inb(ioaddr + 8);
        EL3WINDOW(4);
-       inb(ioaddr + 12);
+       vp->xstats.rx_bad_ssd                   += inb(ioaddr + 12);
 
        {
                u8 up = inb(ioaddr + 13);
@@ -2846,6 +2901,104 @@ static void update_stats(long ioaddr, struct net_device *dev)
        return;
 }
 
+static int vortex_nway_reset(struct net_device *dev)
+{
+       struct vortex_private *vp = netdev_priv(dev);
+       long ioaddr = dev->base_addr;
+       unsigned long flags;
+       int rc;
+
+       spin_lock_irqsave(&vp->lock, flags);
+       EL3WINDOW(4);
+       rc = mii_nway_restart(&vp->mii);
+       spin_unlock_irqrestore(&vp->lock, flags);
+       return rc;
+}
+
+static u32 vortex_get_link(struct net_device *dev)
+{
+       struct vortex_private *vp = netdev_priv(dev);
+       long ioaddr = dev->base_addr;
+       unsigned long flags;
+       int rc;
+
+       spin_lock_irqsave(&vp->lock, flags);
+       EL3WINDOW(4);
+       rc = mii_link_ok(&vp->mii);
+       spin_unlock_irqrestore(&vp->lock, flags);
+       return rc;
+}
+
+static int vortex_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct vortex_private *vp = netdev_priv(dev);
+       long ioaddr = dev->base_addr;
+       unsigned long flags;
+       int rc;
+
+       spin_lock_irqsave(&vp->lock, flags);
+       EL3WINDOW(4);
+       rc = mii_ethtool_gset(&vp->mii, cmd);
+       spin_unlock_irqrestore(&vp->lock, flags);
+       return rc;
+}
+
+static int vortex_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct vortex_private *vp = netdev_priv(dev);
+       long ioaddr = dev->base_addr;
+       unsigned long flags;
+       int rc;
+
+       spin_lock_irqsave(&vp->lock, flags);
+       EL3WINDOW(4);
+       rc = mii_ethtool_sset(&vp->mii, cmd);
+       spin_unlock_irqrestore(&vp->lock, flags);
+       return rc;
+}
+
+static u32 vortex_get_msglevel(struct net_device *dev)
+{
+       return vortex_debug;
+}
+
+static void vortex_set_msglevel(struct net_device *dev, u32 dbg)
+{
+       vortex_debug = dbg;
+}
+
+static int vortex_get_stats_count(struct net_device *dev)
+{
+       return VORTEX_NUM_STATS;
+}
+
+static void vortex_get_ethtool_stats(struct net_device *dev,
+       struct ethtool_stats *stats, u64 *data)
+{
+       struct vortex_private *vp = netdev_priv(dev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&vp->lock, flags);
+       update_stats(dev->base_addr, dev);
+       spin_unlock_irqrestore(&vp->lock, flags);
+
+       data[0] = vp->xstats.tx_deferred;
+       data[1] = vp->xstats.tx_multiple_collisions;
+       data[2] = vp->xstats.rx_bad_ssd;
+}
+
+
+static void vortex_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+       switch (stringset) {
+       case ETH_SS_STATS:
+               memcpy(data, &ethtool_stats_keys, sizeof(ethtool_stats_keys));
+               break;
+       default:
+               WARN_ON(1);
+               break;
+       }
+}
 
 static void vortex_get_drvinfo(struct net_device *dev,
                                        struct ethtool_drvinfo *info)
@@ -2866,43 +3019,48 @@ static void vortex_get_drvinfo(struct net_device *dev,
 }
 
 static struct ethtool_ops vortex_ethtool_ops = {
-       .get_drvinfo =          vortex_get_drvinfo,
+       .get_drvinfo            = vortex_get_drvinfo,
+       .get_strings            = vortex_get_strings,
+       .get_msglevel           = vortex_get_msglevel,
+       .set_msglevel           = vortex_set_msglevel,
+       .get_ethtool_stats      = vortex_get_ethtool_stats,
+       .get_stats_count        = vortex_get_stats_count,
+       .get_settings           = vortex_get_settings,
+       .set_settings           = vortex_set_settings,
+       .get_link               = vortex_get_link,
+       .nway_reset             = vortex_nway_reset,
 };
 
+#ifdef CONFIG_PCI
+/*
+ *     Must power the device up to do MDIO operations
+ */
 static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
+       int err;
        struct vortex_private *vp = netdev_priv(dev);
        long ioaddr = dev->base_addr;
-       struct mii_ioctl_data *data = if_mii(rq);
-       int phy = vp->phys[0] & 0x1f;
-       int retval;
+       unsigned long flags;
+       int state = 0;
 
-       switch(cmd) {
-       case SIOCGMIIPHY:               /* Get address of MII PHY in use. */
-               data->phy_id = phy;
+       if(VORTEX_PCI(vp))
+               state = VORTEX_PCI(vp)->current_state;
 
-       case SIOCGMIIREG:               /* Read MII PHY register. */
-               EL3WINDOW(4);
-               data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
-               retval = 0;
-               break;
+       /* The kernel core really should have pci_get_power_state() */
 
-       case SIOCSMIIREG:               /* Write MII PHY register. */
-               if (!capable(CAP_NET_ADMIN)) {
-                       retval = -EPERM;
-               } else {
-                       EL3WINDOW(4);
-                       mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
-                       retval = 0;
-               }
-               break;
-       default:
-               retval = -EOPNOTSUPP;
-               break;
-       }
+       if(state != 0)
+               pci_set_power_state(VORTEX_PCI(vp), PCI_D0);
+       spin_lock_irqsave(&vp->lock, flags);
+       EL3WINDOW(4);
+       err = generic_mii_ioctl(&vp->mii, if_mii(rq), cmd, NULL);
+       spin_unlock_irqrestore(&vp->lock, flags);
+       if(state != 0)
+               pci_set_power_state(VORTEX_PCI(vp), state);
 
-       return retval;
+       return err;
 }
+#endif
+
 
 /* Pre-Cyclone chips have no documented multicast filter, so the only
    multicast setting is to receive all multicast frames.  At least
@@ -2924,6 +3082,61 @@ static void set_rx_mode(struct net_device *dev)
        outw(new_mode, ioaddr + EL3_CMD);
 }
 
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+/* Setup the card so that it can receive frames with an 802.1q VLAN tag.
+   Note that this must be done after each RxReset due to some backwards
+   compatibility logic in the Cyclone and Tornado ASICs */
+
+/* The Ethernet Type used for 802.1q tagged frames */
+#define VLAN_ETHER_TYPE 0x8100
+
+static void set_8021q_mode(struct net_device *dev, int enable)
+{
+       struct vortex_private *vp = netdev_priv(dev);
+       long ioaddr = dev->base_addr;
+       int old_window = inw(ioaddr + EL3_CMD);
+       int mac_ctrl;
+
+       if ((vp->drv_flags&IS_CYCLONE) || (vp->drv_flags&IS_TORNADO)) {
+               /* cyclone and tornado chipsets can recognize 802.1q
+                * tagged frames and treat them correctly */
+
+               int max_pkt_size = dev->mtu+14; /* MTU+Ethernet header */
+               if (enable)
+                       max_pkt_size += 4;      /* 802.1Q VLAN tag */
+
+               EL3WINDOW(3);
+               outw(max_pkt_size, ioaddr+Wn3_MaxPktSize);
+
+               /* set VlanEtherType to let the hardware checksumming
+                  treat tagged frames correctly */
+               EL3WINDOW(7);
+               outw(VLAN_ETHER_TYPE, ioaddr+Wn7_VlanEtherType);
+       } else {
+               /* on older cards we have to enable large frames */
+
+               vp->large_frames = dev->mtu > 1500 || enable;
+
+               EL3WINDOW(3);
+               mac_ctrl = inw(ioaddr+Wn3_MAC_Ctrl);
+               if (vp->large_frames)
+                       mac_ctrl |= 0x40;
+               else
+                       mac_ctrl &= ~0x40;
+               outw(mac_ctrl, ioaddr+Wn3_MAC_Ctrl);
+       }
+
+       EL3WINDOW(old_window);
+}
+#else
+
+static void set_8021q_mode(struct net_device *dev, int enable)
+{
+}
+
+
+#endif
+
 /* MII transceiver control section.
    Read and write the MII registers using software-generated serial
    MDIO protocol.  See the MII specifications or DP83840A data sheet
@@ -2958,15 +3171,12 @@ static void mdio_sync(long ioaddr, int bits)
 
 static int mdio_read(struct net_device *dev, int phy_id, int location)
 {
-       struct vortex_private *vp = netdev_priv(dev);
        int i;
        long ioaddr = dev->base_addr;
        int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
        unsigned int retval = 0;
        long mdio_addr = ioaddr + Wn4_PhysicalMgmt;
 
-       spin_lock_bh(&vp->mdio_lock);
-
        if (mii_preamble_required)
                mdio_sync(ioaddr, 32);
 
@@ -2986,20 +3196,16 @@ static int mdio_read(struct net_device *dev, int phy_id, int location)
                outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
                mdio_delay();
        }
-       spin_unlock_bh(&vp->mdio_lock);
        return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff;
 }
 
 static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
 {
-       struct vortex_private *vp = netdev_priv(dev);
        long ioaddr = dev->base_addr;
        int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
        long mdio_addr = ioaddr + Wn4_PhysicalMgmt;
        int i;
 
-       spin_lock_bh(&vp->mdio_lock);
-
        if (mii_preamble_required)
                mdio_sync(ioaddr, 32);
 
@@ -3018,7 +3224,6 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val
                outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
                mdio_delay();
        }
-       spin_unlock_bh(&vp->mdio_lock);
        return;
 }
 \f
@@ -3029,16 +3234,18 @@ static void acpi_set_WOL(struct net_device *dev)
        struct vortex_private *vp = netdev_priv(dev);
        long ioaddr = dev->base_addr;
 
-       /* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */
-       EL3WINDOW(7);
-       outw(2, ioaddr + 0x0c);
-       /* The RxFilter must accept the WOL frames. */
-       outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
-       outw(RxEnable, ioaddr + EL3_CMD);
+       if (vp->enable_wol) {
+               /* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */
+               EL3WINDOW(7);
+               outw(2, ioaddr + 0x0c);
+               /* The RxFilter must accept the WOL frames. */
+               outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
+               outw(RxEnable, ioaddr + EL3_CMD);
 
+               pci_enable_wake(VORTEX_PCI(vp), 0, 1);
+       }
        /* Change the power state to D3; RxEnable doesn't take effect. */
-       pci_enable_wake(VORTEX_PCI(vp), 0, 1);
-       pci_set_power_state(VORTEX_PCI(vp), 3);
+       pci_set_power_state(VORTEX_PCI(vp), PCI_D3hot);
 }
 
 
@@ -3059,14 +3266,16 @@ static void __devexit vortex_remove_one (struct pci_dev *pdev)
         * here
         */
        unregister_netdev(dev);
-       /* Should really use issue_and_wait() here */
-       outw(TotalReset|0x14, dev->base_addr + EL3_CMD);
 
-       if (VORTEX_PCI(vp) && vp->enable_wol) {
-               pci_set_power_state(VORTEX_PCI(vp), 0); /* Go active */
+       if (VORTEX_PCI(vp)) {
+               pci_set_power_state(VORTEX_PCI(vp), PCI_D0);    /* Go active */
                if (vp->pm_state_valid)
-                       pci_restore_state(VORTEX_PCI(vp), vp->power_state);
+                       pci_restore_state(VORTEX_PCI(vp));
+               pci_disable_device(VORTEX_PCI(vp));
        }
+       /* Should really use issue_and_wait() here */
+       outw(TotalReset | ((vp->drv_flags & EEPROM_RESET) ? 0x04 : 0x14),
+            dev->base_addr + EL3_CMD);
 
        pci_free_consistent(pdev,
                                                sizeof(struct boom_rx_desc) * RX_RING_SIZE