Module Name:    src
Committed By:   msaitoh
Date:           Thu Dec 20 09:32:13 UTC 2018

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

Log Message:
- Don't setup WoL on non-WoL capable port.
- Setup PHY wakeup feature on PCH and newer. Tested on Thinkpad X220.


To generate a diff of this commit:
cvs rdiff -u -r1.14 -r1.15 src/sys/dev/mii/inbmphyreg.h
cvs rdiff -u -r1.609 -r1.610 src/sys/dev/pci/if_wm.c
cvs rdiff -u -r1.110 -r1.111 src/sys/dev/pci/if_wmreg.h
cvs rdiff -u -r1.40 -r1.41 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/mii/inbmphyreg.h
diff -u src/sys/dev/mii/inbmphyreg.h:1.14 src/sys/dev/mii/inbmphyreg.h:1.15
--- src/sys/dev/mii/inbmphyreg.h:1.14	Thu Dec 13 05:22:44 2018
+++ src/sys/dev/mii/inbmphyreg.h	Thu Dec 20 09:32:12 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: inbmphyreg.h,v 1.14 2018/12/13 05:22:44 msaitoh Exp $	*/
+/*	$NetBSD: inbmphyreg.h,v 1.15 2018/12/20 09:32:12 msaitoh Exp $	*/
 /*******************************************************************************
 Copyright (c) 2001-2015, Intel Corporation 
 All rights reserved.
@@ -160,6 +160,16 @@ POSSIBILITY OF SUCH DAMAGE.
 #define I218_ULP_CONFIG1_DIS_SMB_PERST	__BIT(12)
 
 #define	BM_WUC_PAGE		800
+
+#define	BM_RCTL			BME1000_REG(BM_WUC_PAGE, 0)
+#define BM_RCTL_UPE		0x0001 /* Unicast Promiscuous Mode */
+#define BM_RCTL_MPE		0x0002 /* Multicast Promiscuous Mode */
+#define BM_RCTL_MO_SHIFT	3      /* Multicast Offset Shift */
+#define BM_RCTL_MO_MASK		(3 << 3) /* Multicast Offset Mask */
+#define BM_RCTL_BAM		0x0020 /* Broadcast Accept Mode */
+#define BM_RCTL_PMCF		0x0040 /* Pass MAC Control Frames */
+#define BM_RCTL_RFCE		0x0080 /* Rx Flow Control Enable */
+
 #define	BM_WUC			BME1000_REG(BM_WUC_PAGE, 1)
 #define	BM_WUC_ADDRESS_OPCODE	0x11
 #define	BM_WUC_DATA_OPCODE	0x12
@@ -169,6 +179,15 @@ POSSIBILITY OF SUCH DAMAGE.
 #define	BM_WUC_HOST_WU_BIT	(1 << 4)
 #define	BM_WUC_ME_WU_BIT	(1 << 5)
 
+#define	BM_WUFC			BME1000_REG(BM_WUC_PAGE, 2)
+
 #define	I217_PROXY_CTRL		BME1000_REG(BM_WUC_PAGE, 70)
 #define I217_PROXY_CTRL_AUTO_DISABLE	0x0080
+
+#define BM_RAR_L(_i)		(BME1000_REG(BM_WUC_PAGE, 16 + ((_i) << 2)))
+#define BM_RAR_M(_i)		(BME1000_REG(BM_WUC_PAGE, 17 + ((_i) << 2)))
+#define BM_RAR_H(_i)		(BME1000_REG(BM_WUC_PAGE, 18 + ((_i) << 2)))
+#define BM_RAR_CTRL(_i)		(BME1000_REG(BM_WUC_PAGE, 19 + ((_i) << 2)))
+#define BM_MTA(_i)		(BME1000_REG(BM_WUC_PAGE, 128 + ((_i) << 1)))
+
 #endif /* _DEV_MII_INBMPHYREG_H_ */

Index: src/sys/dev/pci/if_wm.c
diff -u src/sys/dev/pci/if_wm.c:1.609 src/sys/dev/pci/if_wm.c:1.610
--- src/sys/dev/pci/if_wm.c:1.609	Thu Dec 20 08:59:22 2018
+++ src/sys/dev/pci/if_wm.c	Thu Dec 20 09:32:13 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wm.c,v 1.609 2018/12/20 08:59:22 msaitoh Exp $	*/
+/*	$NetBSD: if_wm.c,v 1.610 2018/12/20 09:32:13 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.609 2018/12/20 08:59:22 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.610 2018/12/20 09:32:13 msaitoh Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_net_mpsafe.h"
@@ -710,6 +710,7 @@ static uint16_t	wm_check_alt_mac_addr(st
 static int	wm_read_mac_addr(struct wm_softc *, uint8_t *);
 static void	wm_set_ral(struct wm_softc *, const uint8_t *, int);
 static uint32_t	wm_mchash(struct wm_softc *, const uint8_t *);
+static int	wm_rar_count(struct wm_softc *);
 static void	wm_set_filter(struct wm_softc *);
 /* Reset and init related */
 static void	wm_set_vlan(struct wm_softc *);
@@ -829,7 +830,10 @@ static int	wm_gmii_i80003_readreg(device
 static void	wm_gmii_i80003_writereg(device_t, int, int, int);
 static int	wm_gmii_bm_readreg(device_t, int, int);
 static void	wm_gmii_bm_writereg(device_t, int, int, int);
-static void	wm_access_phy_wakeup_reg_bm(device_t, int, int16_t *, int);
+static int	wm_enable_phy_wakeup_reg_access_bm(device_t, uint16_t *);
+static int	wm_disable_phy_wakeup_reg_access_bm(device_t, uint16_t *);
+static int	wm_access_phy_wakeup_reg_bm(device_t, int, int16_t *, int,
+	bool);
 static int	wm_gmii_hv_readreg(device_t, int, int);
 static int	wm_gmii_hv_readreg_locked(device_t, int, int, uint16_t *);
 static void	wm_gmii_hv_writereg(device_t, int, int, int);
@@ -954,7 +958,7 @@ static void	wm_init_manageability(struct
 static void	wm_release_manageability(struct wm_softc *);
 static void	wm_get_wakeup(struct wm_softc *);
 static int	wm_ulp_disable(struct wm_softc *);
-static void	wm_enable_phy_wakeup(struct wm_softc *);
+static int	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 *);
@@ -972,6 +976,7 @@ static void	wm_set_eee_i350(struct wm_so
 static void	wm_kmrn_lock_loss_workaround_ich8lan(struct wm_softc *);
 static void	wm_gig_downshift_workaround_ich8lan(struct wm_softc *);
 static void	wm_hv_phy_workarounds_ich8lan(struct wm_softc *);
+static void	wm_copy_rx_addrs_to_phy_ich8lan(struct wm_softc *);
 static void	wm_lv_phy_workarounds_ich8lan(struct wm_softc *);
 static int	wm_k1_workaround_lpt_lp(struct wm_softc *, bool);
 static int	wm_k1_gig_workaround_hv(struct wm_softc *, int);
@@ -3566,6 +3571,50 @@ wm_mchash(struct wm_softc *sc, const uin
 }
 
 /*
+ *
+ *
+ */
+static int
+wm_rar_count(struct wm_softc *sc)
+{
+	int size;
+
+	switch (sc->sc_type) {
+	case WM_T_ICH8:
+		size = WM_RAL_TABSIZE_ICH8 -1;
+		break;
+	case WM_T_ICH9:
+	case WM_T_ICH10:
+	case WM_T_PCH:
+		size = WM_RAL_TABSIZE_ICH8;
+		break;
+	case WM_T_PCH2:
+		size = WM_RAL_TABSIZE_PCH2;
+		break;
+	case WM_T_PCH_LPT:
+	case WM_T_PCH_SPT:
+	case WM_T_PCH_CNP:
+		size = WM_RAL_TABSIZE_PCH_LPT;
+		break;
+	case WM_T_82575:
+		size = WM_RAL_TABSIZE_82575;
+		break;
+	case WM_T_82576:
+	case WM_T_82580:
+		size = WM_RAL_TABSIZE_82576;
+		break;
+	case WM_T_I350:
+	case WM_T_I354:
+		size = WM_RAL_TABSIZE_I350;
+		break;
+	default:
+		size = WM_RAL_TABSIZE;    
+	}
+
+	return size;
+}
+
+/*
  * wm_set_filter:
  *
  *	Set up the receive filter.
@@ -3602,24 +3651,7 @@ wm_set_filter(struct wm_softc *sc)
 	 * Set the station address in the first RAL slot, and
 	 * clear the remaining slots.
 	 */
-	if (sc->sc_type == WM_T_ICH8)
-		size = WM_RAL_TABSIZE_ICH8 -1;
-	else if ((sc->sc_type == WM_T_ICH9) || (sc->sc_type == WM_T_ICH10)
-	    || (sc->sc_type == WM_T_PCH))
-		size = WM_RAL_TABSIZE_ICH8;
-	else if (sc->sc_type == WM_T_PCH2)
-		size = WM_RAL_TABSIZE_PCH2;
-	else if ((sc->sc_type == WM_T_PCH_LPT) || (sc->sc_type == WM_T_PCH_SPT)
-	    || (sc->sc_type == WM_T_PCH_CNP))
-		size = WM_RAL_TABSIZE_PCH_LPT;
-	else if (sc->sc_type == WM_T_82575)
-		size = WM_RAL_TABSIZE_82575;
-	else if ((sc->sc_type == WM_T_82576) || (sc->sc_type == WM_T_82580))
-		size = WM_RAL_TABSIZE_82576;
-	else if ((sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I354))
-		size = WM_RAL_TABSIZE_I350;
-	else
-		size = WM_RAL_TABSIZE;
+	size = wm_rar_count(sc);
 	wm_set_ral(sc, CLLADDR(ifp->if_sadl), 0);
 
 	if ((sc->sc_type == WM_T_PCH_LPT) || (sc->sc_type == WM_T_PCH_SPT)
@@ -6050,7 +6082,7 @@ wm_init_locked(struct ifnet *ifp)
 	 */
 	sc->sc_mchash_type = 0;
 	sc->sc_rctl = RCTL_EN | RCTL_LBM_NONE | RCTL_RDMTS_1_2 | RCTL_DPF
-	    | RCTL_MO(sc->sc_mchash_type);
+	    | __SHIFTIN(sc->sc_mchash_type, RCTL_MO);
 
 	/*
 	 * 82574 use one buffer extended Rx descriptor.
@@ -10288,7 +10320,8 @@ wm_gmii_mdic_readreg(device_t dev, int p
 	uint32_t mdic = 0;
 	int i, rv;
 
-	if (reg > MII_ADDRMASK) {
+	if ((sc->sc_phytype != WMPHY_82579) && (sc->sc_phytype != WMPHY_I217)
+	    && (reg > MII_ADDRMASK)) {
 		device_printf(dev, "%s: PHYTYPE = %d, addr 0x%x > 0x1f\n",
 		    __func__, sc->sc_phytype, reg);
 		reg &= MII_ADDRMASK;
@@ -10342,7 +10375,8 @@ wm_gmii_mdic_writereg(device_t dev, int 
 	uint32_t mdic = 0;
 	int i;
 
-	if (reg > MII_ADDRMASK) {
+	if ((sc->sc_phytype != WMPHY_82579) && (sc->sc_phytype != WMPHY_I217)
+	    && (reg > MII_ADDRMASK)) {
 		device_printf(dev, "%s: PHYTYPE = %d, addr 0x%x > 0x1f\n",
 		    __func__, sc->sc_phytype, reg);
 		reg &= MII_ADDRMASK;
@@ -10602,7 +10636,7 @@ wm_gmii_bm_readreg(device_t dev, int phy
 		    || (reg == 31)) ? 1 : phy;
 	/* Page 800 works differently than the rest so it has its own func */
 	if (page == BM_WUC_PAGE) {
-		wm_access_phy_wakeup_reg_bm(dev, reg, &val, 1);
+		wm_access_phy_wakeup_reg_bm(dev, reg, &val, true, false);
 		rv = val;
 		goto release;
 	}
@@ -10650,7 +10684,7 @@ wm_gmii_bm_writereg(device_t dev, int ph
 		uint16_t tmp;
 
 		tmp = val;
-		wm_access_phy_wakeup_reg_bm(dev, reg, &tmp, 0);
+		wm_access_phy_wakeup_reg_bm(dev, reg, &tmp, false, false);
 		goto release;
 	}
 
@@ -10670,39 +10704,139 @@ release:
 	sc->phy.release(sc);
 }
 
-static void
-wm_access_phy_wakeup_reg_bm(device_t dev, int offset, int16_t *val, int rd)
+/*
+ *  wm_enable_phy_wakeup_reg_access_bm - enable access to BM wakeup registers
+ *  @dev: pointer to the HW structure
+ *  @phy_reg: pointer to store original contents of BM_WUC_ENABLE_REG
+ *
+ *  Assumes semaphore already acquired and phy_reg points to a valid memory
+ *  address to store contents of the BM_WUC_ENABLE_REG register.
+ */
+static int
+wm_enable_phy_wakeup_reg_access_bm(device_t dev, uint16_t *phy_regp)
 {
-	struct wm_softc *sc = device_private(dev);
-	uint16_t regnum = BM_PHY_REG_NUM(offset);
-	uint16_t wuce, reg;
+	uint16_t temp;
 
-	DPRINTF(WM_DEBUG_GMII, ("%s: %s called\n",
+	DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
 		device_xname(dev), __func__));
-	/* XXX Gig must be disabled for MDIO accesses to page 800 */
-	if (sc->sc_type == WM_T_PCH) {
-		/* XXX e1000 driver do nothing... why? */
-	}
 
-	/*
-	 * 1) Enable PHY wakeup register first.
-	 * See e1000_enable_phy_wakeup_reg_access_bm().
-	 */
+	if (!phy_regp)
+		return -1;
+
+	/* All page select, port ctrl and wakeup registers use phy address 1 */
 
-	/* Set page 769 */
+	/* Select Port Control Registers page */
 	wm_gmii_mdic_writereg(dev, 1, MII_IGPHY_PAGE_SELECT,
-	    BM_WUC_ENABLE_PAGE << BME1000_PAGE_SHIFT);
+	    BM_PORT_CTRL_PAGE << IGP3_PAGE_SHIFT);
 
 	/* Read WUCE and save it */
-	wuce = wm_gmii_mdic_readreg(dev, 1, BM_WUC_ENABLE_REG);
+	*phy_regp = wm_gmii_mdic_readreg(dev, 1, BM_WUC_ENABLE_REG);
 
-	reg = wuce | BM_WUC_ENABLE_BIT;
-	reg &= ~(BM_WUC_ME_WU_BIT | BM_WUC_HOST_WU_BIT);
-	wm_gmii_mdic_writereg(dev, 1, BM_WUC_ENABLE_REG, reg);
+	/* Enable both PHY wakeup mode and Wakeup register page writes.
+	 * Prevent a power state change by disabling ME and Host PHY wakeup.
+	 */
+	temp = *phy_regp;
+	temp |= BM_WUC_ENABLE_BIT;
+	temp &= ~(BM_WUC_ME_WU_BIT | BM_WUC_HOST_WU_BIT);
 
-	/* Select page 800 */
+	wm_gmii_mdic_writereg(dev, 1, BM_WUC_ENABLE_REG, temp);
+
+	/* Select Host Wakeup Registers page - caller now able to write
+	 * registers on the Wakeup registers page
+	 */
 	wm_gmii_mdic_writereg(dev, 1, MII_IGPHY_PAGE_SELECT,
-	    BM_WUC_PAGE << BME1000_PAGE_SHIFT);
+	    BM_WUC_PAGE << IGP3_PAGE_SHIFT);
+
+	return 0;
+}
+
+/*
+ *  wm_disable_phy_wakeup_reg_access_bm - disable access to BM wakeup regs
+ *  @dev: pointer to the HW structure
+ *  @phy_reg: pointer to original contents of BM_WUC_ENABLE_REG
+ *
+ *  Restore BM_WUC_ENABLE_REG to its original value.
+ *
+ *  Assumes semaphore already acquired and *phy_reg is the contents of the
+ *  BM_WUC_ENABLE_REG before register(s) on BM_WUC_PAGE were accessed by
+ *  caller.
+ */
+static int
+wm_disable_phy_wakeup_reg_access_bm(device_t dev, uint16_t *phy_regp)
+{
+
+	DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
+		device_xname(dev), __func__));
+
+	if (!phy_regp)
+		return -1;
+
+	/* Select Port Control Registers page */
+	wm_gmii_mdic_writereg(dev, 1, MII_IGPHY_PAGE_SELECT,
+	    BM_PORT_CTRL_PAGE << IGP3_PAGE_SHIFT);
+
+	/* Restore 769.17 to its original value */
+	wm_gmii_mdic_writereg(dev, 1, BM_WUC_ENABLE_REG, *phy_regp);
+
+	return 0;
+}
+
+/*
+ *  wm_access_phy_wakeup_reg_bm - Read/write BM PHY wakeup register
+ *  @sc: pointer to the HW structure
+ *  @offset: register offset to be read or written
+ *  @val: pointer to the data to read or write
+ *  @rd: determines if operation is read or write
+ *  @page_set: BM_WUC_PAGE already set and access enabled
+ *
+ *  Read the PHY register at offset and store the retrieved information in
+ *  data, or write data to PHY register at offset.  Note the procedure to
+ *  access the PHY wakeup registers is different than reading the other PHY
+ *  registers. It works as such:
+ *  1) Set 769.17.2 (page 769, register 17, bit 2) = 1
+ *  2) Set page to 800 for host (801 if we were manageability)
+ *  3) Write the address using the address opcode (0x11)
+ *  4) Read or write the data using the data opcode (0x12)
+ *  5) Restore 769.17.2 to its original value
+ *
+ *  Steps 1 and 2 are done by wm_enable_phy_wakeup_reg_access_bm() and
+ *  step 5 is done by wm_disable_phy_wakeup_reg_access_bm().
+ *
+ *  Assumes semaphore is already acquired.  When page_set==TRUE, assumes
+ *  the PHY page is set to BM_WUC_PAGE (i.e. a function in the call stack
+ *  is responsible for calls to wm_[enable|disable]_phy_wakeup_reg_bm()).
+ */
+static int
+wm_access_phy_wakeup_reg_bm(device_t dev, int offset, int16_t *val, int rd,
+	bool page_set)
+{
+	struct wm_softc *sc = device_private(dev);
+	uint16_t regnum = BM_PHY_REG_NUM(offset);
+	uint16_t page = BM_PHY_REG_PAGE(offset);
+	uint16_t wuce;
+	int rv = 0;
+
+	DPRINTF(WM_DEBUG_GMII, ("%s: %s called\n",
+		device_xname(dev), __func__));
+	/* XXX Gig must be disabled for MDIO accesses to page 800 */
+	if ((sc->sc_type == WM_T_PCH)
+	    && ((CSR_READ(sc, WMREG_PHY_CTRL) & PHY_CTRL_GBE_DIS) == 0)) {
+		device_printf(dev,
+		    "Attempting to access page %d while gig enabled.\n", page);
+	}
+
+	if (!page_set) {
+		/* Enable access to PHY wakeup registers */
+		rv = wm_enable_phy_wakeup_reg_access_bm(dev, &wuce);
+		if (rv != 0) {
+			device_printf(dev,
+			    "%s: Could not enable PHY wakeup reg access\n",
+			    __func__);
+			return rv;
+		}
+	}
+	DPRINTF(WM_DEBUG_GMII, ("%s: %s: Accessing PHY page %d reg 0x%x\n",
+		device_xname(sc->sc_dev), __func__, page, regnum));
 
 	/*
 	 * 2) Access PHY wakeup register.
@@ -10720,15 +10854,10 @@ wm_access_phy_wakeup_reg_bm(device_t dev
 		wm_gmii_mdic_writereg(dev, 1, BM_WUC_DATA_OPCODE, *val);
 	}
 
-	/*
-	 * 3) Disable PHY wakeup register.
-	 * See wm_disable_phy_wakeup_reg_access_bm().
-	 */
-	/* Set page 769 */
-	wm_gmii_mdic_writereg(dev, 1, MII_IGPHY_PAGE_SELECT,
-	    BM_WUC_ENABLE_PAGE << BME1000_PAGE_SHIFT);
+	if (!page_set)
+		rv = wm_disable_phy_wakeup_reg_access_bm(dev, &wuce);
 
-	wm_gmii_mdic_writereg(dev, 1, BM_WUC_ENABLE_REG, wuce);
+	return rv;
 }
 
 /*
@@ -10765,10 +10894,8 @@ wm_gmii_hv_readreg_locked(device_t dev, 
 	phy = (page >= HV_INTC_FC_PAGE_START) ? 1 : phy;
 
 	/* Page 800 works differently than the rest so it has its own func */
-	if (page == BM_WUC_PAGE) {
-		wm_access_phy_wakeup_reg_bm(dev, reg, val, 1);
-		return 0;
-	}
+	if (page == BM_WUC_PAGE)
+		return wm_access_phy_wakeup_reg_bm(dev, reg, val, true, false);
 
 	/*
 	 * Lower than page 768 works differently than the rest so it has its
@@ -10825,6 +10952,7 @@ wm_gmii_hv_writereg_locked(device_t dev,
 	struct wm_softc *sc = device_private(dev);
 	uint16_t page = BM_PHY_REG_PAGE(reg);
 	uint16_t regnum = BM_PHY_REG_NUM(reg);
+	int rv;
 
 	phy = (page >= HV_INTC_FC_PAGE_START) ? 1 : phy;
 
@@ -10833,8 +10961,8 @@ wm_gmii_hv_writereg_locked(device_t dev,
 		uint16_t tmp;
 
 		tmp = val;
-		wm_access_phy_wakeup_reg_bm(dev, reg, &tmp, 0);
-		return 0;
+		rv = wm_access_phy_wakeup_reg_bm(dev, reg, &tmp, false, false);
+		return rv;
 	}
 
 	/*
@@ -14263,26 +14391,87 @@ release:
 }
 
 /* WOL in the newer chipset interfaces (pchlan) */
-static void
+static int
 wm_enable_phy_wakeup(struct wm_softc *sc)
 {
-#if 0
-	uint16_t preg;
+	device_t dev = sc->sc_dev;
+	uint32_t mreg, moff;
+	uint16_t wuce, wuc, wufc, preg;
+	int i, rv;
+
+	KASSERT(sc->sc_type >= WM_T_PCH);
 
 	/* Copy MAC RARs to PHY RARs */
+	wm_copy_rx_addrs_to_phy_ich8lan(sc);
+
+	/* Activate PHY wakeup */
+	rv = sc->phy.acquire(sc);
+	if (rv != 0) {
+		device_printf(dev, "%s: failed to acquire semaphore\n",
+		    __func__);
+		return rv;
+	}
+
+	/*
+	 * Enable access to PHY wakeup registers.
+	 * BM_MTA, BM_RCTL, BM_WUFC and BM_WUC are in BM_WUC_PAGE.
+	 */
+	rv = wm_enable_phy_wakeup_reg_access_bm(dev, &wuce);
+	if (rv != 0) {
+		device_printf(dev,
+		    "%s: Could not enable PHY wakeup reg access\n", __func__);
+		goto release;
+	}
 
 	/* Copy MAC MTA to PHY MTA */
+	for (i = 0; i < WM_ICH8_MC_TABSIZE; i++) {
+		uint16_t lo, hi;
+
+		mreg = CSR_READ(sc, WMREG_CORDOVA_MTA + (i * 4));
+		lo = (uint16_t)(mreg & 0xffff);
+		hi = (uint16_t)((mreg >> 16) & 0xffff);
+		wm_access_phy_wakeup_reg_bm(dev, BM_MTA(i), &lo, 0, true);
+		wm_access_phy_wakeup_reg_bm(dev, BM_MTA(i) + 1, &hi, 0, true);
+	}
 
 	/* Configure PHY Rx Control register */
+	wm_access_phy_wakeup_reg_bm(dev, BM_RCTL, &preg, 1, true);
+	mreg = CSR_READ(sc, WMREG_RCTL);
+	if (mreg & RCTL_UPE)
+		preg |= BM_RCTL_UPE;
+	if (mreg & RCTL_MPE)
+		preg |= BM_RCTL_MPE;
+	preg &= ~(BM_RCTL_MO_MASK);
+	moff = __SHIFTOUT(mreg, RCTL_MO);
+	if (moff != 0)
+		preg |= moff << BM_RCTL_MO_SHIFT;
+	if (mreg & RCTL_BAM)
+		preg |= BM_RCTL_BAM;
+	if (mreg & RCTL_PMCF)
+		preg |= BM_RCTL_PMCF;
+	mreg = CSR_READ(sc, WMREG_CTRL);
+	if (mreg & CTRL_RFCE)
+		preg |= BM_RCTL_RFCE;
+	wm_access_phy_wakeup_reg_bm(dev, BM_RCTL, &preg, 0, true);
 
+	wuc = WUC_APME | WUC_PME_EN;
+	wufc = WUFC_MAG;
 	/* Enable PHY wakeup in MAC register */
+	CSR_WRITE(sc, WMREG_WUC,
+	    WUC_PHY_WAKE | WUC_PME_STATUS | WUC_APMPME | wuc);
+	CSR_WRITE(sc, WMREG_WUFC, wufc);
 
 	/* Configure and enable PHY wakeup in PHY registers */
+	wm_access_phy_wakeup_reg_bm(dev, BM_WUC, &wuc, 0, true);
+	wm_access_phy_wakeup_reg_bm(dev, BM_WUFC, &wufc, 0, true);
 
-	/* Activate PHY wakeup */
+	wuce |= BM_WUC_ENABLE_BIT | BM_WUC_HOST_WU_BIT;
+	wm_disable_phy_wakeup_reg_access_bm(dev, &wuce);
 
-	/* XXX */
-#endif
+release:
+	sc->phy.release(sc);
+
+	return 0;
 }
 
 /* Power down workaround on D3 */
@@ -14473,18 +14662,21 @@ wm_enable_wakeup(struct wm_softc *sc)
 {
 	uint32_t reg, pmreg;
 	pcireg_t pmode;
+	int rv = 0;
 
 	DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
 		device_xname(sc->sc_dev), __func__));
 
 	if (pci_get_capability(sc->sc_pc, sc->sc_pcitag, PCI_CAP_PWRMGMT,
-		&pmreg, NULL) == 0)
+	    &pmreg, NULL) == 0)
 		return;
 
+	if ((sc->sc_flags & WM_F_WOL) == 0)
+		goto pme;
+
 	/* Advertise the wakeup capability */
 	CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl | CTRL_SWDPIN(2)
 	    | CTRL_SWDPIN(3));
-	CSR_WRITE(sc, WMREG_WUC, WUC_APME);
 
 	/* Keep the laser running on fiber adapters */
 	if ((sc->sc_mediatype == WM_MEDIATYPE_FIBER)
@@ -14495,21 +14687,25 @@ wm_enable_wakeup(struct wm_softc *sc)
 	}
 
 	if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9) ||
-	    (sc->sc_type == WM_T_ICH10) || (sc->sc_type == WM_T_PCH))
+	    (sc->sc_type == WM_T_ICH10) || (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_suspend_workarounds_ich8lan(sc);
 
-	reg = CSR_READ(sc, WMREG_WUFC) | WUFC_MAG;
 #if 0	/* for the multicast packet */
+	reg = CSR_READ(sc, WMREG_WUFC) | WUFC_MAG;
 	reg |= WUFC_MC;
 	CSR_WRITE(sc, WMREG_RCTL, CSR_READ(sc, WMREG_RCTL) | RCTL_MPE);
 #endif
 
-	if (sc->sc_type >= WM_T_PCH)
-		wm_enable_phy_wakeup(sc);
-	else {
+	if (sc->sc_type >= WM_T_PCH) {
+		rv = wm_enable_phy_wakeup(sc);
+		if (rv != 0)
+			goto pme;
+	} else {
 		/* Enable wakeup by the MAC */
-		CSR_WRITE(sc, WMREG_WUC, CSR_READ(sc, WMREG_WUC) | WUC_PME_EN);
-		CSR_WRITE(sc, WMREG_WUFC, reg);
+		CSR_WRITE(sc, WMREG_WUC, WUC_PME_EN);
+		CSR_WRITE(sc, WMREG_WUFC, WUFC_MAG);
 	}
 
 	if (((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)
@@ -14518,15 +14714,16 @@ wm_enable_wakeup(struct wm_softc *sc)
 	    && (sc->sc_phytype == WMPHY_IGP_3))
 		wm_igp3_phy_powerdown_workaround_ich8lan(sc);
 
+pme:
 	/* Request PME */
 	pmode = pci_conf_read(sc->sc_pc, sc->sc_pcitag, pmreg + PCI_PMCSR);
-#if 0
-	/* Disable WOL */
-	pmode &= ~(PCI_PMCSR_PME_STS | PCI_PMCSR_PME_EN);
-#else
-	/* For WOL */
-	pmode |= PCI_PMCSR_PME_STS | PCI_PMCSR_PME_EN;
-#endif
+	if ((rv == 0) && (sc->sc_flags & WM_F_WOL) != 0) {
+		/* For WOL */
+		pmode |= PCI_PMCSR_PME_STS | PCI_PMCSR_PME_EN;
+	} else {
+		/* Disable WOL */
+		pmode &= ~(PCI_PMCSR_PME_STS | PCI_PMCSR_PME_EN);
+	}
 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, pmreg + PCI_PMCSR, pmode);
 }
 
@@ -14803,6 +15000,49 @@ wm_hv_phy_workarounds_ich8lan(struct wm_
 }
 
 /*
+ *  wm_copy_rx_addrs_to_phy_ich8lan - Copy Rx addresses from MAC to PHY
+ *  @sc:   pointer to the HW structure
+ */
+static void
+wm_copy_rx_addrs_to_phy_ich8lan(struct wm_softc *sc)
+{
+	device_t dev = sc->sc_dev;
+	uint32_t mac_reg;
+	uint16_t i, wuce;
+	int count;
+
+	DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
+		device_xname(sc->sc_dev), __func__));
+
+	if (sc->phy.acquire(sc) != 0)
+		return;
+	if (wm_enable_phy_wakeup_reg_access_bm(dev, &wuce) != 0)
+		goto release;
+
+	/* Copy both RAL/H (rar_entry_count) and SHRAL/H to PHY */
+	count = wm_rar_count(sc);
+	for (i = 0; i < count; i++) {
+		uint16_t lo, hi;
+		mac_reg = CSR_READ(sc, WMREG_CORDOVA_RAL(i));
+		lo = (uint16_t)(mac_reg & 0xffff);
+		hi = (uint16_t)((mac_reg >> 16) & 0xffff);
+		wm_access_phy_wakeup_reg_bm(dev, BM_RAR_L(i), &lo, 0, true);
+		wm_access_phy_wakeup_reg_bm(dev, BM_RAR_M(i), &hi, 0, true);
+
+		mac_reg = CSR_READ(sc, WMREG_CORDOVA_RAH(i));
+		lo = (uint16_t)(mac_reg & 0xffff);
+		hi = (uint16_t)((mac_reg & RAL_AV) >> 16);
+		wm_access_phy_wakeup_reg_bm(dev, BM_RAR_H(i), &lo, 0, true);
+		wm_access_phy_wakeup_reg_bm(dev, BM_RAR_CTRL(i), &hi, 0, true);
+	}
+
+	wm_disable_phy_wakeup_reg_access_bm(dev, &wuce);
+
+release:
+	sc->phy.release(sc);
+}
+
+/*
  *  wm_lv_phy_workarounds_ich8lan - A series of Phy workarounds to be
  *  done after every PHY reset.
  */

Index: src/sys/dev/pci/if_wmreg.h
diff -u src/sys/dev/pci/if_wmreg.h:1.110 src/sys/dev/pci/if_wmreg.h:1.111
--- src/sys/dev/pci/if_wmreg.h:1.110	Fri Dec 14 09:47:40 2018
+++ src/sys/dev/pci/if_wmreg.h	Thu Dec 20 09:32:13 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wmreg.h,v 1.110 2018/12/14 09:47:40 msaitoh Exp $	*/
+/*	$NetBSD: if_wmreg.h,v 1.111 2018/12/20 09:32:13 msaitoh Exp $	*/
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -773,7 +773,7 @@ struct livengood_tcpip_ctxdesc {
 #define RCTL_DTYP_ONEBUF RCTL_DTYP(0)	/* use one buffer(not split header). */
 #define RCTL_DTYP_SPH	RCTL_DTYP(1)	/* split header buffer. */
 					/* RCTL_DTYP(2) and RCTL_DTYP(3) are reserved. */
-#define	RCTL_MO(x)	((x) << 12)	/* multicast offset */
+#define	RCTL_MO		__BITS(13, 12)	/* multicast offset */
 #define	RCTL_BAM	(1U << 15)	/* broadcast accept mode */
 #define	RCTL_RDMTS_HEX	__BIT(16)
 #define	RCTL_2k		(0 << 16)	/* 2k Rx buffers */

Index: src/sys/dev/pci/if_wmvar.h
diff -u src/sys/dev/pci/if_wmvar.h:1.40 src/sys/dev/pci/if_wmvar.h:1.41
--- src/sys/dev/pci/if_wmvar.h:1.40	Fri Dec 14 06:28:09 2018
+++ src/sys/dev/pci/if_wmvar.h	Thu Dec 20 09:32:13 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wmvar.h,v 1.40 2018/12/14 06:28:09 msaitoh Exp $	*/
+/*	$NetBSD: if_wmvar.h,v 1.41 2018/12/20 09:32:13 msaitoh Exp $	*/
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -172,8 +172,8 @@ typedef enum {
 	WMPHY_BM,
 	WMPHY_82577,
 	WMPHY_82578,
-	WMPHY_82579,
-	WMPHY_I217,
+	WMPHY_82579,	/* with PCH2 */
+	WMPHY_I217,	/* with PCH_LPT, PCH_SPT, PCH_CNP */
 	WMPHY_82580,
 	WMPHY_VF,
 	WMPHY_I210

Reply via email to