]> err.no Git - linux-2.6/blobdiff - drivers/net/b44.c
Merge master.kernel.org:/pub/scm/linux/kernel/git/davej/agpgart
[linux-2.6] / drivers / net / b44.c
index 3b6428f004f610adc375d7830c7e25f71201a3a0..c53848f787ebb600632d4f8b05964de4b7b919dd 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/init.h>
-#include <linux/version.h>
 #include <linux/dma-mapping.h>
 
 #include <asm/uaccess.h>
@@ -29,8 +28,8 @@
 
 #define DRV_MODULE_NAME                "b44"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "0.95"
-#define DRV_MODULE_RELDATE     "Aug 3, 2004"
+#define DRV_MODULE_VERSION     "0.96"
+#define DRV_MODULE_RELDATE     "Nov 8, 2005"
 
 #define B44_DEF_MSG_ENABLE       \
        (NETIF_MSG_DRV          | \
@@ -106,6 +105,12 @@ static void b44_init_hw(struct b44 *);
 static int dma_desc_align_mask;
 static int dma_desc_sync_size;
 
+static const char b44_gstrings[][ETH_GSTRING_LEN] = {
+#define _B44(x...)     # x,
+B44_STAT_REG_DECLARE
+#undef _B44
+};
+
 static inline void b44_sync_dma_desc_for_device(struct pci_dev *pdev,
                                                 dma_addr_t dma_base,
                                                 unsigned long offset,
@@ -498,7 +503,10 @@ static void b44_stats_update(struct b44 *bp)
        for (reg = B44_TX_GOOD_O; reg <= B44_TX_PAUSE; reg += 4UL) {
                *val++ += br32(bp, reg);
        }
-       val = &bp->hw_stats.rx_good_octets;
+
+       /* Pad */
+       reg += 8*4UL;
+
        for (reg = B44_RX_GOOD_O; reg <= B44_RX_NPAUSE; reg += 4UL) {
                *val++ += br32(bp, reg);
        }
@@ -886,11 +894,10 @@ static irqreturn_t b44_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        struct net_device *dev = dev_id;
        struct b44 *bp = netdev_priv(dev);
-       unsigned long flags;
        u32 istat, imask;
        int handled = 0;
 
-       spin_lock_irqsave(&bp->lock, flags);
+       spin_lock(&bp->lock);
 
        istat = br32(bp, B44_ISTAT);
        imask = br32(bp, B44_IMASK);
@@ -901,6 +908,12 @@ static irqreturn_t b44_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        istat &= imask;
        if (istat) {
                handled = 1;
+
+               if (unlikely(!netif_running(dev))) {
+                       printk(KERN_INFO "%s: late interrupt.\n", dev->name);
+                       goto irq_ack;
+               }
+
                if (netif_rx_schedule_prep(dev)) {
                        /* NOTE: These writes are posted by the readback of
                         *       the ISTAT register below.
@@ -913,10 +926,11 @@ static irqreturn_t b44_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                               dev->name);
                }
 
+irq_ack:
                bw32(bp, B44_ISTAT, istat);
                br32(bp, B44_ISTAT);
        }
-       spin_unlock_irqrestore(&bp->lock, flags);
+       spin_unlock(&bp->lock);
        return IRQ_RETVAL(handled);
 }
 
@@ -1380,22 +1394,21 @@ static int b44_open(struct net_device *dev)
 
        err = b44_alloc_consistent(bp);
        if (err)
-               return err;
-
-       err = request_irq(dev->irq, b44_interrupt, SA_SHIRQ, dev->name, dev);
-       if (err)
-               goto err_out_free;
-
-       spin_lock_irq(&bp->lock);
+               goto out;
 
        b44_init_rings(bp);
        b44_init_hw(bp);
-       bp->flags |= B44_FLAG_INIT_COMPLETE;
 
        netif_carrier_off(dev);
        b44_check_phy(bp);
 
-       spin_unlock_irq(&bp->lock);
+       err = request_irq(dev->irq, b44_interrupt, SA_SHIRQ, dev->name, dev);
+       if (unlikely(err < 0)) {
+               b44_chip_reset(bp);
+               b44_free_rings(bp);
+               b44_free_consistent(bp);
+               goto out;
+       }
 
        init_timer(&bp->timer);
        bp->timer.expires = jiffies + HZ;
@@ -1404,11 +1417,7 @@ static int b44_open(struct net_device *dev)
        add_timer(&bp->timer);
 
        b44_enable_ints(bp);
-
-       return 0;
-
-err_out_free:
-       b44_free_consistent(bp);
+out:
        return err;
 }
 
@@ -1443,6 +1452,8 @@ static int b44_close(struct net_device *dev)
 
        netif_stop_queue(dev);
 
+       netif_poll_disable(dev);
+
        del_timer_sync(&bp->timer);
 
        spin_lock_irq(&bp->lock);
@@ -1452,13 +1463,14 @@ static int b44_close(struct net_device *dev)
 #endif
        b44_halt(bp);
        b44_free_rings(bp);
-       bp->flags &= ~B44_FLAG_INIT_COMPLETE;
        netif_carrier_off(bp->dev);
 
        spin_unlock_irq(&bp->lock);
 
        free_irq(dev->irq, dev);
 
+       netif_poll_enable(dev);
+
        b44_free_consistent(bp);
 
        return 0;
@@ -1604,7 +1616,7 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
        struct b44 *bp = netdev_priv(dev);
 
-       if (!(bp->flags & B44_FLAG_INIT_COMPLETE))
+       if (!netif_running(dev))
                return -EAGAIN;
        cmd->supported = (SUPPORTED_Autoneg);
        cmd->supported |= (SUPPORTED_100baseT_Half |
@@ -1642,7 +1654,7 @@ static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
        struct b44 *bp = netdev_priv(dev);
 
-       if (!(bp->flags & B44_FLAG_INIT_COMPLETE))
+       if (!netif_running(dev))
                return -EAGAIN;
 
        /* We do not support gigabit. */
@@ -1772,6 +1784,37 @@ static int b44_set_pauseparam(struct net_device *dev,
        return 0;
 }
 
+static void b44_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+       switch(stringset) {
+       case ETH_SS_STATS:
+               memcpy(data, *b44_gstrings, sizeof(b44_gstrings));
+               break;
+       }
+}
+
+static int b44_get_stats_count(struct net_device *dev)
+{
+       return ARRAY_SIZE(b44_gstrings);
+}
+
+static void b44_get_ethtool_stats(struct net_device *dev,
+                                 struct ethtool_stats *stats, u64 *data)
+{
+       struct b44 *bp = netdev_priv(dev);
+       u32 *val = &bp->hw_stats.tx_good_octets;
+       u32 i;
+
+       spin_lock_irq(&bp->lock);
+
+       b44_stats_update(bp);
+
+       for (i = 0; i < ARRAY_SIZE(b44_gstrings); i++)
+               *data++ = *val++;
+
+       spin_unlock_irq(&bp->lock);
+}
+
 static struct ethtool_ops b44_ethtool_ops = {
        .get_drvinfo            = b44_get_drvinfo,
        .get_settings           = b44_get_settings,
@@ -1784,6 +1827,9 @@ static struct ethtool_ops b44_ethtool_ops = {
        .set_pauseparam         = b44_set_pauseparam,
        .get_msglevel           = b44_get_msglevel,
        .set_msglevel           = b44_set_msglevel,
+       .get_strings            = b44_get_strings,
+       .get_stats_count        = b44_get_stats_count,
+       .get_ethtool_stats      = b44_get_ethtool_stats,
        .get_perm_addr          = ethtool_op_get_perm_addr,
 };