patch-2.4.2 linux/drivers/net/ewrk3.c

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

diff -u --recursive --new-file v2.4.1/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c
@@ -5,7 +5,7 @@
    Copyright 1994 Digital Equipment Corporation.
 
    This software may be used and distributed according to the terms of
-   the GNU Public License, incorporated herein by reference.
+   the GNU General Public License, incorporated herein by reference.
 
    This driver is written for the Digital Equipment Corporation series
    of EtherWORKS ethernet cards:
@@ -136,9 +136,6 @@
    =========================================================================
  */
 
-static const char *version = "ewrk3.c:v0.43 96/8/16 davies@maniac.ultranet.com\n";
-
-#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
@@ -147,7 +144,7 @@
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/init.h>
@@ -167,6 +164,9 @@
 
 #include "ewrk3.h"
 
+static const char version[] __initdata =
+"ewrk3.c:v0.43a 2001/02/04 davies@maniac.ultranet.com\n";
+
 #ifdef EWRK3_DEBUG
 static int ewrk3_debug = EWRK3_DEBUG;
 #else
@@ -273,9 +273,9 @@
 	u_char mPage;		/* Maximum 2kB Page number */
 	u_char lemac;		/* Chip rev. level */
 	u_char hard_strapped;	/* Don't allow a full open */
-	u_char lock;		/* Lock the page register */
 	u_char txc;		/* Transmit cut through */
 	u_char *mctbl;		/* Pointer to the multicast table */
+	spinlock_t hw_lock;
 };
 
 /*
@@ -530,6 +530,7 @@
 							lp->shmem_length = shmem_length;
 							lp->lemac = lemac;
 							lp->hard_strapped = hard_strapped;
+							spin_lock_init(&lp->hw_lock);
 
 							lp->mPage = 64;
 							if (cmr & CMR_DRAM)
@@ -715,8 +716,6 @@
 		outb(page, EWRK3_FMQ);	/* to the Free Memory Queue */
 	}
 
-	lp->lock = 0;		/* Ensure there are no locks */
-
 	START_EWRK3;		/* Enable the TX and/or RX */
 }
 
@@ -760,111 +759,118 @@
 /*
    ** Writes a socket buffer to the free page queue
  */
-static int ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev)
+static int ewrk3_queue_pkt (struct sk_buff *skb, struct net_device *dev)
 {
 	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
 	u_long iobase = dev->base_addr;
-	int status = 0;
+	u_long buf = 0;
 	u_char icr;
+	u_char page;
 
-	netif_stop_queue(dev);
-#ifdef CONFIG_SMP
-#error "This needs spinlocks"
-#endif
-	DISABLE_IRQs;	/* So that the page # remains correct */
+	spin_lock_irq (&lp->hw_lock);
+	DISABLE_IRQs;
+
+	/* if no resources available, exit, request packet be queued */
+	if (inb (EWRK3_FMQC) == 0) {
+		printk (KERN_WARNING "%s: ewrk3_queue_pkt(): No free resources...\n",
+			dev->name);
+		printk (KERN_WARNING "%s: ewrk3_queue_pkt(): CSR: %02x ICR: %02x FMQC: %02x\n",
+			dev->name, inb (EWRK3_CSR), inb (EWRK3_ICR),
+			inb (EWRK3_FMQC));
+		goto err_out;
+	}
 
 	/*
-	   ** Get a free page from the FMQ when resources are available
+	 ** Get a free page from the FMQ
 	 */
-	if (inb(EWRK3_FMQC) > 0) 
-	{
-		u_long buf = 0;
-		u_char page;
+	if ((page = inb (EWRK3_FMQ)) >= lp->mPage) {
+		printk ("ewrk3_queue_pkt(): Invalid free memory page (%d).\n",
+		     (u_char) page);
+		goto err_out;
+	}
 
-		if ((page = inb(EWRK3_FMQ)) < lp->mPage) {
-			/*
-			   ** Set up shared memory window and pointer into the window
-			 */
-			while (test_and_set_bit(0, (void *) &lp->lock) != 0);	/* Wait for lock to free */
-			if (lp->shmem_length == IO_ONLY) {
-				outb(page, EWRK3_IOPR);
-			} else if (lp->shmem_length == SHMEM_2K) {
-				buf = lp->shmem_base;
-				outb(page, EWRK3_MPR);
-			} else if (lp->shmem_length == SHMEM_32K) {
-				buf = ((((short) page << 11) & 0x7800) + lp->shmem_base);
-				outb((page >> 4), EWRK3_MPR);
-			} else if (lp->shmem_length == SHMEM_64K) {
-				buf = ((((short) page << 11) & 0xf800) + lp->shmem_base);
-				outb((page >> 5), EWRK3_MPR);
-			} else {
-				status = -1;
-				printk(KERN_ERR "%s: Oops - your private data area is hosed!\n", dev->name);
-			}
 
-			if (!status) {
-				/*
-				   ** Set up the buffer control structures and copy the data from
-				   ** the socket buffer to the shared memory .
-				 */
-					if (lp->shmem_length == IO_ONLY) {
-					int i;
-					u_char *p = skb->data;
-						outb((char) (TCR_QMODE | TCR_PAD | TCR_IFC), EWRK3_DATA);
-					outb((char) (skb->len & 0xff), EWRK3_DATA);
-					outb((char) ((skb->len >> 8) & 0xff), EWRK3_DATA);
-					outb((char) 0x04, EWRK3_DATA);
-					for (i = 0; i < skb->len; i++) {
-						outb(*p++, EWRK3_DATA);
-					}
-					outb(page, EWRK3_TQ);	/* Start sending pkt */
-				} else {
-					writeb((char) (TCR_QMODE | TCR_PAD | TCR_IFC), (char *) buf);	/* ctrl byte */
-					buf += 1;
-					writeb((char) (skb->len & 0xff), (char *) buf);		/* length (16 bit xfer) */
-					buf += 1;
-					if (lp->txc) {
-						writeb((char) (((skb->len >> 8) & 0xff) | XCT), (char *) buf);
-						buf += 1;
-						writeb(0x04, (char *) buf);	/* index byte */
-						buf += 1;
-						writeb(0x00, (char *) (buf + skb->len));	/* Write the XCT flag */
-						isa_memcpy_toio(buf, skb->data, PRELOAD);	/* Write PRELOAD bytes */
-						outb(page, EWRK3_TQ);	/* Start sending pkt */
-						isa_memcpy_toio(buf + PRELOAD, skb->data + PRELOAD, skb->len - PRELOAD);
-						writeb(0xff, (char *) (buf + skb->len));	/* Write the XCT flag */
-					} else {
-						writeb((char) ((skb->len >> 8) & 0xff), (char *) buf);
-						buf += 1;
-						writeb(0x04, (char *) buf);	/* index byte */
-						buf += 1;
-						isa_memcpy_toio(buf, skb->data, skb->len);		/* Write data bytes */
-						outb(page, EWRK3_TQ);	/* Start sending pkt */
-					}
-				}
+	/*
+	 ** Set up shared memory window and pointer into the window
+	 */
+	if (lp->shmem_length == IO_ONLY) {
+		outb (page, EWRK3_IOPR);
+	} else if (lp->shmem_length == SHMEM_2K) {
+		buf = lp->shmem_base;
+		outb (page, EWRK3_MPR);
+	} else if (lp->shmem_length == SHMEM_32K) {
+		buf = ((((short) page << 11) & 0x7800) + lp->shmem_base);
+		outb ((page >> 4), EWRK3_MPR);
+	} else if (lp->shmem_length == SHMEM_64K) {
+		buf = ((((short) page << 11) & 0xf800) + lp->shmem_base);
+		outb ((page >> 5), EWRK3_MPR);
+	} else {
+		printk (KERN_ERR "%s: Oops - your private data area is hosed!\n",
+			dev->name);
+		BUG ();
+	}
 
-				lp->stats.tx_bytes += skb->len;
-				dev->trans_start = jiffies;
-				dev_kfree_skb(skb);
-			} else {	/* return unused page to the free memory queue */
-				outb(page, EWRK3_FMQ);
-			}
-			lp->lock = 0;	/* unlock the page register */
-		} else {
-			printk("ewrk3_queue_pkt(): Invalid free memory page (%d).\n",
-			       (u_char) page);
+	/*
+	 ** Set up the buffer control structures and copy the data from
+	 ** the socket buffer to the shared memory .
+	 */
+	if (lp->shmem_length == IO_ONLY) {
+		int i;
+		u_char *p = skb->data;
+		outb ((char) (TCR_QMODE | TCR_PAD | TCR_IFC), EWRK3_DATA);
+		outb ((char) (skb->len & 0xff), EWRK3_DATA);
+		outb ((char) ((skb->len >> 8) & 0xff), EWRK3_DATA);
+		outb ((char) 0x04, EWRK3_DATA);
+		for (i = 0; i < skb->len; i++) {
+			outb (*p++, EWRK3_DATA);
 		}
+		outb (page, EWRK3_TQ);	/* Start sending pkt */
 	} else {
-		printk(KERN_WARNING "%s: ewrk3_queue_pkt(): No free resources...\n", dev->name);
-		printk(KERN_WARNING "%s: ewrk3_queue_pkt(): CSR: %02x ICR: %02x FMQC: %02x\n", dev->name, inb(EWRK3_CSR), inb(EWRK3_ICR), inb(EWRK3_FMQC));
+		isa_writeb ((char) (TCR_QMODE | TCR_PAD | TCR_IFC), buf);	/* ctrl byte */
+		buf += 1;
+		isa_writeb ((char) (skb->len & 0xff), buf);	/* length (16 bit xfer) */
+		buf += 1;
+		if (lp->txc) {
+			isa_writeb ((char)
+				    (((skb->len >> 8) & 0xff) | XCT), buf);
+			buf += 1;
+			isa_writeb (0x04, buf);	/* index byte */
+			buf += 1;
+			isa_writeb (0x00, (buf + skb->len));	/* Write the XCT flag */
+			isa_memcpy_toio (buf, skb->data, PRELOAD);	/* Write PRELOAD bytes */
+			outb (page, EWRK3_TQ);	/* Start sending pkt */
+			isa_memcpy_toio (buf + PRELOAD,
+					 skb->data + PRELOAD,
+					 skb->len - PRELOAD);
+			isa_writeb (0xff, (buf + skb->len));	/* Write the XCT flag */
+		} else {
+			isa_writeb ((char)
+				    ((skb->len >> 8) & 0xff), buf);
+			buf += 1;
+			isa_writeb (0x04, buf);	/* index byte */
+			buf += 1;
+			isa_memcpy_toio (buf, skb->data, skb->len);	/* Write data bytes */
+			outb (page, EWRK3_TQ);	/* Start sending pkt */
+		}
 	}
 
-	/* Check for free resources: clear 'tbusy' if there are some */
-	if (inb(EWRK3_FMQC) > 0) {
-		netif_wake_queue(dev);
-	}
 	ENABLE_IRQs;
-	return status;
+	spin_unlock_irq (&lp->hw_lock);
+
+	lp->stats.tx_bytes += skb->len;
+	dev->trans_start = jiffies;
+	dev_kfree_skb (skb);
+
+	/* Check for free resources: stop Tx queue if there are none */
+	if (inb (EWRK3_FMQC) == 0)
+		netif_stop_queue (dev);
+
+	return 0;
+
+err_out:
+	ENABLE_IRQs;
+	spin_unlock_irq (&lp->hw_lock);
+	return 1;
 }
 
 /*
@@ -886,6 +892,7 @@
 	/*
 	 ** Mask the EWRK3 board interrupts and turn on the LED
 	 */
+	spin_lock(&lp->hw_lock);
 	DISABLE_IRQs;
 
 	cr = inb(EWRK3_CR);
@@ -917,6 +924,7 @@
 	cr &= ~CR_LED;
 	outb(cr, EWRK3_CR);
 	ENABLE_IRQs;
+	spin_unlock(&lp->hw_lock);
 }
 
 static int ewrk3_rx(struct net_device *dev)
@@ -924,23 +932,12 @@
 	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
 	u_long iobase = dev->base_addr;
 	int i, status = 0;
-	u_char page, tmpPage = 0, tmpLock = 0;
+	u_char page;
 	u_long buf = 0;
 
 	while (inb(EWRK3_RQC) && !status) {	/* Whilst there's incoming data */
 		if ((page = inb(EWRK3_RQ)) < lp->mPage) {	/* Get next entry's buffer page */
 			/*
-			   ** Preempt any process using the current page register. Check for
-			   ** an existing lock to reduce time taken in I/O transactions.
-			 */
-			if ((tmpLock = test_and_set_bit(0, (void *) &lp->lock)) == 1) {		/* Assert lock */
-				if (lp->shmem_length == IO_ONLY) {	/* Get existing page */
-					tmpPage = inb(EWRK3_IOPR);
-				} else {
-					tmpPage = inb(EWRK3_MPR);
-				}
-			}
-			/*
 			   ** Set up shared memory window and pointer into the window
 			 */
 			if (lp->shmem_length == IO_ONLY) {
@@ -968,9 +965,9 @@
 					pkt_len = inb(EWRK3_DATA);
 					pkt_len |= ((u_short) inb(EWRK3_DATA) << 8);
 				} else {
-					rx_status = readb(buf);
+					rx_status = isa_readb(buf);
 					buf += 1;
-					pkt_len = readw(buf);
+					pkt_len = isa_readw(buf);
 					buf += 3;
 				}
 
@@ -1010,6 +1007,7 @@
 						/*
 						   ** Update stats
 						 */
+						dev->last_rx = jiffies;
 						lp->stats.rx_packets++;
 						lp->stats.rx_bytes += pkt_len;
 						for (i = 1; i < EWRK3_PKT_STAT_SZ - 1; i++) {
@@ -1044,15 +1042,6 @@
 			   ** Return the received buffer to the free memory queue
 			 */
 			outb(page, EWRK3_FMQ);
-
-			if (tmpLock) {	/* If a lock was preempted */
-				if (lp->shmem_length == IO_ONLY) {	/* Replace old page */
-					outb(tmpPage, EWRK3_IOPR);
-				} else {
-					outb(tmpPage, EWRK3_MPR);
-				}
-			}
-			lp->lock = 0;	/* Unlock the page register */
 		} else {
 			printk("ewrk3_rx(): Illegal page number, page %d\n", page);
 			printk("ewrk3_rx(): CSR: %02x ICR: %02x FMQC: %02x\n", inb(EWRK3_CSR), inb(EWRK3_ICR), inb(EWRK3_FMQC));
@@ -1190,7 +1179,7 @@
 	u16 hashcode;
 	s32 crc, poly = CRC_POLYNOMIAL_LE;
 
-	while (test_and_set_bit(0, (void *) &lp->lock) != 0);	/* Wait for lock to free */
+	spin_lock_irq(&lp->hw_lock);
 
 	if (lp->shmem_length == IO_ONLY) {
 		outb(0, EWRK3_IOPR);
@@ -1204,7 +1193,7 @@
 			if (lp->shmem_length == IO_ONLY) {
 				outb(0xff, EWRK3_DATA);
 			} else {	/* memset didn't work here */
-				writew(0xffff, p);
+				isa_writew(0xffff, (int) p);
 				p++;
 				i++;
 			}
@@ -1221,8 +1210,8 @@
 				outb(0x00, EWRK3_DATA);
 			}
 		} else {
-			memset_io(lp->mctbl, 0, (HASH_TABLE_LEN >> 3));
-			writeb(0x80, (char *) (lp->mctbl + (HASH_TABLE_LEN >> 4) - 1));
+			isa_memset_io((int) lp->mctbl, 0, (HASH_TABLE_LEN >> 3));
+			isa_writeb(0x80, (int) (lp->mctbl + (HASH_TABLE_LEN >> 4) - 1));
 		}
 
 		/* Update table */
@@ -1251,15 +1240,13 @@
 					outw((short) ((long) lp->mctbl) + byte, EWRK3_PIR1);
 					outb(tmp, EWRK3_DATA);
 				} else {
-					writeb(readb(lp->mctbl + byte) | bit, lp->mctbl + byte);
+					isa_writeb(isa_readb((int)(lp->mctbl + byte)) | bit, (int)(lp->mctbl + byte));
 				}
 			}
 		}
 	}
 
-	lp->lock = 0;		/* Unlock the page register */
-
-	return;
+	spin_unlock_irq(&lp->hw_lock);
 }
 
 /*
@@ -1709,24 +1696,22 @@
 
 		break;
 	case EWRK3_GET_MCA:	/* Get the multicast address table */
-			while (test_and_set_bit(0, (void *) &lp->lock) != 0);	/* Wait for lock to free */
-			if (lp->shmem_length == IO_ONLY) {
-				outb(0, EWRK3_IOPR);
-				outw(PAGE0_HTE, EWRK3_PIR1);
-				for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) {
-					tmp.addr[i] = inb(EWRK3_DATA);
-				}
-			} else {
-				outb(0, EWRK3_MPR);
-				isa_memcpy_fromio(tmp.addr, lp->shmem_base + PAGE0_HTE, (HASH_TABLE_LEN >> 3));
-			}
-			ioc->len = (HASH_TABLE_LEN >> 3);
-			if (copy_to_user(ioc->data, tmp.addr, ioc->len)) {
-				status = -EFAULT;
-				break;
+		spin_lock_irq(&lp->hw_lock);
+		if (lp->shmem_length == IO_ONLY) {
+			outb(0, EWRK3_IOPR);
+			outw(PAGE0_HTE, EWRK3_PIR1);
+			for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) {
+				tmp.addr[i] = inb(EWRK3_DATA);
 			}
+		} else {
+			outb(0, EWRK3_MPR);
+			isa_memcpy_fromio(tmp.addr, lp->shmem_base + PAGE0_HTE, (HASH_TABLE_LEN >> 3));
+		}
+		spin_unlock_irq(&lp->hw_lock);
 
-		lp->lock = 0;	/* Unlock the page register */
+		ioc->len = (HASH_TABLE_LEN >> 3);
+		if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+			status = -EFAULT;
 
 		break;
 	case EWRK3_SET_MCA:	/* Set a multicast address */

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