patch-2.3.47 linux/drivers/net/tulip.c

Next file: linux/drivers/net/via-rhine.c
Previous file: linux/drivers/net/tokenring/olympic.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.46/linux/drivers/net/tulip.c linux/drivers/net/tulip.c
@@ -142,7 +142,7 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/unaligned.h>
-
+#include <asm/delay.h>
 
 
 /* A few user-configurable values. */
@@ -259,7 +259,7 @@
 
 enum tbl_flag {
 	HAS_MII=1, HAS_MEDIA_TABLE=2, CSR12_IN_SROM=4, ALWAYS_CHECK_MII=8,
-	HAS_PWRDWN=0x10, MC_HASH_ONLY=0x20, /* Hash-only multicast filter. */
+	HAS_ACPI=0x10, MC_HASH_ONLY=0x20, /* Hash-only multicast filter. */
 	HAS_PNICNWAY=0x80, HAS_NWAY143=0x40,	/* Uses internal NWay xcvr. */
 	HAS_8023X=0x100,
 };
@@ -275,7 +275,7 @@
   { "Digital DS21140 Tulip", 128, 0x0001ebef,
 	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer },
   { "Digital DS21143 Tulip", 128, 0x0801fbff,
-	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY143,
+	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143,
 	t21142_timer },
   { "Lite-On 82c168 PNIC", 256, 0x0001ebef,
 	HAS_MII | HAS_PNICNWAY, pnic_timer },
@@ -294,10 +294,10 @@
   { "Compex 9881 PMAC", 128, 0x0001ebef,
 	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
   { "Intel DS21145 Tulip", 128, 0x0801fbff,
-	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY143,
+	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_NWAY143,
 	t21142_timer },
   { "Xircom tulip work-alike", 128, 0x0801fbff,
-	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY143,
+	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143,
 	t21142_timer },
   {0},
 };
@@ -316,7 +316,7 @@
 	COMET,
 	COMPEX9881,
 	I21145,
-	XIRCLONE,
+	X3201_3,
 };
 
 
@@ -334,7 +334,7 @@
 	{ 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 },
 	{ 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 },
-	{ 0x115d, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, XIRCLONE },
+	{ 0x115d, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 },
 	{0},
 };
 MODULE_DEVICE_TABLE(pci,tulip_pci_tbl);
@@ -465,6 +465,7 @@
 	int ttimer;
 	int susp_rx;
 	unsigned long nir;
+	unsigned long base_addr;
 	int pad0, pad1;						/* Used for 8-byte alignment */
 };
 
@@ -473,7 +474,6 @@
 static int mdio_read(struct net_device *dev, int phy_id, int location);
 static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
 static void select_media(struct net_device *dev, int startup);
-static int tulip_open(struct net_device *dev);
 /* Chip-specific media selection (timer functions prototyped above). */
 static void t21142_lnk_change(struct net_device *dev, int csr5);
 static void t21142_start_nway(struct net_device *dev);
@@ -486,7 +486,10 @@
 static int tulip_refill_rx(struct net_device *dev);
 static int tulip_rx(struct net_device *dev);
 static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static int tulip_open(struct net_device *dev);
 static int tulip_close(struct net_device *dev);
+static void tulip_up(struct net_device *dev);
+static void tulip_down(struct net_device *dev);
 static struct net_device_stats *tulip_get_stats(struct net_device *dev);
 static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static void set_rx_mode(struct net_device *dev);
@@ -725,7 +728,7 @@
 #define EE_READ_CMD		(6)
 
 /* Note: this routine returns extra data bits for size detection. */
-static int read_eeprom(long ioaddr, int location, int addr_len)
+static int __devinit read_eeprom(long ioaddr, int location, int addr_len)
 {
 	int i;
 	unsigned retval = 0;
@@ -893,9 +896,60 @@
 	return;
 }
 
-
-static int
-tulip_open(struct net_device *dev)
+
+/* The Xircom cards are picky about when certain bits in CSR6 can be
+   manipulated.  Keith Owens <kaos@ocs.com.au>. */
+
+static void outl_CSR6 (struct tulip_private *tp, u32 newcsr6)
+{
+	long ioaddr = tp->base_addr;
+	const int strict_bits = 0x0060e202;
+	int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200;
+	long flags;
+
+	/* really a hw lock */
+	spin_lock_irqsave (&tp->tx_lock, flags);
+
+	if (tp->chip_id != X3201_3)
+		goto out_write;
+
+	newcsr6 &= 0x726cfeca;	/* mask out the reserved CSR6 bits that always */
+	/* read 0 on the Xircom cards */
+	newcsr6 |= 0x320c0000;	/* or in the reserved bits that always read 1 */
+	currcsr6 = inl (ioaddr + CSR6);
+	if (((newcsr6 & strict_bits) == (currcsr6 & strict_bits)) ||
+	    ((currcsr6 & ~0x2002) == 0))
+		goto out_write;
+
+	/* make sure the transmitter and receiver are stopped first */
+	currcsr6 &= ~0x2002;
+	while (1) {
+		csr5 = inl (ioaddr + CSR5);
+		if (csr5 == 0xffffffff)
+			break;	/* cannot read csr5, card removed? */
+		csr5_22_20 = csr5 & 0x700000;
+		csr5_19_17 = csr5 & 0x0e0000;
+		if ((csr5_22_20 == 0 || csr5_22_20 == 0x600000) &&
+		    (csr5_19_17 == 0 || csr5_19_17 == 0x80000 || csr5_19_17 == 0xc0000))
+			break;	/* both are stopped or suspended */
+		if (!--attempts) {
+			printk (KERN_INFO "tulip.c: outl_CSR6 too many attempts,"
+				"csr5=0x%08x\n", csr5);
+			goto out_write;
+		}
+		outl (currcsr6, ioaddr + CSR6);
+		udelay (1);
+	}
+
+out_write:
+	/* now it is safe to change csr6 */
+	outl (newcsr6, ioaddr + CSR6);
+
+	spin_unlock_irqrestore (&tp->lock, flags);
+}
+
+
+static void tulip_up(struct net_device *dev)
 {
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	long ioaddr = dev->base_addr;
@@ -903,19 +957,16 @@
 	int i;
 
 	/* Wake the chip from sleep/snooze mode. */
-	if (tp->flags & HAS_PWRDWN)
+	if (tp->flags & HAS_ACPI)
 		pci_write_config_dword(tp->pdev, 0x40, 0);
 
 	/* On some chip revs we must set the MII/SYM port before the reset!? */
 	if (tp->mii_cnt  ||  (tp->mtable  &&  tp->mtable->has_mii))
-		outl(0x00040000, ioaddr + CSR6);
+		outl_CSR6 (tp, 0x00040000);
 
 	/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
 	outl(0x00000001, ioaddr + CSR0);
 
-	if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev))
-		return -EAGAIN;
-
 	/* Deassert reset.
 	   Wait the specified 50 PCI cycles after a reset by initializing
 	   Tx and Rx queues and the address filter list. */
@@ -924,22 +975,6 @@
 	if (tulip_debug > 1)
 		printk(KERN_DEBUG "%s: tulip_open() irq %d.\n", dev->name, dev->irq);
 
-	MOD_INC_USE_COUNT;
-
-	spin_lock_init(&tp->tx_lock);
-	tulip_init_ring(dev);
-
-#if 0
-	if (tp->chip_id == PNIC2) {
-		u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr));
-		u32 addr_high = cpu_to_le16(get_unaligned((u16 *)(dev->dev_addr+4)));
-		addr_high = (dev->dev_addr[4]<<8) + (dev->dev_addr[5]<<0);
-		outl((dev->dev_addr[0]<<8) + dev->dev_addr[1] +
-			 (dev->dev_addr[2]<<24) + (dev->dev_addr[3]<<16),
-			 ioaddr + 0xB0);
-		outl(addr_high + (addr_high<<16), ioaddr + 0xB8);
-	}
-#endif
 	if (tp->flags & MC_HASH_ONLY) {
 		u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr));
 		u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4)));
@@ -1022,7 +1057,7 @@
 				printk(KERN_INFO "%s: Using MII transceiver %d, status "
 					   "%4.4x.\n",
 					   dev->name, tp->phys[0], mdio_read(dev, tp->phys[0], 1));
-			outl(0x82020000, ioaddr + CSR6);
+			outl_CSR6(tp, 0x82020000);
 			tp->csr6 = 0x820E0000;
 			dev->if_port = 11;
 			outl(0x0000, ioaddr + CSR13);
@@ -1072,13 +1107,13 @@
 		select_media(dev, 1);
 
 	/* Start the chip's Tx to process setup frame. */
-	outl(tp->csr6, ioaddr + CSR6);
-	outl(tp->csr6 | 0x2000, ioaddr + CSR6);
+	outl_CSR6(tp, tp->csr6);
+	outl_CSR6(tp, tp->csr6 | 0x2000);
 
 	/* Enable interrupts by setting the interrupt mask. */
 	outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5);
 	outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
-	outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+	outl_CSR6(tp, tp->csr6 | 0x2002);
 	outl(0, ioaddr + CSR2);		/* Rx poll demand */
 
 	if (tulip_debug > 2) {
@@ -1094,11 +1129,28 @@
 	tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
 	add_timer(&tp->timer);
 
-	netif_start_queue(dev);
+	netif_device_attach(dev);
+}
+
+
+static int
+tulip_open(struct net_device *dev)
+{
+	MOD_INC_USE_COUNT;
+	
+	if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) {
+		MOD_DEC_USE_COUNT;
+		return -EBUSY;
+	}
 
+	tulip_init_ring (dev);
+	
+	tulip_up (dev);
+	
 	return 0;
 }
 
+
 /* Set up the transceiver control registers for the selected media type. */
 static void select_media(struct net_device *dev, int startup)
 {
@@ -1314,7 +1366,6 @@
   */
 static int check_duplex(struct net_device *dev)
 {
-	long ioaddr = dev->base_addr;
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	int mii_reg1, mii_reg5, negotiated, duplex;
 
@@ -1346,8 +1397,8 @@
 			tp->csr6 &= ~0x00400000;
 		if (tp->full_duplex) tp->csr6 |= 0x0200;
 		else				 tp->csr6 &= ~0x0200;
-		outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-		outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+		outl_CSR6(tp, tp->csr6 | 0x0002);
+		outl_CSR6(tp, tp->csr6 | 0x2002);
 		if (tulip_debug > 0)
 			printk(KERN_INFO "%s: Setting %s-duplex based on MII"
 				   "#%d link partner capability of %4.4x.\n",
@@ -1492,8 +1543,8 @@
 					   medianame[tp->mtable->mleaf[tp->cur_index].media]);
 			select_media(dev, 0);
 			/* Restart the transmit process. */
-			outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-			outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+			outl_CSR6(tp, tp->csr6 | 0x0002);
+			outl_CSR6(tp, tp->csr6 | 0x2002);
 			next_tick = (24*HZ)/10;
 			break;
 		}
@@ -1513,6 +1564,7 @@
 	add_timer(&tp->timer);
 }
 
+
 /* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list
    of available transceivers.  */
 static void t21142_timer(unsigned long data)
@@ -1573,8 +1625,8 @@
 			tp->csr6 &= 0x00D5;
 			tp->csr6 |= new_csr6;
 			outl(0x0301, ioaddr + CSR12);
-			outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-			outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+			outl_CSR6(tp, tp->csr6 | 0x0002);
+			outl_CSR6(tp, tp->csr6 | 0x2002);
 		}
 		next_tick = 3*HZ;
 	}
@@ -1583,6 +1635,7 @@
 	add_timer(&tp->timer);
 }
 
+
 static void t21142_start_nway(struct net_device *dev)
 {
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
@@ -1599,7 +1652,7 @@
 	outl(0x0001, ioaddr + CSR13);
 	outl(csr14, ioaddr + CSR14);
 	tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0);
-	outl(tp->csr6, ioaddr + CSR6);
+	outl_CSR6(tp, tp->csr6);
 	if (tp->mtable  &&  tp->mtable->csr15dir) {
 		outl(tp->mtable->csr15dir, ioaddr + CSR15);
 		outl(tp->mtable->csr15val, ioaddr + CSR15);
@@ -1608,6 +1661,7 @@
 	outl(0x1301, ioaddr + CSR12); 		/* Trigger NWAY. */
 }
 
+
 static void t21142_lnk_change(struct net_device *dev, int csr5)
 {
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
@@ -1664,12 +1718,12 @@
 			outl(1, ioaddr + CSR13);
 		}
 #if 0							/* Restart shouldn't be needed. */
-		outl(tp->csr6 | 0x0000, ioaddr + CSR6);
+		outl_CSR6(tp, tp->csr6 | 0x0000);
 		if (debug > 2)
 			printk(KERN_DEBUG "%s:  Restarting Tx and Rx, CSR5 is %8.8x.\n",
 				   dev->name, inl(ioaddr + CSR5));
 #endif
-		outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+		outl_CSR6(tp, tp->csr6 | 0x2002);
 		if (debug > 2)
 			printk(KERN_DEBUG "%s:  Setting CSR6 %8.8x/%x CSR12 %8.8x.\n",
 				   dev->name, tp->csr6, inl(ioaddr + CSR6),
@@ -1715,11 +1769,12 @@
 		tp->csr6 = 0x83860000;
 		outl(0x0003FF7F, ioaddr + CSR14);
 		outl(0x0301, ioaddr + CSR12);
-		outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-		outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+		outl_CSR6(tp, tp->csr6 | 0x0002);
+		outl_CSR6(tp, tp->csr6 | 0x2002);
 	}
 }
 
+
 static void mxic_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
@@ -1737,6 +1792,7 @@
 	}
 }
 
+
 static void pnic_do_nway(struct net_device *dev)
 {
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
@@ -1763,12 +1819,15 @@
 				   dev->name, phy_reg, medianame[dev->if_port]);
 		if (tp->csr6 != new_csr6) {
 			tp->csr6 = new_csr6;
-			outl(tp->csr6 | 0x0002, ioaddr + CSR6);	/* Restart Tx */
-			outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+			/* Restart Tx */
+			outl_CSR6(tp, tp->csr6 | 0x0002);
+			outl_CSR6(tp, tp->csr6 | 0x2002);
 			dev->trans_start = jiffies;
 		}
 	}
 }
+
+
 static void pnic_lnk_change(struct net_device *dev, int csr5)
 {
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
@@ -1782,7 +1841,7 @@
 		outl((inl(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7);
 		if (! tp->nwayset  ||  jiffies - dev->trans_start > 1*HZ) {
 			tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff);
-			outl(tp->csr6, ioaddr + CSR6);
+			outl_CSR6(tp, tp->csr6);
 			outl(0x30, ioaddr + CSR12);
 			outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
 			dev->trans_start = jiffies;
@@ -1792,6 +1851,8 @@
 		outl((inl(ioaddr + CSR7) & ~TPLnkPass) | TPLnkFail, ioaddr + CSR7);
 	}
 }
+
+
 static void pnic_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
@@ -1842,8 +1903,9 @@
 			}
 			if (tp->csr6 != new_csr6) {
 				tp->csr6 = new_csr6;
-				outl(tp->csr6 | 0x0002, ioaddr + CSR6);	/* Restart Tx */
-				outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+				/* Restart Tx */
+				outl_CSR6(tp, tp->csr6 | 0x0002);
+				outl_CSR6(tp, tp->csr6 | 0x2002);
 				dev->trans_start = jiffies;
 				if (tulip_debug > 1)
 					printk(KERN_INFO "%s: Changing PNIC configuration to %s "
@@ -1965,8 +2027,8 @@
 #endif
 
 	/* Stop and restart the chip's Tx processes . */
-	outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-	outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+	outl_CSR6(tp, tp->csr6 | 0x0002);
+	outl_CSR6(tp, tp->csr6 | 0x2002);
 	/* Trigger an immediate transmit demand. */
 	outl(0, ioaddr + CSR1);
 
@@ -2173,8 +2235,8 @@
 					printk(KERN_WARNING "%s: The transmitter stopped."
 						   "  CSR5 is %x, CSR6 %x, new CSR6 %x.\n",
 						   dev->name, csr5, inl(ioaddr + CSR6), tp->csr6);
-				outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-				outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+				outl_CSR6(tp, tp->csr6 | 0x0002);
+				outl_CSR6(tp, tp->csr6 | 0x2002);
 			}
 			spin_unlock(&tp->tx_lock);
 		}
@@ -2190,14 +2252,14 @@
 				else
 					tp->csr6 |= 0x00200000;  /* Store-n-forward. */
 				/* Restart the transmit process. */
-				outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-				outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+				outl_CSR6(tp, tp->csr6 | 0x0002);
+				outl_CSR6(tp, tp->csr6 | 0x2002);
 				outl(0, ioaddr + CSR1);
 			}
 			if (csr5 & RxDied) {		/* Missed a Rx frame. */
 				tp->stats.rx_errors++;
 				tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
-				outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+				outl_CSR6(tp, tp->csr6 | 0x2002);
 			}
 			if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) {
 				if (tp->link_change)
@@ -2378,69 +2440,79 @@
 	return received;
 }
 
-static int
-tulip_close(struct net_device *dev)
+
+static void tulip_down (struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
-	int i;
+	struct tulip_private *tp = (struct tulip_private *) dev->priv;
 
-	netif_stop_queue(dev);
+	netif_device_detach (dev);
 
-	if (tulip_debug > 1)
-		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
-			   dev->name, inl(ioaddr + CSR5));
+	del_timer (&tp->timer);
 
 	/* Disable interrupts by clearing the interrupt mask. */
-	outl(0x00000000, ioaddr + CSR7);
+	outl (0x00000000, ioaddr + CSR7);
+
 	/* Stop the Tx and Rx processes. */
-	outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6);
+	outl_CSR6 (tp, inl (ioaddr + CSR6) & ~0x2002);
+
 	/* 21040 -- Leave the card in 10baseT state. */
 	if (tp->chip_id == DC21040)
-		outl(0x00000004, ioaddr + CSR13);
+		outl (0x00000004, ioaddr + CSR13);
 
-	if (inl(ioaddr + CSR6) != 0xffffffff)
-		tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+	if (inl (ioaddr + CSR6) != 0xffffffff)
+		tp->stats.rx_missed_errors += inl (ioaddr + CSR8) & 0xffff;
+
+	dev->if_port = tp->saved_if_port;
+
+	/* Leave the driver in snooze, not sleep, mode. */
+	if (tp->flags & HAS_ACPI)
+		pci_write_config_dword (tp->pdev, 0x40, 0x40000000);
+}
+  
+  
+static int tulip_close (struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	struct tulip_private *tp = (struct tulip_private *) dev->priv;
+	int i;
 
-	del_timer(&tp->timer);
+	tulip_down (dev);
 
-	free_irq(dev->irq, dev);
+	if (tulip_debug > 1)
+		printk (KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
+			dev->name, inl (ioaddr + CSR5));
 
-	dev->if_port = tp->saved_if_port;
+	free_irq (dev->irq, dev);
 
 	/* Free all the skbuffs in the Rx queue. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		struct sk_buff *skb = tp->rx_skbuff[i];
 		tp->rx_skbuff[i] = 0;
-		tp->rx_ring[i].status = 0;		/* Not owned by Tulip chip. */
+		tp->rx_ring[i].status = 0;	/* Not owned by Tulip chip. */
 		tp->rx_ring[i].length = 0;
-		tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */
+		tp->rx_ring[i].buffer1 = 0xBADF00D0;	/* An invalid address. */
 		if (skb) {
-			dev_kfree_skb(skb);
+			dev_kfree_skb (skb);
 		}
 	}
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		if (tp->tx_skbuff[i])
-			dev_kfree_skb(tp->tx_skbuff[i]);
+			dev_kfree_skb (tp->tx_skbuff[i]);
 		tp->tx_skbuff[i] = 0;
 	}
 
-	/* Leave the driver in snooze, not sleep, mode. */
-	if (tp->flags & HAS_PWRDWN)
-		pci_write_config_dword(tp->pdev, 0x40, 0x40000000);
-
 	MOD_DEC_USE_COUNT;
 
 	return 0;
 }
 
-static struct enet_statistics *
-tulip_get_stats(struct net_device *dev)
+static struct enet_statistics *tulip_get_stats(struct net_device *dev)
 {
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 
-	if (test_bit(LINK_STATE_START, &dev->state))
+	if (netif_running(dev))
 		tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
 
 	return &tp->stats;
@@ -2672,7 +2744,7 @@
 			outl(0, ioaddr + CSR1);
 		}
 	}
-	outl(csr6 | 0x0000, ioaddr + CSR6);
+	outl_CSR6(tp, csr6 | 0x0000);
 }
 
 
@@ -2697,10 +2769,10 @@
 	board_idx++;
 
 	if (tulip_debug > 0  &&  did_version++ == 0)
-		printk(KERN_INFO "%s", version);
+		printk (KERN_INFO "%s", version);
 
         if( pdev->subsystem_vendor == 0x1376 ){
-		printk(KERN_ERR "tulip: skipping LMC card.\n");
+		printk (KERN_ERR PFX "skipping LMC card.\n");
 		return -ENODEV;
 	}
 	
@@ -2709,31 +2781,37 @@
 
 	/* Make certain the data structures are quadword aligned. */
 	dev = init_etherdev (NULL, sizeof (*tp));
-	if (!dev)
+	if (!dev) {
+		printk (KERN_ERR PFX "unable to allocate ether device, aborting\n");
 		return -ENOMEM;
+	}
 
 	/* We do a request_region() only to register /proc/ioports info. */
 	/* Note that proper size is tulip_tbl[chip_idx].chip_name, but... */
-	if (!request_region (ioaddr, tulip_tbl[chip_idx].io_size, dev->name))
+	if (!request_region (ioaddr, tulip_tbl[chip_idx].io_size, dev->name)) {
+		printk (KERN_ERR PFX "unable to allocate ether device, aborting\n");
+		goto err_out_free_netdev;
+	}
+
+	if (pci_enable_device(pdev)) {
+		printk (KERN_ERR PFX "cannot enable PCI device (id %04x:%04x, bus %d, devfn %d), aborting\n",
+			pdev->vendor, pdev->device,
+			pdev->bus->number, pdev->devfn);
 		goto err_out_free_netdev;
+	}
 
-	pci_enable_device (pdev);
+	pci_set_master(pdev);
 
 	tp = dev->priv;
 	memset(tp, 0, sizeof(*tp));
 
 	pci_read_config_byte (pdev, PCI_REVISION_ID, &chip_rev);
 
-	/* Bring the 21041/21143 out of sleep mode.
-	   Caution: Snooze mode does not work with some boards! */
-	if (tulip_tbl[chip_idx].flags & HAS_PWRDWN)
-		pci_write_config_dword(pdev, 0x40, 0x00000000);
-
 	printk(KERN_INFO "%s: %s rev %d at %#3lx,",
 		   dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr);
 
 	/* Stop the chip's Tx and Rx processes. */
-	outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6);
+	outl_CSR6(tp, inl(ioaddr + CSR6) & ~0x2002);
 	/* Clear the missed-packet counter. */
 	(volatile int)inl(ioaddr + CSR8);
 
@@ -2835,6 +2913,7 @@
 	tp->flags = tulip_tbl[chip_idx].flags;
 	tp->csr0 = csr0;
 	tp->pdev = pdev;
+	tp->base_addr = dev->base_addr;
 
 	/* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles.
 	   And the ASIX must have a burst limit or horrible things happen. */
@@ -2853,6 +2932,7 @@
 #ifdef TULIP_NO_MEDIA_SWITCH
 	tp->medialock = 1;
 #endif
+	tp->tx_lock = SPIN_LOCK_UNLOCKED;
 
 	/* The lower four bits are the media type. */
 	if (board_idx >= 0  &&  board_idx < MAX_UNITS) {
@@ -2962,7 +3042,7 @@
 		outl(0x00000000, ioaddr + CSR13);
 		outl(0xFFFFFFFF, ioaddr + CSR14);
 		outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */
-		outl(inl(ioaddr + CSR6) | 0x0200, ioaddr + CSR6);
+		outl_CSR6(tp, inl(ioaddr + CSR6) | 0x0200);
 		outl(0x0000EF05, ioaddr + CSR13);
 		break;
 	case DC21040:
@@ -2976,10 +3056,10 @@
 	case DC21142:
 	case PNIC2:
 		if (tp->mii_cnt  ||  media_cap[dev->if_port] & MediaIsMII) {
-			outl(0x82020000, ioaddr + CSR6);
+			outl_CSR6(tp, 0x82020000);
 			outl(0x0000, ioaddr + CSR13);
 			outl(0x0000, ioaddr + CSR14);
-			outl(0x820E0000, ioaddr + CSR6);
+			outl_CSR6(tp, 0x820E0000);
 		} else
 			t21142_start_nway(dev);
 		break;
@@ -2987,19 +3067,19 @@
 		if ( ! tp->mii_cnt) {
 			tp->nway = 1;
 			tp->nwayset = 0;
-			outl(0x00420000, ioaddr + CSR6);
+			outl_CSR6(tp, 0x00420000);
 			outl(0x30, ioaddr + CSR12);
-			outl(0x0001F078, ioaddr + 0xB8);
-			outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
+			outl_CSR6(tp, 0x0001F078);
+			outl_CSR6(tp, 0x0201F078); /* Turn on autonegotiation. */
 		}
 		break;
 	case MX98713: case COMPEX9881:
-		outl(0x00000000, ioaddr + CSR6);
+		outl_CSR6(tp, 0x00000000);
 		outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */
 		outl(0x00000001, ioaddr + CSR13);
 		break;
 	case MX98715: case MX98725:
-		outl(0x01a80000, ioaddr + CSR6);
+		outl_CSR6(tp, 0x01a80000);
 		outl(0xFFFFFFFF, ioaddr + CSR14);
 		outl(0x00001000, ioaddr + CSR12);
 		break;
@@ -3008,7 +3088,8 @@
 		break;
 	}
 
-	if (tulip_tbl[chip_idx].flags & HAS_PWRDWN)
+	/* put the chip in snooze mode until opened */
+	if (tulip_tbl[chip_idx].flags & HAS_ACPI)
 		pci_write_config_dword(pdev, 0x40, 0x40000000);
 
 	return 0;
@@ -3024,20 +3105,8 @@
 {
 	struct net_device *dev = pdev->driver_data;
 
-	if (dev) {
-		long ioaddr = dev->base_addr;
-		struct tulip_private *tp = (struct tulip_private *)dev->priv;
-		int csr6 = inl(ioaddr + CSR6);
-		/* Disable interrupts, stop the chip, gather stats. */
-		if (csr6 != 0xffffffff) {
-			outl(0x00000000, ioaddr + CSR7);
-			outl(csr6 & ~0x2002, ioaddr + CSR6);
-			tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
-		}
-		tulip_close(dev);
-		/* Put the 21143 into sleep mode. */
-		pci_write_config_dword(pdev, 0x40,0x80000000);
-	}
+	if (dev && netif_device_present (dev))
+		tulip_down (dev);
 }
 
 
@@ -3045,10 +3114,8 @@
 {
 	struct net_device *dev = pdev->driver_data;
 
-	if (dev) {
-		pci_write_config_dword(pdev, 0x40, 0x0000);
-		tulip_open(dev);
-	}
+	if (dev && !netif_device_present (dev))
+		tulip_up (dev);
 }
 
 
@@ -3078,7 +3145,7 @@
 
 static int __init tulip_init (void)
 {
-	return pci_register_driver (&tulip_driver) > 0 ? 0 : -ENODEV;
+	return pci_module_init (&tulip_driver);
 }
 
 

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