summary refs log tree commit diff
path: root/drivers/net/b44.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2005-11-09 08:34:36 -0800
committerLinus Torvalds <torvalds@g5.osdl.org>2005-11-09 08:34:36 -0800
commita7c243b544c0e9f6775c2607decaa59d54fb9e11 (patch)
tree86fdb4d2d6cef932af7497f28827e7d52b29e48c /drivers/net/b44.c
parent7df446e7e043b2ba5fd5de42529f9d797e8b501a (diff)
parentf406db8cba6bbce42b96490e6d31bdec229ad994 (diff)
downloadlinux-a7c243b544c0e9f6775c2607decaa59d54fb9e11.tar.gz
Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6
Diffstat (limited to 'drivers/net/b44.c')
-rw-r--r--drivers/net/b44.c177
1 files changed, 109 insertions, 68 deletions
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 819a17921cb9..c53848f787eb 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -28,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		| \
@@ -101,14 +101,16 @@ MODULE_DEVICE_TABLE(pci, b44_pci_tbl);
 static void b44_halt(struct b44 *);
 static void b44_init_rings(struct b44 *);
 static void b44_init_hw(struct b44 *);
-static int b44_poll(struct net_device *dev, int *budget);
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void b44_poll_controller(struct net_device *dev);
-#endif
 
 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,
@@ -501,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);
 	}
@@ -652,7 +657,7 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
 
 	/* Hardware bug work-around, the chip is unable to do PCI DMA
 	   to/from anything above 1GB :-( */
-	if(mapping+RX_PKT_BUF_SZ > B44_DMA_MASK) {
+	if (mapping + RX_PKT_BUF_SZ > B44_DMA_MASK) {
 		/* Sigh... */
 		pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
 		dev_kfree_skb_any(skb);
@@ -662,7 +667,7 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
 		mapping = pci_map_single(bp->pdev, skb->data,
 					 RX_PKT_BUF_SZ,
 					 PCI_DMA_FROMDEVICE);
-		if(mapping+RX_PKT_BUF_SZ > B44_DMA_MASK) {
+		if (mapping + RX_PKT_BUF_SZ > B44_DMA_MASK) {
 			pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
 			dev_kfree_skb_any(skb);
 			return -ENOMEM;
@@ -889,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);
@@ -904,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.
@@ -916,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);
 }
 
@@ -947,6 +958,7 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct b44 *bp = netdev_priv(dev);
 	struct sk_buff *bounce_skb;
+	int rc = NETDEV_TX_OK;
 	dma_addr_t mapping;
 	u32 len, entry, ctrl;
 
@@ -956,29 +968,28 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	/* This is a hard error, log it. */
 	if (unlikely(TX_BUFFS_AVAIL(bp) < 1)) {
 		netif_stop_queue(dev);
-		spin_unlock_irq(&bp->lock);
 		printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
 		       dev->name);
-		return 1;
+		goto err_out;
 	}
 
 	mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
-	if(mapping+len > B44_DMA_MASK) {
+	if (mapping + len > B44_DMA_MASK) {
 		/* Chip can't handle DMA to/from >1GB, use bounce buffer */
 		pci_unmap_single(bp->pdev, mapping, len, PCI_DMA_TODEVICE);
 
 		bounce_skb = __dev_alloc_skb(TX_PKT_BUF_SZ,
 					     GFP_ATOMIC|GFP_DMA);
 		if (!bounce_skb)
-			return NETDEV_TX_BUSY;
+			goto err_out;
 
 		mapping = pci_map_single(bp->pdev, bounce_skb->data,
 					 len, PCI_DMA_TODEVICE);
-		if(mapping+len > B44_DMA_MASK) {
+		if (mapping + len > B44_DMA_MASK) {
 			pci_unmap_single(bp->pdev, mapping,
 					 len, PCI_DMA_TODEVICE);
 			dev_kfree_skb_any(bounce_skb);
-			return NETDEV_TX_BUSY;
+			goto err_out;
 		}
 
 		memcpy(skb_put(bounce_skb, len), skb->data, skb->len);
@@ -1018,11 +1029,16 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	if (TX_BUFFS_AVAIL(bp) < 1)
 		netif_stop_queue(dev);
 
+	dev->trans_start = jiffies;
+
+out_unlock:
 	spin_unlock_irq(&bp->lock);
 
-	dev->trans_start = jiffies;
+	return rc;
 
-	return 0;
+err_out:
+	rc = NETDEV_TX_BUSY;
+	goto out_unlock;
 }
 
 static int b44_change_mtu(struct net_device *dev, int new_mtu)
@@ -1096,8 +1112,7 @@ static void b44_free_rings(struct b44 *bp)
  *
  * The chip has been shut down and the driver detached from
  * the networking, so no interrupts or new tx packets will
- * end up in the driver.  bp->lock is not held and we are not
- * in an interrupt context and thus may sleep.
+ * end up in the driver.
  */
 static void b44_init_rings(struct b44 *bp)
 {
@@ -1169,16 +1184,14 @@ static int b44_alloc_consistent(struct b44 *bp)
 	int size;
 
 	size  = B44_RX_RING_SIZE * sizeof(struct ring_info);
-	bp->rx_buffers = kmalloc(size, GFP_KERNEL);
+	bp->rx_buffers = kzalloc(size, GFP_KERNEL);
 	if (!bp->rx_buffers)
 		goto out_err;
-	memset(bp->rx_buffers, 0, size);
 
 	size = B44_TX_RING_SIZE * sizeof(struct ring_info);
-	bp->tx_buffers = kmalloc(size, GFP_KERNEL);
+	bp->tx_buffers = kzalloc(size, GFP_KERNEL);
 	if (!bp->tx_buffers)
 		goto out_err;
-	memset(bp->tx_buffers, 0, size);
 
 	size = DMA_TABLE_BYTES;
 	bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma);
@@ -1189,10 +1202,10 @@ static int b44_alloc_consistent(struct b44 *bp)
 		struct dma_desc *rx_ring;
 		dma_addr_t rx_ring_dma;
 
-		if (!(rx_ring = (struct dma_desc *)kmalloc(size, GFP_KERNEL)))
+		rx_ring = kzalloc(size, GFP_KERNEL);
+		if (!rx_ring)
 			goto out_err;
 
-		memset(rx_ring, 0, size);
 		rx_ring_dma = dma_map_single(&bp->pdev->dev, rx_ring,
 		                             DMA_TABLE_BYTES,
 		                             DMA_BIDIRECTIONAL);
@@ -1215,10 +1228,10 @@ static int b44_alloc_consistent(struct b44 *bp)
 		struct dma_desc *tx_ring;
 		dma_addr_t tx_ring_dma;
 
-		if (!(tx_ring = (struct dma_desc *)kmalloc(size, GFP_KERNEL)))
+		tx_ring = kzalloc(size, GFP_KERNEL);
+		if (!tx_ring)
 			goto out_err;
 
-		memset(tx_ring, 0, size);
 		tx_ring_dma = dma_map_single(&bp->pdev->dev, tx_ring,
 		                             DMA_TABLE_BYTES,
 		                             DMA_TO_DEVICE);
@@ -1381,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;
@@ -1405,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;
 }
 
@@ -1444,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);
@@ -1453,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;
@@ -1524,8 +1535,6 @@ static void __b44_set_rx_mode(struct net_device *dev)
 {
 	struct b44 *bp = netdev_priv(dev);
 	u32 val;
-	int i=0;
-	unsigned char zero[6] = {0,0,0,0,0,0};
 
 	val = br32(bp, B44_RXCONFIG);
 	val &= ~(RXCONFIG_PROMISC | RXCONFIG_ALLMULTI);
@@ -1533,14 +1542,17 @@ static void __b44_set_rx_mode(struct net_device *dev)
 		val |= RXCONFIG_PROMISC;
 		bw32(bp, B44_RXCONFIG, val);
 	} else {
+		unsigned char zero[6] = {0, 0, 0, 0, 0, 0};
+		int i = 0;
+
 		__b44_set_mac_addr(bp);
 
 		if (dev->flags & IFF_ALLMULTI)
 			val |= RXCONFIG_ALLMULTI;
 		else
-			i=__b44_load_mcast(bp, dev);
+			i = __b44_load_mcast(bp, dev);
 		
-		for(;i<64;i++) {
+		for (; i < 64; i++) {
 			__b44_cam_write(bp, zero, i);			
 		}
 		bw32(bp, B44_RXCONFIG, val);
@@ -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,
 };
 
@@ -1892,9 +1938,9 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
 	
 	err = pci_set_consistent_dma_mask(pdev, (u64) B44_DMA_MASK);
 	if (err) {
-	  printk(KERN_ERR PFX "No usable DMA configuration, "
-		 "aborting.\n");
-	  goto err_out_free_res;
+		printk(KERN_ERR PFX "No usable DMA configuration, "
+		       "aborting.\n");
+		goto err_out_free_res;
 	}
 
 	b44reg_base = pci_resource_start(pdev, 0);
@@ -1916,10 +1962,8 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
 	bp = netdev_priv(dev);
 	bp->pdev = pdev;
 	bp->dev = dev;
-	if (b44_debug >= 0)
-		bp->msg_enable = (1 << b44_debug) - 1;
-	else
-		bp->msg_enable = B44_DEF_MSG_ENABLE;
+
+	bp->msg_enable = netif_msg_init(b44_debug, B44_DEF_MSG_ENABLE);
 
 	spin_lock_init(&bp->lock);
 
@@ -2009,17 +2053,14 @@ err_out_disable_pdev:
 static void __devexit b44_remove_one(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
+	struct b44 *bp = netdev_priv(dev);
 
-	if (dev) {
-		struct b44 *bp = netdev_priv(dev);
-
-		unregister_netdev(dev);
-		iounmap(bp->regs);
-		free_netdev(dev);
-		pci_release_regions(pdev);
-		pci_disable_device(pdev);
-		pci_set_drvdata(pdev, NULL);
-	}
+	unregister_netdev(dev);
+	iounmap(bp->regs);
+	free_netdev(dev);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
 }
 
 static int b44_suspend(struct pci_dev *pdev, pm_message_t state)