RFC patch to 89K for 21143 w/QS6611 no MII

B. James Phillippe bryan@terran.org
Tue Aug 11 21:11:48 1998


Hello,

	(Let me draw in a deep breath here....)

	I have several generic 21143 ethernet controllers using the Quality
Semiconductor QS6611 PHY chip with no MII tranceiver.  For the last few
days I have been poring over the QS6611 data sheets, the 21143 HRM and any
other scraps of info I could find (the SROM v405 ref, etc).  I've even been
on the phone with Digital and QSI engineers.  All of this research has
pointed me towards one conclusion; without a MII tranceiver this combo
cannot do NWay between 10 and 100Mbp/s; only 10, on the 10BASET port.  I
have only a 10BASET and SYM port using RJ45.  I have also learned that if I
were able to decode the type 2 and 4 infoblocks of the EEPROM, that I might
be able to deduce what the connected media was (though I don't see how this
is possible from the SROM reference).
	Now for an explanation.  When using the tulip.c driver, I was
suffering from some media-detection problems.  These problems were not
present when using davies de4x5.c Linux driver and the stock Windows98
driver on the same equipment.  The tulip.c problems were:

	o When ifconfig up a disconnected interface, the driver quickly
	  reports "negotiation failure" and then tries 100base-Tx.  This
	  also happens after momentarily disconnecting an active 10bT
	  line.
	o Once 100base-Tx has been tried, there is no going back to 10.

The davies driver and Win98 did not suffer from these limitations.  I can
sort of deduce that the davies driver works by forever iterating over the
EEPROM contents, so this must be how it does media detection?  I have no
idea what Win98 does.

Now for the ugly hack I implemented to work around this problem in tulip.c.
Note that this stuff is probably only necessary for poor saps like me with
sucky ethernet equipment; the newer QS6612 apparently does not have this
limitation.  Therefore, this is probably not something that belongs in the
general driver.  However, I would *really* like to get back some commens
from the experts (hopefully Mr. Ethernet, himself ;) as to why this works
and whether or not I'm digging a deep grave with this.  This is a patch
against 89k:

--- tulip.c-orig Fri Aug  7 23:19:36 1998
+++ tulip.c Tue Aug 11 17:38:17 1998
@@ -1754,7 +1754,7 @@
   struct tulip_private *tp = (struct tulip_private *)dev->priv;
   long ioaddr = dev->base_addr;
   int csr12 = inl(ioaddr + CSR12);
-  int next_tick = 60*HZ;
+  int next_tick = 5*HZ;
   int new_csr6 = 0;

   if (tulip_debug > 1)
@@ -1798,6 +1798,10 @@
         }
         next_tick = 60*HZ;
      }
+  } else if ((csr12 & 0xf3c6) == 0x20c6) {
+     if (tulip_debug > 1)
+        printk(KERN_INFO"%s: 21143 no connection detected.\n",
+              dev->name);
   } else if (dev->if_port == 3) {
      if (csr12 & 2) {     /* No 100mbps link beat, revert to 10mbps. */
         new_csr6 = 0x82420200;
@@ -1878,8 +1882,20 @@
      if (!(csr12 & 2))
         printk(KERN_INFO"%s: 21143 100baseTx link beat good.\n",
               dev->name);
-     else
+     else {
+        printk(KERN_INFO"%s: 21143 falling back to 10baseT.\n",
+              dev->name);
         dev->if_port = 0;
+        outl(0, ioaddr + CSR13);
+        tp->csr6 = 0x82420200;
+        outl(0x3ffff, ioaddr + CSR14);
+        outl(0x8, ioaddr + CSR15);
+        outl(0x1, ioaddr + CSR13);
+        outl(0x1301, ioaddr + CSR12);
+        outl(tp->csr6, ioaddr + CSR6);
+        outl(tp->csr6|0x2000, ioaddr + CSR6);
+        outl(tp->csr6|0x2002, ioaddr + CSR6);
+     }
   } else if (dev->if_port == 0) {
      if (!(csr12 & 4))
         printk(KERN_INFO"%s: 21143 10baseT link beat good.\n",
@@ -1898,6 +1914,9 @@
      outl(tp->csr6 | 0x0002, ioaddr + CSR6);
      outl(tp->csr6 | 0x2002, ioaddr + CSR6);
   }
+  
+  /* Clear port activity bits */
+  outl(inl(ioaddr + CSR12)|0x301, ioaddr + CSR12);
 }

 static void mxic_timer(unsigned long data)
@@ -2479,6 +2498,7 @@

   dev->if_port = tp->saved_if_port;

+#ifdef way_too_many_messages
   {
      int i;
      printk("  Rx ring %8.8x: ", (int)tp->rx_ring);
@@ -2489,6 +2509,7 @@
         printk(" %8.8x", (unsigned int)tp->tx_ring[i].status);
      printk("\n");
   }
+#endif

   /* Free all the skbuffs in the Rx queue. */
   for (i = 0; i < RX_RING_SIZE; i++) {

thanks,
-bp
--
B. James Phillippe <bryan@terran.org>
Linux Software Engineer, WGT Inc.
http://earth.terran.org/~bryan