[netdrvr] sfc: Increment rx_reset when reported as driver event
[safe/jmp/linux-2.6] / drivers / net / natsemi.c
index 223e0e6..46119bb 100644 (file)
@@ -108,7 +108,7 @@ static int full_duplex[MAX_UNITS];
 #define TX_TIMEOUT  (2*HZ)
 
 #define NATSEMI_HW_TIMEOUT     400
-#define NATSEMI_TIMER_FREQ     3*HZ
+#define NATSEMI_TIMER_FREQ     5*HZ
 #define NATSEMI_PG0_NREGS      64
 #define NATSEMI_RFDR_NREGS     8
 #define NATSEMI_PG1_NREGS      4
@@ -127,11 +127,10 @@ static int full_duplex[MAX_UNITS];
 #define NATSEMI_RX_LIMIT       2046    /* maximum supported by hardware */
 
 /* These identify the driver base version and may not be removed. */
-static const char version[] __devinitdata =
+static char version[] __devinitdata =
   KERN_INFO DRV_NAME " dp8381x driver, version "
       DRV_VERSION ", " DRV_RELDATE "\n"
   KERN_INFO "  originally by Donald Becker <becker@scyld.com>\n"
-  KERN_INFO "  http://www.scyld.com/network/natsemi.html\n"
   KERN_INFO "  2.4.x kernel port by Jeff Garzik, Tjeerd Mulder\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
@@ -204,22 +203,8 @@ skbuff at an offset of "+2", 16-byte aligning the IP header.
 IIId. Synchronization
 
 Most operations are synchronized on the np->lock irq spinlock, except the
-performance critical codepaths:
-
-The rx process only runs in the interrupt handler. Access from outside
-the interrupt handler is only permitted after disable_irq().
-
-The rx process usually runs under the netif_tx_lock. If np->intr_tx_reap
-is set, then access is permitted under spin_lock_irq(&np->lock).
-
-Thus configuration functions that want to access everything must call
-       disable_irq(dev->irq);
-       netif_tx_lock_bh(dev);
-       spin_lock_irq(&np->lock);
-
-IV. Notes
-
-NatSemi PCI network controllers are very uncommon.
+recieve and transmit paths which are synchronised using a combination of
+hardware descriptor ownership, disabling interrupts and NAPI poll scheduling.
 
 IVb. References
 
@@ -253,7 +238,7 @@ enum {
 };
 
 /* array of board data directly indexed by pci_tbl[x].driver_data */
-static const struct {
+static struct {
        const char *name;
        unsigned long flags;
        unsigned int eeprom_size;
@@ -262,7 +247,7 @@ static const struct {
        { "NatSemi DP8381[56]", 0, 24 },
 };
 
-static const struct pci_device_id natsemi_pci_tbl[] __devinitdata = {
+static struct pci_device_id natsemi_pci_tbl[] __devinitdata = {
        { PCI_VENDOR_ID_NS, 0x0020, 0x12d9,     0x000c,     0, 0, 0 },
        { PCI_VENDOR_ID_NS, 0x0020, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
        { }     /* terminate list */
@@ -526,10 +511,10 @@ enum PhyCtrl_bits {
 /* Note that using only 32 bit fields simplifies conversion to big-endian
    architectures. */
 struct netdev_desc {
-       u32 next_desc;
-       s32 cmd_status;
-       u32 addr;
-       u32 software_use;
+       __le32 next_desc;
+       __le32 cmd_status;
+       __le32 addr;
+       __le32 software_use;
 };
 
 /* Bits in network_desc.status */
@@ -561,6 +546,8 @@ struct netdev_private {
        /* address of a sent-in-place packet/buffer, for later free() */
        struct sk_buff *tx_skbuff[TX_RING_SIZE];
        dma_addr_t tx_dma[TX_RING_SIZE];
+       struct net_device *dev;
+       struct napi_struct napi;
        struct net_device_stats stats;
        /* Media monitoring timer */
        struct timer_list timer;
@@ -637,7 +624,7 @@ static void init_registers(struct net_device *dev);
 static int start_tx(struct sk_buff *skb, struct net_device *dev);
 static irqreturn_t intr_handler(int irq, void *dev_instance);
 static void netdev_error(struct net_device *dev, int intr_status);
-static int natsemi_poll(struct net_device *dev, int *budget);
+static int natsemi_poll(struct napi_struct *napi, int budget);
 static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do);
 static void netdev_tx_done(struct net_device *dev);
 static int natsemi_change_mtu(struct net_device *dev, int new_mtu);
@@ -672,7 +659,7 @@ static ssize_t natsemi_show_##_name(struct device *dev, \
 #define NATSEMI_CREATE_FILE(_dev, _name) \
          device_create_file(&_dev->dev, &dev_attr_##_name)
 #define NATSEMI_REMOVE_FILE(_dev, _name) \
-         device_create_file(&_dev->dev, &dev_attr_##_name)
+         device_remove_file(&_dev->dev, &dev_attr_##_name)
 
 NATSEMI_ATTR(dspcfg_workaround);
 
@@ -691,7 +678,7 @@ static ssize_t natsemi_set_dspcfg_workaround(struct device *dev,
 {
        struct netdev_private *np = netdev_priv(to_net_dev(dev));
        int new_setting;
-       u32 flags;
+       unsigned long flags;
 
         /* Find out the new setting */
         if (!strncmp("on", buf, count - 1) || !strncmp("1", buf, count - 1))
@@ -799,11 +786,13 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
        struct netdev_private *np;
        int i, option, irq, chip_idx = ent->driver_data;
        static int find_cnt = -1;
-       unsigned long iostart, iosize;
+       resource_size_t iostart;
+       unsigned long iosize;
        void __iomem *ioaddr;
        const int pcibar = 1; /* PCI base address register */
        int prev_eedata;
        u32 tmp;
+       DECLARE_MAC_BUF(mac);
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -836,7 +825,6 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
        dev = alloc_etherdev(sizeof (struct netdev_private));
        if (!dev)
                return -ENOMEM;
-       SET_MODULE_OWNER(dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
 
        i = pci_request_regions(pdev, DRV_NAME);
@@ -862,6 +850,8 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
        dev->irq = irq;
 
        np = netdev_priv(dev);
+       netif_napi_add(dev, &np->napi, natsemi_poll, 64);
+       np->dev = dev;
 
        np->pci_dev = pdev;
        pci_set_drvdata(pdev, dev);
@@ -932,8 +922,6 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
        dev->do_ioctl = &netdev_ioctl;
        dev->tx_timeout = &tx_timeout;
        dev->watchdog_timeo = TX_TIMEOUT;
-       dev->poll = natsemi_poll;
-       dev->weight = 64;
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
        dev->poll_controller = &natsemi_poll_controller;
@@ -959,12 +947,11 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
                goto err_create_file;
 
        if (netif_msg_drv(np)) {
-               printk(KERN_INFO "natsemi %s: %s at %#08lx (%s), ",
-                       dev->name, natsemi_pci_info[chip_idx].name, iostart,
-                       pci_name(np->pci_dev));
-               for (i = 0; i < ETH_ALEN-1; i++)
-                               printk("%02x:", dev->dev_addr[i]);
-               printk("%02x, IRQ %d", dev->dev_addr[i], irq);
+               printk(KERN_INFO "natsemi %s: %s at %#08llx "
+                      "(%s), %s, IRQ %d",
+                      dev->name, natsemi_pci_info[chip_idx].name,
+                      (unsigned long long)iostart, pci_name(np->pci_dev),
+                      print_mac(mac, dev->dev_addr), irq);
                if (dev->if_port == PORT_TP)
                        printk(", port TP.\n");
                else if (np->ignore_phy)
@@ -998,7 +985,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
    a delay.  Note that pre-2.0.34 kernels had a cache-alignment bug that
    made udelay() unreliable.
    The old method of using an ISA access as a delay, __SLOW_DOWN_IO__, is
-   depricated.
+   deprecated.
 */
 #define eeprom_delay(ee_addr)  readl(ee_addr)
 
@@ -1555,6 +1542,8 @@ static int netdev_open(struct net_device *dev)
                free_irq(dev->irq, dev);
                return i;
        }
+       napi_enable(&np->napi);
+
        init_ring(dev);
        spin_lock_irq(&np->lock);
        init_registers(dev);
@@ -1576,7 +1565,7 @@ static int netdev_open(struct net_device *dev)
 
        /* Set the timer to check for link beat. */
        init_timer(&np->timer);
-       np->timer.expires = jiffies + NATSEMI_TIMER_FREQ;
+       np->timer.expires = round_jiffies(jiffies + NATSEMI_TIMER_FREQ);
        np->timer.data = (unsigned long)dev;
        np->timer.function = &netdev_timer; /* timer handler */
        add_timer(&np->timer);
@@ -1615,7 +1604,7 @@ static void do_cable_magic(struct net_device *dev)
                 * (these values all come from National)
                 */
                if (!(data & 0x80) || ((data >= 0xd8) && (data <= 0xff))) {
-                       struct netdev_private *np = netdev_priv(dev);
+                       np = netdev_priv(dev);
 
                        /* the bug has been triggered - fix the coefficient */
                        writew(TSTDAT_FIXED, ioaddr + TSTDAT);
@@ -1798,7 +1787,7 @@ static void netdev_timer(unsigned long data)
        struct net_device *dev = (struct net_device *)data;
        struct netdev_private *np = netdev_priv(dev);
        void __iomem * ioaddr = ns_ioaddr(dev);
-       int next_tick = 5*HZ;
+       int next_tick = NATSEMI_TIMER_FREQ;
 
        if (netif_msg_timer(np)) {
                /* DO NOT read the IntrStatus register,
@@ -1856,7 +1845,11 @@ static void netdev_timer(unsigned long data)
                        next_tick = 1;
                }
        }
-       mod_timer(&np->timer, jiffies + next_tick);
+
+       if (next_tick > 1)
+               mod_timer(&np->timer, round_jiffies(jiffies + next_tick));
+       else
+               mod_timer(&np->timer, jiffies + next_tick);
 }
 
 static void dump_ring(struct net_device *dev)
@@ -2027,7 +2020,7 @@ static void drain_rx(struct net_device *dev)
        /* Free all the skbuffs in the Rx queue. */
        for (i = 0; i < RX_RING_SIZE; i++) {
                np->rx_ring[i].cmd_status = 0;
-               np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */
+               np->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
                if (np->rx_skbuff[i]) {
                        pci_unmap_single(np->pci_dev,
                                np->rx_dma[i], buflen,
@@ -2201,10 +2194,10 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
 
        prefetch(&np->rx_skbuff[np->cur_rx % RX_RING_SIZE]);
 
-       if (netif_rx_schedule_prep(dev)) {
+       if (netif_rx_schedule_prep(dev, &np->napi)) {
                /* Disable interrupts and register for poll */
                natsemi_irq_disable(dev);
-               __netif_rx_schedule(dev);
+               __netif_rx_schedule(dev, &np->napi);
        } else
                printk(KERN_WARNING
                       "%s: Ignoring interrupt, status %#08x, mask %#08x.\n",
@@ -2217,12 +2210,11 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
 /* This is the NAPI poll routine.  As well as the standard RX handling
  * it also handles all other interrupts that the chip might raise.
  */
-static int natsemi_poll(struct net_device *dev, int *budget)
+static int natsemi_poll(struct napi_struct *napi, int budget)
 {
-       struct netdev_private *np = netdev_priv(dev);
+       struct netdev_private *np = container_of(napi, struct netdev_private, napi);
+       struct net_device *dev = np->dev;
        void __iomem * ioaddr = ns_ioaddr(dev);
-
-       int work_to_do = min(*budget, dev->quota);
        int work_done = 0;
 
        do {
@@ -2237,7 +2229,7 @@ static int natsemi_poll(struct net_device *dev, int *budget)
                if (np->intr_status &
                    (IntrRxDone | IntrRxIntr | RxStatusFIFOOver |
                     IntrRxErr | IntrRxOverrun)) {
-                       netdev_rx(dev, &work_done, work_to_do);
+                       netdev_rx(dev, &work_done, budget);
                }
 
                if (np->intr_status &
@@ -2251,25 +2243,22 @@ static int natsemi_poll(struct net_device *dev, int *budget)
                if (np->intr_status & IntrAbnormalSummary)
                        netdev_error(dev, np->intr_status);
 
-               *budget -= work_done;
-               dev->quota -= work_done;
-
-               if (work_done >= work_to_do)
-                       return 1;
+               if (work_done >= budget)
+                       return work_done;
 
                np->intr_status = readl(ioaddr + IntrStatus);
        } while (np->intr_status);
 
-       netif_rx_complete(dev);
+       netif_rx_complete(dev, napi);
 
        /* Reenable interrupts providing nothing is trying to shut
         * the chip down. */
        spin_lock(&np->lock);
-       if (!np->hands_off && netif_running(dev))
+       if (!np->hands_off)
                natsemi_irq_enable(dev);
        spin_unlock(&np->lock);
 
-       return 0;
+       return work_done;
 }
 
 /* This routine is logically part of the interrupt handler, but separated
@@ -2358,8 +2347,8 @@ static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do)
                                        np->rx_dma[entry],
                                        buflen,
                                        PCI_DMA_FROMDEVICE);
-                               eth_copy_and_sum(skb,
-                                       np->rx_skbuff[entry]->data, pkt_len, 0);
+                               skb_copy_to_linear_data(skb,
+                                       np->rx_skbuff[entry]->data, pkt_len);
                                skb_put(skb, pkt_len);
                                pci_dma_sync_single_for_device(np->pci_dev,
                                        np->rx_dma[entry],
@@ -2439,13 +2428,16 @@ static void netdev_error(struct net_device *dev, int intr_status)
                                dev->name);
                }
                np->stats.rx_fifo_errors++;
+               np->stats.rx_errors++;
        }
        /* Hmmmmm, it's not clear how to recover from PCI faults. */
        if (intr_status & IntrPCIErr) {
                printk(KERN_NOTICE "%s: PCI error %#08x\n", dev->name,
                        intr_status & IntrPCIErr);
                np->stats.tx_fifo_errors++;
+               np->stats.tx_errors++;
                np->stats.rx_fifo_errors++;
+               np->stats.rx_errors++;
        }
        spin_unlock(&np->lock);
 }
@@ -2503,8 +2495,8 @@ static void __set_rx_mode(struct net_device *dev)
                memset(mc_filter, 0, sizeof(mc_filter));
                for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
                         i++, mclist = mclist->next) {
-                       int i = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 23) & 0x1ff;
-                       mc_filter[i/8] |= (1 << (i & 0x07));
+                       int b = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 23) & 0x1ff;
+                       mc_filter[b/8] |= (1 << (b & 0x07));
                }
                rx_mode = RxFilterEnable | AcceptBroadcast
                        | AcceptMulticast | AcceptMyPhys;
@@ -3156,6 +3148,8 @@ static int netdev_close(struct net_device *dev)
                        dev->name, np->cur_tx, np->dirty_tx,
                        np->cur_rx, np->dirty_rx);
 
+       napi_disable(&np->napi);
+
        /*
         * FIXME: what if someone tries to close a device
         * that is suspended?
@@ -3251,7 +3245,7 @@ static void __devexit natsemi_remove1 (struct pci_dev *pdev)
  *             disable_irq() to enforce synchronization.
  *      * natsemi_poll: checks before reenabling interrupts.  suspend
  *              sets hands_off, disables interrupts and then waits with
- *              netif_poll_disable().
+ *              napi_disable().
  *
  * Interrupts must be disabled, otherwise hands_off can cause irq storms.
  */
@@ -3277,7 +3271,7 @@ static int natsemi_suspend (struct pci_dev *pdev, pm_message_t state)
                spin_unlock_irq(&np->lock);
                enable_irq(dev->irq);
 
-               netif_poll_disable(dev);
+               napi_disable(&np->napi);
 
                /* Update the error counts. */
                __get_stats(dev);
@@ -3309,15 +3303,23 @@ static int natsemi_resume (struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata (pdev);
        struct netdev_private *np = netdev_priv(dev);
+       int ret = 0;
 
        rtnl_lock();
        if (netif_device_present(dev))
                goto out;
        if (netif_running(dev)) {
                BUG_ON(!np->hands_off);
-               pci_enable_device(pdev);
+               ret = pci_enable_device(pdev);
+               if (ret < 0) {
+                       dev_err(&pdev->dev,
+                               "pci_enable_device() failed: %d\n", ret);
+                       goto out;
+               }
        /*      pci_power_on(pdev); */
 
+               napi_enable(&np->napi);
+
                natsemi_reset(dev);
                init_ring(dev);
                disable_irq(dev->irq);
@@ -3328,13 +3330,12 @@ static int natsemi_resume (struct pci_dev *pdev)
                spin_unlock_irq(&np->lock);
                enable_irq(dev->irq);
 
-               mod_timer(&np->timer, jiffies + 1*HZ);
+               mod_timer(&np->timer, round_jiffies(jiffies + 1*HZ));
        }
        netif_device_attach(dev);
-       netif_poll_enable(dev);
 out:
        rtnl_unlock();
-       return 0;
+       return ret;
 }
 
 #endif /* CONFIG_PM */