fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / net / e100.c
index f57a85f..0cefef5 100644 (file)
@@ -1,27 +1,27 @@
 /*******************************************************************************
 
-
-  Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+  Intel PRO/100 Linux driver
+  Copyright(c) 1999 - 2006 Intel Corporation.
 
   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.
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
 
-  This program is distributed in the hope that it will be useful, but WITHOUT
+  This program is distributed in the hope it will be useful, but WITHOUT
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   more details.
 
   You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc., 59
-  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 
-  The full GNU General Public License is included in this distribution in the
-  file called LICENSE.
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
 
   Contact Information:
   Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
 *******************************************************************************/
  *     - Stratus87247: protect MDI control register manipulations
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
 
 
 #define DRV_NAME               "e100"
-#define DRV_EXT                "-NAPI"
-#define DRV_VERSION            "3.5.10-k2"DRV_EXT
+#define DRV_EXT                        "-NAPI"
+#define DRV_VERSION            "3.5.17-k2"DRV_EXT
 #define DRV_DESCRIPTION                "Intel(R) PRO/100 Network Driver"
-#define DRV_COPYRIGHT          "Copyright(c) 1999-2005 Intel Corporation"
+#define DRV_COPYRIGHT          "Copyright(c) 1999-2006 Intel Corporation"
 #define PFX                    DRV_NAME ": "
 
 #define E100_WATCHDOG_PERIOD   (2 * HZ)
@@ -174,8 +173,11 @@ MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
 static int debug = 3;
+static int eeprom_bad_csum_allow = 0;
 module_param(debug, int, 0);
+module_param(eeprom_bad_csum_allow, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+MODULE_PARM_DESC(eeprom_bad_csum_allow, "Allow bad eeprom checksums");
 #define DPRINTK(nlevel, klevel, fmt, args...) \
        (void)((NETIF_MSG_##nlevel & nic->msg_enable) && \
        printk(KERN_##klevel PFX "%s: %s: " fmt, nic->netdev->name, \
@@ -598,8 +600,8 @@ static void e100_enable_irq(struct nic *nic)
 
        spin_lock_irqsave(&nic->cmd_lock, flags);
        writeb(irq_mask_none, &nic->csr->scb.cmd_hi);
-       spin_unlock_irqrestore(&nic->cmd_lock, flags);
        e100_write_flush(nic);
+       spin_unlock_irqrestore(&nic->cmd_lock, flags);
 }
 
 static void e100_disable_irq(struct nic *nic)
@@ -608,8 +610,8 @@ static void e100_disable_irq(struct nic *nic)
 
        spin_lock_irqsave(&nic->cmd_lock, flags);
        writeb(irq_mask_all, &nic->csr->scb.cmd_hi);
-       spin_unlock_irqrestore(&nic->cmd_lock, flags);
        e100_write_flush(nic);
+       spin_unlock_irqrestore(&nic->cmd_lock, flags);
 }
 
 static void e100_hw_reset(struct nic *nic)
@@ -757,7 +759,8 @@ static int e100_eeprom_load(struct nic *nic)
        checksum = le16_to_cpu(0xBABA - checksum);
        if(checksum != nic->eeprom[nic->eeprom_wc - 1]) {
                DPRINTK(PROBE, ERR, "EEPROM corrupted\n");
-               return -EAGAIN;
+               if (!eeprom_bad_csum_allow)
+                       return -EAGAIN;
        }
 
        return 0;
@@ -1212,7 +1215,7 @@ static void e100_setup_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb
 *  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.
+*  INTDELAY - This loads the dead-man timer with its initial 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)
@@ -1392,15 +1395,11 @@ static int e100_phy_init(struct nic *nic)
        }
 
        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);
+          (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000) &&
+               !(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))) {
+               /* enable/disable MDI/MDI-X auto-switching. */
+               mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG,
+                               nic->mii.force_media ? 0 : NCONFIG_AUTO_SWITCH);
        }
 
        return 0;
@@ -1582,8 +1581,8 @@ static void e100_watchdog(unsigned long data)
         * 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);
-       spin_unlock_irq(&nic->cmd_lock);
        e100_write_flush(nic);
+       spin_unlock_irq(&nic->cmd_lock);
 
        e100_update_stats(nic);
        e100_adjust_adaptive_ifs(nic, cmd.speed, cmd.duplex);
@@ -1658,13 +1657,14 @@ static int e100_tx_clean(struct nic *nic)
 
        spin_lock(&nic->cb_lock);
 
-       DPRINTK(TX_DONE, DEBUG, "cb->status = 0x%04X\n",
-               nic->cb_to_clean->status);
-
        /* Clean CBs marked complete */
        for(cb = nic->cb_to_clean;
            cb->status & cpu_to_le16(cb_complete);
            cb = nic->cb_to_clean = cb->next) {
+               DPRINTK(TX_DONE, DEBUG, "cb[%d]->status = 0x%04X\n",
+                       (int)(((void*)cb - (void*)nic->cbs)/sizeof(struct cb)),
+                       cb->status);
+
                if(likely(cb->skb != NULL)) {
                        nic->net_stats.tx_packets++;
                        nic->net_stats.tx_bytes += cb->skb->len;
@@ -1764,11 +1764,10 @@ static inline void e100_start_receiver(struct nic *nic, struct rx *rx)
 #define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN)
 static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
 {
-       if(!(rx->skb = dev_alloc_skb(RFD_BUF_LEN + NET_IP_ALIGN)))
+       if(!(rx->skb = netdev_alloc_skb(nic->netdev, RFD_BUF_LEN + NET_IP_ALIGN)))
                return -ENOMEM;
 
        /* Align, init, and map the RFD. */
-       rx->skb->dev = nic->netdev;
        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,
@@ -1931,9 +1930,8 @@ static int e100_rx_alloc_list(struct nic *nic)
        nic->rx_to_use = nic->rx_to_clean = NULL;
        nic->ru_running = RU_UNINITIALIZED;
 
-       if(!(nic->rxs = kmalloc(sizeof(struct rx) * count, GFP_ATOMIC)))
+       if(!(nic->rxs = kcalloc(count, sizeof(struct rx), GFP_ATOMIC)))
                return -ENOMEM;
-       memset(nic->rxs, 0, sizeof(struct rx) * count);
 
        for(rx = nic->rxs, i = 0; i < count; rx++, i++) {
                rx->next = (i + 1 < count) ? rx + 1 : nic->rxs;
@@ -1950,7 +1948,7 @@ static int e100_rx_alloc_list(struct nic *nic)
        return 0;
 }
 
-static irqreturn_t e100_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t e100_intr(int irq, void *dev_id)
 {
        struct net_device *netdev = dev_id;
        struct nic *nic = netdev_priv(netdev);
@@ -2006,7 +2004,7 @@ static void e100_netpoll(struct net_device *netdev)
        struct nic *nic = netdev_priv(netdev);
 
        e100_disable_irq(nic);
-       e100_intr(nic->pdev->irq, netdev, NULL);
+       e100_intr(nic->pdev->irq, netdev);
        e100_tx_clean(nic);
        e100_enable_irq(nic);
 }
@@ -2040,7 +2038,6 @@ static int e100_change_mtu(struct net_device *netdev, int new_mtu)
        return 0;
 }
 
-#ifdef CONFIG_PM
 static int e100_asf(struct nic *nic)
 {
        /* ASF can be enabled from eeprom */
@@ -2049,7 +2046,6 @@ static int e100_asf(struct nic *nic)
           !(nic->eeprom[eeprom_config_asf] & eeprom_gcl) &&
           ((nic->eeprom[eeprom_smbus_addr] & 0xFF) != 0xFE));
 }
-#endif
 
 static int e100_up(struct nic *nic)
 {
@@ -2064,7 +2060,7 @@ static int e100_up(struct nic *nic)
        e100_set_multicast_list(nic->netdev);
        e100_start_receiver(nic, NULL);
        mod_timer(&nic->watchdog, jiffies);
-       if((err = request_irq(nic->pdev->irq, e100_intr, SA_SHIRQ,
+       if((err = request_irq(nic->pdev->irq, e100_intr, IRQF_SHARED,
                nic->netdev->name, nic->netdev)))
                goto err_no_irq;
        netif_wake_queue(nic->netdev);
@@ -2105,9 +2101,10 @@ static void e100_tx_timeout(struct net_device *netdev)
        schedule_work(&nic->tx_timeout_task);
 }
 
-static void e100_tx_timeout_task(struct net_device *netdev)
+static void e100_tx_timeout_task(struct work_struct *work)
 {
-       struct nic *nic = netdev_priv(netdev);
+       struct nic *nic = container_of(work, struct nic, tx_timeout_task);
+       struct net_device *netdev = nic->netdev;
 
        DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n",
                readb(&nic->csr->scb.status));
@@ -2144,7 +2141,7 @@ static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode)
 
        e100_start_receiver(nic, NULL);
 
-       if(!(skb = dev_alloc_skb(ETH_DATA_LEN))) {
+       if(!(skb = netdev_alloc_skb(nic->netdev, ETH_DATA_LEN))) {
                err = -ENOMEM;
                goto err_loopback_none;
        }
@@ -2479,7 +2476,7 @@ static void e100_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
        }
 }
 
-static struct ethtool_ops e100_ethtool_ops = {
+static const struct ethtool_ops e100_ethtool_ops = {
        .get_settings           = e100_get_settings,
        .set_settings           = e100_set_settings,
        .get_drvinfo            = e100_get_drvinfo,
@@ -2574,7 +2571,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        netdev->poll_controller = e100_netpoll;
 #endif
-       strcpy(netdev->name, pci_name(pdev));
+       strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
 
        nic = netdev_priv(netdev);
        nic->netdev = netdev;
@@ -2640,8 +2637,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
        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);
+       INIT_WORK(&nic->tx_timeout_task, e100_tx_timeout_task);
 
        if((err = e100_alloc(nic))) {
                DPRINTK(PROBE, ERR, "Cannot alloc driver memory, aborting.\n");
@@ -2678,9 +2674,9 @@ static int __devinit e100_probe(struct pci_dev *pdev,
                goto err_out_free;
        }
 
-       DPRINTK(PROBE, INFO, "addr 0x%lx, irq %d, "
+       DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, "
                "MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n",
-               pci_resource_start(pdev, 0), pdev->irq,
+               (unsigned long long)pci_resource_start(pdev, 0), pdev->irq,
                netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
                netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
 
@@ -2721,22 +2717,26 @@ static int e100_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct nic *nic = netdev_priv(netdev);
-       int retval;
 
-       if(netif_running(netdev))
-               e100_down(nic);
-       e100_hw_reset(nic);
+       if (netif_running(netdev))
+               netif_poll_disable(nic->netdev);
+       del_timer_sync(&nic->watchdog);
+       netif_carrier_off(nic->netdev);
        netif_device_detach(netdev);
 
        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");
+
+       if ((nic->flags & wol_magic) | e100_asf(nic)) {
+               pci_enable_wake(pdev, PCI_D3hot, 1);
+               pci_enable_wake(pdev, PCI_D3cold, 1);
+       } else {
+               pci_enable_wake(pdev, PCI_D3hot, 0);
+               pci_enable_wake(pdev, PCI_D3cold, 0);
+       }
+
        pci_disable_device(pdev);
-       retval = pci_set_power_state(pdev, pci_choose_state(pdev, state));
-       if (retval)
-               DPRINTK(PROBE,ERR, "Error %d setting power state\n", retval);
+       free_irq(pdev->irq, netdev);
+       pci_set_power_state(pdev, PCI_D3hot);
 
        return 0;
 }
@@ -2745,41 +2745,117 @@ static int e100_resume(struct pci_dev *pdev)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
        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_set_power_state(pdev, PCI_D0);
        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");
+       pci_enable_wake(pdev, 0, 0);
 
        netif_device_attach(netdev);
-       if(netif_running(netdev))
+       if (netif_running(netdev))
                e100_up(nic);
 
        return 0;
 }
-#endif
-
+#endif /* CONFIG_PM */
 
 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");
+       if (netif_running(netdev))
+               netif_poll_disable(nic->netdev);
+       del_timer_sync(&nic->watchdog);
+       netif_carrier_off(nic->netdev);
+
+       if ((nic->flags & wol_magic) | e100_asf(nic)) {
+               pci_enable_wake(pdev, PCI_D3hot, 1);
+               pci_enable_wake(pdev, PCI_D3cold, 1);
+       } else {
+               pci_enable_wake(pdev, PCI_D3hot, 0);
+               pci_enable_wake(pdev, PCI_D3cold, 0);
+       }
+
+       pci_disable_device(pdev);
+       pci_set_power_state(pdev, PCI_D3hot);
 }
 
+/* ------------------ PCI Error Recovery infrastructure  -------------- */
+/**
+ * e100_io_error_detected - called when PCI error is detected.
+ * @pdev: Pointer to PCI device
+ * @state: The current pci conneection state
+ */
+static pci_ers_result_t e100_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+
+       /* Similar to calling e100_down(), but avoids adpater I/O. */
+       netdev->stop(netdev);
+
+       /* Detach; put netif into state similar to hotplug unplug. */
+       netif_poll_enable(netdev);
+       netif_device_detach(netdev);
+       pci_disable_device(pdev);
+
+       /* Request a slot reset. */
+       return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * e100_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch.
+ */
+static pci_ers_result_t e100_io_slot_reset(struct pci_dev *pdev)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct nic *nic = netdev_priv(netdev);
+
+       if (pci_enable_device(pdev)) {
+               printk(KERN_ERR "e100: Cannot re-enable PCI device after reset.\n");
+               return PCI_ERS_RESULT_DISCONNECT;
+       }
+       pci_set_master(pdev);
+
+       /* Only one device per card can do a reset */
+       if (0 != PCI_FUNC(pdev->devfn))
+               return PCI_ERS_RESULT_RECOVERED;
+       e100_hw_reset(nic);
+       e100_phy_init(nic);
+
+       return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * e100_io_resume - resume normal operations
+ * @pdev: Pointer to PCI device
+ *
+ * Resume normal operations after an error recovery
+ * sequence has been completed.
+ */
+static void e100_io_resume(struct pci_dev *pdev)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct nic *nic = netdev_priv(netdev);
+
+       /* ack any pending wake events, disable PME */
+       pci_enable_wake(pdev, 0, 0);
+
+       netif_device_attach(netdev);
+       if (netif_running(netdev)) {
+               e100_open(netdev);
+               mod_timer(&nic->watchdog, jiffies);
+       }
+}
+
+static struct pci_error_handlers e100_err_handler = {
+       .error_detected = e100_io_error_detected,
+       .slot_reset = e100_io_slot_reset,
+       .resume = e100_io_resume,
+};
 
 static struct pci_driver e100_driver = {
        .name =         DRV_NAME,
@@ -2787,10 +2863,12 @@ static struct pci_driver e100_driver = {
        .probe =        e100_probe,
        .remove =       __devexit_p(e100_remove),
 #ifdef CONFIG_PM
+       /* Power Management hooks */
        .suspend =      e100_suspend,
        .resume =       e100_resume,
 #endif
        .shutdown =     e100_shutdown,
+       .err_handler = &e100_err_handler,
 };
 
 static int __init e100_init_module(void)
@@ -2799,7 +2877,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);
        }
-       return pci_module_init(&e100_driver);
+       return pci_register_driver(&e100_driver);
 }
 
 static void __exit e100_cleanup_module(void)