Module Name:    src
Committed By:   msaitoh
Date:           Fri Jun 25 04:03:14 UTC 2010

Modified Files:
        src/sys/dev/pci: if_wm.c if_wmreg.h

Log Message:
Add some code to support 82580[ER]. Tested on my own I340-T4.

 - Fix CTRL_EXT_SWDPIN() and CTRL_EXT_SWDPIO() macros. The bit order of the
   SW definable pin is not 6543 but 3654!!!

 - Rewrite the code to read MAC address from eeprom.

 - Add some code to support 82580.

TODO:
 - ukphy -> somephy


To generate a diff of this commit:
cvs rdiff -u -r1.207 -r1.208 src/sys/dev/pci/if_wm.c
cvs rdiff -u -r1.41 -r1.42 src/sys/dev/pci/if_wmreg.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/if_wm.c
diff -u src/sys/dev/pci/if_wm.c:1.207 src/sys/dev/pci/if_wm.c:1.208
--- src/sys/dev/pci/if_wm.c:1.207	Tue May 25 01:17:55 2010
+++ src/sys/dev/pci/if_wm.c	Fri Jun 25 04:03:14 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wm.c,v 1.207 2010/05/25 01:17:55 msaitoh Exp $	*/
+/*	$NetBSD: if_wm.c,v 1.208 2010/06/25 04:03:14 msaitoh Exp $	*/
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -76,7 +76,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.207 2010/05/25 01:17:55 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.208 2010/06/25 04:03:14 msaitoh Exp $");
 
 #include "rnd.h"
 
@@ -510,6 +510,7 @@
 static int	wm_read_eeprom(struct wm_softc *, int, int, u_int16_t *);
 static int	wm_read_eeprom_eerd(struct wm_softc *, int, int, u_int16_t *);
 static int	wm_validate_eeprom_checksum(struct wm_softc *);
+static int	wm_read_mac_addr(struct wm_softc *, uint8_t *);
 static void	wm_tick(void *);
 
 static void	wm_set_filter(struct wm_softc *);
@@ -1098,7 +1099,7 @@
 	prop_data_t ea;
 	prop_number_t pn;
 	uint8_t enaddr[ETHER_ADDR_LEN];
-	uint16_t myea[ETHER_ADDR_LEN / 2], cfg1, cfg2, swdpin, io3;
+	uint16_t cfg1, cfg2, swdpin, io3;
 	pcireg_t preg, memtype;
 	uint16_t eeprom_data, apme_mask;
 	uint32_t reg;
@@ -1246,7 +1247,8 @@
 	 */
 	if ((sc->sc_type == WM_T_82546) || (sc->sc_type == WM_T_82546_3)
 	    || (sc->sc_type ==  WM_T_82571) || (sc->sc_type == WM_T_80003)
-	    || (sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576))
+	    || (sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576)
+	    || (sc->sc_type == WM_T_82580) || (sc->sc_type == WM_T_82580ER))
 		sc->sc_funcid = (CSR_READ(sc, WMREG_STATUS)
 		    >> STATUS_FUNCID_SHIFT) & STATUS_FUNCID_MASK;
 	else
@@ -1605,29 +1607,10 @@
 		KASSERT(prop_data_size(ea) == ETHER_ADDR_LEN);
 		memcpy(enaddr, prop_data_data_nocopy(ea), ETHER_ADDR_LEN);
 	} else {
-		if (wm_read_eeprom(sc, EEPROM_OFF_MACADDR,
-		    sizeof(myea) / sizeof(myea[0]), myea)) {
+		if (wm_read_mac_addr(sc, enaddr) != 0)
 			aprint_error_dev(sc->sc_dev,
 			    "unable to read Ethernet address\n");
-			return;
-		}
-		enaddr[0] = myea[0] & 0xff;
-		enaddr[1] = myea[0] >> 8;
-		enaddr[2] = myea[1] & 0xff;
-		enaddr[3] = myea[1] >> 8;
-		enaddr[4] = myea[2] & 0xff;
-		enaddr[5] = myea[2] >> 8;
-	}
-
-	/*
-	 * Toggle the LSB of the MAC address on the second port
-	 * of the dual port controller.
-	 */
-	if ((sc->sc_type == WM_T_82546) || (sc->sc_type == WM_T_82546_3)
-	    || (sc->sc_type ==  WM_T_82571) || (sc->sc_type == WM_T_80003)
-	    || (sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576)) {
-		if (sc->sc_funcid == 1)
-			enaddr[5] ^= 1;
+		return;
 	}
 
 	aprint_normal_dev(sc->sc_dev, "Ethernet address %s\n",
@@ -3595,6 +3578,8 @@
 	case WM_T_82574:
 	case WM_T_82575:
 	case WM_T_82576:
+	case WM_T_82580:
+	case WM_T_82580ER:
 	case WM_T_82583:
 	default:
 		/* Everything else can safely use the documented method. */
@@ -3653,6 +3638,8 @@
 		break;
 	case WM_T_82575:
 	case WM_T_82576:
+	case WM_T_82580:
+	case WM_T_82580ER:
 	case WM_T_80003:
 	case WM_T_ICH8:
 	case WM_T_ICH9:
@@ -3671,13 +3658,19 @@
 	switch (sc->sc_type) {
 	case WM_T_82575:
 	case WM_T_82576:
+#if 0 /* XXX */
 	case WM_T_82580:
+	case WM_T_82580ER:
+#endif
 	case WM_T_ICH8:
 	case WM_T_ICH9:
 		if ((CSR_READ(sc, WMREG_EECD) & EECD_EE_PRES) == 0) {
 			/* Not found */
 			sc->sc_flags |= WM_F_EEPROM_INVALID;
-			if (sc->sc_type == WM_T_82575) /* 82575 only */
+			if ((sc->sc_type == WM_T_82575)
+			    || (sc->sc_type == WM_T_82576)
+			    || (sc->sc_type == WM_T_82580)
+			    || (sc->sc_type == WM_T_82580ER))
 				wm_reset_init_script_82575(sc);
 		}
 		break;
@@ -3685,6 +3678,11 @@
 		break;
 	}
 
+	if ((sc->sc_type == WM_T_82580) || (sc->sc_type == WM_T_82580ER)) {
+		/* clear global device reset status bit */
+		CSR_WRITE(sc, WMREG_STATUS, STATUS_DEV_RST_SET);
+	}
+
 	/* Clear any pending interrupt events. */
 	CSR_WRITE(sc, WMREG_IMC, 0xffffffffU);
 	reg = CSR_READ(sc, WMREG_ICR);
@@ -4224,6 +4222,8 @@
 	case WM_T_82583:
 	case WM_T_82575:
 	case WM_T_82576:
+	case WM_T_82580:
+	case WM_T_82580ER:
 	case WM_T_80003:
 	case WM_T_ICH8:
 	case WM_T_ICH9:
@@ -4309,6 +4309,7 @@
 	case WM_T_82575:
 	case WM_T_82576:
 	case WM_T_82580:
+	case WM_T_82580ER:
 		mask = EEMNGCTL_CFGDONE_0 << sc->sc_funcid;
 		for (i = 0; i < WM_PHY_CFG_TIMEOUT; i++) {
 			if (CSR_READ(sc, WMREG_EEMNGCTL) & mask)
@@ -4692,6 +4693,101 @@
 	return done;
 }
 
+static int
+wm_read_mac_addr(struct wm_softc *sc, uint8_t *enaddr)
+{
+	uint16_t myea[ETHER_ADDR_LEN / 2];
+	uint16_t offset;
+	int do_invert = 0;
+
+	if (sc->sc_funcid == 0)
+		offset = EEPROM_OFF_MACADDR;
+	else {
+		switch (sc->sc_type) {
+		case WM_T_82580:
+		case WM_T_82580ER:
+			switch (sc->sc_funcid) {
+			case 1:
+				offset = EEPROM_OFF_LAN1;
+				break;
+			case 2:
+				offset = EEPROM_OFF_LAN2;
+				break;
+			case 3:
+				offset = EEPROM_OFF_LAN3;
+				break;
+			default:
+				goto bad;
+				/* NOTREACHED */
+				break;
+			}
+			break;
+		case WM_T_82571:
+		case WM_T_82575:
+		case WM_T_82576:
+		case WM_T_80003:
+			if (wm_read_eeprom(sc, EEPROM_ALT_MAC_ADDR_PTR, 1,
+				&offset) != 0) {
+				goto bad;
+			}
+
+			/* no pointer */
+			if (offset == 0xffff) {
+				/* reset the offset to LAN0 */
+				offset = EEPROM_OFF_MACADDR;
+				do_invert = 1;
+				goto do_read;
+			}
+
+			switch (sc->sc_funcid) {
+			case 1:
+				offset += EEPROM_OFF_MACADDR_LAN1;
+				break;
+			case 2:
+				offset += EEPROM_OFF_MACADDR_LAN2;
+				break;
+			case 3:
+				offset += EEPROM_OFF_MACADDR_LAN3;
+				break;
+			default:
+				goto bad;
+				/* NOTREACHED */
+				break;
+			}
+			break;
+		default:
+			do_invert = 1;
+			break;
+		}
+	}
+ do_read:
+	if (wm_read_eeprom(sc, offset, sizeof(myea) / sizeof(myea[0]),
+		myea) != 0) {
+		goto bad;
+	}
+
+	enaddr[0] = myea[0] & 0xff;
+	enaddr[1] = myea[0] >> 8;
+	enaddr[2] = myea[1] & 0xff;
+	enaddr[3] = myea[1] >> 8;
+	enaddr[4] = myea[2] & 0xff;
+	enaddr[5] = myea[2] >> 8;
+
+	/*
+	 * Toggle the LSB of the MAC address on the second port
+	 * of some dual port cards.
+	 */
+	if (do_invert != 0)
+		enaddr[5] ^= 1;
+
+	return 0;
+
+ bad:
+	aprint_error_dev(sc->sc_dev, "unable to read Ethernet address\n");
+
+	return -1;
+}
+
 /*
  * wm_add_rxbuf:
  *
@@ -5494,8 +5590,35 @@
 	ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK, wm_gmii_mediachange,
 	    wm_gmii_mediastatus);
 
-	mii_attach(sc->sc_dev, &sc->sc_mii, 0xffffffff, MII_PHY_ANY,
-	    MII_OFFSET_ANY, MIIF_DOPAUSE);
+	if ((sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576)
+	    || (sc->sc_type == WM_T_82580) || (sc->sc_type == WM_T_82580ER)) {
+		if ((sc->sc_flags & WM_F_SGMII) == 0) {
+			/* Attach only one port */
+			mii_attach(sc->sc_dev, &sc->sc_mii, 0xffffffff, 1,
+			    MII_OFFSET_ANY, MIIF_DOPAUSE);
+		} else {
+			int i;
+			uint32_t ctrl_ext;
+
+			/* Power on sgmii phy if it is disabled */
+			ctrl_ext = CSR_READ(sc, WMREG_CTRL_EXT);
+			CSR_WRITE(sc, WMREG_CTRL_EXT,
+			    ctrl_ext &~ CTRL_EXT_SWDPIN(3));
+			CSR_WRITE_FLUSH(sc);
+			delay(300*1000); /* XXX too long */
+
+			/* from 1 to 8 */
+			for (i = 1; i < 8; i++)
+				mii_attach(sc->sc_dev, &sc->sc_mii, 0xffffffff,
+				    i, MII_OFFSET_ANY, MIIF_DOPAUSE);
+
+			/* restore previous sfp cage power state */
+			CSR_WRITE(sc, WMREG_CTRL_EXT, ctrl_ext);
+		}
+	} else {
+		mii_attach(sc->sc_dev, &sc->sc_mii, 0xffffffff, MII_PHY_ANY,
+		    MII_OFFSET_ANY, MIIF_DOPAUSE);
+	}
 
 	if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
 		/* if failed, retry with *_bm_* */
@@ -7290,6 +7413,10 @@
 	case WM_T_82574:
 	case WM_T_82575:
 	case WM_T_82576:
+#if 0 /* XXX */
+	case WM_T_82580:
+	case WM_T_82580ER:
+#endif
 		if ((CSR_READ(sc, WMREG_FWSM) & FWSM_MODE_MASK) != 0)
 			sc->sc_flags |= WM_F_ARC_SUBSYS_VALID;
 		sc->sc_flags |= WM_F_ASF_FIRMWARE_PRES;

Index: src/sys/dev/pci/if_wmreg.h
diff -u src/sys/dev/pci/if_wmreg.h:1.41 src/sys/dev/pci/if_wmreg.h:1.42
--- src/sys/dev/pci/if_wmreg.h:1.41	Fri Jun 25 03:47:57 2010
+++ src/sys/dev/pci/if_wmreg.h	Fri Jun 25 04:03:14 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wmreg.h,v 1.41 2010/06/25 03:47:57 msaitoh Exp $	*/
+/*	$NetBSD: if_wmreg.h,v 1.42 2010/06/25 04:03:14 msaitoh Exp $	*/
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -232,6 +232,7 @@
 #define	STATUS_PCIXSPD_100_133 STATUS_PCIXSPD(2)
 #define	STATUS_PCIXSPD_MASK    STATUS_PCIXSPD(3)
 #define	STATUS_GIO_M_ENA (1U << 19)	/* GIO master enable */
+#define	STATUS_DEV_RST_SET (1U << 20)	/* Device Reset Set */
 
 #define	WMREG_EECD	0x0010	/* EEPROM Control Register */
 #define	EECD_SK		(1U << 0)	/* clock */
@@ -280,6 +281,7 @@
 #define	EEPROM_OFF_K1_CONFIG	0x1b	/* NVM K1 Config */
 #define	EEPROM_OFF_SWDPIN	0x20	/* SWD Pins (Cordova) */
 #define	EEPROM_OFF_CFG3_PORTA	0x24	/* config word 3 */
+#define EEPROM_ALT_MAC_ADDR_PTR	0x37	/* to the alternative MAC addresses */
 
 #define	EEPROM_CFG1_LVDID	(1U << 0)
 #define	EEPROM_CFG1_LSSID	(1U << 1)
@@ -323,6 +325,18 @@
 
 #define EEPROM_CFG3_APME	(1U << 10)	
 
+#define	EEPROM_OFF_MACADDR_LAN1	3	/* macaddr offset from PTR (port 1) */
+#define	EEPROM_OFF_MACADDR_LAN2	6	/* macaddr offset from PTR (port 2) */
+#define	EEPROM_OFF_MACADDR_LAN3	9	/* macaddr offset from PTR (port 3) */
+
+/*
+ * EEPROM Partitioning. See Table 6-1, "EEPROM Top Level Partitioning"
+ * in 82580's datasheet.
+ */
+#define EEPROM_OFF_LAN1	0x0080	/* Offset for LAN1 (82580)*/
+#define EEPROM_OFF_LAN2	0x00c0	/* Offset for LAN1 (82580)*/
+#define EEPROM_OFF_LAN3	0x0100	/* Offset for LAN1 (82580)*/
+
 #define	WMREG_EERD	0x0014	/* EEPROM read */
 #define	EERD_DONE	0x02    /* done bit */
 #define	EERD_START	0x01	/* First bit for telling part to start operation */
@@ -333,10 +347,13 @@
 #define	CTRL_EXT_GPI_EN(x)	(1U << (x)) /* gpin interrupt enable */
 #define	CTRL_EXT_SWDPINS_SHIFT	4
 #define	CTRL_EXT_SWDPINS_MASK	0x0d
-#define	CTRL_EXT_SWDPIN(x)	(1U << (CTRL_EXT_SWDPINS_SHIFT + (x) - 4))
+/* The bit order of the SW Definable pin is not 6543 but 3654! */
+#define	CTRL_EXT_SWDPIN(x)	(1U << (CTRL_EXT_SWDPINS_SHIFT \
+		+ ((x) == 3 ? 3 : ((x) - 4))))
 #define	CTRL_EXT_SWDPIO_SHIFT	8
 #define	CTRL_EXT_SWDPIO_MASK	0x0d
-#define	CTRL_EXT_SWDPIO(x)	(1U << (CTRL_EXT_SWDPIO_SHIFT + (x) - 4))
+#define	CTRL_EXT_SWDPIO(x)	(1U << (CTRL_EXT_SWDPIO_SHIFT \
+		+ ((x) == 3 ? 3 : ((x) - 4))))
 #define	CTRL_EXT_ASDCHK		(1U << 12) /* ASD check */
 #define	CTRL_EXT_EE_RST		(1U << 13) /* EEPROM reset */
 #define	CTRL_EXT_IPS		(1U << 14) /* invert power state bit 0 */

Reply via email to