patch-2.4.11-dontuse linux/drivers/net/ns83820.c

Next file: linux/drivers/net/pcmcia/3c574_cs.c
Previous file: linux/drivers/net/ni65.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.10/linux/drivers/net/ns83820.c linux/drivers/net/ns83820.c
@@ -1,7 +1,7 @@
-#define VERSION "0.11"
+#define VERSION "0.13"
 /* ns83820.c by Benjamin LaHaise <bcrl@redhat.com>
  *
- * $Revision: 1.34.2.2 $
+ * $Revision: 1.34.2.8 $
  *
  * Copyright 2001 Benjamin LaHaise.
  * Copyright 2001 Red Hat.
@@ -41,7 +41,10 @@
  *	20010827	0.10 - fix ia64 unaligned access.
  *	20010906	0.11 - accept all packets with checksum errors as
  *			       otherwise fragments get lost
-			     - fix >> 32 bugs
+ *			     - fix >> 32 bugs
+ *			0.12 - add statistics counters
+ *			     - add allmulti/promisc support
+ *	20011009	0.13 - hotplug support, other smaller pci api cleanups
  *
  * Driver Overview
  * ===============
@@ -61,7 +64,9 @@
  *	Cameo		SOHO-GA2000T	SOHO-GA2500T
  *	D-Link		DGE-500T
  *	PureData	PDP8023Z-TG
- *	SMC		SMC9462TX
+ *	SMC		SMC9452TX	SMC9462TX
+ *
+ * Special thanks to SMC for providing hardware to test this driver on.
  *
  * Reports of success or failure would be greatly appreciated.
  */
@@ -366,10 +371,10 @@
 
 struct ns83820 {
 	struct net_device	net_dev;
+	struct net_device_stats	stats;
 	u8			*base;
 
 	struct pci_dev		*pci_dev;
-	struct ns83820		*next_dev;
 
 	struct rx_info		rx_info;
 
@@ -405,8 +410,6 @@
 #define start_tx_okay(dev)	\
 	(((NR_TX_DESC-2 + dev->tx_done_idx - dev->tx_free_idx) % NR_TX_DESC) > NR_TX_DESC/2)
 
-static struct ns83820	*ns83820_chain;
-
 
 /* Packet Receiver
  *
@@ -732,39 +735,22 @@
 			kfree_skb(skb);
 			skb = tmp;
 #endif
+			if (cmdsts & CMDSTS_DEST_MULTI)
+				dev->stats.multicast ++;
+			dev->stats.rx_packets ++;
+			dev->stats.rx_bytes += len;
 			if ((extsts & 0x002a0000) && !(extsts & 0x00540000)) {
 				skb->ip_summed = CHECKSUM_UNNECESSARY;
 			} else {
 				skb->ip_summed = CHECKSUM_NONE;
 			}
 			skb->protocol = eth_type_trans(skb, &dev->net_dev);
-			switch (netif_rx(skb)) {
-			case NET_RX_SUCCESS:
-				dev->ihr = 3;
-				break;
-			case NET_RX_CN_LOW:
-				dev->ihr = 3;
-				break;
-			case NET_RX_CN_MOD:
-				dev->ihr = dev->ihr + 1;
-				break;
-			case NET_RX_CN_HIGH:
-				dev->ihr += dev->ihr/2 + 1;
-				break;
-			case NET_RX_DROP:
-				dev->ihr = 255;
-				break;
-			}
-			if (dev->ihr > 255)
-				dev->ihr = 255;
+			if (NET_RX_DROP == netif_rx(skb))
+				dev->stats.rx_dropped ++;
 #ifndef __i386__
 		done:;
 #endif
 		} else {
-			static int err;
-			if (err++ < 20) {
-				Dprintk("error packet: cmdsts: %08x extsts: %08x\n", cmdsts, extsts);
-			}
 			kfree_skb(skb);
 		}
 
@@ -807,6 +793,13 @@
 	       !(CMDSTS_OWN & (cmdsts = desc[CMDSTS])) ) {
 		struct sk_buff *skb;
 
+		if (cmdsts & CMDSTS_ERR)
+			dev->stats.tx_errors ++;
+		if (cmdsts & CMDSTS_OK)
+			dev->stats.tx_packets ++;
+		if (cmdsts & CMDSTS_OK)
+			dev->stats.tx_bytes += cmdsts & 0xffff;
+
 		dprintk("tx_done_idx=%d free_idx=%d cmdsts=%08x\n",
 			tx_done_idx, dev->tx_free_idx, desc[CMDSTS]);
 		skb = dev->tx_skbs[tx_done_idx];
@@ -985,6 +978,35 @@
 	return 0;
 }
 
+static void ns83820_update_stats(struct ns83820 *dev)
+{
+	u8 *base = dev->base;
+
+	dev->stats.rx_errors		+= readl(base + 0x60) & 0xffff;
+	dev->stats.rx_crc_errors	+= readl(base + 0x64) & 0xffff;
+	dev->stats.rx_missed_errors	+= readl(base + 0x68) & 0xffff;
+	dev->stats.rx_frame_errors	+= readl(base + 0x6c) & 0xffff;
+	/*dev->stats.rx_symbol_errors +=*/ readl(base + 0x70);
+	dev->stats.rx_length_errors	+= readl(base + 0x74) & 0xffff;
+	dev->stats.rx_length_errors	+= readl(base + 0x78) & 0xffff;
+	/*dev->stats.rx_badopcode_errors += */ readl(base + 0x7c);
+	/*dev->stats.rx_pause_count += */  readl(base + 0x80);
+	/*dev->stats.tx_pause_count += */  readl(base + 0x84);
+	dev->stats.tx_carrier_errors	+= readl(base + 0x88) & 0xff;
+}
+
+static struct net_device_stats *ns83820_get_stats(struct net_device *_dev)
+{
+	struct ns83820 *dev = (void *)_dev;
+
+	/* somewhat overkill */
+	spin_lock_irq(&dev->misc_lock);
+	ns83820_update_stats(dev);
+	spin_unlock_irq(&dev->misc_lock);
+
+	return &dev->stats;
+}
+
 static void ns83820_irq(int foo, void *data, struct pt_regs *regs)
 {
 	struct ns83820 *dev = data;
@@ -1060,6 +1082,12 @@
 	if ((ISR_TXDESC | ISR_TXIDLE) & isr)
 		do_tx_done(dev);
 
+	if (ISR_MIB & isr) {
+		spin_lock(&dev->misc_lock);
+		ns83820_update_stats(dev);
+		spin_unlock(&dev->misc_lock);
+	}
+
 	if (ISR_PHY & isr)
 		phy_intr(dev);
 	}
@@ -1178,7 +1206,29 @@
 	return 0;
 }
 
-static int ns83820_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
+static void ns83820_set_multicast(struct net_device *_dev)
+{
+	struct ns83820 *dev = (void *)_dev;
+	u8 *rfcr = dev->base + RFCR;
+	u32 and_mask = 0xffffffff;
+	u32 or_mask = 0;
+
+	if (dev->net_dev.flags & IFF_PROMISC)
+		or_mask |= RFCR_AAU | RFCR_AAM;
+	else
+		and_mask &= ~(RFCR_AAU | RFCR_AAM);
+
+	if (dev->net_dev.flags & IFF_ALLMULTI)
+		or_mask |= RFCR_AAM;
+	else
+		and_mask &= ~RFCR_AAM;
+
+	spin_lock_irq(&dev->misc_lock);
+	writel((readl(rfcr) & and_mask) | or_mask, rfcr);
+	spin_unlock_irq(&dev->misc_lock);
+}
+
+static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_device_id *id)
 {
 	struct ns83820 *dev;
 	long addr;
@@ -1241,12 +1291,12 @@
 	dev->net_dev.stop = ns83820_stop;
 	dev->net_dev.hard_start_xmit = ns83820_hard_start_xmit;
 	dev->net_dev.change_mtu = ns83820_change_mtu;
+	dev->net_dev.get_stats = ns83820_get_stats;
+	dev->net_dev.change_mtu = ns83820_change_mtu;
+	dev->net_dev.set_multicast_list = ns83820_set_multicast;
 	//FIXME: dev->net_dev.tx_timeout = ns83820_tx_timeout;
 
-	lock_kernel();
-	dev->next_dev = ns83820_chain;
-	ns83820_chain = dev;
-	unlock_kernel();
+	pci_set_drvdata(pci_dev, dev);
 
 	ns83820_do_reset(dev, CR_RST);
 
@@ -1368,21 +1418,45 @@
 	pci_disable_device(pci_dev);
 out_free:
 	kfree(dev);
+	pci_set_drvdata(pci_dev, NULL);
 out:
 	return err;
 }
 
-static struct pci_device_id pci_device_id[] __devinitdata = {
+static void __devexit ns83820_remove_one(struct pci_dev *pci_dev)
+{
+	struct ns83820	*dev = pci_get_drvdata(pci_dev);
+
+	if (!dev)			/* paranoia */
+		return;
+
+	writel(0, dev->base + IMR);	/* paranoia */
+	writel(0, dev->base + IER);
+	readl(dev->base + IER);
+
+	unregister_netdev(&dev->net_dev);
+	free_irq(dev->pci_dev->irq, dev);
+	iounmap(dev->base);
+	pci_free_consistent(dev->pci_dev, 4 * DESC_SIZE * NR_TX_DESC,
+			dev->tx_descs, dev->tx_phy_descs);
+	pci_free_consistent(dev->pci_dev, 4 * DESC_SIZE * NR_RX_DESC,
+			dev->rx_info.descs, dev->rx_info.phy_descs);
+	pci_disable_device(dev->pci_dev);
+	kfree(dev);
+	pci_set_drvdata(pci_dev, NULL);
+}
+
+static struct pci_device_id ns83820_pci_tbl[] __devinitdata = {
 	{ 0x100b, 0x0022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
 	{ 0, },
 };
 
 static struct pci_driver driver = {
 	name:		"ns83820",
-	id_table:	pci_device_id,
-	probe:		ns83820_probe,
+	id_table:	ns83820_pci_tbl,
+	probe:		ns83820_init_one,
+	remove:		ns83820_remove_one,
 #if 0	/* FIXME: implement */
-	remove:		,
 	suspend:	,
 	resume:		,
 #endif
@@ -1395,34 +1469,16 @@
 	return pci_module_init(&driver);
 }
 
-static void ns83820_exit(void)
+static void __exit ns83820_exit(void)
 {
-	struct ns83820	*dev;
-
-	for (dev = ns83820_chain; dev; ) {
-		struct ns83820 *next = dev->next_dev;
-
-		writel(0, dev->base + IMR);	/* paranoia */
-		writel(0, dev->base + IER);
-		readl(dev->base + IER);
-
-		unregister_netdev(&dev->net_dev);
-		free_irq(dev->pci_dev->irq, dev);
-		iounmap(dev->base);
-		pci_free_consistent(dev->pci_dev, 4 * DESC_SIZE * NR_TX_DESC,
-				dev->tx_descs, dev->tx_phy_descs);
-		pci_free_consistent(dev->pci_dev, 4 * DESC_SIZE * NR_RX_DESC,
-				dev->rx_info.descs, dev->rx_info.phy_descs);
-		pci_disable_device(dev->pci_dev);
-		kfree(dev);
-		dev = next;
-	}
 	pci_unregister_driver(&driver);
-	ns83820_chain = NULL;
 }
 
 MODULE_AUTHOR("Benjamin LaHaise <bcrl@redhat.com>");
 MODULE_DESCRIPTION("National Semiconductor DP83820 10/100/1000 driver");
-MODULE_DEVICE_TABLE(pci, pci_device_id);
+MODULE_LICENSE("GPL");
+
+MODULE_DEVICE_TABLE(pci, ns83820_pci_tbl);
+
 module_init(ns83820_init);
 module_exit(ns83820_exit);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)