Subject: kern/17510: tulip driver fix for 2114[23] autonegotiation failures
To: None <gnats-bugs@gnats.netbsd.org>
From: None <stephen@degler.net>
List: netbsd-bugs
Date: 07/07/2002 15:46:02
>Number:         17510
>Category:       kern
>Synopsis:       tulip driver fix for 2114[23] autonegotiation failures
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Jul 07 12:47:00 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator:     Stephen Degler
>Release:        NetBSD 1.6C
>Organization:
	very little, at best.
>Environment:
	
	
System: NetBSD stand.degler.net 1.6C NetBSD 1.6C (STAND) #8: Sun Jul 7 01:38:29 EDT 2002 sdegler@stand.degler.net:/vol1/kernel/STAND alpha
Architecture: alpha
Machine: alpha
>Description:
	A 4 port Znyx 34X (21143 based) card on a miata (alpha) reports
        negotiating 100BaseTX FDX but sees horrible throughput and collisions.
	This is because CSR13-15 need to be reprogrammed when duplex changes,
	as per data book.  In current driver, only CSR6 gets reprogrammed.

	The included patch fixes this.  It locates the media descriptor found
	by Auto Negotiation  and then calls a routine that will set up the
	chip properly, based on that new descriptor.

	Note that my card is using a SYM srom block and someone with a
	MII interface should test this as well.  The patch was also tested
	on an ADMtek AN985 and it continued to work properly.

	
>How-To-Repeat:

	Bring up netbsd with a 2114[23] based NIC on an NWAY based
	hub/switch and start a large data transfer over the network.
	Ifconfig reports 100BaseTX FDX but interface does not work
	poperly.  Also, collsions are reported on
	the interface with netstat -i.

	
>Fix:
	

Index: tulip.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/ic/tulip.c,v
retrieving revision 1.115
diff -u -r1.115 tulip.c
--- tulip.c	2002/06/01 23:50:59	1.115
+++ tulip.c	2002/07/07 18:35:23
@@ -3934,6 +3934,7 @@
 void	tlp_sia_update_link __P((struct tulip_softc *));
 void	tlp_sia_get __P((struct tulip_softc *, struct ifmediareq *));
 int	tlp_sia_set __P((struct tulip_softc *));
+int	tlp_sia_media __P((struct tulip_softc *, struct ifmedia_entry *));
 void	tlp_sia_fixup __P((struct tulip_softc *));
 
 void
@@ -4075,12 +4076,27 @@
 tlp_sia_set(sc)
 	struct tulip_softc *sc;
 {
+	return(tlp_sia_media(sc,TULIP_CURRENT_MEDIA(sc)));
+}
+
+int
+tlp_sia_media(sc,ife)
+        struct tulip_softc *sc;
 	struct ifmedia_entry *ife;
+{
 	struct tulip_21x4x_media *tm;
 
-	ife = TULIP_CURRENT_MEDIA(sc);
 	tm = ife->ifm_aux;
 
+#ifdef TLP_DEBUG
+	if ( ife->ifm_media != sc->sc_mii.mii_media_active )
+	{
+	    printf("ife->ifmedia is %x, and sc->sc_mii is %x\n",
+		   ife->ifm_media,sc->sc_mii.mii_media_active);
+	}
+	printf("tlp_sia_media: programming for %x\n",ife->ifm_media);
+#endif
+
 	/*
 	 * XXX This appears to be necessary on a bunch of the clone chips.
 	 */
@@ -4098,6 +4114,9 @@
 	TULIP_WRITE(sc, CSR_SIACONN, 0);		/* SRL bit clear */
 	delay(1000);
 
+	sc->sc_opmode = (sc->sc_opmode & ~OPMODE_MEDIA_BITS) | tm->tm_opmode;
+	TULIP_WRITE(sc, CSR_OPMODE, sc->sc_opmode & ~(OPMODE_SR|OPMODE_ST));
+
 	TULIP_WRITE(sc, CSR_SIATXRX, tm->tm_siatxrx);
 
 	switch (sc->sc_chip) {
@@ -4116,7 +4135,6 @@
 	 * Set the OPMODE bits for this media and write OPMODE.
 	 * This will resume the transmit and receive processes.
 	 */
-	sc->sc_opmode = (sc->sc_opmode & ~OPMODE_MEDIA_BITS) | tm->tm_opmode;
 	TULIP_WRITE(sc, CSR_OPMODE, sc->sc_opmode);
 
 	return (0);
@@ -5016,29 +5034,19 @@
 {
 	struct tulip_softc *sc = (struct tulip_softc *)self;
 	struct mii_data *mii = &sc->sc_mii;
+        struct ifmedia_entry *ife;
 
 	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_NONE)
 		return;
-
-	/* Idle the transmit and receive processes. */
-	tlp_idle(sc, OPMODE_ST|OPMODE_SR);
-
-	sc->sc_opmode &= ~(OPMODE_TTM|OPMODE_FD|OPMODE_PS|OPMODE_PCS|
-	    OPMODE_SCR|OPMODE_HBD);
-
-	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T)
-		sc->sc_opmode |= OPMODE_TTM;
-	else
-		sc->sc_opmode |= OPMODE_PS|OPMODE_PCS|OPMODE_SCR|OPMODE_HBD;
-
-	if (mii->mii_media_active & IFM_FDX)
-		sc->sc_opmode |= OPMODE_FD|OPMODE_HBD;
+	
+	if ((ife = ifmedia_match(&mii->mii_media,mii->mii_media_active,mii->mii_media.ifm_mask)) == NULL )
+	{
+	    printf("tlp_2114x_nway_statchg: no match for media 0x%x/0x%x\n",
+		   mii->mii_media_active, ~mii->mii_media.ifm_mask);
+	    panic("tlp_2114x_nway_statchg");
+	}
 
-	/*
-	 * Write new OPMODE bits.  This also restarts the transmit
-	 * and receive processes.
-	 */
-	TULIP_WRITE(sc, CSR_OPMODE, sc->sc_opmode);
+	tlp_sia_media(sc,ife);
 }
 
 void
>Release-Note:
>Audit-Trail:
>Unformatted: