patch-2.2.0-pre2 linux/drivers/net/de4x5.c
Next file: linux/drivers/net/de4x5.h
Previous file: linux/drivers/net/bmac.c
Back to the patch index
Back to the overall index
- Lines: 378
- Date:
Wed Dec 30 15:09:18 1998
- Orig file:
v2.2.0-pre1/linux/drivers/net/de4x5.c
- Orig date:
Sun Nov 8 14:03:00 1998
diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
@@ -415,11 +415,12 @@
alignment for Alpha's and avoid their unaligned
access traps. This flag is merely for log messages:
should do something more definitive though...
+ 0.543 30-Dec-98 Add SMP spin locking.
=========================================================================
*/
-static const char *version = "de4x5.c:V0.542 1998/9/15 davies@maniac.ultranet.com\n";
+static const char *version = "de4x5.c:V0.543 1998/12/30 davies@maniac.ultranet.com\n";
#include <linux/config.h>
#include <linux/module.h>
@@ -443,6 +444,7 @@
#include <asm/byteorder.h>
#include <asm/unaligned.h>
#include <asm/uaccess.h>
+#include <asm/spinlock.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -508,11 +510,11 @@
** recognised by this driver.
*/
static struct phy_table phy_info[] = {
- {0, NATIONAL_TX, 1, {0x19, 0x40, 0x00}}, /* National TX */
- {1, BROADCOM_T4, 1, {0x10, 0x02, 0x02}}, /* Broadcom T4 */
- {0, SEEQ_T4 , 1, {0x12, 0x10, 0x10}}, /* SEEQ T4 */
- {0, CYPRESS_T4 , 1, {0x05, 0x20, 0x20}}, /* Cypress T4 */
- {0, 0x7810 , 1, {0x05, 0x0380, 0x0380}} /* Level One? */
+ {0, NATIONAL_TX, 1, {0x19, 0x40, 0x00}}, /* National TX */
+ {1, BROADCOM_T4, 1, {0x10, 0x02, 0x02}}, /* Broadcom T4 */
+ {0, SEEQ_T4 , 1, {0x12, 0x10, 0x10}}, /* SEEQ T4 */
+ {0, CYPRESS_T4 , 1, {0x05, 0x20, 0x20}}, /* Cypress T4 */
+ {0, 0x7810 , 1, {0x14, 0x0800, 0x0800}} /* Level One LTX970 */
};
/*
@@ -759,7 +761,8 @@
int tx_new, tx_old; /* TX descriptor ring pointers */
char setup_frame[SETUP_FRAME_LEN]; /* Holds MCA and PA info. */
char frame[64]; /* Min sized packet for loopback*/
- struct net_device_stats stats; /* Public stats */
+ spinlock_t lock; /* Adapter specific spinlock */
+ struct net_device_stats stats; /* Public stats */
struct {
u_int bins[DE4X5_PKT_STAT_SZ]; /* Private stats counters */
u_int unicast;
@@ -1192,6 +1195,7 @@
lp->timeout = -1;
lp->useSROM = useSROM;
memcpy((char *)&lp->srom,(char *)&bus.srom,sizeof(struct de4x5_srom));
+ lp->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
de4x5_parse_params(dev);
/*
@@ -1345,7 +1349,7 @@
** Re-initialize the DE4X5...
*/
status = de4x5_init(dev);
-
+ lp->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
lp->state = OPEN;
de4x5_dbg_open(dev);
@@ -1497,6 +1501,7 @@
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
u_long iobase = dev->base_addr;
int status = 0;
+ u_long flags = 0;
test_and_set_bit(0, (void*)&dev->tbusy); /* Stop send re-tries */
if (lp->tx_enable == NO) { /* Cannot send for now */
@@ -1508,9 +1513,9 @@
** interrupts are lost by delayed descriptor status updates relative to
** the irq assertion, especially with a busy PCI bus.
*/
- cli();
+ spin_lock_irqsave(&lp->lock, flags);
de4x5_tx(dev);
- sti();
+ spin_unlock_irqrestore(&lp->lock, flags);
/* Test if cache is already locked - requeue skb if so */
if (test_and_set_bit(0, (void *)&lp->cache.lock) && !lp->interrupt)
@@ -1534,7 +1539,7 @@
}
while (skb && !dev->tbusy && !lp->tx_skb[lp->tx_new]) {
- cli();
+ spin_lock_irqsave(&lp->lock, flags);
test_and_set_bit(0, (void*)&dev->tbusy);
load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
lp->stats.tx_bytes += skb->len;
@@ -1547,7 +1552,7 @@
dev->tbusy = 0; /* Another pkt may be queued */
}
skb = de4x5_get_cache(dev);
- sti();
+ spin_unlock_irqrestore(&lp->lock, flags);
}
if (skb) de4x5_putb_cache(dev, skb);
}
@@ -1581,6 +1586,7 @@
return;
}
lp = (struct de4x5_private *)dev->priv;
+ spin_lock(&lp->lock);
iobase = dev->base_addr;
DISABLE_IRQs; /* Ensure non re-entrancy */
@@ -1628,6 +1634,7 @@
lp->interrupt = UNMASK_INTERRUPTS;
ENABLE_IRQs;
+ spin_unlock(&lp->lock);
return;
}
@@ -2069,7 +2076,9 @@
irq = inb(EISA_REG0);
irq = de4x5_irq[(irq >> 1) & 0x03];
- if (is_DC2114x) device |= (cfrv & CFRV_RN);
+ if (is_DC2114x) {
+ device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
+ }
lp->chipset = device;
/* Write the PCI Configuration Registers */
@@ -2165,7 +2174,9 @@
lp->bus_num = pb;
/* Set the chipset information */
- if (is_DC2114x) device |= (cfrv & CFRV_RN);
+ if (is_DC2114x) {
+ device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
+ }
lp->chipset = device;
/* Get the board I/O address (64 bits on sparc64) */
@@ -2249,7 +2260,9 @@
lp->bus_num = pb;
/* Set the chipset information */
- if (is_DC2114x) device |= (cfrv & CFRV_RN);
+ if (is_DC2114x) {
+ device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
+ }
lp->chipset = device;
/* Get the board I/O address (64 bits on sparc64) */
@@ -3223,18 +3236,19 @@
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
u_long iobase = dev->base_addr;
+ u_long flags = 0;
if (lp->media != lp->c_media) {
de4x5_dbg_media(dev);
lp->c_media = lp->media; /* Stop scrolling media messages */
}
- cli();
+ spin_lock_irqsave(&lp->lock, flags);
de4x5_rst_desc_ring(dev);
de4x5_setup_intr(dev);
lp->tx_enable = YES;
dev->tbusy = 0;
- sti();
+ spin_unlock_irqrestore(&lp->lock, flags);
outl(POLL_DEMAND, DE4X5_TPD);
mark_bh(NET_BH);
@@ -5524,116 +5538,90 @@
u16 sval[72];
u32 lval[36];
} tmp;
+ u_long flags = 0;
switch(ioc->cmd) {
case DE4X5_GET_HWADDR: /* Get the hardware address */
ioc->len = ETH_ALEN;
- status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len);
- if (status)
- break;
+ if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT;
for (i=0; i<ETH_ALEN; i++) {
tmp.addr[i] = dev->dev_addr[i];
}
copy_to_user(ioc->data, tmp.addr, ioc->len);
-
break;
+
case DE4X5_SET_HWADDR: /* Set the hardware address */
- status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN);
- if (status)
- break;
- status = -EPERM;
- if (!capable(CAP_NET_ADMIN))
- break;
- status = 0;
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ if (verify_area(VERIFY_READ, ioc->data, ETH_ALEN)) return -EFAULT;
copy_from_user(tmp.addr, ioc->data, ETH_ALEN);
for (i=0; i<ETH_ALEN; i++) {
dev->dev_addr[i] = tmp.addr[i];
}
build_setup_frame(dev, PHYS_ADDR_ONLY);
/* Set up the descriptor and give ownership to the card */
- while (test_and_set_bit(0, (void *)&dev->tbusy) != 0);
+ while (test_and_set_bit(0, (void *)&dev->tbusy) != 0) barrier();
load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET |
SETUP_FRAME_LEN, NULL);
lp->tx_new = (++lp->tx_new) % lp->txRingSize;
outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */
dev->tbusy = 0; /* Unlock the TX ring */
-
break;
+
case DE4X5_SET_PROM: /* Set Promiscuous Mode */
- if (capable(CAP_NET_ADMIN)) {
- omr = inl(DE4X5_OMR);
- omr |= OMR_PR;
- outl(omr, DE4X5_OMR);
- dev->flags |= IFF_PROMISC;
- } else {
- status = -EPERM;
- }
-
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ omr = inl(DE4X5_OMR);
+ omr |= OMR_PR;
+ outl(omr, DE4X5_OMR);
+ dev->flags |= IFF_PROMISC;
break;
+
case DE4X5_CLR_PROM: /* Clear Promiscuous Mode */
- if (capable(CAP_NET_ADMIN)) {
- omr = inl(DE4X5_OMR);
- omr &= ~OMR_PR;
- outb(omr, DE4X5_OMR);
- dev->flags &= ~IFF_PROMISC;
- } else {
- status = -EPERM;
- }
-
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ omr = inl(DE4X5_OMR);
+ omr &= ~OMR_PR;
+ outb(omr, DE4X5_OMR);
+ dev->flags &= ~IFF_PROMISC;
break;
+
case DE4X5_SAY_BOO: /* Say "Boo!" to the kernel log file */
printk("%s: Boo!\n", dev->name);
-
break;
+
case DE4X5_MCA_EN: /* Enable pass all multicast addressing */
- if (capable(CAP_NET_ADMIN)) {
- omr = inl(DE4X5_OMR);
- omr |= OMR_PM;
- outl(omr, DE4X5_OMR);
- } else {
- status = -EPERM;
- }
-
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ omr = inl(DE4X5_OMR);
+ omr |= OMR_PM;
+ outl(omr, DE4X5_OMR);
break;
+
case DE4X5_GET_STATS: /* Get the driver statistics */
ioc->len = sizeof(lp->pktStats);
- status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len);
- if (status)
- break;
-
- cli();
+ if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT;
+ spin_lock_irqsave(&lp->lock, flags);
copy_to_user(ioc->data, &lp->pktStats, ioc->len);
- sti();
-
+ spin_unlock_irqrestore(&lp->lock, flags);
break;
+
case DE4X5_CLR_STATS: /* Zero out the driver statistics */
- if (capable(CAP_NET_ADMIN)) {
- cli();
- memset(&lp->pktStats, 0, sizeof(lp->pktStats));
- sti();
- } else {
- status = -EPERM;
- }
-
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ spin_lock_irqsave(&lp->lock, flags);
+ memset(&lp->pktStats, 0, sizeof(lp->pktStats));
+ spin_unlock_irqrestore(&lp->lock, flags);
break;
+
case DE4X5_GET_OMR: /* Get the OMR Register contents */
tmp.addr[0] = inl(DE4X5_OMR);
- if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, 1))) {
- copy_to_user(ioc->data, tmp.addr, 1);
- }
-
+ if (verify_area(VERIFY_WRITE, ioc->data, 1)) return -EFAULT;
+ copy_to_user(ioc->data, tmp.addr, 1);
break;
+
case DE4X5_SET_OMR: /* Set the OMR Register contents */
- if (capable(CAP_NET_ADMIN)) {
- if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, 1))) {
- copy_from_user(tmp.addr, ioc->data, 1);
- outl(tmp.addr[0], DE4X5_OMR);
- }
- } else {
- status = -EPERM;
- }
-
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ if (verify_area(VERIFY_READ, ioc->data, 1)) return -EFAULT;
+ copy_from_user(tmp.addr, ioc->data, 1);
+ outl(tmp.addr[0], DE4X5_OMR);
break;
+
case DE4X5_GET_REG: /* Get the DE4X5 Registers */
j = 0;
tmp.lval[0] = inl(DE4X5_STS); j+=4;
@@ -5645,9 +5633,8 @@
tmp.lval[6] = inl(DE4X5_STRR); j+=4;
tmp.lval[7] = inl(DE4X5_SIGR); j+=4;
ioc->len = j;
- if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) {
- copy_to_user(ioc->data, tmp.addr, ioc->len);
- }
+ if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT;
+ copy_to_user(ioc->data, tmp.addr, ioc->len);
break;
#define DE4X5_DUMP 0x0f /* Dump the DE4X5 Status */
@@ -5736,14 +5723,13 @@
tmp.addr[j++] = dev->tbusy;
ioc->len = j;
- if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) {
- copy_to_user(ioc->data, tmp.addr, ioc->len);
- }
-
+ if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT;
+ copy_to_user(ioc->data, tmp.addr, ioc->len);
break;
+
*/
default:
- status = -EOPNOTSUPP;
+ return -EOPNOTSUPP;
}
return status;
@@ -5775,6 +5761,12 @@
if (!mdev) mdev = p;
if (register_netdev(p) != 0) {
+ struct de4x5_private *lp = (struct de4x5_private *)p->priv;
+ if (lp) {
+ release_region(p->base_addr, (lp->bus == PCI ?
+ DE4X5_PCI_TOTAL_SIZE :
+ DE4X5_EISA_TOTAL_SIZE));
+ }
kfree(p);
} else {
status = 0; /* At least one adapter will work */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov