Module Name:    src
Committed By:   msaitoh
Date:           Wed Dec 12 08:49:33 UTC 2018

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

Log Message:
Add some code for suspend/resume:
- Rename wm_smbustopci() to wm_init_phy_workarounds_pchlan(). It will also
  called when resume.
- Call wm_phy_resetisblocked() after PHY reset in
  wm_init_phy_workarounds_pchlan() to wait for the PHY to quiesce to an
  accessible state.
- Add new wm_resume_workarounds_pchlan() function and use it in wm_resume().
  This workaround is only for PCH2 and newer.
- Don't call wm_disable_aspm() neither in wm_attach() nor in wm_resume()
  but in wm_reset().
- Do some initialization in wm_resume() when IFF_UP is NOT set.
- Don't continue when it failed to acquire semaphore in wm_ulp_disable().
- Add comment.


To generate a diff of this commit:
cvs rdiff -u -r1.12 -r1.13 src/sys/dev/mii/inbmphyreg.h
cvs rdiff -u -r1.602 -r1.603 src/sys/dev/pci/if_wm.c

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/mii/inbmphyreg.h
diff -u src/sys/dev/mii/inbmphyreg.h:1.12 src/sys/dev/mii/inbmphyreg.h:1.13
--- src/sys/dev/mii/inbmphyreg.h:1.12	Thu Nov 22 15:09:45 2018
+++ src/sys/dev/mii/inbmphyreg.h	Wed Dec 12 08:49:33 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: inbmphyreg.h,v 1.12 2018/11/22 15:09:45 msaitoh Exp $	*/
+/*	$NetBSD: inbmphyreg.h,v 1.13 2018/12/12 08:49:33 msaitoh Exp $	*/
 /*******************************************************************************
 Copyright (c) 2001-2005, Intel Corporation 
 All rights reserved.
@@ -126,6 +126,20 @@ POSSIBILITY OF SUCH DAMAGE.
 #define	IGP3_KMRN_DIAG		BME1000_REG(770, 19)
 #define	IGP3_KMRN_DIAG_PCS_LOCK_LOSS	(1 << 1)
 
+#define	I217_LPI_GPIO_CTRL	BME1000_REG(772, 18)
+#define	I217_LPI_GPIO_CTRL_AUTO_EN_LPI	__BIT(11)
+
+#define	I82579_LPI_CTRL		BME1000_REG(772, 20)
+#define	I82579_LPI_CTRL_ENABLE	__BITS(14, 13)
+#define	I82579_LPI_CTRL_EN_100	__BIT(13)
+#define	I82579_LPI_CTRL_EN_1000	__BIT(14)
+
+#define	I217_MEMPWR		BME1000_REG(772, 26)
+#define	I217_MEMPWR_DISABLE_SMB_RELEASE		0x0010
+
+#define	I217_CFGREG		BME1000_REG(772, 29)
+#define I217_CGFREG_ENABLE_MTA_RESET	0x0002
+
 #define HV_MUX_DATA_CTRL	BME1000_REG(776, 16)
 #define HV_MUX_DATA_CTRL_FORCE_SPEED	(1 << 2)
 #define HV_MUX_DATA_CTRL_GEN_TO_MAC	(1 << 10)
@@ -151,4 +165,6 @@ POSSIBILITY OF SUCH DAMAGE.
 #define	BM_WUC_HOST_WU_BIT	(1 << 4)
 #define	BM_WUC_ME_WU_BIT	(1 << 5)
 
+#define	I217_PROXY_CTRL		BME1000_REG(BM_WUC_PAGE, 70)
+#define I217_PROXY_CTRL_AUTO_DISABLE	0x0080
 #endif /* _DEV_MII_INBMPHYREG_H_ */

Index: src/sys/dev/pci/if_wm.c
diff -u src/sys/dev/pci/if_wm.c:1.602 src/sys/dev/pci/if_wm.c:1.603
--- src/sys/dev/pci/if_wm.c:1.602	Wed Nov 28 08:19:19 2018
+++ src/sys/dev/pci/if_wm.c	Wed Dec 12 08:49:33 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wm.c,v 1.602 2018/11/28 08:19:19 msaitoh Exp $	*/
+/*	$NetBSD: if_wm.c,v 1.603 2018/12/12 08:49:33 msaitoh Exp $	*/
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -83,7 +83,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.602 2018/11/28 08:19:19 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.603 2018/12/12 08:49:33 msaitoh Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_net_mpsafe.h"
@@ -723,7 +723,7 @@ static void	wm_init_lcd_from_nvm(struct 
 static int	wm_oem_bits_config_ich8lan(struct wm_softc *, bool);
 static void	wm_initialize_hardware_bits(struct wm_softc *);
 static uint32_t	wm_rxpbs_adjust_82580(uint32_t);
-static void	wm_reset_phy(struct wm_softc *);
+static int	wm_reset_phy(struct wm_softc *);
 static void	wm_flush_desc_rings(struct wm_softc *);
 static void	wm_reset(struct wm_softc *);
 static int	wm_add_rxbuf(struct wm_rxqueue *, int);
@@ -949,7 +949,7 @@ static bool	wm_phy_resetisblocked(struct
 static void	wm_get_hw_control(struct wm_softc *);
 static void	wm_release_hw_control(struct wm_softc *);
 static void	wm_gate_hw_phy_config_ich8lan(struct wm_softc *, bool);
-static void	wm_smbustopci(struct wm_softc *);
+static int	wm_init_phy_workarounds_pchlan(struct wm_softc *);
 static void	wm_init_manageability(struct wm_softc *);
 static void	wm_release_manageability(struct wm_softc *);
 static void	wm_get_wakeup(struct wm_softc *);
@@ -957,6 +957,7 @@ static int	wm_ulp_disable(struct wm_soft
 static void	wm_enable_phy_wakeup(struct wm_softc *);
 static void	wm_igp3_phy_powerdown_workaround_ich8lan(struct wm_softc *);
 static void	wm_suspend_workarounds_ich8lan(struct wm_softc *);
+static int	wm_resume_workarounds_pchlan(struct wm_softc *);
 static void	wm_enable_wakeup(struct wm_softc *);
 static void	wm_disable_aspm(struct wm_softc *);
 /* LPLU (Low Power Link Up) */
@@ -2099,9 +2100,6 @@ alloc_retry:
 		    (sc->sc_flags & WM_F_PCIX) ? "PCIX" : "PCI");
 	}
 
-	/* Disable ASPM L0s and/or L1 for workaround */
-	wm_disable_aspm(sc);
-
 	/* clear interesting stat counters */
 	CSR_READ(sc, WMREG_COLC);
 	CSR_READ(sc, WMREG_RXERRC);
@@ -2978,10 +2976,24 @@ static bool
 wm_resume(device_t self, const pmf_qual_t *qual)
 {
 	struct wm_softc *sc = device_private(self);
+	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
 
-	/* Disable ASPM L0s and/or L1 for workaround */
-	wm_disable_aspm(sc);
-	wm_init_manageability(sc);
+	if (sc->sc_type >= WM_T_PCH2)
+		wm_resume_workarounds_pchlan(sc);
+	if ((ifp->if_flags & IFF_UP) == 0) {
+		wm_reset(sc);
+		/* Non-AMT based hardware can now take control from firmware */
+		if ((sc->sc_flags & WM_F_HAS_AMT) == 0)
+			wm_get_hw_control(sc);
+		wm_init_manageability(sc);
+	} else {
+		/*
+		 * We called pmf_class_network_register(), so if_init() is
+		 * automatically called when IFF_UP. wm_reset(),
+		 * wm_get_hw_control() and wm_init_manageability() are called
+		 * via wm_init().
+		 */
+	}
 
 	return true;
 }
@@ -4365,7 +4377,7 @@ wm_rxpbs_adjust_82580(uint32_t val)
  *	generic PHY reset function.
  *	Same as e1000_phy_hw_reset_generic()
  */
-static void
+static int
 wm_reset_phy(struct wm_softc *sc)
 {
 	uint32_t reg;
@@ -4373,7 +4385,7 @@ wm_reset_phy(struct wm_softc *sc)
 	DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
 		device_xname(sc->sc_dev), __func__));
 	if (wm_phy_resetisblocked(sc))
-		return;
+		return -1;
 
 	sc->phy.acquire(sc);
 
@@ -4392,6 +4404,8 @@ wm_reset_phy(struct wm_softc *sc)
 
 	wm_get_cfg_done(sc);
 	wm_phy_post_reset(sc);
+
+	return 0;
 }
 
 /*
@@ -4893,6 +4907,9 @@ wm_reset(struct wm_softc *sc)
 	if (sc->sc_type >= WM_T_82544)
 		CSR_WRITE(sc, WMREG_WUC, 0);
 
+	if (sc->sc_type < WM_T_82575)
+		wm_disable_aspm(sc);
+
 	wm_reset_mdicnfg_82580(sc);
 
 	if ((sc->sc_flags & WM_F_PLL_WA_I210) != 0)
@@ -9907,7 +9924,7 @@ wm_gmii_mediainit(struct wm_softc *sc, p
 	if ((sc->sc_type == WM_T_PCH) || (sc->sc_type == WM_T_PCH2)
 	    || (sc->sc_type == WM_T_PCH_LPT) || (sc->sc_type == WM_T_PCH_SPT)
 	    || (sc->sc_type == WM_T_PCH_CNP))
-		wm_smbustopci(sc);
+		wm_init_phy_workarounds_pchlan(sc);
 
 	wm_gmii_reset(sc);
 
@@ -13839,8 +13856,8 @@ wm_gate_hw_phy_config_ich8lan(struct wm_
 	CSR_WRITE(sc, WMREG_EXTCNFCTR, reg);
 }
 
-static void
-wm_smbustopci(struct wm_softc *sc)
+static int
+wm_init_phy_workarounds_pchlan(struct wm_softc *sc)
 {
 	uint32_t fwsm, reg;
 	int rv = 0;
@@ -13855,8 +13872,17 @@ wm_smbustopci(struct wm_softc *sc)
 	wm_ulp_disable(sc);
 
 	/* Acquire PHY semaphore */
-	sc->phy.acquire(sc);
+	rv = sc->phy.acquire(sc);
+	if (rv != 0) {
+		DPRINTF(WM_DEBUG_INIT, ("%s: %s: failed\n",
+		device_xname(sc->sc_dev), __func__));
+		return -1;
+	}
 
+	/* The MAC-PHY interconnect may be in SMBus mode.  If the PHY is
+	 * inaccessible and resetting the PHY is not blocked, toggle the
+	 * LANPHYPC Value bit to force the interconnect to PCIe mode.
+	 */
 	fwsm = CSR_READ(sc, WMREG_FWSM);
 	switch (sc->sc_type) {
 	case WM_T_PCH_LPT:
@@ -13865,6 +13891,9 @@ wm_smbustopci(struct wm_softc *sc)
 		if (wm_phy_is_accessible_pchlan(sc))
 			break;
 
+		/* Before toggling LANPHYPC, see if PHY is accessible by
+		 * forcing MAC to SMBus mode first.
+		 */
 		reg = CSR_READ(sc, WMREG_CTRL_EXT);
 		reg |= CTRL_EXT_FORCE_SMBUS;
 		CSR_WRITE(sc, WMREG_CTRL_EXT, reg);
@@ -13872,6 +13901,10 @@ wm_smbustopci(struct wm_softc *sc)
 		/* XXX Isn't this required??? */
 		CSR_WRITE_FLUSH(sc);
 #endif
+		/* Wait 50 milliseconds for MAC to finish any retries
+		 * that it might be trying to perform from previous
+		 * attempts to acknowledge any phy read requests.
+		 */
 		delay(50 * 1000);
 		/* FALLTHROUGH */
 	case WM_T_PCH2:
@@ -13888,12 +13921,16 @@ wm_smbustopci(struct wm_softc *sc)
 			break;
 		}
 
+		/* Toggle LANPHYPC Value bit */
 		wm_toggle_lanphypc_pch_lpt(sc);
 
 		if (sc->sc_type >= WM_T_PCH_LPT) {
 			if (wm_phy_is_accessible_pchlan(sc) == true)
 				break;
 
+			/* Toggling LANPHYPC brings the PHY out of SMBus mode
+			 * so ensure that the MAC is also out of SMBus mode
+			 */
 			reg = CSR_READ(sc, WMREG_CTRL_EXT);
 			reg &= ~CTRL_EXT_FORCE_SMBUS;
 			CSR_WRITE(sc, WMREG_CTRL_EXT, reg);
@@ -13911,23 +13948,38 @@ wm_smbustopci(struct wm_softc *sc)
 	sc->phy.release(sc);
 
 	if (rv == 0) {
+		/* Check to see if able to reset PHY.  Print error if not */
 		if (wm_phy_resetisblocked(sc)) {
 			printf("XXX reset is blocked(4)\n");
 			goto out;
 		}
-		wm_reset_phy(sc);
+
+		/* Reset the PHY before any access to it.  Doing so, ensures
+		 * that the PHY is in a known good state before we read/write
+		 * PHY registers.  The generic reset is sufficient here,
+		 * because we haven't determined the PHY type yet.
+		 */
+		if (wm_reset_phy(sc) != 0)
+			goto out;
+
+		/* On a successful reset, possibly need to wait for the PHY
+		 * to quiesce to an accessible state before returning control
+		 * to the calling function.  If the PHY does not quiesce, then
+		 * return E1000E_BLK_PHY_RESET, as this is the condition that
+		 *  the PHY is in.
+		 */
 		if (wm_phy_resetisblocked(sc))
 			printf("XXX reset is blocked(4)\n");
 	}
 
 out:
-	/*
-	 * Ungate automatic PHY configuration by hardware on non-managed 82579
-	 */
+	/* Ungate automatic PHY configuration on non-managed 82579 */
 	if ((sc->sc_type == WM_T_PCH2) && ((fwsm & FWSM_FW_VALID) == 0)) {
 		delay(10*1000);
 		wm_gate_hw_phy_config_ich8lan(sc, false);
 	}
+
+	return 0;
 }
 
 static void
@@ -14066,7 +14118,12 @@ wm_ulp_disable(struct wm_softc *sc)
 	}
 
 	/* Acquire semaphore */
-	sc->phy.acquire(sc);
+	rv = sc->phy.acquire(sc);
+	if (rv != 0) {
+		DPRINTF(WM_DEBUG_INIT, ("%s: %s: failed\n",
+		device_xname(sc->sc_dev), __func__));
+		goto release;
+	}
 
 	/* Toggle LANPHYPC */
 	wm_toggle_lanphypc_pch_lpt(sc);
@@ -14269,6 +14326,73 @@ out:
 	}
 }
 
+/*
+ *  wm_resume_workarounds_pchlan - workarounds needed during Sx->S0
+ *  @hw: pointer to the HW structure
+ *
+ *  During Sx to S0 transitions on non-managed devices or managed devices
+ *  on which PHY resets are not blocked, if the PHY registers cannot be
+ *  accessed properly by the s/w toggle the LANPHYPC value to power cycle
+ *  the PHY.
+ *  On i217, setup Intel Rapid Start Technology.
+ */
+static int
+wm_resume_workarounds_pchlan(struct wm_softc *sc)
+{
+	device_t dev = sc->sc_dev;
+	int rv;
+
+	if (sc->sc_type < WM_T_PCH2)
+		return 0;
+
+	rv = wm_init_phy_workarounds_pchlan(sc);
+	if (rv != 0)
+		return -1;
+
+	/* For i217 Intel Rapid Start Technology support when the system
+	 * is transitioning from Sx and no manageability engine is present
+	 * configure SMBus to restore on reset, disable proxy, and enable
+	 * the reset on MTA (Multicast table array).
+	 */
+	if (sc->sc_phytype == WMPHY_I217) {
+		uint16_t phy_reg;
+
+		if (sc->phy.acquire(sc) != 0)
+			goto release;
+
+		/* Clear Auto Enable LPI after link up */
+		sc->phy.readreg_locked(dev, 1, I217_LPI_GPIO_CTRL, &phy_reg);
+		phy_reg &= ~I217_LPI_GPIO_CTRL_AUTO_EN_LPI;
+		sc->phy.writereg_locked(dev, 1, I217_LPI_GPIO_CTRL, phy_reg);
+
+		if ((CSR_READ(sc, WMREG_FWSM) & FWSM_FW_VALID) == 0) {
+			/* Restore clear on SMB if no manageability engine
+			 * is present
+			 */
+			sc->phy.readreg_locked(dev, 1, I217_MEMPWR, &phy_reg);
+			if (rv != 0)
+				goto release;
+			phy_reg |= I217_MEMPWR_DISABLE_SMB_RELEASE;
+			sc->phy.writereg_locked(dev, 1, I217_MEMPWR, phy_reg);
+
+			/* Disable Proxy */
+			sc->phy.writereg_locked(dev, 1, I217_PROXY_CTRL, 0);
+		}
+		/* Enable reset on MTA */
+		sc->phy.readreg_locked(dev, 1, I217_CFGREG, &phy_reg);
+		if (rv != 0)
+			goto release;
+		phy_reg &= ~I217_CGFREG_ENABLE_MTA_RESET;
+		sc->phy.writereg_locked(dev, 1, I217_CFGREG, phy_reg);
+
+release:
+		sc->phy.release(sc);
+		return rv;
+	}
+
+	return 0;
+}
+
 static void
 wm_enable_wakeup(struct wm_softc *sc)
 {

Reply via email to