[1262] in linux-net channel archive

home help back first fref pref prev next nref lref last post

Re: Network Drivers as Module

daemon@ATHENA.MIT.EDU (Paul Gortmaker)
Fri Oct 27 12:20:02 1995

From: Paul Gortmaker <gpg109@rsphy4.anu.edu.au>
To: gniibe@mri.co.jp (NIIBE Yutaka)
Date: Thu, 26 Oct 1995 18:34:11 +1000 (EST)
Cc: torvalds@cs.helsinki.fi (Linus Torvalds), linux-net@vger.rutgers.edu
In-Reply-To: <199510250452.NAA00227@megatherium.mri.co.jp> from "NIIBE Yutaka" at Oct 25, 95 01:52:47 pm

From "NIIBE Yutaka" Oct 25, 95 01:52:47 pm

> Currently (as of 1.3.35), most network drivers cannot handle two (or
> more) cards simulteneously as module.  That is, we don't use module
> for multi-homed host with same network cards.

First up, I didn't do all the net module stuff that took place around
1.3.17  so it isn't my fault ;-)  The ISA cards shouldn't have been
modules anyway, but since they are already, I guess it should be done 
right...  <sigh>

Unfortunately the two things that usually get overlooked when people
do device driver work is consideration for multiple card systems,
and safe probing techniques.

Anyway here is a fix for the wd80x3 driver. I can now do as follows:
------------------------------------------------------------------
ratbag:~# insmod wd.o io=0x240,0x280,0x300
wd.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)
eth0: WD80x3 at 0x240,  00 00 C0 8F 53 1C WD8003, IRQ 7, shared memory
at 0xde000-0xdffff.
eth1: WD80x3 at 0x280,  00 00 C0 72 4D 1C WD8003, IRQ 9, shared memory
at 0xd8000-0xd9fff.
eth2: WD80x3 at 0x300,  00 00 C0 4E DC 52 WD8003, IRQ 5, shared memory
at 0xe0000-0xe1fff.
ratbag:~#
------------------------------------------------------------------

If no io arg(s) is/are given, the user is warned against autoprobing
for these devices, and then a *single* autoprobe takes place. To use 
multiple devices per insmod, you *have* to specify the i/o bases.

I will do the same for the other 8390 cards, one at a time, when 
I get a free moment. Somebody else can do the non-8390 ones. If 
somebody uses the following patch as a pattern, it is then just an 
editing job. Also, I dscovered that none of the 8390 cards would have 
ever worked as modules with the 8390 core compiled in, due to missing 
ksyms. That is fixed as well. And I got rid of "loading device %s...",
as each device has its own initialization banner/message anyway.

Paul.


diff -ur linux-1336-oem/drivers/net/net_init.c linux/drivers/net/net_init.c
--- linux-1336-oem/drivers/net/net_init.c	Tue Oct 10 22:01:01 1995
+++ linux/drivers/net/net_init.c	Thu Oct 26 15:20:28 1995
@@ -247,7 +247,6 @@
 			for (i = 0; i < MAX_ETH_CARDS; ++i)
 				if (ethdev_index[i] == NULL) {
 					sprintf(dev->name, "eth%d", i);
-					printk("loading device '%s'...\n", dev->name);
 					ethdev_index[i] = dev;
 					break;
 				}
diff -ur linux-1336-oem/drivers/net/wd.c linux/drivers/net/wd.c
--- linux-1336-oem/drivers/net/wd.c	Tue Oct 10 22:03:45 1995
+++ linux/drivers/net/wd.c	Thu Oct 26 17:44:44 1995
@@ -15,6 +15,11 @@
 	This is a driver for WD8003 and WD8013 "compatible" ethercards.
 
 	Thanks to Russ Nelson (nelson@crnwyr.com) for loaning me a WD8013.
+
+	Changelog:
+
+	Paul Gortmaker	: multiple card support for module users
+
 */
 
 static const char *version =
@@ -110,6 +115,7 @@
 	int ancient = 0;			/* An old card without config registers. */
 	int word16 = 0;				/* 0 = 8 bit, 1 = 16 bit */
 	const char *model_name;
+	static unsigned version_printed = 0;
 
 	for (i = 0; i < 8; i++)
 		checksum += inb(ioaddr + 8 + i);
@@ -121,6 +127,9 @@
 	if (dev == NULL)
 		dev = init_etherdev(0, sizeof(struct ei_device));
 
+	if (ei_debug  &&  version_printed++ == 0)
+		printk(version);
+
 	printk("%s: WD80x3 at %#3x, ", dev->name, ioaddr);
 	for (i = 0; i < 6; i++)
 		printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i));
@@ -257,8 +266,6 @@
 
 	printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
 		   model_name, dev->irq, dev->mem_start, dev->mem_end-1);
-	if (ei_debug > 0)
-		printk(version);
 
 	ei_status.reset_8390 = &wd_reset_8390;
 	ei_status.block_input = &wd_block_input;
@@ -408,44 +415,61 @@
 
 
 #ifdef MODULE
+#define MAX_WD_MODS	4	/* Max number of wd modules allowed */
+#define NAMELEN		9	/* # of chars for storing dev->name */
 char kernel_version[] = UTS_RELEASE;
-static char devicename[9] = { 0, };
-static struct device dev_wd80x3 = {
-	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
-	0, 0, 0, 0,
-	0, 0,
-	0, 0, 0, NULL, wd_probe };
-
-int io = 0x300;
-int irq = 0;
-int mem = 0;
-
-int init_module(void)
+static char namelist[NAMELEN * MAX_WD_MODS] = { 0, };
+static struct device dev_wd80x3[MAX_WD_MODS] = {
+	{
+		NULL,		/* assign a chunk of namelist[] below */
+		0, 0, 0, 0,
+		0, 0,
+		0, 0, 0, NULL, NULL
+	},
+};
+
+static int io[MAX_WD_MODS] = { 0, };
+static int irq[MAX_WD_MODS]  = { 0, };
+static int mem[MAX_WD_MODS] = { 0, };
+
+/* This is set up so that only a single autoprobe takes place per call.
+ISA device autoprobes on a running machine are not recommended. */
+int
+init_module(void)
 {
-	if (io == 0)
-		printk("wd: You should not use auto-probing with insmod!\n");
-	dev_wd80x3.base_addr = io;
-	dev_wd80x3.irq       = irq;
-	dev_wd80x3.mem_start = mem;
-	if (register_netdev(&dev_wd80x3) != 0)
-		return -EIO;
+	int this_dev;
+
+	for (this_dev = 0; this_dev < MAX_WD_MODS; this_dev++) {
+		dev_wd80x3[this_dev].name = namelist+(NAMELEN*this_dev);
+		dev_wd80x3[this_dev].irq = irq[this_dev];
+		dev_wd80x3[this_dev].base_addr = io[this_dev];
+		dev_wd80x3[this_dev].mem_start = mem[this_dev];
+		dev_wd80x3[this_dev].init = wd_probe;
+		if (io[this_dev] == 0)  {
+			if (this_dev != 0) break; /* only autoprobe 1st one */
+			printk(KERN_NOTICE "wd.c: Presently autoprobing (not recommended) for a single card.\n");
+		}
+		if (register_netdev(&dev_wd80x3[this_dev]) != 0) {
+			printk(KERN_WARNING "modules: No wd80x3 card found (i/o = 0x%x).\n", io[this_dev]);
+			return -EIO;
+		}
+	}
+
 	return 0;
 }
 
 void
 cleanup_module(void)
 {
-	if (MOD_IN_USE)
-		printk("wd80x3: device busy, remove delayed\n");
-	else
-	{
-		int ioaddr = dev_wd80x3.base_addr - WD_NIC_OFFSET;
+	int this_dev;
 
-		unregister_netdev(&dev_wd80x3);
-
-		/* If we don't do this, we can't re-insmod it later. */
-		free_irq(dev_wd80x3.irq);
-		release_region(ioaddr, WD_IO_EXTENT);
+	for (this_dev = 0; this_dev < MAX_WD_MODS; this_dev++) {
+		if (dev_wd80x3[this_dev].priv != NULL) {
+			int ioaddr = dev_wd80x3[this_dev].base_addr - WD_NIC_OFFSET;
+			unregister_netdev(&dev_wd80x3[this_dev]);
+			free_irq(dev_wd80x3[this_dev].irq);
+			release_region(ioaddr, WD_IO_EXTENT);
+		}
 	}
 }
 #endif /* MODULE */
diff -ur linux-1336-oem/kernel/ksyms.c linux/kernel/ksyms.c
--- linux-1336-oem/kernel/ksyms.c	Fri Oct 20 21:33:10 1995
+++ linux/kernel/ksyms.c	Thu Oct 26 14:30:16 1995
@@ -78,6 +78,13 @@
 
 extern void *sys_call_table;
 
+#if	defined(CONFIG_ULTRA)	||	defined(CONFIG_WD80x3)		|| \
+	defined(CONFIG_EL2)	||	defined(CONFIG_NE2000)		|| \
+	defined(CONFIG_E2100)	||	defined(CONFIG_HPLAN_PLUS)	|| \
+	defined(CONFIG_HPLAN)	||	defined(CONFIG_AC3200)		
+#include "../drivers/net/8390.h"
+#endif
+
 #ifdef CONFIG_SCSI
 #include "../drivers/scsi/scsi.h"
 #include "../drivers/scsi/scsi_ioctl.h"
@@ -329,6 +336,17 @@
 	X(arp_send),
 #ifdef CONFIG_IP_FORWARD
 	X(ip_forward),
+#endif
+#if	defined(CONFIG_ULTRA)	||	defined(CONFIG_WD80x3)		|| \
+	defined(CONFIG_EL2)	||	defined(CONFIG_NE2000)		|| \
+	defined(CONFIG_E2100)	||	defined(CONFIG_HPLAN_PLUS)	|| \
+	defined(CONFIG_HPLAN)	||	defined(CONFIG_AC3200)		
+	/* If 8390 NIC support is built in, we will need these. */
+	X(ei_open),
+	X(ei_debug),
+	X(ei_interrupt),
+	X(ethdev_init),
+	X(NS8390_init),
 #endif
 #if defined(CONFIG_PPP) || defined(CONFIG_SLIP)
     	/* VJ header compression */
 }

home help back first fref pref prev next nref lref last post