#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>
#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 | \
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,
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);
}
{
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);
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.
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);
}
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;
add_timer(&bp->timer);
b44_enable_ints(bp);
-
- return 0;
-
-err_out_free:
- b44_free_consistent(bp);
+out:
return err;
}
netif_stop_queue(dev);
+ netif_poll_disable(dev);
+
del_timer_sync(&bp->timer);
spin_lock_irq(&bp->lock);
#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;
{
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 |
{
struct b44 *bp = netdev_priv(dev);
- if (!(bp->flags & B44_FLAG_INIT_COMPLETE))
+ if (!netif_running(dev))
return -EAGAIN;
/* We do not support gigabit. */
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,
.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,
};