Subject: kern/17429: tlp driver is not working with Macronix MX98715AEC-x
To: None <gnats-bugs@gnats.netbsd.org>
From: None <jbernard@mines.edu>
List: netbsd-bugs
Date: 06/28/2002 21:01:10
>Number:         17429
>Category:       kern
>Synopsis:       tlp driver is not working with Macronix MX98715AEC-x
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Jun 28 20:02:00 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator:     Jim Bernard
>Release:        NetBSD 1.6B
>Organization:
>Environment:
System: NetBSD zoo 1.6B NetBSD 1.6B (ZOO-$Revision: 1.76 $) #5: Fri Jun 28 10:22:28 MDT 2002 jim@roc:/wd1/var/tmp/compile/sys/arch/i386/compile/ZOO i386
Architecture: i386
Machine: i386
>Description:
	Changes made to the tlp driver on May 3 (revisions 1.110 -- 1.113
	of sys/dev/ic/tulip.c) caused it to stop working with my Macronix
	MX98715AEC-x based 10/100 ethernet card.  Booting a kernel based
	on sources since that date results in the following behavior:

	  * If ifconfig.tlp0 is set up to permit autonegotiation (just
	    specify "inet" and ip), then after boot ifconfig -m reports:

	      media: Ethernet autoselect (none)
	      status: no carrier

	    The interface is not totally nonfunctional, but ping times
	    (inbound or outbound) are extremely erratic, ranging from
	    a reasonably normal 0.5 ms or so to several seconds.  The
	    data switch shows it thinks the link is configured for
	    100baseTX-FDX.  Nfs mount attempts sometimes claim failure
	    (portmapper failure).  The link is essentially unusable.

	  * If ifconfig.tlp0 is set up to hardwire the interface to
	    100baseTX full duplex, then after boot ifconfig -m reports:

	      media: Ethernet 100baseTX full-duplex
	      status: active

	    and the switch shows the link as 100baseTX-FDX (i.e., the
	    driver and the switch are in apparent agreement).  But ping
	    times are still extremely erratic, and nfs mount attempts
	    are likely to report failure.  The link is just as unusable
	    as in the case where it autonegotiates and claims no carrier.

>How-To-Repeat:
	Try to boot a -current kernel.  Notice network failure.

>Fix:
	Reverting to revision 1.109 of tulip.c, together with retaining
	the changes from revisions 1.114 and 1.115 seems to give good
	results (autonegotiation is prompt and reliable and the link
	appears to work well).  However, that would revert quite a
	number of changes that were evidently deemed useful on some
	hardware.

	A more minimal set of changes reverts one change each from revisions
	1.110, 1.111, and 1.113.  The change reverted from 1.110 is the
	critical one that actually gets things working (the 1-line
	restoration of a use of the TULIP_CLR macro in tlp_2114x_nway_status
	in the third hunk in the patch below), but with that alone, the
	switch claims the link is at half duplex, even though the driver
	thinks full duplex, and the link seems to work normally.  The
	change reverted in 1.111 (in tlp_2114x_nway_tick, appearing in
	the first hunk of the patch below) fixes that disagreement between
	the driver and the switch.  But a change in 1.113 breaks things
	entirely when that change in 1.111 is reverted, so that change
	in 1.113 is also reverted here.  That is in tlp_2114x_nway_auto
	and appears as the second hunk in the patch below.

	I doubt that these changes are optimal, but they get my card working
	again (there is still a noticeable delay at the nfs-mount attempt and
	sometimes a claim of portmapper failure by mount_nfs, but even when
	that happens, the mount always succeeds by the time the system is
	fully up, and the link always works normally, with the driver and
	the switch in agreement about the speed and duplex settings).  This
	was tested with autonegotiation, not with manual media settings.

	I have no idea whether these will cause breakage with other hardware.

--- tulip.c-dist	Tue Jun  4 04:08:41 2002
+++ tulip.c	Fri Jun 28 11:30:53 2002
@@ -5045,17 +5045,29 @@
 tlp_2114x_nway_tick(arg)
 	void *arg;
 {
 	struct tulip_softc *sc = arg;
 	struct mii_data *mii = &sc->sc_mii;
+	uint32_t siastat;
 	int s, ticks;
 
 	if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
 		return;
 
 	s = splnet();
-	tlp_2114x_nway_service(sc, MII_TICK);
+	siastat = TULIP_READ(sc, CSR_SIASTAT);
+	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX &&
+	    (siastat & SIASTAT_LS100) != 0) {
+		sc->sc_flags &= ~TULIPF_LINK_UP;
+		tlp_2114x_nway_service(sc, MII_MEDIACHG);
+	} else if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T &&
+	    (siastat & SIASTAT_LS10) != 0) {
+		sc->sc_flags &= ~TULIPF_LINK_UP;
+		tlp_2114x_nway_service(sc, MII_MEDIACHG);
+	}
+	if ((sc->sc_flags & TULIPF_LINK_UP) == 0)
+		tlp_2114x_nway_service(sc, MII_TICK);
 	if ((sc->sc_flags & TULIPF_LINK_UP) == 0 &&
 	    (mii->mii_media_status & IFM_ACTIVE) != 0 &&
 	    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
 		sc->sc_flags |= TULIPF_LINK_UP;
 		tlp_start(&sc->sc_ethercom.ec_if);
@@ -5156,13 +5168,12 @@
 {
 	uint32_t siastat;
 
 	tlp_idle(sc, OPMODE_ST|OPMODE_SR);
 
-	sc->sc_opmode &= ~(OPMODE_PS|OPMODE_PCS|OPMODE_SCR|OPMODE_TTM);
-	sc->sc_opmode |= OPMODE_FD|OPMODE_HBD;
-	TULIP_WRITE(sc, CSR_OPMODE, sc->sc_opmode);
+	TULIP_CLR(sc, CSR_OPMODE, OPMODE_PS);
+	TULIP_SET(sc, CSR_OPMODE, OPMODE_FD);
 
 	TULIP_WRITE(sc, CSR_SIACONN, 0);
 	delay(1000);
 	TULIP_WRITE(sc, CSR_SIACONN, SIACONN_SRL);
 
@@ -5231,10 +5242,11 @@
 			else if ((siastat & SIASTAT_LS10) == 0)
 				mii->mii_media_active |= IFM_10_T;
 			else
 				mii->mii_media_active |= IFM_NONE;
 		}
+		TULIP_CLR(sc, CSR_SIATXRX, SIATXRX_ANE);
 	} else {
 		if (~siastat & (SIASTAT_LS10 | SIASTAT_LS100))
 			mii->mii_media_status |= IFM_ACTIVE;
 
 		if (sc->sc_opmode & OPMODE_TTM)
>Release-Note:
>Audit-Trail:
>Unformatted:
 		June 28, 2002 sources