]> err.no Git - linux-2.6/blobdiff - drivers/net/3c59x.c
Merge branch 'origin'
[linux-2.6] / drivers / net / 3c59x.c
index 2bad41bebd1b2137b636d63c63442f3ab16bbf65..7f47124f118d37021cb84b467ac26d873b0d2cb4 100644 (file)
@@ -753,9 +753,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 {
@@ -863,12 +865,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);
@@ -903,14 +907,16 @@ static void set_8021q_mode(struct net_device *dev, int enable);
 /* 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;
+static int global_use_mmio = -1;
 
 /* #define dev_alloc_skb dev_alloc_skb_debug */
 
@@ -935,21 +941,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)
@@ -1109,15 +1119,32 @@ static int __init vortex_eisa_init (void)
 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);
        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);
                goto out;
@@ -1341,6 +1368,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]);
@@ -1457,7 +1485,7 @@ static int __devinit vortex_probe1(struct device *gendev,
                if (vp->drv_flags & EXTRA_PREAMBLE)
                        mii_preamble_required++;
                mdio_sync(ioaddr, 32);
-               mdio_read(dev, 24, 1);
+               mdio_read(dev, 24, MII_BMSR);
                for (phy = 0; phy < 32 && phy_idx < 1; phy++) {
                        int mii_status, phyx;
 
@@ -1471,7 +1499,7 @@ static int __devinit vortex_probe1(struct device *gendev,
                                phyx = phy - 1;
                        else
                                phyx = phy;
-                       mii_status = mdio_read(dev, phyx, 1);
+                       mii_status = mdio_read(dev, phyx, MII_BMSR);
                        if (mii_status  &&  mii_status != 0xffff) {
                                vp->phys[phy_idx++] = phyx;
                                if (print_info) {
@@ -1487,7 +1515,7 @@ static int __devinit vortex_probe1(struct device *gendev,
                        printk(KERN_WARNING"  ***WARNING*** No MII transceivers found!\n");
                        vp->phys[0] = 24;
                } else {
-                       vp->advertising = mdio_read(dev, vp->phys[0], 4);
+                       vp->advertising = mdio_read(dev, vp->phys[0], MII_ADVERTISE);
                        if (vp->full_duplex) {
                                /* Only advertise the FD media types. */
                                vp->advertising &= ~0x02A0;
@@ -1512,10 +1540,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;
@@ -1661,8 +1689,8 @@ vortex_up(struct net_device *dev)
                int mii_reg1, mii_reg5;
                EL3WINDOW(4);
                /* Read BMSR (reg1) only to clear old status. */
-               mii_reg1 = mdio_read(dev, vp->phys[0], 1);
-               mii_reg5 = mdio_read(dev, vp->phys[0], 5);
+               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 {
@@ -1892,14 +1920,17 @@ vortex_timer(unsigned long data)
        case XCVR_MII: case XCVR_NWAY:
                {
                        spin_lock_bh(&vp->lock);
-                       mii_status = mdio_read(dev, vp->phys[0], 1);
-                       mii_status = mdio_read(dev, vp->phys[0], 1);
+                       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], 5);
+                               int mii_reg5 = mdio_read(dev, vp->phys[0], MII_LPA);
                                if (! vp->force_fd  &&  mii_reg5 != 0xffff) {
                                        int duplex;
 
@@ -2081,9 +2112,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);
                }
@@ -2603,8 +2637,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);
        }
 
@@ -2788,10 +2822,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
                
@@ -2898,7 +2933,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);
@@ -2911,10 +2945,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;
@@ -3008,8 +3047,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;
 }
 
 
@@ -3054,6 +3095,7 @@ static struct ethtool_ops vortex_ethtool_ops = {
        .set_settings           = vortex_set_settings,
        .get_link               = vortex_get_link,
        .nway_reset             = vortex_nway_reset,
+       .get_perm_addr                  = ethtool_op_get_perm_addr,
 };
 
 #ifdef CONFIG_PCI