netdev
[Top] [All Lists]

[PATCH 2.6.6-bk8] pcnet32: fix bogus carrier errors with 79c973

To: tsbogend@xxxxxxxxxxxxxxxx, jgarzik@xxxxxxxxx, netdev@xxxxxxxxxxx
Subject: [PATCH 2.6.6-bk8] pcnet32: fix bogus carrier errors with 79c973
From: Don Fry <brazilnut@xxxxxxxxxx>
Date: Mon, 24 May 2004 12:33:07 -0700 (PDT)
Sender: netdev-bounce@xxxxxxxxxxx
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.6.6-bk8/drivers/net/limit.pcnet32.c Sat May 22 15:16:50 2004
+++ linux-2.6.6-bk8/drivers/net/pcnet32.c       Mon May 24 11:24:22 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@xxxxxxxxxxxxxxxxxxxxxx>.
  */
 
 
@@ -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 */
@@ -1751,6 +1763,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++;
@@ -2116,39 +2131,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@xxxxxxxxxx

<Prev in Thread] Current Thread [Next in Thread>