patch-2.4.5 linux/drivers/net/tulip/tulip_core.c

Next file: linux/drivers/net/wan/comx-hw-comx.c
Previous file: linux/drivers/net/tulip/tulip.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.4/linux/drivers/net/tulip/tulip_core.c linux/drivers/net/tulip/tulip_core.c
@@ -14,16 +14,24 @@
 
 */
 
+#define DRV_NAME	"tulip"
+#define DRV_VERSION	"0.9.15-pre2"
+#define DRV_RELDATE	"May 16, 2001"
+
+#include <linux/config.h>
 #include <linux/module.h>
 #include "tulip.h"
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/etherdevice.h>
 #include <linux/delay.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
 #include <asm/unaligned.h>
+#include <asm/uaccess.h>
 
 static char version[] __devinitdata =
-	"Linux Tulip driver version 0.9.14e (April 20, 2001)\n";
+	"Linux Tulip driver version " DRV_VERSION " (" DRV_RELDATE ")\n";
 
 
 /* A few user-configurable values. */
@@ -100,8 +108,7 @@
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 
-#define TULIP_MODULE_NAME "tulip"
-#define PFX TULIP_MODULE_NAME ": "
+#define PFX DRV_NAME ": "
 
 #ifdef TULIP_DEBUG
 int tulip_debug = TULIP_DEBUG;
@@ -127,12 +134,12 @@
 
   /* DC21140 */
   { "Digital DS21140 Tulip", 128, 0x0001ebef,
-	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer },
+	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_PCI_MWI, tulip_timer },
 
   /* DC21142, DC21143 */
   { "Digital DS21143 Tulip", 128, 0x0801fbff,
 	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY
-	| HAS_INTR_MITIGATION, t21142_timer },
+	| HAS_INTR_MITIGATION | HAS_PCI_MWI, t21142_timer },
 
   /* LC82C168 */
   { "Lite-On 82c168 PNIC", 256, 0x0001fbef,
@@ -152,11 +159,12 @@
 
   /* AX88140 */
   { "ASIX AX88140", 128, 0x0001fbff,
-	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY | IS_ASIX, tulip_timer },
+	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY
+	| IS_ASIX, tulip_timer },
 
   /* PNIC2 */
   { "Lite-On PNIC-II", 256, 0x0801fbff,
-	HAS_MII | HAS_NWAY | HAS_8023X, t21142_timer },
+	HAS_MII | HAS_NWAY | HAS_8023X | HAS_PCI_MWI, t21142_timer },
 
   /* COMET */
   { "ADMtek Comet", 256, 0x0001abef,
@@ -168,18 +176,13 @@
 
   /* I21145 */
   { "Intel DS21145 Tulip", 128, 0x0801fbff,
-	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY,
-	t21142_timer },
+	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI
+	| HAS_NWAY | HAS_PCI_MWI, t21142_timer },
 
   /* DM910X */
   { "Davicom DM9102/DM9102A", 128, 0x0001ebef,
 	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_ACPI,
 	tulip_timer },
-
-  /* CONEXANT */
-  { "Conexant LANfinity", 0x100, 0x0001ebef,
-	HAS_MII | HAS_ACPI,
-	tulip_timer },
 };
 
 
@@ -208,7 +211,6 @@
 	{ 0x1113, 0x1216, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x1113, 0x1217, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 },
 	{ 0x1113, 0x9511, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
-	{ 0x14f1, 0x1803, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CONEXANT },
 	{ } /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, tulip_pci_tbl);
@@ -269,8 +271,6 @@
 	int next_tick = 3*HZ;
 	int i;
 
-	DPRINTK("ENTER\n");
-
 	/* Wake the chip from sleep/snooze mode. */
 	tulip_set_power_state (tp, 0, 0);
 
@@ -379,10 +379,30 @@
 	tp->csr6 = 0;
 	tp->cur_index = i;
 	tp->nwayset = 0;
-	if (dev->if_port == 0  && tp->chip_id == DC21041)
-		tp->nway = 1;
 
-	if (dev->if_port == 0  &&  tp->chip_id == DC21142) {
+	if (dev->if_port) {
+		if (tp->chip_id == DC21143  &&
+		    (tulip_media_cap[dev->if_port] & MediaIsMII)) {
+			/* We must reset the media CSRs when we force-select MII mode. */
+			outl(0x0000, ioaddr + CSR13);
+			outl(0x0000, ioaddr + CSR14);
+			outl(0x0008, ioaddr + CSR15);
+		}
+		tulip_select_media(dev, 1);
+	} else if (tp->chip_id == DC21041) {
+		dev->if_port = 0;
+		tp->nway = tp->mediasense = 1;
+		tp->nwayset = tp->lpar = 0;
+		outl(0x00000000, ioaddr + CSR13);
+		outl(0xFFFFFFFF, ioaddr + CSR14);
+		outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */
+		tp->csr6 = 0x80020000;
+		if (tp->sym_advertise & 0x0040)
+			tp->csr6 |= FullDuplex;
+		outl(tp->csr6, ioaddr + CSR6);
+		outl(0x0000EF01, ioaddr + CSR13);
+
+	} else if (tp->chip_id == DC21142) {
 		if (tp->mii_cnt) {
 			tulip_select_media(dev, 1);
 			if (tulip_debug > 1)
@@ -424,12 +444,6 @@
 		tp->csr6 = 0x01a80200;
 		outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80);
 		outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0);
-	} else if (tp->chip_id == DC21143  &&
-			   tulip_media_cap[dev->if_port] & MediaIsMII) {
-		/* We must reset the media CSRs when we force-select MII mode. */
-		outl(0x0000, ioaddr + CSR13);
-		outl(0x0000, ioaddr + CSR14);
-		outl(0x0008, ioaddr + CSR15);
 	} else if (tp->chip_id == COMET) {
 		/* Enable automatic Tx underrun recovery. */
 		outl(inl(ioaddr + 0x88) | 1, ioaddr + 0x88);
@@ -464,10 +478,27 @@
 	add_timer(&tp->timer);
 }
 
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+/* Enable receiver */
+void tulip_xon(struct net_device *dev)
+{
+        struct tulip_private *tp = (struct tulip_private *)dev->priv;
+
+        clear_bit(tp->fc_bit, &netdev_fc_xoff);
+        if (netif_running(dev)){
+
+                tulip_refill_rx(dev);
+                outl(tulip_tbl[tp->chip_id].valid_intrs,  dev->base_addr+CSR7);
+        }
+}
+#endif
 
 static int
 tulip_open(struct net_device *dev)
 {
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+        struct tulip_private *tp = (struct tulip_private *)dev->priv;
+#endif
 	int retval;
 	MOD_INC_USE_COUNT;
 
@@ -480,6 +511,10 @@
 
 	tulip_up (dev);
 
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+        tp->fc_bit = netdev_register_fc(dev, tulip_xon);
+#endif
+
 	netif_start_queue (dev);
 
 	return 0;
@@ -492,8 +527,6 @@
 	long ioaddr = dev->base_addr;
 	unsigned long flags;
 
-	DPRINTK("ENTER\n");
-
 	spin_lock_irqsave (&tp->lock, flags);
 
 	if (tulip_media_cap[dev->if_port] & MediaIsMII) {
@@ -549,6 +582,11 @@
 			printk(KERN_WARNING "%s: transmit timed out, switching to %s "
 				   "media.\n", dev->name, medianame[dev->if_port]);
 		}
+	} else if (tp->chip_id == PNIC2) {
+		printk(KERN_WARNING "%s: PNIC2 transmit timed out, status %8.8x, "
+		       "CSR6/7 %8.8x / %8.8x CSR12 %8.8x, resetting...\n",
+		       dev->name, (int)inl(ioaddr + CSR5), (int)inl(ioaddr + CSR6),
+		       (int)inl(ioaddr + CSR7), (int)inl(ioaddr + CSR12));
 	} else {
 		printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 "
 			   "%8.8x, resetting...\n",
@@ -584,6 +622,10 @@
 #endif
 
 	/* Stop and restart the chip's Tx processes . */
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+        if (tp->fc_bit && test_bit(tp->fc_bit,&netdev_fc_xoff))
+                printk("BUG tx_timeout restarting rx when fc on\n");
+#endif
 	tulip_restart_rxtx(tp, tp->csr6);
 	/* Trigger an immediate transmit demand. */
 	outl(0, ioaddr + CSR1);
@@ -603,8 +645,6 @@
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	int i;
 
-	DPRINTK("ENTER\n");
-
 	tp->cur_rx = tp->cur_tx = 0;
 	tp->dirty_rx = tp->dirty_tx = 0;
 	tp->susp_rx = 0;
@@ -742,6 +782,13 @@
 
 	netif_stop_queue (dev);
 
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+        if (tp->fc_bit) {
+                int bit = tp->fc_bit;
+                tp->fc_bit = 0;
+                netdev_unregister_fc(bit);
+        }
+#endif
 	tulip_down (dev);
 
 	if (tulip_debug > 1)
@@ -803,16 +850,43 @@
 }
 
 
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	struct tulip_private *np = dev->priv;
+	u32 ethcmd;
+		
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+
+        switch (ethcmd) {
+        case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strcpy(info.driver, DRV_NAME);
+		strcpy(info.version, DRV_VERSION);
+		strcpy(info.bus_info, np->pdev->slot_name);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+
+        }
+	
+	return -EOPNOTSUPP;
+}
+
 /* Provide ioctl() calls to examine the MII xcvr state. */
 static int private_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct tulip_private *tp = dev->priv;
 	long ioaddr = dev->base_addr;
 	u16 *data = (u16 *) & rq->ifr_data;
-	int phy = tp->phys[0] & 0x1f;
+	const unsigned int phy_idx = 0;
+	int phy = tp->phys[phy_idx] & 0x1f;
 	unsigned int regnum = data[1];
 
 	switch (cmd) {
+	case SIOCETHTOOL:
+		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 	case SIOCDEVPRIVATE:	/* Get the address of the PHY in use. */
 		if (tp->mii_cnt)
 			data[0] = phy;
@@ -828,26 +902,31 @@
 			int csr14 = inl (ioaddr + CSR14);
 			switch (regnum) {
 			case 0:
-				data[3] = (csr14 << 5) & 0x1000;
+                                if (((csr14<<5) & 0x1000) ||
+                                        (dev->if_port == 5 && tp->nwayset))
+                                        data[3] = 0x1000;
+                                else
+                                        data[3] = (tulip_media_cap[dev->if_port]&MediaIs100 ? 0x2000 : 0)
+                                                | (tulip_media_cap[dev->if_port]&MediaIsFD ? 0x0100 : 0);
 				break;
 			case 1:
-				data[3] =
-				  0x7848 +
-				  ((csr12 & 0x7000) == 0x5000 ? 0x20 : 0) +
-				  (csr12 & 0x06 ? 0x04 : 0);
+                                data[3] =
+					0x1848 +
+					((csr12&0x7000) == 0x5000 ? 0x20 : 0) +
+					((csr12&0x06) == 6 ? 0 : 4);
+                                if (tp->chip_id != DC21041)
+                                        data[3] |= 0x6048;
 				break;
 			case 4:
-				data[3] =
-				  ((csr14 >> 9) & 0x07C0) +
-				  ((inl (ioaddr + CSR6) >> 3) & 0x0040) +
-				  ((csr14 >> 1) & 0x20) + 1;
-				break;
-			case 5:
-				data[3] = csr12 >> 16;
-				break;
-			default:
-				data[3] = 0;
+                                /* Advertised value, bogus 10baseTx-FD value from CSR6. */
+                                data[3] =
+					((inl(ioaddr + CSR6) >> 3) & 0x0040) + 
+					((csr14 >> 1) & 0x20) + 1;
+                                if (tp->chip_id != DC21041)
+                                         data[3] |= ((csr14 >> 9) & 0x03C0);
 				break;
+			case 5: data[3] = tp->lpar; break;
+			default: data[3] = 0; break;
 			}
 		} else {
 			data[3] = tulip_mdio_read (dev, data[0] & 0x1f, regnum);
@@ -867,7 +946,8 @@
 					tp->full_duplex = (value & 0x0100) ? 1 : 0;
 				break;
 			case 4:
-				tp->to_advertise = data[2];
+				tp->advertising[phy_idx] =
+				tp->mii_advertise = data[2];
 				break;
 			}
 		}
@@ -877,7 +957,7 @@
 				if ((value & 0x1200) == 0x1200)
 					t21142_start_nway (dev);
 			} else if (regnum == 4)
-				tp->to_advertise = value;
+				tp->sym_advertise = value;
 		} else {
 			tulip_mdio_write (dev, data[0] & 0x1f, regnum, data[2]);
 		}
@@ -998,8 +1078,6 @@
 	long ioaddr = dev->base_addr;
 	int csr6;
 
-	DPRINTK("ENTER\n");
-
 	csr6 = inl(ioaddr + CSR6) & ~0x00D5;
 
 	tp->csr6 &= ~0x00D5;
@@ -1119,6 +1197,91 @@
 	tulip_outl_csr(tp, csr6 | 0x0000, CSR6);
 }
 
+static void __devinit tulip_mwi_config (struct pci_dev *pdev,
+					struct net_device *dev)
+{
+	struct tulip_private *tp = dev->priv;
+	u8 pci_cacheline;
+	u16 pci_command, new_command;
+	unsigned mwi = 1;
+	
+	if (tulip_debug > 3)
+		printk(KERN_DEBUG "%s: tulip_mwi_config()\n", pdev->slot_name);
+
+	/* get a sane cache line size, if possible */
+	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &pci_cacheline);
+	if (pci_cacheline < (SMP_CACHE_BYTES / 4))
+		pci_cacheline = SMP_CACHE_BYTES / 4;
+	if (pci_cacheline > TULIP_MAX_CACHE_LINE)
+		pci_cacheline = TULIP_MAX_CACHE_LINE;
+	switch (pci_cacheline) {
+	case 8:
+	case 16:
+	case 32: break;
+	default: pci_cacheline = TULIP_MIN_CACHE_LINE; break;
+	}
+	pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, pci_cacheline);
+
+	/* read back the result.  if zero, or if a buggy chip rev,
+	 * disable MWI
+	 */
+	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &pci_cacheline);
+	if (!pci_cacheline || (tp->chip_id == DC21143 && tp->revision == 65))
+		mwi = 0;
+
+	/* re-clamp cache line values to ones supported by tulip */
+	/* From this point forward, 'pci_cacheline' is really
+	 * the value used for csr0 cache alignment and
+	 * csr0 programmable burst length
+	 */
+	switch (pci_cacheline) {
+	case 0:
+	case 8:
+	case 16:
+	case 32: break;
+	default: pci_cacheline = TULIP_MIN_CACHE_LINE; break;
+	}
+
+	/* set or disable MWI in the standard PCI command bit.
+	 * Check for the case where  mwi is desired but not available
+	 */
+	pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
+	if (mwi)	new_command = pci_command | PCI_COMMAND_INVALIDATE;
+	else		new_command = pci_command & ~PCI_COMMAND_INVALIDATE;
+	if (new_command != pci_command) {
+		pci_write_config_word(pdev, PCI_COMMAND, new_command);
+		pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
+		if ((new_command != pci_command) && mwi &&
+		    ((pci_command & PCI_COMMAND_INVALIDATE) == 0))
+			mwi = 0;
+	}
+
+	tp->csr0 = MRL | MRM;	
+
+	/* if no PCI cache line size, bail out with minimal
+	 * burst size and cache alignment of 8 dwords.
+	 * We always want to have some sort of limit.
+	 */
+	if (!pci_cacheline) {
+		tp->csr0 |= (8 << BurstLenShift) | (1 << CALShift);
+		goto out;
+	}
+	
+	/* finally, build the csr0 value */
+	if (mwi)
+		tp->csr0 |= MWI;
+	tp->csr0 |= (pci_cacheline << BurstLenShift);
+	switch (pci_cacheline) {
+	case 8:  tp->csr0 |= (1 << CALShift);
+	case 16: tp->csr0 |= (2 << CALShift);
+	case 32: tp->csr0 |= (3 << CALShift);
+	}
+
+out:
+	if (tulip_debug > 2)
+		printk(KERN_DEBUG "%s: MWI config mwi=%d, cacheline=%d, csr0=%08x\n",
+		       pdev->slot_name, mwi, pci_cacheline, tp->csr0);
+}
 
 static int __devinit tulip_init_one (struct pci_dev *pdev,
 				     const struct pci_device_id *ent)
@@ -1136,8 +1299,9 @@
 	long ioaddr;
 	static int board_idx = -1;
 	int chip_idx = ent->driver_data;
-	int t2104x_mode = 0;
-	int eeprom_missing = 0;
+	unsigned int t2104x_mode = 0;
+	unsigned int eeprom_missing = 0;
+	unsigned int force_csr0 = 0;
 
 #ifndef MODULE
 	static int did_version;		/* Already printed version info. */
@@ -1183,12 +1347,26 @@
 	   thankfully its an old 486 chipset.
 	*/
 	
-	if (pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82424, NULL))
-		csr0 = 0x00A04800;
+	if (pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82424, NULL)) {
+		csr0 = MRL | MRM | (8 << BurstLenShift) | (1 << CALShift);
+		force_csr0 = 1;
+	}
 	/* The dreaded SiS496 486 chipset. Same workaround as above. */
-	if (pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, NULL))
-		csr0 = 0x00A04800;
+	if (pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, NULL)) {
+		csr0 = MRL | MRM | (8 << BurstLenShift) | (1 << CALShift);
+		force_csr0 = 1;
+	}
 		
+	/* bugfix: the ASIX must have a burst limit or horrible things happen. */
+	if (chip_idx == AX88140) {
+		if ((csr0 & 0x3f00) == 0)
+			csr0 |= 0x2000;
+	}
+	
+	/* PNIC doesn't have MWI/MRL/MRM... */
+	if (chip_idx == LC82C168)
+		csr0 &= ~0xfff10000; /* zero reserved bits 31:20, 16 */
+
 	/*
 	 *	And back to business
 	 */
@@ -1255,13 +1433,8 @@
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
 
-	/* bugfix: the ASIX must have a burst limit or horrible things happen. */
-	if (chip_idx == AX88140) {
-		if ((tp->csr0 & 0x3f00) == 0)
-			tp->csr0 |= 0x2000;
-	}
-	else if (chip_idx == DC21143  &&  chip_rev == 65)
-		tp->csr0 &= ~0x01000000;
+	if (!force_csr0 && (tp->flags & HAS_PCI_MWI))
+		tulip_mwi_config (pdev, dev);
 
 	/* Stop the chip's Tx and Rx processes. */
 	tulip_stop_rxtx(tp, inl(ioaddr + CSR6));
@@ -1373,8 +1546,8 @@
 	if (dev->mem_start & MEDIA_MASK)
 		tp->default_port = dev->mem_start & MEDIA_MASK;
 	if (tp->default_port) {
-		printk(KERN_INFO "%s: Transceiver selection forced to %s.\n",
-		       pdev->slot_name, medianame[tp->default_port & MEDIA_MASK]);
+		printk(KERN_INFO "tulip%d: Transceiver selection forced to %s.\n",
+		       board_idx, medianame[tp->default_port & MEDIA_MASK]);
 		tp->medialock = 1;
 		if (tulip_media_cap[tp->default_port] & MediaAlwaysFD)
 			tp->full_duplex = 1;
@@ -1384,11 +1557,9 @@
 
 	if (tulip_media_cap[tp->default_port] & MediaIsMII) {
 		u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 };
-		tp->to_advertise = media2advert[tp->default_port - 9];
-	} else if (tp->flags & HAS_8023X)
-		tp->to_advertise = 0x05e1;
-	else
-		tp->to_advertise = 0x01e1;
+		tp->mii_advertise = media2advert[tp->default_port - 9];
+		tp->mii_advertise |= (tp->flags & HAS_8023X); /* Matching bits! */
+	}
 
 	if (tp->flags & HAS_MEDIA_TABLE) {
 		memcpy(tp->eeprom, ee_data, sizeof(tp->eeprom));
@@ -1401,55 +1572,21 @@
 	if ((tp->flags & ALWAYS_CHECK_MII) ||
 		(tp->mtable  &&  tp->mtable->has_mii) ||
 		( ! tp->mtable  &&  (tp->flags & HAS_MII))) {
-		int phyn, phy_idx = 0;
 		if (tp->mtable  &&  tp->mtable->has_mii) {
 			for (i = 0; i < tp->mtable->leafcount; i++)
 				if (tp->mtable->mleaf[i].media == 11) {
 					tp->cur_index = i;
 					tp->saved_if_port = dev->if_port;
-					tulip_select_media(dev, 1);
+					tulip_select_media(dev, 2);
 					dev->if_port = tp->saved_if_port;
 					break;
 				}
 		}
+
 		/* Find the connected MII xcvrs.
-		   Doing this in open() would allow detecting external xcvrs later,
-		   but takes much time. */
-		for (phyn = 1; phyn <= 32 && phy_idx < sizeof(tp->phys); phyn++) {
-			int phy = phyn & 0x1f;
-			int mii_status = tulip_mdio_read(dev, phy, 1);
-			if ((mii_status & 0x8301) == 0x8001 ||
-				((mii_status & 0x8000) == 0  && (mii_status & 0x7800) != 0)) {
-				int mii_reg0 = tulip_mdio_read(dev, phy, 0);
-				int mii_advert = tulip_mdio_read(dev, phy, 4);
-				int reg4 = ((mii_status>>6) & tp->to_advertise) | 1;
-				tp->phys[phy_idx] = phy;
-				tp->advertising[phy_idx++] = reg4;
-				printk(KERN_INFO "%s:  MII transceiver #%d "
-					   "config %4.4x status %4.4x advertising %4.4x.\n",
-					   pdev->slot_name, phy, mii_reg0, mii_status, mii_advert);
-				/* Fixup for DLink with miswired PHY. */
-				if (mii_advert != reg4) {
-					printk(KERN_DEBUG "%s:  Advertising %4.4x on PHY %d,"
-						   " previously advertising %4.4x.\n",
-						   pdev->slot_name, reg4, phy, mii_advert);
-					printk(KERN_DEBUG "%s:  Advertising %4.4x (to advertise"
-						   " is %4.4x).\n",
-						   pdev->slot_name, reg4, tp->to_advertise);
-					tulip_mdio_write(dev, phy, 4, reg4);
-				}
-				/* Enable autonegotiation: some boards default to off. */
-				tulip_mdio_write(dev, phy, 0, mii_reg0 |
-						   (tp->full_duplex ? 0x1100 : 0x1000) |
-						   (tulip_media_cap[tp->default_port]&MediaIs100 ? 0x2000:0));
-			}
-		}
-		tp->mii_cnt = phy_idx;
-		if (tp->mtable  &&  tp->mtable->has_mii  &&  phy_idx == 0) {
-			printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n",
-			       pdev->slot_name);
-			tp->phys[0] = 1;
-		}
+		   Doing this in open() would allow detecting external xcvrs
+		   later, but takes much time. */
+		tulip_find_mii (dev, board_idx);
 	}
 
 	/* The Tulip-specific entries in the device structure. */
@@ -1481,18 +1618,21 @@
 
 	if ((tp->flags & HAS_NWAY)  || tp->chip_id == DC21041)
 		tp->link_change = t21142_lnk_change;
+	else if (tp->chip_id == PNIC2)
+		tp->link_change = pnic2_lnk_change;
 	else if (tp->flags & HAS_PNICNWAY)
 		tp->link_change = pnic_lnk_change;
 
 	/* Reset the xcvr interface and turn on heartbeat. */
 	switch (chip_idx) {
 	case DC21041:
-		tp->to_advertise = 0x0061;
+		if (tp->sym_advertise == 0)
+			tp->sym_advertise = 0x0061;
 		outl(0x00000000, ioaddr + CSR13);
 		outl(0xFFFFFFFF, ioaddr + CSR14);
 		outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */
 		tulip_outl_csr(tp, inl(ioaddr + CSR6) | csr6_fd, CSR6);
-		outl(0x0000EF05, ioaddr + CSR13);
+		outl(0x0000EF01, ioaddr + CSR13);
 		break;
 	case DC21040:
 		outl(0x00000000, ioaddr + CSR13);
@@ -1552,7 +1692,6 @@
 err_out_free_res:
 	pci_release_regions (pdev);
 err_out_free_netdev:
-	unregister_netdev (dev);
 	kfree (dev);
 	return -ENODEV;
 }
@@ -1610,7 +1749,7 @@
 
 
 static struct pci_driver tulip_driver = {
-	name:		TULIP_MODULE_NAME,
+	name:		DRV_NAME,
 	id_table:	tulip_pci_tbl,
 	probe:		tulip_init_one,
 	remove:		tulip_remove_one,

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