Subject: kern/36576: Fix if_nfe to correctly read in MAC address for MCP6x adapters
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: None <richy@fatkid.org>
List: netbsd-bugs
Date: 06/29/2007 08:15:05
>Number:         36576
>Category:       kern
>Synopsis:       Fix if_nfe to correctly read in MAC address for MCP6x adapters
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Jun 29 08:15:05 +0000 2007
>Originator:     Richy Kim
>Release:        NetBSD 4.99.21 -current at 2007-06-28
>Organization:
>Environment:
>Description:
Not all NVIDIA nForce network adapters, in particular MCP6x, read in the MAC address backwards from non-volatile storage.

The -current if_nfe driver always restores the MAC address backwards -- generally resulting in a bad/invalid tuple. So in turn you get a cycling of random MAC addresses on reboot.

>How-To-Repeat:
The ECS GeForce6100SM-M motherboard was my reference platform.

Observe MAC address cycling between reboots.


>Fix:
Read NFE_MAC_ADDR_INORDER (0x8000) flag in NFE_TX_UNK register and reverse (or not) accordingly as confirmed by nVidia staff on FreeBSD's if_nfe port and Linux's forcedepth driver.

Fix/patch attached inline below:

http://fatkid.org/netbsd/netbsd.nfe_mac.diff

Index: if_nfe.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_nfe.c,v
retrieving revision 1.15
diff -u -r1.15 if_nfe.c
--- if_nfe.c	4 Mar 2007 06:02:22 -0000	1.15
+++ if_nfe.c	29 Jun 2007 03:48:18 -0000
@@ -241,6 +241,10 @@
 
 	sc->sc_dmat = pa->pa_dmat;
 
+	/* Check for reversed ethernet address */
+	if ((NFE_READ(sc, NFE_TX_UNK) & NFE_MAC_ADDR_INORDER) != 0)
+		sc->sc_flags |= NFE_CORRECT_MACADDR;
+
 	nfe_get_macaddr(sc, sc->sc_enaddr);
 	printf("%s: Ethernet address %s\n",
 	    sc->sc_dev.dv_xname, ether_sprintf(sc->sc_enaddr));
@@ -1844,15 +1848,27 @@
 {
 	uint32_t tmp;
 
-	tmp = NFE_READ(sc, NFE_MACADDR_LO);
-	addr[0] = (tmp >> 8) & 0xff;
-	addr[1] = (tmp & 0xff);
-
-	tmp = NFE_READ(sc, NFE_MACADDR_HI);
-	addr[2] = (tmp >> 24) & 0xff;
-	addr[3] = (tmp >> 16) & 0xff;
-	addr[4] = (tmp >>  8) & 0xff;
-	addr[5] = (tmp & 0xff);
+	if ((sc->sc_flags & NFE_CORRECT_MACADDR) == 0) {
+		tmp = NFE_READ(sc, NFE_MACADDR_LO);
+		addr[0] = (tmp >> 8) & 0xff;
+		addr[1] = (tmp & 0xff);
+
+		tmp = NFE_READ(sc, NFE_MACADDR_HI);
+		addr[2] = (tmp >> 24) & 0xff;
+		addr[3] = (tmp >> 16) & 0xff;
+		addr[4] = (tmp >>  8) & 0xff;
+		addr[5] = (tmp & 0xff);
+	} else {
+		tmp = NFE_READ(sc, NFE_MACADDR_LO);
+		addr[5] = (tmp >> 8) & 0xff;
+		addr[4] = (tmp & 0xff);
+
+		tmp = NFE_READ(sc, NFE_MACADDR_HI);
+		addr[3] = (tmp >> 24) & 0xff;
+		addr[2] = (tmp >> 16) & 0xff;
+		addr[1] = (tmp >>  8) & 0xff;
+		addr[0] = (tmp & 0xff);
+	}
 }
 
 void
Index: if_nfereg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_nfereg.h,v
retrieving revision 1.4
diff -u -r1.4 if_nfereg.h
--- if_nfereg.h	28 Feb 2007 17:40:11 -0000	1.4
+++ if_nfereg.h	29 Jun 2007 03:48:18 -0000
@@ -84,6 +84,8 @@
 
 #define NFE_STATUS_MAGIC	0x140000
 
+#define NFE_MAC_ADDR_INORDER	0x8000
+
 #define NFE_R1_MAGIC		0x16070f
 #define NFE_R2_MAGIC		0x16
 #define NFE_R4_MAGIC		0x08
Index: if_nfevar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_nfevar.h,v
retrieving revision 1.2
diff -u -r1.2 if_nfevar.h
--- if_nfevar.h	4 Mar 2007 06:02:22 -0000	1.2
+++ if_nfevar.h	29 Jun 2007 03:48:18 -0000
@@ -79,11 +79,12 @@
 
 	int			sc_if_flags;
 	u_int			sc_flags;
-#define NFE_JUMBO_SUP	0x01
-#define NFE_40BIT_ADDR	0x02
-#define NFE_HW_CSUM	0x04
-#define NFE_HW_VLAN	0x08
-#define NFE_USE_JUMBO	0x10
+#define NFE_JUMBO_SUP		0x01
+#define NFE_40BIT_ADDR		0x02
+#define NFE_HW_CSUM		0x04
+#define NFE_HW_VLAN		0x08
+#define NFE_USE_JUMBO		0x10
+#define NFE_CORRECT_MACADDR	0x20
 
 	uint32_t		rxtxctl;
 	uint8_t			mii_phyaddr;