patch-2.0.34 linux/drivers/net/lance.c

Next file: linux/drivers/net/lance32.c
Previous file: linux/drivers/net/hp100.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.0.33/linux/drivers/net/lance.c linux/drivers/net/lance.c
@@ -1,6 +1,6 @@
-/* lance.c: An AMD LANCE ethernet driver for linux. */
+/* lance.c: An AMD LANCE/PCnet ethernet driver for Linux. */
 /*
-	Written 1993,1994,1995 by Donald Becker.
+	Written/copyright 1993-1998 by Donald Becker.
 
 	Copyright 1993 United States Government as represented by the
 	Director, National Security Agency.
@@ -8,13 +8,12 @@
 	of the GNU Public License, incorporated herein by reference.
 
 	This driver is for the Allied Telesis AT1500 and HP J2405A, and should work
-	with most other LANCE-based bus-master (NE2100 clone) ethercards.
+	with most other LANCE-based bus-master (NE2100/NE2500) ethercards.
 
 	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
 	Center of Excellence in Space Data and Information Sciences
 	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
 
-
 	Fixing alignment problem with 1.3.* kernel and some minor changes
 	by Andrey V. Savochkin, 1996.
 
@@ -28,12 +27,33 @@
 	But I should to inform you that I'm not an expert in the LANCE card
 	and it may occurs that you will receive no answer on your mail
 	to Donald Becker. I didn't receive any answer on all my letters
-	to him. Who knows why... But may be you are more lucky?  ;-)
+	to him. Who knows why... But may be you are more lucky?  ;->
                                                           SAW
-    Fixed 7990 autoIRQ failure and reversed unneeded alignment. 8/20/96 djb
+
+	Thomas Bogendoerfer (tsbogend@bigbug.franken.de):
+	- added support for Linux/Alpha, but removed most of it, because
+        it worked only for the PCI chip. 
+      - added hook for the 32bit lance driver
+      - added PCnetPCI II (79C970A) to chip table
+	Paul Gortmaker (gpg109@rsphy1.anu.edu.au):
+	- hopefully fix above so Linux/Alpha can use ISA cards too.
+    8/20/96 Fixed 7990 autoIRQ failure and reversed unneeded alignment -djb
+    v1.12 10/27/97 Module support -djb
+    v1.14  2/3/98 Module support modified, made PCI support optional -djb
 */
 
-static const char *version = "lance.c:v1.09 Aug 20 1996 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n";
+static const char *version = "lance.c:v1.14 2/3/1998 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n";
+
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -54,8 +74,9 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
-static unsigned int lance_portlist[] = {0x300, 0x320, 0x340, 0x360, 0};
-void lance_probe1(int ioaddr);
+static unsigned int lance_portlist[] = { 0x300, 0x320, 0x340, 0x360, 0};
+int lance_probe(struct device *dev);
+int lance_probe1(struct device *dev, int ioaddr, int irq, int options);
 
 #ifdef HAVE_DEVLIST
 struct netdev_entry lance_drv =
@@ -96,7 +117,7 @@
 probed for by enabling each free DMA channel in turn and checking if
 initialization succeeds.
 
-The HP-J2405A board is an exception: with this board it's easy to read the
+The HP-J2405A board is an exception: with this board it is easy to read the
 EEPROM-set values for the base, IRQ, and DMA.  (Of course you must already
 _know_ the base address -- that field is for writing the EEPROM.)
 
@@ -155,26 +176,11 @@
 
 */
 
-/* Memory accessed from LANCE card must be aligned on 8-byte boundaries.
-   But we can't believe that kmalloc()'ed memory satisfies it. -- SAW */
-#define LANCE_KMALLOC(x) \
-	((void *) (((unsigned long)kmalloc((x)+7, GFP_DMA | GFP_KERNEL)+7) & ~7))
-
-/*
- * Changes:
- *	Thomas Bogendoerfer (tsbogend@bigbug.franken.de):
- *	- added support for Linux/Alpha, but removed most of it, because
- *        it worked only for the PCI chip. 
- *      - added hook for the 32bit lance driver
- *      - added PCnetPCI II (79C970A) to chip table
- *
- *	Paul Gortmaker (gpg109@rsphy1.anu.edu.au):
- *	- hopefully fix above so Linux/Alpha can use ISA cards too.
- */
-
 /* Set the number of Tx and Rx buffers, using Log_2(# buffers).
    Reasonable default values are 16 Tx buffers, and 16 Rx buffers.
-   That translates to 4 and 4 (16 == 2^^4). */
+   That translates to 4 and 4 (16 == 2^^4).
+   This is a compile-time option for efficiency.
+   */
 #ifndef LANCE_LOG_TX_BUFFERS
 #define LANCE_LOG_TX_BUFFERS 4
 #define LANCE_LOG_RX_BUFFERS 4
@@ -228,6 +234,8 @@
 	const char *name;
 	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
 	struct sk_buff* tx_skbuff[TX_RING_SIZE];
+	/* The addresses of receive-in-place skbuffs. */
+	struct sk_buff* rx_skbuff[RX_RING_SIZE];
 	unsigned long rx_buffs;		/* Address of Rx and Tx buffers. */
 	/* Tx low-memory "bounce buffer" address. */
 	char (*tx_bounce_buffs)[PKT_BUF_SZ];
@@ -299,15 +307,74 @@
 
 
 
-/* This lance probe is unlike the other board probes in 1.0.*.  The LANCE may
-   have to allocate a contiguous low-memory region for bounce buffers.
-   This requirement is satisfied by having the lance initialization occur
-   before the memory management system is started, and thus well before the
-   other probes. */
+#ifdef MODULE
+#define MAX_CARDS		8	/* Max number of interfaces (cards) per module */
+#define IF_NAMELEN		8	/* # of chars for storing dev->name */
+
+static int io[MAX_CARDS] = { 0, };
+static int dma[MAX_CARDS] = { 0, };
+static int irq[MAX_CARDS]  = { 0, };
+
+static char ifnames[MAX_CARDS][IF_NAMELEN] = { {0, }, };
+static struct device dev_lance[MAX_CARDS] =
+{{
+    0, /* device name is inserted by linux/drivers/net/net_init.c */
+	0, 0, 0, 0,
+	0, 0,
+	0, 0, 0, NULL, NULL}};
+
+int init_module(void)
+{
+	int this_dev, found = 0;
+
+	for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) {
+		struct device *dev = &dev_lance[this_dev];
+		dev->name = ifnames[this_dev];
+		dev->irq = irq[this_dev];
+		dev->base_addr = io[this_dev];
+		dev->dma = dma[this_dev];
+		dev->init = lance_probe;
+		if (io[this_dev] == 0)  {
+			if (this_dev != 0) break; /* only complain once */
+			printk(KERN_NOTICE "lance.c: Module autoprobing not allowed. Append \"io=0xNNN\" value(s).\n");
+			return -EPERM;
+		}
+		if (register_netdev(dev) != 0) {
+			printk(KERN_WARNING "lance.c: No PCnet/LANCE card found (i/o = 0x%x).\n", io[this_dev]);
+			if (found != 0) return 0;	/* Got at least one. */
+			return -ENXIO;
+		}
+		found++;
+	}
+
+	return 0;
+}
 
-int lance_init(void)
+void
+cleanup_module(void)
 {
-	int *port;
+	int this_dev;
+
+	for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) {
+		struct device *dev = &dev_lance[this_dev];
+		if (dev->priv != NULL) {
+			kfree(dev->priv);
+			dev->priv = NULL;
+			free_irq(dev->irq, NULL);
+			release_region(dev->base_addr, LANCE_TOTAL_SIZE);
+			unregister_netdev(dev);
+		}
+	}
+}
+#endif /* MODULE */
+
+/* Starting in v2.1.*, the LANCE/PCnet probe is now similar to the other
+   board probes now that kmalloc() can allocate ISA DMA-able regions.
+   This also allows the LANCE driver to be used as a module.
+   */
+int lance_probe(struct device *dev)
+{
+	int *port, result;
 
 	if (high_memory <= 16*1024*1024)
 		lance_need_isa_bounce_buffers = 0;
@@ -346,8 +413,9 @@
 			}
 			printk("Found PCnet/PCI at %#x, irq %d.\n",
 				   pci_ioaddr, pci_irq_line);
-			lance_probe1(pci_ioaddr);
+			result = lance_probe1(dev, pci_ioaddr, pci_irq_line, 0);
 			pci_irq_line = 0;
+			if (!result) return 0;
 		}
 	}
 #endif  /* defined(CONFIG_PCI) */
@@ -361,16 +429,17 @@
 			char offset15, offset14 = inb(ioaddr + 14);
 			
 			if ((offset14 == 0x52 || offset14 == 0x57) &&
-				((offset15 = inb(ioaddr + 15)) == 0x57 || offset15 == 0x44))
-				lance_probe1(ioaddr);
+				((offset15 = inb(ioaddr + 15)) == 0x57 || offset15 == 0x44)) {
+				result = lance_probe1(dev, ioaddr, 0, 0);
+				if ( !result ) return 0;
+			}
 		}
 	}
-	return 0;
+	return -ENODEV;
 }
 
-void lance_probe1(int ioaddr)
+int lance_probe1(struct device *dev, int ioaddr, int irq, int options)
 {
-	struct device *dev;
 	struct lance_private *lp;
 	short dma_channels;					/* Mark spuriously-busy DMA channels */
 	int i, reset_val, lance_version;
@@ -407,7 +476,7 @@
 
 	outw(0x0000, ioaddr+LANCE_ADDR); /* Switch to window 0 */
 	if (inw(ioaddr+LANCE_DATA) != 0x0004)
-		return;
+		return -ENODEV;
 
 	/* Get the version of the chip. */
 	outw(88, ioaddr+LANCE_ADDR);
@@ -420,7 +489,7 @@
 		if (lance_debug > 2)
 			printk("  LANCE chip version is %#x.\n", chip_version);
 		if ((chip_version & 0xfff) != 0x003)
-			return;
+			return -ENODEV;
 		chip_version = (chip_version >> 12) & 0xffff;
 		for (lance_version = 1; chip_table[lance_version].id_number; lance_version++) {
 			if (chip_table[lance_version].id_number == chip_version)
@@ -428,7 +497,9 @@
 		}
 	}
 
-	dev = init_etherdev(0, 0);
+	/* We can't use init_etherdev() to allocate dev->priv because it must
+	   a ISA DMA-able region. */
+	dev = init_etherdev(dev, 0);
 	dev->open = lance_open_fail;
 	chipname = chip_table[lance_version].name;
 	printk("%s: %s at %#3x,", dev->name, chipname, ioaddr);
@@ -442,15 +513,15 @@
 	request_region(ioaddr, LANCE_TOTAL_SIZE, chip_table[lance_version].name);
 
 #ifdef CONFIG_LANCE32
-        /* look if it's a PCI or VLB chip */
-        if (lance_version == PCNET_PCI || lance_version == PCNET_VLB || lance_version == PCNET_PCI_II) {
-	    extern void lance32_probe1 (struct device *dev, const char *chipname, int pci_irq_line);
+	/* look if it's a PCI or VLB chip */
+	if (lance_version == PCNET_PCI || lance_version == PCNET_VLB || lance_version == PCNET_PCI_II) {
+	    extern int lance32_probe1 (struct device *dev, const char *chipname, int pci_irq_line);
 	    
-	    lance32_probe1 (dev, chipname, pci_irq_line);
-	    return;
+	    return lance32_probe1 (dev, chipname, pci_irq_line);
 	}
 #endif    
 	/* Make certain the data structures used by the LANCE are aligned and DMAble. */
+		
 	lp = (struct lance_private *)(((unsigned long)kmalloc(sizeof(*lp)+7,
 										   GFP_DMA | GFP_KERNEL)+7) & ~7);
 	if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp);
@@ -484,9 +555,9 @@
 	outw(0x0000, ioaddr+LANCE_ADDR);
 	inw(ioaddr+LANCE_ADDR);
 
-	if (pci_irq_line) {
+	if (irq) {					/* Set iff PCI card. */
 		dev->dma = 4;			/* Native bus-master, no DMA channel needed. */
-		dev->irq = pci_irq_line;
+		dev->irq = irq;
 	} else if (hp_builtin) {
 		static const char dma_tbl[4] = {3, 5, 6, 0};
 		static const char irq_tbl[4] = {3, 4, 5, 9};
@@ -535,7 +606,7 @@
 			printk(", probed IRQ %d", dev->irq);
 		else {
 			printk(", failed to detect IRQ line.\n");
-			return;
+			return -ENODEV;
 		}
 
 		/* Check for the initialization done bit, 0x0100, which means
@@ -549,7 +620,7 @@
 	} else if (dev->dma) {
 		if (request_dma(dev->dma, chipname)) {
 			printk("DMA %d allocation failed.\n", dev->dma);
-			return;
+			return -ENODEV;
 		} else
 			printk(", assigned DMA %d.\n", dev->dma);
 	} else {			/* OK, we have to auto-DMA. */
@@ -584,7 +655,7 @@
 		}
 		if (i == 4) {			/* Failure: bail. */
 			printk("DMA detection failed.\n");
-			return;
+			return -ENODEV;
 		}
 	}
 
@@ -597,7 +668,7 @@
 		dev->irq = autoirq_report(4);
 		if (dev->irq == 0) {
 			printk("  Failed to detect the 7990 IRQ line.\n");
-			return;
+			return -ENODEV;
 		}
 		printk("  Auto-IRQ detected IRQ%d.\n", dev->irq);
 	}
@@ -606,7 +677,8 @@
 		/* Turn on auto-select of media (10baseT or BNC) so that the user
 		   can watch the LEDs even if the board isn't opened. */
 		outw(0x0002, ioaddr+LANCE_ADDR);
-		outw(0x0002, ioaddr+LANCE_BUS_IF);
+		/* Don't touch 10base2 power bit. */
+		outw(inw(ioaddr+LANCE_BUS_IF) | 0x0002, ioaddr+LANCE_BUS_IF);
 	}
 
 	if (lance_debug > 0  &&  did_version++ == 0)
@@ -619,7 +691,7 @@
 	dev->get_stats = lance_get_stats;
 	dev->set_multicast_list = set_multicast_list;
 
-	return;
+	return 0;
 }
 
 static int
@@ -638,15 +710,15 @@
 	int i;
 
 	if (dev->irq == 0 ||
-		request_irq(dev->irq, &lance_interrupt, 0, lp->name, NULL)) {
+		request_irq(dev->irq, &lance_interrupt, 0, lp->name, dev)) {
 		return -EAGAIN;
 	}
 
+	MOD_INC_USE_COUNT;
+
 	/* We used to allocate DMA here, but that was silly.
 	   DMA lines can't be shared!  We now permanently allocate them. */
 
-	irq2dev_map[dev->irq] = dev;
-
 	/* Reset the LANCE */
 	inw(ioaddr+LANCE_RESET);
 
@@ -663,8 +735,9 @@
 	if (chip_table[lp->chip_version].flags & LANCE_ENABLE_AUTOSELECT) {
 		/* This is 79C960-specific: Turn on auto-select of media (AUI, BNC). */
 		outw(0x0002, ioaddr+LANCE_ADDR);
-		outw(0x0002, ioaddr+LANCE_BUS_IF);
-	}
+		/* Only touch autoselect bit. */
+		outw(inw(ioaddr+LANCE_BUS_IF) | 0x0002, ioaddr+LANCE_BUS_IF);
+ 	}
 
 	if (lance_debug > 1)
 		printk("%s: lance_open() irq %d dma %d tx/rx rings %#x/%#x init %#x.\n",
@@ -745,12 +818,26 @@
 	lp->dirty_rx = lp->dirty_tx = 0;
 
 	for (i = 0; i < RX_RING_SIZE; i++) {
-		lp->rx_ring[i].base = (u32)virt_to_bus((char *)lp->rx_buffs + i*PKT_BUF_SZ) | 0x80000000;
+		struct sk_buff *skb;
+		void *rx_buff;
+
+		skb = alloc_skb(PKT_BUF_SZ, GFP_DMA | GFP_KERNEL);
+		lp->rx_skbuff[i] = skb;
+		if (skb) {
+			skb->dev = dev;
+			rx_buff = skb->tail;
+		} else
+			rx_buff = kmalloc(PKT_BUF_SZ, GFP_DMA | GFP_KERNEL);
+		if (rx_buff == NULL)
+			lp->rx_ring[i].base = 0;
+		else
+			lp->rx_ring[i].base = (u32)virt_to_bus(rx_buff) | 0x80000000;
 		lp->rx_ring[i].buf_length = -PKT_BUF_SZ;
 	}
 	/* The Tx buffer address is filled in as needed, but we do need to clear
 	   the upper ownership bit. */
 	for (i = 0; i < TX_RING_SIZE; i++) {
+		lp->tx_skbuff[i] = 0;
 		lp->tx_ring[i].base = 0;
 	}
 
@@ -816,18 +903,10 @@
 
 		dev->tbusy=0;
 		dev->trans_start = jiffies;
-		dev_kfree_skb(skb, FREE_WRITE);
-		return 0;
-	}
 
-	if (skb == NULL) {
-		dev_tint(dev);
 		return 0;
 	}
 
-	if (skb->len <= 0)
-		return 0;
-
 	if (lance_debug > 3) {
 		outw(0x0000, ioaddr+LANCE_ADDR);
 		printk("%s: lance_start_xmit() called, csr0 %4.4x.\n", dev->name,
@@ -904,7 +983,7 @@
 static void
 lance_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
-	struct device *dev = (struct device *)(irq2dev_map[irq]);
+	struct device *dev = (struct device *)dev_id;
 	struct lance_private *lp;
 	int csr0, ioaddr, boguscnt=10;
 	int must_restart;
@@ -1111,6 +1190,7 @@
 {
 	int ioaddr = dev->base_addr;
 	struct lance_private *lp = (struct lance_private *)dev->priv;
+	int i;
 
 	dev->start = 0;
 	dev->tbusy = 1;
@@ -1132,10 +1212,25 @@
 	if (dev->dma != 4)
 		disable_dma(dev->dma);
 
-	free_irq(dev->irq, NULL);
+	free_irq(dev->irq, dev);
 
-	irq2dev_map[dev->irq] = 0;
+	/* Free all the skbuffs in the Rx and Tx queues. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		struct sk_buff *skb = lp->rx_skbuff[i];
+		lp->rx_skbuff[i] = 0;
+		lp->rx_ring[i].base = 0;		/* Not owned by LANCE chip. */
+		if (skb) {
+			skb->free = 1;
+			dev_kfree_skb(skb, FREE_WRITE);
+		}
+	}
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		if (lp->tx_skbuff[i])
+			dev_kfree_skb(lp->tx_skbuff[i], FREE_WRITE);
+		lp->tx_skbuff[i] = 0;
+	}
 
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -1198,8 +1293,9 @@
 
 /*
  * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c lance.c"
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c lance.c"
  *  c-indent-level: 4
+ *  c-basic-offset: 4
  *  tab-width: 4
  * End:
  */

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov