patch-2.3.99-pre9 linux/drivers/net/8139too.c

Next file: linux/drivers/net/Config.in
Previous file: linux/drivers/net/3c59x.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.99-pre8/linux/drivers/net/8139too.c linux/drivers/net/8139too.c
@@ -24,6 +24,15 @@
 		Daniel Kobras - identified specific locations of
 			posted MMIO write bugginess
 
+		Gerard Sharp - bug fix
+
+	Submitting bug reports:
+
+		"rtl8139-diag -mmmaaavvveefN" output
+		enable RTL8139_DEBUG below, and look at 'dmesg' or kernel log
+
+		See 8139too.txt for more details.
+
 -----------------------------------------------------------------------------
 
 				Theory of Operation
@@ -88,7 +97,7 @@
 #include <asm/io.h>
 
 
-#define RTL8139_VERSION "0.9.4.1"
+#define RTL8139_VERSION "0.9.5"
 #define RTL8139_MODULE_NAME "8139too"
 #define RTL8139_DRIVER_NAME   RTL8139_MODULE_NAME " Fast Ethernet driver " RTL8139_VERSION
 #define PFX RTL8139_MODULE_NAME ": "
@@ -201,7 +210,7 @@
 /*	{0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MPX5030 },*/
 	{0x1500, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DELTA8139 },
 	{0x4033, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ADDTRON8139 },
-	{0,},
+	{0,}
 };
 MODULE_DEVICE_TABLE (pci, rtl8139_pci_tbl);
 
@@ -304,6 +313,17 @@
 	AcceptAllPhys = 0x01,
 };
 
+/* Bits in TxConfig. */
+enum tx_config_bits {
+	TxIFG1 = (1 << 25),	/* Interframe Gap Time */
+	TxIFG0 = (1 << 24),	/* Enabling these bits violates IEEE 802.3 */
+	TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
+	TxCRC = (1 << 16),	/* DISABLE appending CRC to end of Tx packets */
+	TxClearAbt = (1 << 0),	/* Clear abort (WO) */
+
+	TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
+};
+
 /* Bits in Config1 */
 enum Config1Bits {
 	Cfg1_PM_Enable = 0x01,
@@ -369,28 +389,53 @@
 	dma_addr_t mapping;
 };
 
+
 typedef enum {
 	CH_8139 = 0,
 	CH_8139A,
+	CH_8139A_G,
 	CH_8139B,
+	CH_8130,
+	CH_8139C,
 } chip_t;
 
+
 /* directly indexed by chip_t, above */
 const static struct {
 	const char *name;
+	u32 version; /* from RTL8139C docs */
 	u32 RxConfigMask; /* should clear the bits supported by this chip */
 } rtl_chip_info[] = {
 	{ "RTL-8139",
+	  0x60000000,
 	  0xf0fe0040, /* XXX copied from RTL8139A, verify */
 	},
 	
 	{ "RTL-8139A",
+	  0x70000000,
 	  0xf0fe0040,
 	},
 	
-	{ "RTL-8139B(L)",
+	{ "RTL-8139A rev. G",
+	  0x70800000,
+	  0xf0fe0040,
+	},
+	
+	{ "RTL-8139B",
+	  0x78000000,
 	  0xf0fc0040
 	},
+
+	{ "RTL-8130",
+	  0x7C000000,
+	  0xf0fe0040, /* XXX copied from RTL8139A, verify */
+	},
+
+	{ "RTL-8139C",
+	  0x74000000,
+	  0xf0fc0040, /* XXX copied from RTL8139B, verify */
+	},
+
 };
 
 
@@ -574,12 +619,8 @@
 	
 	/* enable device (incl. PCI PM wakeup), and bus-mastering */
 	rc = pci_enable_device (pdev);
-	if (rc) {
-		printk (KERN_ERR PFX "cannot enable PCI device (bus %d, "
-			"devfn %d), aborting\n",
-			pdev->bus->number, pdev->devfn);
+	if (rc)
 		goto err_out_free_mmio;
-	}
 
 	pci_set_master (pdev);
 
@@ -631,15 +672,20 @@
 	}
 	
 	/* identify chip attached to board */
-	tmp = RTL_R32 (TxConfig);
-	if (((tmp >> 28) & 7) == 7) {
-		if (pio_len == RTL8139B_IO_SIZE)
-			tp->chipset = CH_8139B;
-		else
-			tp->chipset = CH_8139A;
-	} else {
-		tp->chipset = CH_8139;
-	}
+	tmp = RTL_R32 (TxConfig) & TxVersionMask;
+	for (i = arraysize (rtl_chip_info) - 1; i >= 0; i--)
+		if (tmp == rtl_chip_info[i].version) {
+			tp->chipset = i;
+			goto match;
+		}
+
+	/* if unknown chip, assume array element #0, original RTL-8139 in this case */
+	printk (KERN_DEBUG PFX "PCI device %s: unknown chip version, assuming RTL-8139\n",
+		pdev->slot_name);
+	printk (KERN_DEBUG PFX "PCI device %s: TxConfig = 0x%x\n", pdev->slot_name, RTL_R32 (TxConfig));
+	tp->chipset = 0;
+
+match:
 	DPRINTK ("chipset id (%d/%d/%d) == %d, '%s'\n",
 		CH_8139,
 		CH_8139A,
@@ -738,7 +784,7 @@
 
 	tp->phys[0] = 32;
 
-	printk (KERN_INFO "%s: '%s' board found at 0x%lx, IRQ %d\n",
+	printk (KERN_INFO "%s: %s board found at 0x%lx, IRQ %d\n",
 		dev->name, board_info[ent->driver_data].name,
 		dev->base_addr, dev->irq);
 
@@ -1122,6 +1168,7 @@
 	/* Check this value: the documentation for IFG contradicts ifself. */
 	RTL_W32 (TxConfig, (TX_DMA_BURST << 8));
 
+#if 0
 	/* if link status not ok... */
 	if ((RTL_R16 (BasicModeStatus) & (1<<2)) == 0) {
 		printk (KERN_INFO "%s: no link, starting NWay\n", dev->name);
@@ -1144,10 +1191,13 @@
 		/* XXX writing Config1 here is flat out wrong */
 		/* RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); */
 	}
+#endif
 
-	tmp = RTL_R8 (Config1) & Config1Clear;
-	tmp |= (tp->chipset == CH_8139B) ? 3 : 1; /* Enable PM/VPD */
-	RTL_W8_F (Config1, tmp);
+	if (tp->chipset > CH_8139) {
+		tmp = RTL_R8 (Config1) & Config1Clear;
+		tmp |= (tp->chipset == CH_8139B) ? 3 : 1; /* Enable PM/VPD */
+		RTL_W8_F (Config1, tmp);
+	}
 
 	if (tp->chipset == CH_8139B) {
 		tmp = RTL_R8 (Config4) & ~(1<<2);
@@ -1596,13 +1646,19 @@
 			/* A.C.: Reset the multicast list. */
 			rtl8139_set_rx_mode (dev);
 
+			/* XXX potentially temporary hack to
+			 * restart hung receiver */
 			while (--tmp_work > 0) {
-				tmp8 = RTL_R8 (ChipCmd) & ChipCmdClear;
+				tmp8 = RTL_R8 (ChipCmd);
 				if ((tmp8 & CmdRxEnb) && (tmp8 & CmdTxEnb))
 					break;
-				RTL_W8_F (ChipCmd, tmp8 | CmdRxEnb | CmdTxEnb);
+				RTL_W8_F (ChipCmd, (tmp8 & ChipCmdClear) | CmdRxEnb | CmdTxEnb);
 			}
 
+			/* G.S.: Re-enable receiver */
+			/* XXX temporary hack to work around receiver hang */
+			rtl8139_set_rx_mode (dev);
+
 			if (tmp_work <= 0)			
 				printk (KERN_WARNING PFX "tx/rx enable wait too long\n");
 		} else {
@@ -1973,7 +2029,6 @@
 	u32 mc_filter[2];	/* Multicast hash filter */
 	int i, rx_mode;
 	u32 tmp;
-	unsigned long flags=0;
 
 	DPRINTK ("ENTER\n");
 
@@ -2006,7 +2061,7 @@
 	
 	/* if called from irq handler, lock already acquired */
 	if (!in_irq ())
-		spin_lock_irqsave (&tp->lock, flags);
+		spin_lock_irq (&tp->lock);
 
 	/* We can safely update without stopping the chip. */
 	tmp = rtl8139_rx_config | rx_mode |
@@ -2016,7 +2071,7 @@
 	RTL_W32_F (MAR0 + 4, mc_filter[1]);
 
 	if (!in_irq ())
-		spin_unlock_irqrestore (&tp->lock, flags);
+		spin_unlock_irq (&tp->lock);
 
 	DPRINTK ("EXIT\n");
 }

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