patch-1.3.73 linux/drivers/net/eexpress.c

Next file: linux/drivers/net/eth82586.h
Previous file: linux/drivers/net/Space.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.72/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c
@@ -5,6 +5,10 @@
  * Modularized by Pauline Middelink <middelin@polyware.iaf.nl>
  * Changed to support io= irq= by Alan Cox <Alan.Cox@linux.org>
  * Reworked 1995 by John Sullivan <js10039@cam.ac.uk>
+ *
+ *  06mar96 Philip Blundell <pjb27@cam.ac.uk>
+ *     - move started, buffer sizes, and so on into private data area.
+ *     - fix module loading for multiple cards
  * 
  *  31jan96 Philip Blundell <pjb27@cam.ac.uk>
  *     - Tidy up
@@ -17,7 +21,6 @@
  *     - look at RAM size check
  *
  * ToDo:
- *   Move private globals into net_local structure
  *   Multicast/Promiscuous mode handling
  *   Put back debug reporting?
  *   More documentation
@@ -149,6 +152,9 @@
 
 #include "eth82586.h"
 
+#define PRIV(x)         ((struct net_local *)(x)->priv)
+#define EEXP_IO_EXTENT  16
+
 /*
  * Private data declarations
  */
@@ -164,6 +170,11 @@
 	unsigned short tx_tail;         /* previous tx buf to tx_head */
 	unsigned short tx_link;         /* last known-executing tx buf */
 	unsigned short last_tx_restart; /* set to tx_link when we restart the CU */
+	unsigned char started;
+	unsigned short rx_buf_start;
+	unsigned short rx_buf_end;
+	unsigned short num_tx_bufs;
+	unsigned short num_rx_bufs;
 };
 
 unsigned short start_code[] = {
@@ -208,8 +219,6 @@
 /* maps irq number to EtherExpress magic value */
 static char irqrmap[] = { 0,0,1,2,3,4,0,0,0,1,5,6,0,0,0,0 };
 
-static unsigned char started=0;
-
 /*
  * Prototypes for Linux interface
  */
@@ -294,10 +303,10 @@
 	if (irq2dev_map[irq] ||
 	      /* more consistent, surely? */
 	   ((irq2dev_map[irq]=dev),0) ||
-	     request_irq(irq,&eexp_irq,0,"EExpress",NULL)) 
+	     request_irq(irq,&eexp_irq,0,"eexpress",NULL)) 
 		return -EAGAIN;
 
-	request_region(ioaddr,16,"EExpress");
+	request_region(ioaddr, EEXP_IO_EXTENT, "eexpress");
 	dev->tbusy = 0;
 	dev->interrupt = 0;
 	eexp_hw_init586(dev);
@@ -318,7 +327,7 @@
 	dev->start = 0;
   
 	outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);
-	started = 0;
+	PRIV(dev)->started = 0;
 	outw(SCB_CUsuspend|SCB_RUsuspend,ioaddr+SCB_CMD);
 	outb(0,ioaddr+SIGNAL_CA);
 	free_irq(irq,NULL);
@@ -366,7 +375,7 @@
 		 * tbusy==0. If it happens too much, we probably ought
 		 * to think about unwedging ourselves...
 		 */
-		if (test_bit(0,(void *)&started)) 
+		if (test_bit(0,(void *)&PRIV(dev)->started)) 
 		{
 			if ((jiffies - dev->trans_start)>5) 
 			{
@@ -506,16 +515,16 @@
 	status = inw(ioaddr+SCB_STATUS);
 	ack_cmd = SCB_ack(status);
 
-	if (started==0 && SCB_complete(status)) 
+	if (PRIV(dev)->started==0 && SCB_complete(status)) 
 	{
 		if (SCB_CUstat(status)==2) 
 			while (SCB_CUstat(inw(ioaddr+SCB_STATUS))==2);
-		started=1;
+		PRIV(dev)->started=1;
 		outw(lp->tx_link,ioaddr+SCB_CBL);
-		outw(RX_BUF_START,ioaddr+SCB_RFA);
+		outw(PRIV(dev)->rx_buf_start,ioaddr+SCB_RFA);
 		ack_cmd |= SCB_CUstart | SCB_RUstart;
 	}
-	else if (started) 
+	else if (PRIV(dev)->started) 
 	{
 		unsigned short txstatus;
 		txstatus = eexp_hw_lasttxstat(dev);
@@ -526,17 +535,17 @@
 		eexp_hw_rx(dev);
 	}
 
-	if ((started&2)!=0 && SCB_RUstat(status)!=4) 
+	if ((PRIV(dev)->started&2)!=0 && SCB_RUstat(status)!=4) 
 	{
 		printk("%s: RU stopped status %04x, restarting...\n",
 			dev->name,status);
 		lp->stats.rx_errors++;
 		eexp_hw_rxinit(dev);
-		outw(RX_BUF_START,ioaddr+SCB_RFA);
+		outw(PRIV(dev)->rx_buf_start,ioaddr+SCB_RFA);
 		ack_cmd |= SCB_RUstart;
 	} 
-	else if (started==1 && SCB_RUstat(status)==4) 
-		started|=2;
+	else if (PRIV(dev)->started==1 && SCB_RUstat(status)==4) 
+		PRIV(dev)->started|=2;
 
 	outw(ack_cmd,ioaddr+SCB_CMD);
 	outb(0,ioaddr+SIGNAL_CA);
@@ -563,7 +572,7 @@
 	unsigned short old_wp = inw(ioaddr+WRITE_PTR);
 	unsigned short old_rp = inw(ioaddr+READ_PTR);
 	unsigned short rx_block = lp->rx_first;
-	unsigned short boguscount = NUM_RX_BUFS;
+	unsigned short boguscount = lp->num_rx_bufs;
 
 #if NET_DEBUG > 6
 	printk("%s: eexp_hw_rx()\n", dev->name);
@@ -665,7 +674,7 @@
 	outw(lp->tx_head,ioaddr);
 	dev->trans_start = jiffies;
 	lp->tx_tail = lp->tx_head;
-	if (lp->tx_head==TX_BUF_START+((NUM_TX_BUFS-1)*TX_BUF_SIZE)) 
+	if (lp->tx_head==TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE)) 
 		lp->tx_head = TX_BUF_START;
 	else 
 		lp->tx_head += TX_BUF_SIZE;
@@ -723,6 +732,9 @@
 
 	eexp_hw_ASICrst(dev);
 
+	dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+	memset(dev->priv, 0, sizeof(struct net_local));
+
 	{
 		unsigned short i586mso = 0x023e;
 		unsigned short old_wp,old_rp,old_a0,old_a1;
@@ -753,14 +765,15 @@
 			(a1_0 != 0x5a5a) || (a0_0 != 0x55aa)) 
 		{
 			printk("32k\n");
-			RX_BUF_END = 0x7ff6;
+			PRIV(dev)->rx_buf_end = 0x7ff6;
+			PRIV(dev)->num_tx_bufs = 4;
 		}
 		else
 		{
 			printk("64k\n");
-			NUM_TX_BUFS = 8;
-			RX_BUF_START = TX_BUF_START + (NUM_TX_BUFS*TX_BUF_SIZE);
-			RX_BUF_END = 0xfff6;
+			PRIV(dev)->num_tx_bufs = 8;
+			PRIV(dev)->rx_buf_start = TX_BUF_START + (PRIV(dev)->num_tx_bufs*TX_BUF_SIZE);
+			PRIV(dev)->rx_buf_end = 0xfff6;
 		}
 
 		outw(0x8000+i586mso,ioaddr+WRITE_PTR);
@@ -773,9 +786,6 @@
   
 	if (net_debug) 
 		printk(version);
-
-	dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
-	memset(dev->priv, 0, sizeof(struct net_local));
 	dev->open = eexp_open;
 	dev->stop = eexp_close;
 	dev->hard_start_xmit = eexp_xmit;
@@ -875,7 +885,7 @@
 			else
 				lp->stats.tx_packets++;
 		}
-		if (tx_block == TX_BUF_START+((NUM_TX_BUFS-1)*TX_BUF_SIZE)) 
+		if (tx_block == TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE)) 
 			lp->tx_reap = tx_block = TX_BUF_START;
 		else
 			lp->tx_reap = tx_block += TX_BUF_SIZE;
@@ -959,7 +969,7 @@
 	unsigned short tx_block = TX_BUF_START;
 	unsigned short curtbuf;
 
-	for ( curtbuf=0 ; curtbuf<NUM_TX_BUFS ; curtbuf++ ) 
+	for ( curtbuf=0 ; curtbuf<lp->num_tx_bufs ; curtbuf++ ) 
 	{
 		outw(tx_block,ioaddr+WRITE_PTR);
 		outw(0x0000,ioaddr);
@@ -979,7 +989,7 @@
 	lp->tx_reap = TX_BUF_START;
 	lp->tx_tail = tx_block - TX_BUF_SIZE;
 	lp->tx_link = lp->tx_tail + 0x08;
-	RX_BUF_START = tx_block;
+	lp->rx_buf_start = tx_block;
 	outw(old_wp,ioaddr+WRITE_PTR);
 }
 
@@ -1004,13 +1014,13 @@
 	struct net_local *lp = (struct net_local *)dev->priv;
 	unsigned short ioaddr = dev->base_addr;
 	unsigned short old_wp = inw(ioaddr+WRITE_PTR);
-	unsigned short rx_block = RX_BUF_START;
+	unsigned short rx_block = lp->rx_buf_start;
 
-	NUM_RX_BUFS = 0;
+	lp->num_rx_bufs = 0;
 	lp->rx_first = rx_block;
 	do 
 	{
-		NUM_RX_BUFS++;
+		lp->num_rx_bufs++;
 		outw(rx_block,ioaddr+WRITE_PTR);
 		outw(0x0000,ioaddr);
 		outw(0x0000,ioaddr);
@@ -1024,7 +1034,7 @@
 		outw(0x8000|(RX_BUF_SIZE-0x20),ioaddr);
 		lp->rx_last = rx_block;
 		rx_block += RX_BUF_SIZE;
-	} while (rx_block <= RX_BUF_END-RX_BUF_SIZE);
+	} while (rx_block <= lp->rx_buf_end-RX_BUF_SIZE);
 
 	outw(lp->rx_last+4,ioaddr+WRITE_PTR);
 	outw(lp->rx_first,ioaddr);
@@ -1072,7 +1082,7 @@
 	struct net_local *lp = (struct net_local *)dev->priv;
 	unsigned short ioaddr = dev->base_addr;
 
-	started = 0;
+	PRIV(dev)->started = 0;
 	set_loopback;
 
 	outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
@@ -1082,11 +1092,11 @@
 		unsigned short wcnt;
 		wcnt = 0;
 		outw(0,ioaddr+WRITE_PTR);
-		while ((wcnt+=2) != RX_BUF_END+12) 
+		while ((wcnt+=2) != lp->rx_buf_end+12) 
 			outw(0,ioaddr);
 	} 
   
-	outw(RX_BUF_END,ioaddr+WRITE_PTR);
+	outw(lp->rx_buf_end,ioaddr+WRITE_PTR);
 	outsw(ioaddr, start_code, sizeof(start_code)>>1);
 	outw(CONF_HW_ADDR,ioaddr+WRITE_PTR);
 	outsw(ioaddr,dev->dev_addr,3);
@@ -1150,7 +1160,7 @@
 	outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);
 	clear_loopback;
 	lp->init_time = jiffies;
-	if (started) 
+	if (PRIV(dev)->started) 
 		printk("%s: Uh? We haven't started yet\n",dev->name);
 	return;
 }
@@ -1170,8 +1180,8 @@
 
 	set_loopback;  /* yet more paranoia - since we're resetting the ASIC
 			* that controls this function, how can it possibly work?
-                        */
-	started = 0;
+			*/
+	PRIV(dev)->started = 0;
 	outb(ASIC_RST|i586_RST,ioaddr+EEPROM_Ctrl);
 	while (succount<20) 
 	{
@@ -1201,30 +1211,61 @@
 /*
  * MODULE stuff
  */
-
 #ifdef MODULE
 
-static struct device dev_eexpress = 
+#define EEXP_MAX_CARDS     4    /* max number of cards to support */
+#define NAMELEN            8    /* max length of dev->name (inc null) */
+
+static char namelist[NAMELEN * EEXP_MAX_CARDS] = { 0, };
+
+static struct device dev_eexp[EEXP_MAX_CARDS] = 
 {
-	"EExpress", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, express_probe 
+        NULL,         /* will allocate dynamically */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, express_probe 
 };
 
-int irq = 0;
-int io = 0;
+int irq[MAX_EEXP_CARDS] = {0, };
+int io[MAX_EEXP_CARDS] = {0, };
 
+/* Ideally the user would give us io=, irq= for every card.  If any parameters
+ * are specified, we verify and then use them.  If no parameters are given, we
+ * autoprobe for one card only.
+ */
 int init_module(void)
 {
-	dev_eexpress.base_addr = io;
-	dev_eexpress.irq = irq;
-	if (register_netdev(&dev_eexpress) != 0) 
-		return -EIO;
+	int this_dev, found = 0;
+
+	for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) {
+		struct device *dev = &dev_eexp[this_dev];
+		dev->name = namelist + (NAMELEN*this_dev);
+		dev->irq = irq[this_dev];
+		dev->base_addr = io[this_dev];
+		if (io[this_dev] == 0) {
+			if (this_dev) break;
+			printk(KERN_NOTICE "eexpress.c: Module autoprobe not recommended, give io=xx.\n");
+		}
+		if (register_netdev(dev) != 0) {
+			printk(KERN_WARNING "eexpress.c: Failed to register card at 0x%x.\n", io[this_dev]);
+			if (found != 0) return 0;
+			return -ENXIO;
+		}
+		found++;
+	}
 	return 0;
 }
 
 void cleanup_module(void)
 {
-	unregister_netdev(&dev_eexpress);
-	kfree_s(dev_eexpress.priv,sizeof(struct net_local));
-	dev_eexpress.priv = NULL;
+	int this_dev;
+        
+	for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) {
+		struct device *dev = &dev_eexp[this_dev];
+		if (dev->priv != NULL) {
+			kfree_s(dev->priv. sizeof(struct net_local));
+			dev->priv = NULL;
+			release_region(dev->base_addr, EEXP_IO_EXTENT);
+			unregister_netdev(dev);
+		}
+	}
 }
 #endif

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this