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

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