DORMANTno replies

[PATCH 2.4.27-pre3] pcnet32: fix bogus carrier errors with 79c973

From: Don Fry <hidden>
Date: 2004-05-24 19:35:02

The 79C973 version of the pcnet32 chipset would report all transmit
operations as being sent with a carrier error.  The root cause was
writing reserved bits in bcr33.  It caused the 973 to report xmit
as errors, and caused 975 and 976 to hard hang when reading bcr34.

My thanks to Bruce Penrod for his help in finding the cause of this
bug.
--- linux-2.4.27-pre3/drivers/net/limit.pcnet32.c	Mon May 24 11:35:30 2004
+++ linux-2.4.27-pre3/drivers/net/pcnet32.c	Mon May 24 11:35:41 2004
@@ -22,8 +22,8 @@
  *************************************************************************/
 
 #define DRV_NAME	"pcnet32"
-#define DRV_VERSION	"1.30a"
-#define DRV_RELDATE	"05.22.2004"
+#define DRV_VERSION	"1.30b"
+#define DRV_RELDATE	"05.24.2004"
 #define PFX		DRV_NAME ": "
 
 static const char *version =
@@ -132,7 +132,7 @@
 };
 #define PCNET32_TEST_LEN (sizeof(pcnet32_gstrings_test) / ETH_GSTRING_LEN)
 
-#define PCNET32_NUM_REGS 146
+#define PCNET32_NUM_REGS 168
 
 #define MAX_UNITS 8	/* More are supported, limit only on options */
 static int options[MAX_UNITS];
@@ -242,6 +242,8 @@
  * v1.30   18 May 2004 Don Fry removed timer and Last Transmit Interrupt
  *	   (ltint) as they added complexity and didn't give good throughput.
  * v1.30a  22 May 2004 Don Fry limit frames received during interrupt.
+ * v1.30b  24 May 2004 Don Fry fix bogus tx carrier errors with 79c973,
+ *	   assisted by Bruce Penrod <bmpenrod@endruntechnologies.com>.
  */
 
 
@@ -889,15 +891,25 @@
     for (i=0; i<16; i += 2)
 	*buff++ = inw(ioaddr + i);
 
-    for (i = 0; i <= 89; i++) {
+    /* read control and status registers */
+    for (i=0; i<90; i++) {
 	*buff++ = a->read_csr(ioaddr, i);
     }
 
     *buff++ = a->read_csr(ioaddr, 112);
     *buff++ = a->read_csr(ioaddr, 114);
 
-    for (i = 0; i <= 35; i++) {
-	*buff++ = (i == 34) ? 0xdead : a->read_bcr(ioaddr, i);
+    /* read bus configuration registers */
+    for (i=0; i<36; i++) {
+	*buff++ = a->read_bcr(ioaddr, i);
+    }
+
+    /* read mii phy registers */
+    if (lp->mii) {
+	for (i=0; i<32; i++) {
+	    lp->a.write_bcr(ioaddr, 33, ((lp->mii_if.phy_id) << 5) | i);
+	    *buff++ = lp->a.read_bcr(ioaddr, 34);
+	}
     }
 
     if (!(csr0 & 0x0004)) {	/* If not stopped */
@@ -1750,6 +1762,9 @@
 		    /* There was an major error, log it. */
 		    int err_status = le32_to_cpu(lp->tx_ring[entry].misc);
 		    lp->stats.tx_errors++;
+		    if (netif_msg_tx_err(lp))
+			printk(KERN_ERR "%s: Tx error status=%04x err_status=%08x\n",
+				dev->name, status, err_status);
 		    if (err_status & 0x04000000) lp->stats.tx_aborted_errors++;
 		    if (err_status & 0x08000000) lp->stats.tx_carrier_errors++;
 		    if (err_status & 0x10000000) lp->stats.tx_window_errors++;
@@ -2109,39 +2124,33 @@
     spin_unlock_irqrestore(&lp->lock, flags);
 }
 
+/* This routine assumes that the lp->lock is held */
 static int mdio_read(struct net_device *dev, int phy_id, int reg_num)
 {
     struct pcnet32_private *lp = dev->priv;
     unsigned long ioaddr = dev->base_addr;
     u16 val_out;
-    int phyaddr;
 
     if (!lp->mii)
 	return 0;
 
-    phyaddr = lp->a.read_bcr(ioaddr, 33);
-
     lp->a.write_bcr(ioaddr, 33, ((phy_id & 0x1f) << 5) | (reg_num & 0x1f));
     val_out = lp->a.read_bcr(ioaddr, 34);
-    lp->a.write_bcr(ioaddr, 33, phyaddr);
 
     return val_out;
 }
 
+/* This routine assumes that the lp->lock is held */
 static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val)
 {
     struct pcnet32_private *lp = dev->priv;
     unsigned long ioaddr = dev->base_addr;
-    int phyaddr;
 
     if (!lp->mii)
 	return;
 
-    phyaddr = lp->a.read_bcr(ioaddr, 33);
-
     lp->a.write_bcr(ioaddr, 33, ((phy_id & 0x1f) << 5) | (reg_num & 0x1f));
     lp->a.write_bcr(ioaddr, 34, val);
-    lp->a.write_bcr(ioaddr, 33, phyaddr);
 }
 
 static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-- 
Don Fry
brazilnut@us.ibm.com
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help