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
- Lines: 437
- Date:
Fri Feb 16 16:06:17 2001
- Orig file:
v2.4.1/linux/drivers/net/ewrk3.c
- Orig date:
Mon Dec 11 13:38:29 2000
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)