Module Name:    src
Committed By:   msaitoh
Date:           Thu Jan  7 17:45:58 UTC 2010

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

Log Message:
Make wm_reset() and wm_gmii_reset() close to e1000 driver.
At least, this change make wm_attach() be stable on ICH9.


To generate a diff of this commit:
cvs rdiff -u -r1.188 -r1.189 src/sys/dev/pci/if_wm.c
cvs rdiff -u -r1.31 -r1.32 src/sys/dev/pci/if_wmreg.h
cvs rdiff -u -r1.5 -r1.6 src/sys/dev/pci/if_wmvar.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.188 src/sys/dev/pci/if_wm.c:1.189
--- src/sys/dev/pci/if_wm.c:1.188	Thu Jan  7 17:34:38 2010
+++ src/sys/dev/pci/if_wm.c	Thu Jan  7 17:45:58 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wm.c,v 1.188 2010/01/07 17:34:38 msaitoh Exp $	*/
+/*	$NetBSD: if_wm.c,v 1.189 2010/01/07 17:45:58 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.188 2010/01/07 17:34:38 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.189 2010/01/07 17:45:58 msaitoh Exp $");
 
 #include "bpfilter.h"
 #include "rnd.h"
@@ -535,6 +535,8 @@
 static void	wm_attach(device_t, device_t, void *);
 static int	wm_is_onboard_nvm_eeprom(struct wm_softc *);
 static void	wm_get_auto_rd_done(struct wm_softc *);
+static void	wm_lan_init_done(struct wm_softc *);
+static void	wm_get_cfg_done(struct wm_softc *);
 static int	wm_get_swsm_semaphore(struct wm_softc *);
 static void	wm_put_swsm_semaphore(struct wm_softc *);
 static int	wm_poll_eerd_eewr_done(struct wm_softc *, int);
@@ -555,6 +557,7 @@
 static int	wm_check_mng_mode_ich8lan(struct wm_softc *);
 static int	wm_check_mng_mode_82574(struct wm_softc *);
 static int	wm_check_mng_mode_generic(struct wm_softc *);
+static int	wm_check_reset_block(struct wm_softc *);
 static void	wm_get_hw_control(struct wm_softc *);
 static int	wm_check_for_link(struct wm_softc *);
 
@@ -994,6 +997,7 @@
 		break;
 	default:
 		memh_valid = 0;
+		break;
 	}
 
 	if (memh_valid) {
@@ -1171,6 +1175,7 @@
 				    "unknown PCIXSPD %d; assuming 66MHz\n",
 				    reg & STATUS_PCIXSPD_MASK);
 				sc->sc_bus_speed = 66;
+				break;
 			}
 		} else
 			sc->sc_bus_speed = (reg & STATUS_PCI66) ? 66 : 33;
@@ -3013,7 +3018,9 @@
 static void
 wm_reset(struct wm_softc *sc)
 {
-	uint32_t reg;
+	int phy_reset = 0;
+	uint32_t reg, func, mask;
+	int i;
 
 	/*
 	 * Allocate on-chip memory according to the MTU size.
@@ -3074,6 +3081,37 @@
 	/* clear interrupt */
 	CSR_WRITE(sc, WMREG_IMC, 0xffffffffU);
 
+	/* Stop the transmit and receive processes. */
+	CSR_WRITE(sc, WMREG_RCTL, 0);
+	CSR_WRITE(sc, WMREG_TCTL, TCTL_PSP);
+
+	/* set_tbi_sbp_82543() */
+
+	delay(10*1000);
+
+	/* Must acquire the MDIO ownership before MAC reset */
+	switch(sc->sc_type) {
+	case WM_T_82573:
+	case WM_T_82574:
+	case WM_T_82583:
+		i = 0;
+		reg = CSR_READ(sc, WMREG_EXTCNFCTR)
+		    | EXTCNFCTR_MDIO_SW_OWNERSHIP;
+		do {
+			CSR_WRITE(sc, WMREG_EXTCNFCTR,
+			    reg | EXTCNFCTR_MDIO_SW_OWNERSHIP);
+			reg = CSR_READ(sc, WMREG_EXTCNFCTR);
+			if ((reg & EXTCNFCTR_MDIO_SW_OWNERSHIP) != 0)
+				break;
+			reg |= EXTCNFCTR_MDIO_SW_OWNERSHIP;
+			delay(2*1000);
+			i++;
+		} while (i < WM_MDIO_OWNERSHIP_TIMEOUT);
+		break;
+	default:
+		break;
+	}
+
 	/*
 	 * 82541 Errata 29? & 82547 Errata 28?
 	 * See also the description about PHY_RST bit in CTRL register
@@ -3086,12 +3124,11 @@
 	}
 
 	switch (sc->sc_type) {
-	case WM_T_82544:
-	case WM_T_82540:
-	case WM_T_82545:
-	case WM_T_82546:
+	case WM_T_82544: /* XXX check whether WM_F_IOH_VALID is set */
 	case WM_T_82541:
 	case WM_T_82541_2:
+	case WM_T_82547:
+	case WM_T_82547_2:
 		/*
 		 * On some chipsets, a reset through a memory-mapped write
 		 * cycle can cause the chip to reset before completing the
@@ -3108,26 +3145,51 @@
 		else
 			CSR_WRITE(sc, WMREG_CTRL, CTRL_RST);
 		break;
-
 	case WM_T_82545_3:
 	case WM_T_82546_3:
 		/* Use the shadow control register on these chips. */
 		CSR_WRITE(sc, WMREG_CTRL_SHADOW, CTRL_RST);
 		break;
-
+	case WM_T_80003:
+		func = (CSR_READ(sc, WMREG_STATUS) >> STATUS_FUNCID_SHIFT) & 1;
+		mask = func ? SWFW_PHY1_SM : SWFW_PHY0_SM;
+		reg = CSR_READ(sc, WMREG_CTRL) | CTRL_RST;
+		wm_get_swfw_semaphore(sc, mask);
+		CSR_WRITE(sc, WMREG_CTRL, reg);
+		wm_put_swfw_semaphore(sc, mask);
+		break;
 	case WM_T_ICH8:
 	case WM_T_ICH9:
 	case WM_T_ICH10:
+		reg = CSR_READ(sc, WMREG_CTRL) | CTRL_RST;
+		if (wm_check_reset_block(sc) == 0) {
+			reg |= CTRL_PHY_RESET;
+			phy_reset = 1;
+		}
 		wm_get_swfwhw_semaphore(sc);
-		CSR_WRITE(sc, WMREG_CTRL, CTRL_RST | CTRL_PHY_RESET);
-		delay(10000);
+		CSR_WRITE(sc, WMREG_CTRL, reg);
+		delay(20*1000);
+		wm_put_swfwhw_semaphore(sc);
 		break;
+	case WM_T_82542_2_0:
+	case WM_T_82542_2_1:
+	case WM_T_82543:
+	case WM_T_82540:
+	case WM_T_82545:
+	case WM_T_82546:
+	case WM_T_82571:
+	case WM_T_82572:
+	case WM_T_82573:
+	case WM_T_82574:
+	case WM_T_82583:
 	default:
 		/* Everything else can safely use the documented method. */
-		CSR_WRITE(sc, WMREG_CTRL, CTRL_RST);
+		CSR_WRITE(sc, WMREG_CTRL, CSR_READ(sc, WMREG_CTRL) | CTRL_RST);
 		break;
 	}
-	delay(10000);
+
+	if (phy_reset != 0)
+		wm_get_cfg_done(sc);
 
 	/* reload EEPROM */
 	switch(sc->sc_type) {
@@ -3140,12 +3202,23 @@
 		CSR_WRITE(sc, WMREG_CTRL_EXT, reg);
 		delay(2000);
 		break;
+	case WM_T_82540:
+	case WM_T_82545:
+	case WM_T_82545_3:
+	case WM_T_82546:
+	case WM_T_82546_3:
+		delay(5*1000);
+		/* XXX Disable HW ARPs on ASF enabled adapters */
+		break;
 	case WM_T_82541:
 	case WM_T_82541_2:
 	case WM_T_82547:
 	case WM_T_82547_2:
 		delay(20000);
+		/* XXX Disable HW ARPs on ASF enabled adapters */
 		break;
+	case WM_T_82571:
+	case WM_T_82572:
 	case WM_T_82573:
 	case WM_T_82574:
 	case WM_T_82583:
@@ -3154,10 +3227,27 @@
 			reg = CSR_READ(sc, WMREG_CTRL_EXT) | CTRL_EXT_EE_RST;
 			CSR_WRITE(sc, WMREG_CTRL_EXT, reg);
 		}
-		/* FALLTHROUGH */
-	default:
 		/* check EECD_EE_AUTORD */
 		wm_get_auto_rd_done(sc);
+		/*
+		 * Phy configuration from NVM just starts after EECD_AUTO_RD
+		 * is set.
+		 */
+		if ((sc->sc_type == WM_T_82573) || (sc->sc_type == WM_T_82574)
+		    || (sc->sc_type == WM_T_82583))
+			delay(25*1000);
+		break;
+	case WM_T_80003:
+	case WM_T_ICH8:
+	case WM_T_ICH9:
+		/* check EECD_EE_AUTORD */
+		wm_get_auto_rd_done(sc);
+		break;
+	case WM_T_ICH10: /* & PCH */
+		wm_lan_init_done(sc);
+		break;
+	default:
+		panic("%s: unknown type\n", __func__);
 	}
 
 	/* reload sc_ctrl */
@@ -3648,12 +3738,12 @@
 	case WM_T_ICH8:
 	case WM_T_ICH9:
 	case WM_T_ICH10:
-		for (i = 10; i > 0; i--) {
+		for (i = 0; i < 10; i++) {
 			if (CSR_READ(sc, WMREG_EECD) & EECD_EE_AUTORD)
 				break;
 			delay(1000);
 		}
-		if (i == 0) {
+		if (i == 10) {
 			log(LOG_ERR, "%s: auto read from eeprom failed to "
 			    "complete\n", device_xname(sc->sc_dev));
 		}
@@ -3662,11 +3752,95 @@
 		delay(5000);
 		break;
 	}
+}
 
-	/* Phy configuration starts after EECD_AUTO_RD is set */
-	if (sc->sc_type == WM_T_82573 || sc->sc_type == WM_T_82574
-	    || sc->sc_type == WM_T_82574)
-		delay(25000);
+void
+wm_lan_init_done(struct wm_softc *sc)
+{
+	uint32_t reg = 0;
+	int i;
+
+	/* wait for eeprom to reload */
+	switch (sc->sc_type) {
+	case WM_T_ICH10: /* & PCH */
+		for (i = 0; i < WM_ICH8_LAN_INIT_TIMEOUT; i++) {
+			reg = CSR_READ(sc, WMREG_STATUS);
+			if ((reg & STATUS_LAN_INIT_DONE) != 0)
+				break;
+			delay(100);
+		}
+		if (i >= WM_ICH8_LAN_INIT_TIMEOUT) {
+			log(LOG_ERR, "%s: %s: lan_init_done failed to "
+			    "complete\n", device_xname(sc->sc_dev), __func__);
+		}
+		break;
+	default:
+		panic("%s: %s: unknown type\n", device_xname(sc->sc_dev),
+		    __func__);
+		break;
+	}
+
+	reg &= ~STATUS_LAN_INIT_DONE;
+	CSR_WRITE(sc, WMREG_STATUS, reg);
+}
+
+void
+wm_get_cfg_done(struct wm_softc *sc)
+{
+	int func = 0;
+	int mask;
+	int i;
+
+	/* wait for eeprom to reload */
+	switch (sc->sc_type) {
+	case WM_T_82542_2_0:
+	case WM_T_82542_2_1:
+		/* null */
+		break;
+	case WM_T_82543:
+	case WM_T_82544:
+	case WM_T_82540:
+	case WM_T_82545:
+	case WM_T_82545_3:
+	case WM_T_82546:
+	case WM_T_82546_3:
+	case WM_T_82541:
+	case WM_T_82541_2:
+	case WM_T_82547:
+	case WM_T_82547_2:
+	case WM_T_82573:
+	case WM_T_82574:
+	case WM_T_82583:
+		/* generic */
+		delay(10*1000);
+		break;
+	case WM_T_80003:
+	case WM_T_82571:
+	case WM_T_82572:
+	case WM_T_ICH8:
+	case WM_T_ICH9:
+	case WM_T_ICH10:
+		if (sc->sc_type == WM_T_80003)
+			func = (CSR_READ(sc, WMREG_STATUS)
+			    >> STATUS_FUNCID_SHIFT) & 1;
+		else
+			func = 0; /* XXX Is it true for 82571? */
+		mask = (func == 1) ? EEMNGCTL_CFGDONE_1 : EEMNGCTL_CFGDONE_0;
+		for (i = 0; i < WM_PHY_CFG_TIMEOUT; i++) {
+			if (CSR_READ(sc, WMREG_EEMNGCTL) & mask)
+				break;
+			delay(1000);
+		}
+		if (i >= WM_PHY_CFG_TIMEOUT) {
+			DPRINTF(WM_DEBUG_GMII, ("%s: %s failed\n",
+				device_xname(sc->sc_dev), __func__));
+		}
+		break;
+	default:
+		panic("%s: %s: unknown type\n", device_xname(sc->sc_dev),
+		    __func__);
+		break;
+	}
 }
 
 /*
@@ -4523,29 +4697,43 @@
 {
 	uint32_t reg;
 	int func = 0; /* XXX gcc */
+	int rv;
 
-	if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)
-	    || (sc->sc_type == WM_T_ICH10)) {
-		if (wm_get_swfwhw_semaphore(sc)) {
-			aprint_error_dev(sc->sc_dev,
-			    "%s: failed to get semaphore\n", __func__);
-			return;
-		}
-	}
-	if (sc->sc_type == WM_T_80003) {
+	/* get phy semaphore */
+	switch (sc->sc_type) {
+	case WM_T_82571:
+	case WM_T_82572:
+	case WM_T_82573:
+	case WM_T_82574:
+	case WM_T_82583:
+		 /* XXX sould get sw semaphore, too */
+		rv = wm_get_swsm_semaphore(sc);
+		break;
+	case WM_T_80003:
 		func = (CSR_READ(sc, WMREG_STATUS) >> STATUS_FUNCID_SHIFT) & 1;
-		if (wm_get_swfw_semaphore(sc,
-			func ? SWFW_PHY1_SM : SWFW_PHY0_SM)) {
-			aprint_error_dev(sc->sc_dev,
-			    "%s: failed to get semaphore\n", __func__);
-			return;
-		}
+		rv = wm_get_swfw_semaphore(sc,
+		    func ? SWFW_PHY1_SM : SWFW_PHY0_SM);
+		break;
+	case WM_T_ICH8:
+	case WM_T_ICH9:
+	case WM_T_ICH10:
+		rv = wm_get_swfwhw_semaphore(sc);
+		break;
+	default:
+		/* nothing to do*/
+		rv = 0;
+		break;
+	}
+	if (rv != 0) {
+		aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",
+		    __func__);
+		return;
 	}
 
 	switch (sc->sc_type) {
 	case WM_T_82542_2_0:
 	case WM_T_82542_2_1:
-		/* null ? */
+		/* null */
 		break;
 	case WM_T_82543:
 		/*
@@ -4563,9 +4751,6 @@
 		    CTRL_EXT_SWDPIN(4));
 		reg |= CTRL_EXT_SWDPIO(4);
 
-		CSR_WRITE(sc, WMREG_CTRL_EXT, reg | CTRL_EXT_SWDPIN(4));
-		delay(10);
-
 		CSR_WRITE(sc, WMREG_CTRL_EXT, reg);
 		delay(10*1000);
 
@@ -4574,7 +4759,7 @@
 #if 0
 		sc->sc_ctrl_ext = reg | CTRL_EXT_SWDPIN(4);
 #endif
-		delay(20*1000);	/* extra delay to get PHY ID? */
+		delay(20*1000);	/* XXX extra delay to get PHY ID? */
 		break;
 	case WM_T_82544:	/* reset 10000us */
 	case WM_T_82540:
@@ -4621,15 +4806,72 @@
 		/* XXX add code to set LED after phy reset */
 		break;
 	default:
-		panic("unknown sc_type\n");
+		panic("%s: %s: unknown type\n", device_xname(sc->sc_dev),
+		    __func__);
 		break;
 	}
 
-	if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)
-	    || (sc->sc_type == WM_T_ICH10))
-		wm_put_swfwhw_semaphore(sc);
-	if (sc->sc_type == WM_T_80003)
+	/* release PHY semaphore */
+	switch (sc->sc_type) {
+	case WM_T_82571:
+	case WM_T_82572:
+	case WM_T_82573:
+	case WM_T_82574:
+	case WM_T_82583:
+		 /* XXX sould put sw semaphore, too */
+		wm_put_swsm_semaphore(sc);
+		break;
+	case WM_T_80003:
 		wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM);
+		break;
+	case WM_T_ICH8:
+	case WM_T_ICH9:
+	case WM_T_ICH10:
+		wm_put_swfwhw_semaphore(sc);
+		break;
+	default:
+		/* nothing to do*/
+		rv = 0;
+		break;
+	}
+
+	/* get_cfg_done */
+	wm_get_cfg_done(sc);
+
+	/* extra setup */
+	switch (sc->sc_type) {
+	case WM_T_82542_2_0:
+	case WM_T_82542_2_1:
+	case WM_T_82543:
+	case WM_T_82544:
+	case WM_T_82540:
+	case WM_T_82545:
+	case WM_T_82545_3:
+	case WM_T_82546:
+	case WM_T_82546_3:
+	case WM_T_82541_2:
+	case WM_T_82547_2:
+	case WM_T_82571:
+	case WM_T_82572:
+	case WM_T_82573:
+	case WM_T_82574:
+	case WM_T_82583:
+	case WM_T_80003:
+		/* null */
+		break;
+	case WM_T_82541:
+	case WM_T_82547:
+		/* XXX Configure actively LED after PHY reset */
+		break;
+	case WM_T_ICH8:
+	case WM_T_ICH9:
+	case WM_T_ICH10:
+		delay(10*1000);
+		break;
+	default:
+		panic("%s: unknown type\n", __func__);
+		break;
+	}
 }
 
 /*
@@ -5734,6 +5976,41 @@
 	return 0;
 }
 
+static int
+wm_check_reset_block(struct wm_softc *sc)
+{
+	uint32_t reg;
+
+	switch (sc->sc_type) {
+	case WM_T_ICH8:
+	case WM_T_ICH9:
+	case WM_T_ICH10:
+		reg = CSR_READ(sc, WMREG_FWSM);
+		if ((reg & FWSM_RSPCIPHY) != 0)
+			return 0;
+		else
+			return -1;
+		break;
+	case WM_T_82571:
+	case WM_T_82572:
+	case WM_T_82573:
+	case WM_T_82574:
+	case WM_T_82583:
+	case WM_T_80003:
+		reg = CSR_READ(sc, WMREG_MANC);
+		if ((reg & MANC_BLK_PHY_RST_ON_IDE) != 0)
+			return -1;
+		else
+			return 0;
+		break;
+	default:
+		/* no problem */
+		break;
+	}
+
+	return 0;
+}
+
 static void
 wm_get_hw_control(struct wm_softc *sc)
 {

Index: src/sys/dev/pci/if_wmreg.h
diff -u src/sys/dev/pci/if_wmreg.h:1.31 src/sys/dev/pci/if_wmreg.h:1.32
--- src/sys/dev/pci/if_wmreg.h:1.31	Thu Jan  7 17:34:38 2010
+++ src/sys/dev/pci/if_wmreg.h	Thu Jan  7 17:45:58 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wmreg.h,v 1.31 2010/01/07 17:34:38 msaitoh Exp $	*/
+/*	$NetBSD: if_wmreg.h,v 1.32 2010/01/07 17:45:58 msaitoh Exp $	*/
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -220,6 +220,7 @@
 #define	STATUS_SPEED_100  STATUS_SPEED(1)
 #define	STATUS_SPEED_1000 STATUS_SPEED(2)
 #define	STATUS_ASDV(x)	((x) << 8)	/* auto speed det. val. (Livengood) */
+#define	STATUS_LAN_INIT_DONE (1U << 9)	/* Lan Init Completion by NVM */
 #define	STATUS_MTXCKOK	(1U << 10)	/* MTXD clock running */
 #define	STATUS_PCI66	(1U << 11)	/* 66MHz bus (Livengood) */
 #define	STATUS_BUS64	(1U << 12)	/* 64-bit bus (Livengood) */
@@ -612,6 +613,10 @@
 
 #define	WMREG_PBS	0x1008	/* Packet Buffer Size (ICH) */
 
+#define WMREG_EEMNGCTL	0x1010	/* MNG EEprom Control */
+#define EEMNGCTL_CFGDONE_0 0x040000	/* MNG config cycle done */
+#define EEMNGCTL_CFGDONE_1 0x080000	/*  2nd port */
+
 #define	WMREG_TXDMAC	0x3000	/* Transfer DMA Control */
 #define	TXDMAC_DPP	(1U << 0)	/* disable packet prefetch */
 
@@ -670,7 +675,10 @@
 
 #define	WMREG_MDPHYA	0x003C	/* PHY address - RW */
 
-#define	WMREG_MANC2H	0x5860	/* Managment Control To Host - RW */
+#define	WMREG_MANC	0x5820	/* Management Control */
+#define	MANC_BLK_PHY_RST_ON_IDE	0x00040000
+
+#define	WMREG_MANC2H	0x5860	/* Manaegment Control To Host - RW */
 
 #define	WMREG_SWSM	0x5b50	/* SW Semaphore */
 #define	SWSM_SMBI	0x00000001	/* Driver Semaphore bit */
@@ -683,6 +691,7 @@
 #define	FWSM_MODE_SHIFT		0x1
 #define	MNG_ICH_IAMT_MODE	0x2
 #define	MNG_IAMT_MODE		0x3
+#define FWSM_RSPCIPHY	0x00000040	/* Reset PHY on PCI reset */
 
 #define	WMREG_SW_FW_SYNC 0x5b5c	/* software-firmware semaphore */
 #define	SWFW_EEP_SM		0x0001 /* eeprom access */

Index: src/sys/dev/pci/if_wmvar.h
diff -u src/sys/dev/pci/if_wmvar.h:1.5 src/sys/dev/pci/if_wmvar.h:1.6
--- src/sys/dev/pci/if_wmvar.h:1.5	Tue Dec 29 16:01:21 2009
+++ src/sys/dev/pci/if_wmvar.h	Thu Jan  7 17:45:58 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wmvar.h,v 1.5 2009/12/29 16:01:21 msaitoh Exp $	*/
+/*	$NetBSD: if_wmvar.h,v 1.6 2010/01/07 17:45:58 msaitoh Exp $	*/
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -113,4 +113,8 @@
 	WM_T_ICH10,			/* ICH10 LAN */
 } wm_chip_type;
 
+#define WM_PHY_CFG_TIMEOUT	100
+#define	WM_ICH8_LAN_INIT_TIMEOUT 1500
+#define	WM_MDIO_OWNERSHIP_TIMEOUT 10
+
 #endif /* _DEV_PCI_IF_WMVAR_H_ */

Reply via email to