[PATCH] pcmcia: default suspend and resume handling
[safe/jmp/linux-2.6] / drivers / net / 3c59x.c
index e1f773d..70f6389 100644 (file)
 
 
 #define DRV_NAME       "3c59x"
-#define DRV_VERSION    "LK1.1.19"
-#define DRV_RELDATE    "10 Nov 2002"
 
 
 
@@ -258,6 +256,7 @@ static int vortex_debug = 1;
 #include <linux/highmem.h>
 #include <linux/eisa.h>
 #include <linux/bitops.h>
+#include <linux/jiffies.h>
 #include <asm/irq.h>                   /* For NR_IRQS only. */
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -274,10 +273,8 @@ static char version[] __devinitdata =
 DRV_NAME ": Donald Becker and others. www.scyld.com/network/vortex.html\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
-MODULE_DESCRIPTION("3Com 3c59x/3c9xx ethernet driver "
-                                       DRV_VERSION " " DRV_RELDATE);
+MODULE_DESCRIPTION("3Com 3c59x/3c9xx ethernet driver ");
 MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
 
 
 /* Operational parameter that usually are not changed. */
@@ -753,9 +750,11 @@ enum tx_desc_status {
 enum ChipCaps { CapBusMaster=0x20, CapPwrMgmt=0x2000 };
 
 struct vortex_extra_stats {
-        unsigned long tx_deferred;
-        unsigned long tx_multiple_collisions;
-        unsigned long rx_bad_ssd;
+       unsigned long tx_deferred;
+       unsigned long tx_max_collisions;
+       unsigned long tx_multiple_collisions;
+       unsigned long tx_single_collisions;
+       unsigned long rx_bad_ssd;
 };
 
 struct vortex_private {
@@ -839,7 +838,7 @@ enum xcvr_types {
        XCVR_100baseFx, XCVR_MII=6, XCVR_NWAY=8, XCVR_ExtMII=9, XCVR_Default=10,
 };
 
-static struct media_table {
+static const struct media_table {
        char *name;
        unsigned int media_bits:16,             /* Bits to set in Wn4_Media register. */
                mask:8,                                         /* The transceiver-present bit in Wn3_Config.*/
@@ -863,12 +862,14 @@ static struct {
        const char str[ETH_GSTRING_LEN];
 } ethtool_stats_keys[] = {
        { "tx_deferred" },
+       { "tx_max_collisions" },
        { "tx_multiple_collisions" },
+       { "tx_single_collisions" },
        { "rx_bad_ssd" },
 };
 
 /* number of ETHTOOL_GSTATS u64's */
-#define VORTEX_NUM_STATS     3
+#define VORTEX_NUM_STATS    5
 
 static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq,
                                   int chip_idx, int card_idx);
@@ -899,20 +900,19 @@ 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. */
 #define MAX_UNITS 8
-static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,};
-static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int hw_checksums[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int flow_ctrl[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int enable_wol[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int options[MAX_UNITS] = { [0 ... MAX_UNITS-1] = -1 };
+static int full_duplex[MAX_UNITS] = {[0 ... MAX_UNITS-1] = -1 };
+static int hw_checksums[MAX_UNITS] = {[0 ... MAX_UNITS-1] = -1 };
+static int flow_ctrl[MAX_UNITS] = {[0 ... MAX_UNITS-1] = -1 };
+static int enable_wol[MAX_UNITS] = {[0 ... MAX_UNITS-1] = -1 };
+static int use_mmio[MAX_UNITS] = {[0 ... MAX_UNITS-1] = -1 };
 static int global_options = -1;
 static int global_full_duplex = -1;
 static int global_enable_wol = -1;
-
-/* #define dev_alloc_skb dev_alloc_skb_debug */
+static int global_use_mmio = -1;
 
 /* Variables to work-around the Compaq PCI BIOS32 problem. */
 static int compaq_ioaddr, compaq_irq, compaq_device_id = 0x5900;
@@ -935,21 +935,25 @@ 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_param(global_use_mmio, int, 0);
+module_param_array(use_mmio, int, NULL, 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(global_full_duplex, "3c59x: same as full_duplex, but applies to all NICs if full_duplex 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(global_enable_wol, "3c59x: same as enable_wol, but applies to all NICs if enable_wol 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");
+MODULE_PARM_DESC(global_use_mmio, "3c59x: same as use_mmio, but applies to all NICs if options is unset");
+MODULE_PARM_DESC(use_mmio, "3c59x: use memory-mapped PCI I/O resource (0-1)");
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void poll_vortex(struct net_device *dev)
@@ -965,7 +969,7 @@ static void poll_vortex(struct net_device *dev)
 
 #ifdef CONFIG_PM
 
-static int vortex_suspend (struct pci_dev *pdev, pm_message_t state)
+static int vortex_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
 
@@ -983,7 +987,7 @@ static int vortex_suspend (struct pci_dev *pdev, pm_message_t state)
        return 0;
 }
 
-static int vortex_resume (struct pci_dev *pdev)
+static int vortex_resume(struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
        struct vortex_private *vp = netdev_priv(dev);
@@ -1016,8 +1020,8 @@ static struct eisa_device_id vortex_eisa_ids[] = {
        { "" }
 };
 
-static int vortex_eisa_probe (struct device *device);
-static int vortex_eisa_remove (struct device *device);
+static int vortex_eisa_probe(struct device *device);
+static int vortex_eisa_remove(struct device *device);
 
 static struct eisa_driver vortex_eisa_driver = {
        .id_table = vortex_eisa_ids,
@@ -1028,12 +1032,12 @@ static struct eisa_driver vortex_eisa_driver = {
        }
 };
 
-static int vortex_eisa_probe (struct device *device)
+static int vortex_eisa_probe(struct device *device)
 {
        void __iomem *ioaddr;
        struct eisa_device *edev;
 
-       edev = to_eisa_device (device);
+       edev = to_eisa_device(device);
 
        if (!request_region(edev->base_addr, VORTEX_TOTAL_SIZE, DRV_NAME))
                return -EBUSY;
@@ -1042,7 +1046,7 @@ static int vortex_eisa_probe (struct device *device)
 
        if (vortex_probe1(device, ioaddr, ioread16(ioaddr + 0xC88) >> 12,
                                          edev->id.driver_data, vortex_cards_found)) {
-               release_region (edev->base_addr, VORTEX_TOTAL_SIZE);
+               release_region(edev->base_addr, VORTEX_TOTAL_SIZE);
                return -ENODEV;
        }
 
@@ -1051,15 +1055,15 @@ static int vortex_eisa_probe (struct device *device)
        return 0;
 }
 
-static int vortex_eisa_remove (struct device *device)
+static int vortex_eisa_remove(struct device *device)
 {
        struct eisa_device *edev;
        struct net_device *dev;
        struct vortex_private *vp;
        void __iomem *ioaddr;
 
-       edev = to_eisa_device (device);
-       dev = eisa_get_drvdata (edev);
+       edev = to_eisa_device(device);
+       dev = eisa_get_drvdata(edev);
 
        if (!dev) {
                printk("vortex_eisa_remove called for Compaq device!\n");
@@ -1069,30 +1073,34 @@ static int vortex_eisa_remove (struct device *device)
        vp = netdev_priv(dev);
        ioaddr = vp->ioaddr;
        
-       unregister_netdev (dev);
-       iowrite16 (TotalReset|0x14, ioaddr + EL3_CMD);
-       release_region (dev->base_addr, VORTEX_TOTAL_SIZE);
+       unregister_netdev(dev);
+       iowrite16(TotalReset|0x14, ioaddr + EL3_CMD);
+       release_region(dev->base_addr, VORTEX_TOTAL_SIZE);
 
-       free_netdev (dev);
+       free_netdev(dev);
        return 0;
 }
 #endif
 
 /* returns count found (>= 0), or negative on error */
-static int __init vortex_eisa_init (void)
+static int __init vortex_eisa_init(void)
 {
        int eisa_found = 0;
        int orig_cards_found = vortex_cards_found;
 
 #ifdef CONFIG_EISA
-       if (eisa_driver_register (&vortex_eisa_driver) >= 0) {
-                       /* Because of the way EISA bus is probed, we cannot assume
-                        * any device have been found when we exit from
-                        * eisa_driver_register (the bus root driver may not be
-                        * initialized yet). So we blindly assume something was
-                        * found, and let the sysfs magic happend... */
-                       
-                       eisa_found = 1;
+       int err;
+
+       err = eisa_driver_register (&vortex_eisa_driver);
+       if (!err) {
+               /*
+                * Because of the way EISA bus is probed, we cannot assume
+                * any device have been found when we exit from
+                * eisa_driver_register (the bus root driver may not be
+                * initialized yet). So we blindly assume something was
+                * found, and let the sysfs magic happend...
+                */
+               eisa_found = 1;
        }
 #endif
        
@@ -1106,20 +1114,37 @@ static int __init vortex_eisa_init (void)
 }
 
 /* returns count (>= 0), or negative on error */
-static int __devinit vortex_init_one (struct pci_dev *pdev,
+static int __devinit vortex_init_one(struct pci_dev *pdev,
                                      const struct pci_device_id *ent)
 {
-       int rc;
+       int rc, unit, pci_bar;
+       struct vortex_chip_info *vci;
+       void __iomem *ioaddr;
 
        /* wake up and enable device */         
-       rc = pci_enable_device (pdev);
+       rc = pci_enable_device(pdev);
        if (rc < 0)
                goto out;
 
-       rc = vortex_probe1 (&pdev->dev, pci_iomap(pdev, 0, 0),
-                           pdev->irq, ent->driver_data, vortex_cards_found);
+       unit = vortex_cards_found;
+
+       if (global_use_mmio < 0 && (unit >= MAX_UNITS || use_mmio[unit] < 0)) {
+               /* Determine the default if the user didn't override us */
+               vci = &vortex_info_tbl[ent->driver_data];
+               pci_bar = vci->drv_flags & (IS_CYCLONE | IS_TORNADO) ? 1 : 0;
+       } else if (unit < MAX_UNITS && use_mmio[unit] >= 0)
+               pci_bar = use_mmio[unit] ? 1 : 0;
+       else
+               pci_bar = global_use_mmio ? 1 : 0;
+
+       ioaddr = pci_iomap(pdev, pci_bar, 0);
+       if (!ioaddr) /* If mapping fails, fall-back to BAR 0... */
+               ioaddr = pci_iomap(pdev, 0, 0);
+
+       rc = vortex_probe1(&pdev->dev, ioaddr, pdev->irq,
+                          ent->driver_data, unit);
        if (rc < 0) {
-               pci_disable_device (pdev);
+               pci_disable_device(pdev);
                goto out;
        }
 
@@ -1204,7 +1229,7 @@ static int __devinit vortex_probe1(struct device *gendev,
        if (print_info)
                printk (KERN_INFO "See Documentation/networking/vortex.txt\n");
 
-       printk(KERN_INFO "%s: 3Com %s %s at %p. Vers " DRV_VERSION "\n",
+       printk(KERN_INFO "%s: 3Com %s %s at %p.\n",
               print_name,
               pdev ? "PCI" : "EISA",
               vci->name,
@@ -1234,7 +1259,7 @@ static int __devinit vortex_probe1(struct device *gendev,
 
                /* enable bus-mastering if necessary */         
                if (vci->flags & PCI_USES_MASTER)
-                       pci_set_master (pdev);
+                       pci_set_master(pdev);
 
                if (vci->drv_flags & IS_VORTEX) {
                        u8 pci_latency;
@@ -1278,7 +1303,7 @@ static int __devinit vortex_probe1(struct device *gendev,
        if (pdev)
                pci_set_drvdata(pdev, dev);
        if (edev)
-               eisa_set_drvdata (edev, dev);
+               eisa_set_drvdata(edev, dev);
 
        vp->media_override = 7;
        if (option >= 0) {
@@ -1303,7 +1328,7 @@ static int __devinit vortex_probe1(struct device *gendev,
                        vp->enable_wol = 1;
        }
 
-       vp->force_fd = vp->full_duplex;
+       vp->mii.force_media = vp->full_duplex;
        vp->options = option;
        /* Read the station address from the EEPROM. */
        EL3WINDOW(0);
@@ -1341,6 +1366,7 @@ static int __devinit vortex_probe1(struct device *gendev,
                printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
        for (i = 0; i < 3; i++)
                ((u16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]);
+       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
        if (print_info) {
                for (i = 0; i < 6; i++)
                        printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
@@ -1417,7 +1443,7 @@ static int __devinit vortex_probe1(struct device *gendev,
        }
 
        {
-               static const char * ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
+               static const char * const ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
                unsigned int config;
                EL3WINDOW(3);
                vp->available_media = ioread16(ioaddr + Wn3_Options);
@@ -1512,10 +1538,10 @@ static int __devinit vortex_probe1(struct device *gendev,
        if (vp->full_bus_master_tx) {
                dev->hard_start_xmit = boomerang_start_xmit;
                /* Actually, it still should work with iommu. */
-               dev->features |= NETIF_F_SG;
-               if (((hw_checksums[card_idx] == -1) && (vp->drv_flags & HAS_HWCKSM)) ||
-                                       (hw_checksums[card_idx] == 1)) {
-                               dev->features |= NETIF_F_IP_CSUM;
+               if (card_idx < MAX_UNITS &&
+                   ((hw_checksums[card_idx] == -1 && (vp->drv_flags & HAS_HWCKSM)) ||
+                               hw_checksums[card_idx] == 1)) {
+                       dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
                }
        } else {
                dev->hard_start_xmit = vortex_start_xmit;
@@ -1592,6 +1618,46 @@ issue_and_wait(struct net_device *dev, int cmd)
 }
 
 static void
+vortex_set_duplex(struct net_device *dev)
+{
+       struct vortex_private *vp = netdev_priv(dev);
+       void __iomem *ioaddr = vp->ioaddr;
+
+       printk(KERN_INFO "%s:  setting %s-duplex.\n",
+               dev->name, (vp->full_duplex) ? "full" : "half");
+
+       EL3WINDOW(3);
+       /* Set the full-duplex bit. */
+       iowrite16(((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) |
+                       (vp->large_frames ? 0x40 : 0) |
+                       ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ?
+                                       0x100 : 0),
+                       ioaddr + Wn3_MAC_Ctrl);
+
+       issue_and_wait(dev, TxReset);
+       /*
+        * Don't reset the PHY - that upsets autonegotiation during DHCP operations.
+        */
+       issue_and_wait(dev, RxReset|0x04);
+}
+
+static void vortex_check_media(struct net_device *dev, unsigned int init)
+{
+       struct vortex_private *vp = netdev_priv(dev);
+       unsigned int ok_to_print = 0;
+
+       if (vortex_debug > 3)
+               ok_to_print = 1;
+
+       if (mii_check_media(&vp->mii, ok_to_print, init)) {
+               vp->full_duplex = vp->mii.full_duplex;
+               vortex_set_duplex(dev);
+       } else if (init) {
+               vortex_set_duplex(dev);
+       }
+}
+
+static void
 vortex_up(struct net_device *dev)
 {
        struct vortex_private *vp = netdev_priv(dev);
@@ -1651,53 +1717,20 @@ vortex_up(struct net_device *dev)
                printk(KERN_DEBUG "%s: Initial media type %s.\n",
                           dev->name, media_tbl[dev->if_port].name);
 
-       vp->full_duplex = vp->force_fd;
+       vp->full_duplex = vp->mii.force_media;
        config = BFINS(config, dev->if_port, 20, 4);
        if (vortex_debug > 6)
                printk(KERN_DEBUG "vortex_up(): writing 0x%x to InternalConfig\n", config);
        iowrite32(config, ioaddr + Wn3_Config);
 
+       netif_carrier_off(dev);
        if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
-               int mii_reg1, mii_reg5;
                EL3WINDOW(4);
-               /* Read BMSR (reg1) only to clear old status. */
-               mii_reg1 = mdio_read(dev, vp->phys[0], MII_BMSR);
-               mii_reg5 = mdio_read(dev, vp->phys[0], MII_LPA);
-               if (mii_reg5 == 0xffff  ||  mii_reg5 == 0x0000) {
-                       netif_carrier_off(dev); /* No MII device or no link partner report */
-               } else {
-                       mii_reg5 &= vp->advertising;
-                       if ((mii_reg5 & 0x0100) != 0    /* 100baseTx-FD */
-                                || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */
-                       vp->full_duplex = 1;
-                       netif_carrier_on(dev);
-               }
-               vp->partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0);
-               if (vortex_debug > 1)
-                       printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x,"
-                                  " info1 %04x, setting %s-duplex.\n",
-                                       dev->name, vp->phys[0],
-                                       mii_reg1, mii_reg5,
-                                       vp->info1, ((vp->info1 & 0x8000) || vp->full_duplex) ? "full" : "half");
-               EL3WINDOW(3);
-       }
-
-       /* Set the full-duplex bit. */
-       iowrite16(      ((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 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) {
-               printk(KERN_DEBUG "%s: vortex_up() InternalConfig %8.8x.\n",
-                       dev->name, config);
+               vortex_check_media(dev, 1);
        }
+       else
+               vortex_set_duplex(dev);
 
-       issue_and_wait(dev, TxReset);
-       /*
-        * Don't reset the PHY - that upsets autonegotiation during DHCP operations.
-        */
-       issue_and_wait(dev, RxReset|0x04);
 
        iowrite16(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
 
@@ -1772,7 +1805,6 @@ vortex_up(struct net_device *dev)
        set_8021q_mode(dev, 1);
        iowrite16(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
 
-//     issue_and_wait(dev, SetTxStart|0x07ff);
        iowrite16(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
        iowrite16(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
        /* Allow status bits to be seen. */
@@ -1859,7 +1891,7 @@ vortex_timer(unsigned long data)
        void __iomem *ioaddr = vp->ioaddr;
        int next_tick = 60*HZ;
        int ok = 0;
-       int media_status, mii_status, old_window;
+       int media_status, old_window;
 
        if (vortex_debug > 2) {
                printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n",
@@ -1867,8 +1899,6 @@ vortex_timer(unsigned long data)
                printk(KERN_DEBUG "dev->watchdog_timeo=%d\n", dev->watchdog_timeo);
        }
 
-       if (vp->medialock)
-               goto leave_media_alone;
        disable_irq(dev->irq);
        old_window = ioread16(ioaddr + EL3_CMD) >> 13;
        EL3WINDOW(4);
@@ -1891,44 +1921,9 @@ 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], MII_BMSR);
-                       if (!(mii_status & BMSR_LSTATUS)) {
-                               /* Re-read to get actual link status */
-                               mii_status = mdio_read(dev, vp->phys[0], MII_BMSR);
-                       }
                        ok = 1;
-                       if (vortex_debug > 2)
-                               printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n",
-                                       dev->name, mii_status);
-                       if (mii_status & BMSR_LSTATUS) {
-                               int mii_reg5 = mdio_read(dev, vp->phys[0], MII_LPA);
-                               if (! vp->force_fd  &&  mii_reg5 != 0xffff) {
-                                       int duplex;
-
-                                       mii_reg5 &= vp->advertising;
-                                       duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040;
-                                       if (vp->full_duplex != duplex) {
-                                               vp->full_duplex = duplex;
-                                               printk(KERN_INFO "%s: Setting %s-duplex based on MII "
-                                                       "#%d link partner capability of %4.4x.\n",
-                                                       dev->name, vp->full_duplex ? "full" : "half",
-                                                       vp->phys[0], mii_reg5);
-                                               /* Set the full-duplex bit. */
-                                               EL3WINDOW(3);
-                                               iowrite16(      (vp->full_duplex ? 0x20 : 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)
-                                                       printk(KERN_DEBUG "Setting duplex in Wn3_MAC_Ctrl\n");
-                                               /* AKPM: bug: should reset Tx and Rx after setting Duplex.  Page 180 */
-                                       }
-                               }
-                               netif_carrier_on(dev);
-                       } else {
-                               netif_carrier_off(dev);
-                       }
+                       spin_lock_bh(&vp->lock);
+                       vortex_check_media(dev, 0);
                        spin_unlock_bh(&vp->lock);
                }
                break;
@@ -1938,7 +1933,14 @@ vortex_timer(unsigned long data)
                                 dev->name, media_tbl[dev->if_port].name, media_status);
                ok = 1;
        }
-       if ( ! ok) {
+
+       if (!netif_carrier_ok(dev))
+               next_tick = 5*HZ;
+
+       if (vp->medialock)
+               goto leave_media_alone;
+
+       if (!ok) {
                unsigned int config;
 
                do {
@@ -1971,14 +1973,14 @@ vortex_timer(unsigned long data)
                        printk(KERN_DEBUG "wrote 0x%08x to Wn3_Config\n", config);
                /* AKPM: FIXME: Should reset Rx & Tx here.  P60 of 3c90xc.pdf */
        }
-       EL3WINDOW(old_window);
-       enable_irq(dev->irq);
 
 leave_media_alone:
        if (vortex_debug > 2)
          printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n",
                         dev->name, media_tbl[dev->if_port].name);
 
+       EL3WINDOW(old_window);
+       enable_irq(dev->irq);
        mod_timer(&vp->timer, RUN_AT(next_tick));
        if (vp->deferred)
                iowrite16(FakeIntr, ioaddr + EL3_CMD);
@@ -2084,9 +2086,12 @@ vortex_error(struct net_device *dev, int status)
                iowrite8(0, ioaddr + TxStatus);
                if (tx_status & 0x30) {                 /* txJabber or txUnderrun */
                        do_tx_reset = 1;
-               } else if ((tx_status & 0x08) && (vp->drv_flags & MAX_COLLISION_RESET)) {       /* maxCollisions */
-                       do_tx_reset = 1;
-                       reset_mask = 0x0108;            /* Reset interface logic, but not download logic */
+               } else if (tx_status & 0x08) {  /* maxCollisions */
+                       vp->xstats.tx_max_collisions++;
+                       if (vp->drv_flags & MAX_COLLISION_RESET) {
+                               do_tx_reset = 1;
+                               reset_mask = 0x0108;            /* Reset interface logic, but not download logic */
+                       }
                } else {                                                /* Merely re-enable the transmitter. */
                        iowrite16(TxEnable, ioaddr + EL3_CMD);
                }
@@ -2170,7 +2175,7 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (vp->bus_master) {
                /* Set the bus-master controller to transfer the packet. */
                int len = (skb->len + 3) & ~3;
-               iowrite32(      vp->tx_skb_dma = pci_map_single(VORTEX_PCI(vp), skb->data, len, PCI_DMA_TODEVICE),
+               iowrite32(vp->tx_skb_dma = pci_map_single(VORTEX_PCI(vp), skb->data, len, PCI_DMA_TODEVICE),
                                ioaddr + Wn7_MasterAddr);
                iowrite16(len, ioaddr + Wn7_MasterLen);
                vp->tx_skb = skb;
@@ -2606,8 +2611,8 @@ static int vortex_rx(struct net_device *dev)
                        } else if (vortex_debug > 0)
                                printk(KERN_NOTICE "%s: No memory to allocate a sk_buff of "
                                           "size %d.\n", dev->name, pkt_len);
+                       vp->stats.rx_dropped++;
                }
-               vp->stats.rx_dropped++;
                issue_and_wait(dev, RxDiscard);
        }
 
@@ -2693,7 +2698,7 @@ boomerang_rx(struct net_device *dev)
                        skb = dev_alloc_skb(PKT_BUF_SZ);
                        if (skb == NULL) {
                                static unsigned long last_jif;
-                               if ((jiffies - last_jif) > 10 * HZ) {
+                               if (time_after(jiffies, last_jif + 10 * HZ)) {
                                        printk(KERN_WARNING "%s: memory shortage\n", dev->name);
                                        last_jif = jiffies;
                                }
@@ -2791,10 +2796,11 @@ vortex_close(struct net_device *dev)
        }
 
 #if DO_ZEROCOPY
-       if (    vp->rx_csumhits &&
-                       ((vp->drv_flags & HAS_HWCKSM) == 0) &&
-                       (hw_checksums[vp->card_idx] == -1)) {
-               printk(KERN_WARNING "%s supports hardware checksums, and we're not using them!\n", dev->name);
+       if (vp->rx_csumhits &&
+           (vp->drv_flags & HAS_HWCKSM) == 0 &&
+           (vp->card_idx >= MAX_UNITS || hw_checksums[vp->card_idx] == -1)) {
+                       printk(KERN_WARNING "%s supports hardware checksums, and we're "
+                                               "not using them!\n", dev->name);
        }
 #endif
                
@@ -2901,7 +2907,6 @@ static void update_stats(void __iomem *ioaddr, struct net_device *dev)
        EL3WINDOW(6);
        vp->stats.tx_carrier_errors             += ioread8(ioaddr + 0);
        vp->stats.tx_heartbeat_errors           += ioread8(ioaddr + 1);
-       vp->stats.collisions                    += ioread8(ioaddr + 3);
        vp->stats.tx_window_errors              += ioread8(ioaddr + 4);
        vp->stats.rx_fifo_errors                += ioread8(ioaddr + 5);
        vp->stats.tx_packets                    += ioread8(ioaddr + 6);
@@ -2914,10 +2919,15 @@ static void update_stats(void __iomem *ioaddr, struct net_device *dev)
        vp->stats.tx_bytes                      += ioread16(ioaddr + 12);
        /* Extra stats for get_ethtool_stats() */
        vp->xstats.tx_multiple_collisions       += ioread8(ioaddr + 2);
+       vp->xstats.tx_single_collisions         += ioread8(ioaddr + 3);
        vp->xstats.tx_deferred                  += ioread8(ioaddr + 8);
        EL3WINDOW(4);
        vp->xstats.rx_bad_ssd                   += ioread8(ioaddr + 12);
 
+       vp->stats.collisions = vp->xstats.tx_multiple_collisions
+               + vp->xstats.tx_single_collisions
+               + vp->xstats.tx_max_collisions;
+
        {
                u8 up = ioread8(ioaddr + 13);
                vp->stats.rx_bytes += (up & 0x0f) << 16;
@@ -2942,20 +2952,6 @@ static int vortex_nway_reset(struct net_device *dev)
        return rc;
 }
 
-static u32 vortex_get_link(struct net_device *dev)
-{
-       struct vortex_private *vp = netdev_priv(dev);
-       void __iomem *ioaddr = vp->ioaddr;
-       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);
@@ -3011,8 +3007,10 @@ static void vortex_get_ethtool_stats(struct net_device *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;
+       data[1] = vp->xstats.tx_max_collisions;
+       data[2] = vp->xstats.tx_multiple_collisions;
+       data[3] = vp->xstats.tx_single_collisions;
+       data[4] = vp->xstats.rx_bad_ssd;
 }
 
 
@@ -3034,7 +3032,6 @@ static void vortex_get_drvinfo(struct net_device *dev,
        struct vortex_private *vp = netdev_priv(dev);
 
        strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
        if (VORTEX_PCI(vp)) {
                strcpy(info->bus_info, pci_name(VORTEX_PCI(vp)));
        } else {
@@ -3055,8 +3052,9 @@ static struct ethtool_ops vortex_ethtool_ops = {
        .get_stats_count        = vortex_get_stats_count,
        .get_settings           = vortex_get_settings,
        .set_settings           = vortex_set_settings,
-       .get_link               = vortex_get_link,
+       .get_link               = ethtool_op_get_link,
        .nway_reset             = vortex_nway_reset,
+       .get_perm_addr          = ethtool_op_get_perm_addr,
 };
 
 #ifdef CONFIG_PCI
@@ -3257,7 +3255,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val
        }
        return;
 }
-\f
+
 /* ACPI: Advanced Configuration and Power Interface. */
 /* Set Wake-On-LAN mode and put the board into D3 (power-down) state. */
 static void acpi_set_WOL(struct net_device *dev)
@@ -3281,7 +3279,7 @@ static void acpi_set_WOL(struct net_device *dev)
 }
 
 
-static void __devexit vortex_remove_one (struct pci_dev *pdev)
+static void __devexit vortex_remove_one(struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
        struct vortex_private *vp;
@@ -3337,7 +3335,7 @@ static int vortex_have_pci;
 static int vortex_have_eisa;
 
 
-static int __init vortex_init (void)
+static int __init vortex_init(void)
 {
        int pci_rc, eisa_rc;
 
@@ -3353,14 +3351,14 @@ static int __init vortex_init (void)
 }
 
 
-static void __exit vortex_eisa_cleanup (void)
+static void __exit vortex_eisa_cleanup(void)
 {
        struct vortex_private *vp;
        void __iomem *ioaddr;
 
 #ifdef CONFIG_EISA
        /* Take care of the EISA devices */
-       eisa_driver_unregister (&vortex_eisa_driver);
+       eisa_driver_unregister(&vortex_eisa_driver);
 #endif
        
        if (compaq_net_device) {
@@ -3368,33 +3366,24 @@ static void __exit vortex_eisa_cleanup (void)
                ioaddr = ioport_map(compaq_net_device->base_addr,
                                    VORTEX_TOTAL_SIZE);
 
-               unregister_netdev (compaq_net_device);
-               iowrite16 (TotalReset, ioaddr + EL3_CMD);
+               unregister_netdev(compaq_net_device);
+               iowrite16(TotalReset, ioaddr + EL3_CMD);
                release_region(compaq_net_device->base_addr,
                               VORTEX_TOTAL_SIZE);
 
-               free_netdev (compaq_net_device);
+               free_netdev(compaq_net_device);
        }
 }
 
 
-static void __exit vortex_cleanup (void)
+static void __exit vortex_cleanup(void)
 {
        if (vortex_have_pci)
-               pci_unregister_driver (&vortex_driver);
+               pci_unregister_driver(&vortex_driver);
        if (vortex_have_eisa)
-               vortex_eisa_cleanup ();
+               vortex_eisa_cleanup();
 }
 
 
 module_init(vortex_init);
 module_exit(vortex_cleanup);
-
-\f
-/*
- * Local variables:
- *  c-indent-level: 4
- *  c-basic-offset: 4
- *  tab-width: 4
- * End:
- */