Module Name:    src
Committed By:   martin
Date:           Thu Jan 31 06:43:48 UTC 2019

Modified Files:
        src/sys/dev/mii [netbsd-8]: inbmphyreg.h
        src/sys/dev/pci [netbsd-8]: if_wm.c if_wmreg.h if_wmvar.h

Log Message:
Pull up the following, requested by msaitoh in ticket #1179:

        sys/dev/pci/if_wm.c                     1.603-1.605,1.607-1.611,
                                                1.613,1.615,1.618-1.620
                                                via patch
        sys/dev/pci/if_wmreg.h                  1.110-1.111
        sys/dev/pci/if_wmvar.h                  1.40-1.42
        sys/dev/mii/inbmphyreg.h                1.13-1.15

- 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().
- Print CLSEM workaround bit correctly.
- Fix availability detection of WoL on some chips.
- Print the WUS (WakeUp Status) register bits when resume.
- Don't setup WoL on non-WoL capable port.
- Setup PHY wakeup feature on PCH and newer. Tested on Thinkpad X220.
- Remove an extra register read in
  wm_kmrn_lock_loss_workaround_ich8lan().
- Don't leave the MDICNFG register modified when the Power Management
  capability offset can't get.
- Reduce indent level of wm_linkintr_gmii(). No functional change.
- 80003's SERDES is not the same as 82575's but the same as legacy
  devices. Use the old methods on 80003.
- Use __nothing for null DPRINTF().
- Rename functions. Add comment.


To generate a diff of this commit:
cvs rdiff -u -r1.9.8.3 -r1.9.8.4 src/sys/dev/mii/inbmphyreg.h
cvs rdiff -u -r1.508.4.28 -r1.508.4.29 src/sys/dev/pci/if_wm.c
cvs rdiff -u -r1.98.6.6 -r1.98.6.7 src/sys/dev/pci/if_wmreg.h
cvs rdiff -u -r1.33.6.3 -r1.33.6.4 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.9.8.3 src/sys/dev/mii/inbmphyreg.h:1.9.8.4
--- src/sys/dev/mii/inbmphyreg.h:1.9.8.3	Tue Dec  4 11:21:32 2018
+++ src/sys/dev/mii/inbmphyreg.h	Thu Jan 31 06:43:48 2019
@@ -1,6 +1,6 @@
-/*	$NetBSD: inbmphyreg.h,v 1.9.8.3 2018/12/04 11:21:32 martin Exp $	*/
+/*	$NetBSD: inbmphyreg.h,v 1.9.8.4 2019/01/31 06:43:48 martin Exp $	*/
 /*******************************************************************************
-Copyright (c) 2001-2005, Intel Corporation 
+Copyright (c) 2001-2015, Intel Corporation 
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without 
@@ -39,12 +39,16 @@ POSSIBILITY OF SUCH DAMAGE.
 #define	_DEV_MII_INBMPHYREG_H_
 
 /* Bits...
- * 15-5: page
- * 4-0: register offset
+ * 31-16: register offset (high)
+ * 15-5:  page
+ * 4-0:   register offset (low)
  */
-#define BME1000_PAGE_SHIFT        5
+#define BME1000_PAGE_SHIFT	5
+#define BM_PHY_UPPER_SHIFT	21
 #define BME1000_REG(page, reg)    \
-        (((page) << BME1000_PAGE_SHIFT) | ((reg) & MII_ADDRMASK))
+        (((reg) & MII_ADDRMASK) | 			\
+	    (((page) & 0xffff) << BME1000_PAGE_SHIFT) |	\
+	    (((reg) & ~MII_ADDRMASK) << (BM_PHY_UPPER_SHIFT - BME1000_PAGE_SHIFT)))
 
 #define BME1000_MAX_MULTI_PAGE_REG     0xf   /* Registers equal on all pages */
 
@@ -52,7 +56,7 @@ POSSIBILITY OF SUCH DAMAGE.
 	((uint16_t)(((offset) >> BME1000_PAGE_SHIFT) & 0xffff))
 #define	BM_PHY_REG_NUM(offset)				\
 	((uint16_t)((offset) & MII_ADDRMASK)		\
-	| (((offset) >> (21 - BME1000_PAGE_SHIFT)) & ~MII_ADDRMASK))
+	| (((offset) >> (BM_PHY_UPPER_SHIFT - BME1000_PAGE_SHIFT)) & ~MII_ADDRMASK))
 
 /* BME1000 Specific Registers */
 #define BME1000_PHY_SPEC_CTRL	BME1000_REG(0, 16) /* PHY Specific Control */
@@ -126,6 +130,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)
@@ -142,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
@@ -151,4 +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.508.4.28 src/sys/dev/pci/if_wm.c:1.508.4.29
--- src/sys/dev/pci/if_wm.c:1.508.4.28	Tue Dec 18 18:24:09 2018
+++ src/sys/dev/pci/if_wm.c	Thu Jan 31 06:43:48 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wm.c,v 1.508.4.28 2018/12/18 18:24:09 martin Exp $	*/
+/*	$NetBSD: if_wm.c,v 1.508.4.29 2019/01/31 06:43:48 martin 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.508.4.28 2018/12/18 18:24:09 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.508.4.29 2019/01/31 06:43:48 martin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_net_mpsafe.h"
@@ -159,7 +159,7 @@ int	wm_debug = WM_DEBUG_TX | WM_DEBUG_RX
 
 #define	DPRINTF(x, y)	if (wm_debug & (x)) printf y
 #else
-#define	DPRINTF(x, y)	/* nothing */
+#define	DPRINTF(x, y)	__nothing
 #endif /* WM_DEBUG */
 
 #ifdef NET_MPSAFE
@@ -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 *);
@@ -723,7 +724,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);
@@ -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);
@@ -949,14 +953,15 @@ 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 *);
 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 *);
 static void	wm_enable_wakeup(struct wm_softc *);
 static void	wm_disable_aspm(struct wm_softc *);
 /* LPLU (Low Power Link Up) */
@@ -970,8 +975,9 @@ 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_workaround_ich8lan(struct wm_softc *);
-static void	wm_lv_phy_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);
 static int	wm_k1_workaround_lv(struct wm_softc *);
@@ -2099,9 +2105,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);
@@ -2381,6 +2384,25 @@ alloc_retry:
 	 */
 	wm_gmii_setup_phytype(sc, 0, 0);
 
+	/* Check for WM_F_WOL on some chips before wm_reset() */
+	switch (sc->sc_type) {
+	case WM_T_ICH8:
+	case WM_T_ICH9:
+	case WM_T_ICH10:
+	case WM_T_PCH:
+	case WM_T_PCH2:
+	case WM_T_PCH_LPT:
+	case WM_T_PCH_SPT:
+	case WM_T_PCH_CNP:
+		apme_mask = WUC_APME;
+		eeprom_data = CSR_READ(sc, WMREG_WUC);
+		if ((eeprom_data & apme_mask) != 0)
+			sc->sc_flags |= WM_F_WOL;
+		break;
+	default:
+		break;
+	}
+
 	/* Reset the chip to a known state. */
 	wm_reset(sc);
 
@@ -2482,16 +2504,22 @@ alloc_retry:
 	case WM_T_82574:
 	case WM_T_82583:
 	case WM_T_80003:
-	default:
+	case WM_T_82575:
+	case WM_T_82576:
 		apme_mask = NVM_CFG3_APME;
 		wm_nvm_read(sc, (sc->sc_funcid == 1) ? NVM_OFF_CFG3_PORTB
 		    : NVM_OFF_CFG3_PORTA, 1, &eeprom_data);
 		break;
-	case WM_T_82575:
-	case WM_T_82576:
 	case WM_T_82580:
 	case WM_T_I350:
-	case WM_T_I354: /* XXX ok? */
+	case WM_T_I354:
+	case WM_T_I210:
+	case WM_T_I211:
+		apme_mask = NVM_CFG3_APME;
+		wm_nvm_read(sc,
+		    NVM_OFF_LAN_FUNC_82580(sc->sc_funcid) + NVM_OFF_CFG3_PORTA,
+		    1, &eeprom_data);
+		break;
 	case WM_T_ICH8:
 	case WM_T_ICH9:
 	case WM_T_ICH10:
@@ -2500,16 +2528,54 @@ alloc_retry:
 	case WM_T_PCH_LPT:
 	case WM_T_PCH_SPT:
 	case WM_T_PCH_CNP:
-		/* XXX The funcid should be checked on some devices */
-		apme_mask = WUC_APME;
-		eeprom_data = CSR_READ(sc, WMREG_WUC);
+		/* Already checked before wm_reset () */
+		apme_mask = eeprom_data = 0;
+		break;
+	default: /* XXX 82540 */
+		apme_mask = NVM_CFG3_APME;
+		wm_nvm_read(sc, NVM_OFF_CFG3_PORTA, 1, &eeprom_data);
 		break;
 	}
-
 	/* Check for WM_F_WOL flag after the setting of the EEPROM stuff */
 	if ((eeprom_data & apme_mask) != 0)
 		sc->sc_flags |= WM_F_WOL;
 
+	/*
+	 * We have the eeprom settings, now apply the special cases
+	 * where the eeprom may be wrong or the board won't support
+	 * wake on lan on a particular port
+	 */
+	switch (sc->sc_pcidevid) {
+	case PCI_PRODUCT_INTEL_82546GB_PCIE:
+		sc->sc_flags &= ~WM_F_WOL;
+		break;
+	case PCI_PRODUCT_INTEL_82546EB_FIBER:
+	case PCI_PRODUCT_INTEL_82546GB_FIBER:
+		/* Wake events only supported on port A for dual fiber
+		 * regardless of eeprom setting */
+		if (sc->sc_funcid == 1)
+			sc->sc_flags &= ~WM_F_WOL;
+		break;
+	case PCI_PRODUCT_INTEL_82546GB_QUAD_COPPER_KSP3:
+		/* if quad port adapter, disable WoL on all but port A */
+		if (sc->sc_funcid != 0)
+			sc->sc_flags &= ~WM_F_WOL;
+		break;
+	case PCI_PRODUCT_INTEL_82571EB_FIBER:
+		/* Wake events only supported on port A for dual fiber
+		 * regardless of eeprom setting */
+		if (sc->sc_funcid == 1)
+			sc->sc_flags &= ~WM_F_WOL;
+		break;
+	case PCI_PRODUCT_INTEL_82571EB_QUAD_COPPER:
+	case PCI_PRODUCT_INTEL_82571EB_QUAD_FIBER:
+	case PCI_PRODUCT_INTEL_82571GB_QUAD_COPPER:
+		/* if quad port adapter, disable WoL on all but port A */
+		if (sc->sc_funcid != 0)
+			sc->sc_flags &= ~WM_F_WOL;
+		break;
+	}
+
 	if ((sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576)) {
 		/* Check NVM for autonegotiation */
 		if (wm_nvm_read(sc, NVM_OFF_COMPAT, 1, &nvmword) == 0) {
@@ -2872,7 +2938,7 @@ alloc_retry:
 		aprint_error_dev(self, "couldn't establish power handler\n");
 
 	sc->sc_flags |= WM_F_ATTACHED;
- out:
+out:
 	return;
 }
 
@@ -2978,10 +3044,33 @@ 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;
+	pcireg_t reg;
+	char buf[256];
 
-	/* Disable ASPM L0s and/or L1 for workaround */
-	wm_disable_aspm(sc);
-	wm_init_manageability(sc);
+	reg = CSR_READ(sc, WMREG_WUS);
+	if (reg != 0) {
+		snprintb(buf, sizeof(buf), WUS_FLAGS, reg);
+		device_printf(sc->sc_dev, "wakeup status %s\n", buf);
+		CSR_WRITE(sc, WMREG_WUS, 0xffffffff); /* W1C */
+	}
+
+	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;
 }
@@ -3149,7 +3238,7 @@ wm_tick(void *arg)
 
 	if (sc->sc_flags & WM_F_HAS_MII)
 		mii_tick(&sc->sc_mii);
-	else if ((sc->sc_type >= WM_T_82575)
+	else if ((sc->sc_type >= WM_T_82575) && (sc->sc_type <= WM_T_I211)
 	    && (sc->sc_mediatype == WM_MEDIATYPE_SERDES))
 		wm_serdes_tick(sc);
 	else
@@ -3482,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.
@@ -3518,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)
@@ -3815,10 +3931,9 @@ wm_get_cfg_done(struct wm_softc *sc)
 				break;
 			delay(1000);
 		}
-		if (i >= WM_PHY_CFG_TIMEOUT) {
+		if (i >= WM_PHY_CFG_TIMEOUT)
 			DPRINTF(WM_DEBUG_GMII, ("%s: %s failed\n",
 				device_xname(sc->sc_dev), __func__));
-		}
 		break;
 	case WM_T_ICH8:
 	case WM_T_ICH9:
@@ -3866,9 +3981,9 @@ wm_phy_post_reset(struct wm_softc *sc)
 
 	/* Perform any necessary post-reset workarounds */
 	if (sc->sc_type == WM_T_PCH)
-		wm_hv_phy_workaround_ich8lan(sc);
+		wm_hv_phy_workarounds_ich8lan(sc);
 	else if (sc->sc_type == WM_T_PCH2)
-		wm_lv_phy_workaround_ich8lan(sc);
+		wm_lv_phy_workarounds_ich8lan(sc);
 
 	/* Clear the host wakeup bit after lcd reset */
 	if (sc->sc_type >= WM_T_PCH) {
@@ -3927,11 +4042,10 @@ wm_write_smbus_addr(struct wm_softc *sc)
 			    HV_SMB_ADDR_FREQ_LOW);
 			phy_data |= __SHIFTIN((freq & 0x02) != 0,
 			    HV_SMB_ADDR_FREQ_HIGH);
-		} else {
+		} else
 			DPRINTF(WM_DEBUG_INIT,
 			    ("%s: %s Unsupported SMB frequency in PHY\n",
 				device_xname(sc->sc_dev), __func__));
-		}
 	}
 
 	return wm_gmii_hv_writereg_locked(sc->sc_dev, 2, HV_SMB_ADDR,
@@ -4365,7 +4479,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 +4487,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 +4506,8 @@ wm_reset_phy(struct wm_softc *sc)
 
 	wm_get_cfg_done(sc);
 	wm_phy_post_reset(sc);
+
+	return 0;
 }
 
 /*
@@ -4893,6 +5009,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); /* Workaround for some chips */
+
 	wm_reset_mdicnfg_82580(sc);
 
 	if ((sc->sc_flags & WM_F_PLL_WA_I210) != 0)
@@ -5961,7 +6080,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.
@@ -8782,133 +8901,135 @@ wm_rxeof(struct wm_rxqueue *rxq, u_int l
 static void
 wm_linkintr_gmii(struct wm_softc *sc, uint32_t icr)
 {
+	uint32_t status, reg;
+	bool link;
 
 	KASSERT(WM_CORE_LOCKED(sc));
 
 	DPRINTF(WM_DEBUG_LINK, ("%s: %s:\n", device_xname(sc->sc_dev),
 		__func__));
 
-	if (icr & ICR_LSC) {
-		uint32_t status = CSR_READ(sc, WMREG_STATUS);
-		uint32_t reg;
-		bool link;
-
-		link = status & STATUS_LU;
-		if (link) {
-			DPRINTF(WM_DEBUG_LINK, ("%s: LINK: LSC -> up %s\n",
-				device_xname(sc->sc_dev),
-				(status & STATUS_FD) ? "FDX" : "HDX"));
-		} else {
-			DPRINTF(WM_DEBUG_LINK, ("%s: LINK: LSC -> down\n",
+	if ((icr & ICR_LSC) == 0) {
+		if (icr & ICR_RXSEQ)
+			DPRINTF(WM_DEBUG_LINK,
+			    ("%s: LINK Receive sequence error\n",
 				device_xname(sc->sc_dev)));
-		}
-		if ((sc->sc_type == WM_T_ICH8) && (link == false))
-			wm_gig_downshift_workaround_ich8lan(sc);
-
-		if ((sc->sc_type == WM_T_ICH8)
-		    && (sc->sc_phytype == WMPHY_IGP_3)) {
-			wm_kmrn_lock_loss_workaround_ich8lan(sc);
-		}
-		DPRINTF(WM_DEBUG_LINK, ("%s: LINK: LSC -> mii_pollstat\n",
+		return;
+	}
+	/* Link status changed */
+	status = CSR_READ(sc, WMREG_STATUS);
+	link = status & STATUS_LU;
+	if (link) {
+		DPRINTF(WM_DEBUG_LINK, ("%s: LINK: LSC -> up %s\n",
+			device_xname(sc->sc_dev),
+			(status & STATUS_FD) ? "FDX" : "HDX"));
+	} else {
+		DPRINTF(WM_DEBUG_LINK, ("%s: LINK: LSC -> down\n",
 			device_xname(sc->sc_dev)));
-		mii_pollstat(&sc->sc_mii);
-		if (sc->sc_type == WM_T_82543) {
-			int miistatus, active;
-
-			/*
-			 * With 82543, we need to force speed and
-			 * duplex on the MAC equal to what the PHY
-			 * speed and duplex configuration is.
-			 */
-			miistatus = sc->sc_mii.mii_media_status;
+	}
+	if ((sc->sc_type == WM_T_ICH8) && (link == false))
+		wm_gig_downshift_workaround_ich8lan(sc);
 
-			if (miistatus & IFM_ACTIVE) {
-				active = sc->sc_mii.mii_media_active;
-				sc->sc_ctrl &= ~(CTRL_SPEED_MASK | CTRL_FD);
-				switch (IFM_SUBTYPE(active)) {
-				case IFM_10_T:
-					sc->sc_ctrl |= CTRL_SPEED_10;
-					break;
-				case IFM_100_TX:
-					sc->sc_ctrl |= CTRL_SPEED_100;
-					break;
-				case IFM_1000_T:
-					sc->sc_ctrl |= CTRL_SPEED_1000;
-					break;
-				default:
-					/*
-					 * fiber?
-					 * Shoud not enter here.
-					 */
-					printf("unknown media (%x)\n", active);
-					break;
-				}
-				if (active & IFM_FDX)
-					sc->sc_ctrl |= CTRL_FD;
-				CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
-			}
-		} else if (sc->sc_type == WM_T_PCH) {
-			wm_k1_gig_workaround_hv(sc,
-			    ((sc->sc_mii.mii_media_status & IFM_ACTIVE) != 0));
-		}
+	if ((sc->sc_type == WM_T_ICH8)
+	    && (sc->sc_phytype == WMPHY_IGP_3)) {
+		wm_kmrn_lock_loss_workaround_ich8lan(sc);
+	}
+	DPRINTF(WM_DEBUG_LINK, ("%s: LINK: LSC -> mii_pollstat\n",
+		device_xname(sc->sc_dev)));
+	mii_pollstat(&sc->sc_mii);
+	if (sc->sc_type == WM_T_82543) {
+		int miistatus, active;
 
 		/*
-		 * I217 Packet Loss issue:
-		 * ensure that FEXTNVM4 Beacon Duration is set correctly
-		 * on power up.
-		 * Set the Beacon Duration for I217 to 8 usec
+		 * With 82543, we need to force speed and
+		 * duplex on the MAC equal to what the PHY
+		 * speed and duplex configuration is.
 		 */
-		if (sc->sc_type >= WM_T_PCH_LPT) {
-			reg = CSR_READ(sc, WMREG_FEXTNVM4);
-			reg &= ~FEXTNVM4_BEACON_DURATION;
-			reg |= FEXTNVM4_BEACON_DURATION_8US;
-			CSR_WRITE(sc, WMREG_FEXTNVM4, reg);
+		miistatus = sc->sc_mii.mii_media_status;
+
+		if (miistatus & IFM_ACTIVE) {
+			active = sc->sc_mii.mii_media_active;
+			sc->sc_ctrl &= ~(CTRL_SPEED_MASK | CTRL_FD);
+			switch (IFM_SUBTYPE(active)) {
+			case IFM_10_T:
+				sc->sc_ctrl |= CTRL_SPEED_10;
+				break;
+			case IFM_100_TX:
+				sc->sc_ctrl |= CTRL_SPEED_100;
+				break;
+			case IFM_1000_T:
+				sc->sc_ctrl |= CTRL_SPEED_1000;
+				break;
+			default:
+				/*
+				 * fiber?
+				 * Shoud not enter here.
+				 */
+				printf("unknown media (%x)\n", active);
+				break;
+			}
+			if (active & IFM_FDX)
+				sc->sc_ctrl |= CTRL_FD;
+			CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
 		}
+	} else if (sc->sc_type == WM_T_PCH) {
+		wm_k1_gig_workaround_hv(sc,
+		    ((sc->sc_mii.mii_media_status & IFM_ACTIVE) != 0));
+	}
 
-		/* Work-around I218 hang issue */
-		if ((sc->sc_pcidevid == PCI_PRODUCT_INTEL_I218_LM) ||
-		    (sc->sc_pcidevid == PCI_PRODUCT_INTEL_I218_V) ||
-		    (sc->sc_pcidevid == PCI_PRODUCT_INTEL_I218_LM3) ||
-		    (sc->sc_pcidevid == PCI_PRODUCT_INTEL_I218_V3))
-			wm_k1_workaround_lpt_lp(sc, link);
+	/*
+	 * I217 Packet Loss issue:
+	 * ensure that FEXTNVM4 Beacon Duration is set correctly
+	 * on power up.
+	 * Set the Beacon Duration for I217 to 8 usec
+	 */
+	if (sc->sc_type >= WM_T_PCH_LPT) {
+		reg = CSR_READ(sc, WMREG_FEXTNVM4);
+		reg &= ~FEXTNVM4_BEACON_DURATION;
+		reg |= FEXTNVM4_BEACON_DURATION_8US;
+		CSR_WRITE(sc, WMREG_FEXTNVM4, reg);
+	}
 
-		if (sc->sc_type >= WM_T_PCH_LPT) {
-			/*
-			 * Set platform power management values for Latency
-			 * Tolerance Reporting (LTR)
-			 */
-			wm_platform_pm_pch_lpt(sc,
-			    ((sc->sc_mii.mii_media_status & IFM_ACTIVE) != 0));
-		}
+	/* Work-around I218 hang issue */
+	if ((sc->sc_pcidevid == PCI_PRODUCT_INTEL_I218_LM) ||
+	    (sc->sc_pcidevid == PCI_PRODUCT_INTEL_I218_V) ||
+	    (sc->sc_pcidevid == PCI_PRODUCT_INTEL_I218_LM3) ||
+	    (sc->sc_pcidevid == PCI_PRODUCT_INTEL_I218_V3))
+		wm_k1_workaround_lpt_lp(sc, link);
 
-		/* FEXTNVM6 K1-off workaround */
-		if (sc->sc_type == WM_T_PCH_SPT) {
-			reg = CSR_READ(sc, WMREG_FEXTNVM6);
-			if (CSR_READ(sc, WMREG_PCIEANACFG)
-			    & FEXTNVM6_K1_OFF_ENABLE)
-				reg |= FEXTNVM6_K1_OFF_ENABLE;
-			else
-				reg &= ~FEXTNVM6_K1_OFF_ENABLE;
-			CSR_WRITE(sc, WMREG_FEXTNVM6, reg);
-		}
+	if (sc->sc_type >= WM_T_PCH_LPT) {
+		/*
+		 * Set platform power management values for Latency
+		 * Tolerance Reporting (LTR)
+		 */
+		wm_platform_pm_pch_lpt(sc,
+		    ((sc->sc_mii.mii_media_status & IFM_ACTIVE) != 0));
+	}
 
-		if (!link)
-			return;
+	/* FEXTNVM6 K1-off workaround */
+	if (sc->sc_type == WM_T_PCH_SPT) {
+		reg = CSR_READ(sc, WMREG_FEXTNVM6);
+		if (CSR_READ(sc, WMREG_PCIEANACFG)
+		    & FEXTNVM6_K1_OFF_ENABLE)
+			reg |= FEXTNVM6_K1_OFF_ENABLE;
+		else
+			reg &= ~FEXTNVM6_K1_OFF_ENABLE;
+		CSR_WRITE(sc, WMREG_FEXTNVM6, reg);
+	}
 
-		switch (sc->sc_type) {
-		case WM_T_PCH2:
-			wm_k1_workaround_lv(sc);
-			/* FALLTHROUGH */
-		case WM_T_PCH:
-			if (sc->sc_phytype == WMPHY_82578)
-				wm_link_stall_workaround_hv(sc);
-			break;
-		default:
-			break;
-		}
-	} else if (icr & ICR_RXSEQ) {
-		DPRINTF(WM_DEBUG_LINK, ("%s: LINK Receive sequence error\n",
-			device_xname(sc->sc_dev)));
+	if (!link)
+		return;
+
+	switch (sc->sc_type) {
+	case WM_T_PCH2:
+		wm_k1_workaround_lv(sc);
+		/* FALLTHROUGH */
+	case WM_T_PCH:
+		if (sc->sc_phytype == WMPHY_82578)
+			wm_link_stall_workaround_hv(sc);
+		break;
+	default:
+		break;
 	}
 }
 
@@ -8962,10 +9083,9 @@ wm_linkintr_tbi(struct wm_softc *sc, uin
 		}
 		/* Update LED */
 		wm_tbi_serdes_set_linkled(sc);
-	} else if (icr & ICR_RXSEQ) {
+	} else if (icr & ICR_RXSEQ)
 		DPRINTF(WM_DEBUG_LINK, ("%s: LINK: Receive sequence error\n",
 			device_xname(sc->sc_dev)));
-	}
 }
 
 /*
@@ -9038,10 +9158,9 @@ wm_linkintr_serdes(struct wm_softc *sc, 
 		}
 		/* Update LED */
 		wm_tbi_serdes_set_linkled(sc);
-	} else {
+	} else
 		DPRINTF(WM_DEBUG_LINK, ("%s: LINK: Receive sequence error\n",
 		    device_xname(sc->sc_dev)));
-	}
 }
 
 /*
@@ -9058,7 +9177,7 @@ wm_linkintr(struct wm_softc *sc, uint32_
 	if (sc->sc_flags & WM_F_HAS_MII)
 		wm_linkintr_gmii(sc, icr);
 	else if ((sc->sc_mediatype == WM_MEDIATYPE_SERDES)
-	    && (sc->sc_type >= WM_T_82575))
+	    && ((sc->sc_type >= WM_T_82575) && (sc->sc_type <= WM_T_I211)))
 		wm_linkintr_serdes(sc, icr);
 	else
 		wm_linkintr_tbi(sc, icr);
@@ -9083,10 +9202,9 @@ wm_intr_legacy(void *arg)
 		icr = CSR_READ(sc, WMREG_ICR);
 		if ((icr & sc->sc_icr) == 0)
 			break;
-		if (handled == 0) {
+		if (handled == 0)
 			DPRINTF(WM_DEBUG_TX,
 			    ("%s: INTx: got intr\n",device_xname(sc->sc_dev)));
-		}
 		if (rndval == 0)
 			rndval = icr;
 
@@ -9907,7 +10025,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);
 
@@ -10199,7 +10317,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;
@@ -10253,7 +10372,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;
@@ -10513,7 +10633,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;
 	}
@@ -10561,7 +10681,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;
 	}
 
@@ -10581,62 +10701,160 @@ 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;
 
-	/* Set page 769 */
+	/* All page select, port ctrl and wakeup registers use phy address 1 */
+
+	/* 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);
+
+	/* 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);
+
+	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 << 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__));
 
-	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);
+	if (!phy_regp)
+		return -1;
 
-	/* Select page 800 */
+	/* Select Port Control Registers page */
 	wm_gmii_mdic_writereg(dev, 1, MII_IGPHY_PAGE_SELECT,
-	    BM_WUC_PAGE << BME1000_PAGE_SHIFT);
+	    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.
-	 * See e1000_access_phy_wakeup_reg_bm.
+	 * See wm_access_phy_wakeup_reg_bm.
 	 */
 
-	/* Write page 800 */
+	/* Write the Wakeup register page offset value using opcode 0x11 */
 	wm_gmii_mdic_writereg(dev, 1, BM_WUC_ADDRESS_OPCODE, regnum);
 
-	if (rd)
+	if (rd) {
+		/* Read the Wakeup register page value using opcode 0x12 */
 		*val = wm_gmii_mdic_readreg(dev, 1, BM_WUC_DATA_OPCODE);
-	else
+	} else {
+		/* Write the Wakeup register page value using opcode 0x12 */
 		wm_gmii_mdic_writereg(dev, 1, BM_WUC_DATA_OPCODE, *val);
+	}
 
-	/*
-	 * 3) Disable PHY wakeup register.
-	 * See e1000_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;
 }
 
 /*
@@ -10673,10 +10891,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
@@ -10733,6 +10949,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;
 
@@ -10741,8 +10958,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;
 	}
 
 	/*
@@ -11220,7 +11437,7 @@ wm_tbi_mediainit(struct wm_softc *sc)
 	sc->sc_mii.mii_ifp = ifp;
 	sc->sc_ethercom.ec_mii = &sc->sc_mii;
 
-	if ((sc->sc_type >= WM_T_82575)
+	if (((sc->sc_type >= WM_T_82575) && (sc->sc_type <= WM_T_I211))
 	    && (sc->sc_mediatype == WM_MEDIATYPE_SERDES))
 		ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK,
 		    wm_serdes_mediachange, wm_serdes_mediastatus);
@@ -11495,14 +11712,13 @@ wm_check_for_link(struct wm_softc *sc)
 			__func__));
 		CSR_WRITE(sc, WMREG_TXCW, sc->sc_txcw);
 		CSR_WRITE(sc, WMREG_CTRL, (ctrl & ~CTRL_SLU));
-	} else if (signal && ((rxcw & RXCW_C) != 0)) {
+	} else if (signal && ((rxcw & RXCW_C) != 0))
 		DPRINTF(WM_DEBUG_LINK, ("%s: %s: /C/",
 			device_xname(sc->sc_dev), __func__));
-	} else {
+	else
 		DPRINTF(WM_DEBUG_LINK, ("%s: %s: linkup %08x,%08x,%08x\n",
 			device_xname(sc->sc_dev), __func__, rxcw, ctrl,
 			status));
-	}
 
 	return 0;
 }
@@ -12882,12 +13098,11 @@ wm_nvm_validate_checksum(struct wm_softc
 	    || (sc->sc_type == WM_T_PCH2) || (sc->sc_type == WM_T_PCH_LPT)) {
 		/* XXX PCH_SPT? */
 		wm_nvm_read(sc, csum_wordaddr, 1, &eeprom_data);
-		if ((eeprom_data & valid_checksum) == 0) {
+		if ((eeprom_data & valid_checksum) == 0)
 			DPRINTF(WM_DEBUG_NVM,
 			    ("%s: NVM need to be updated (%04x != %04x)\n",
 				device_xname(sc->sc_dev), eeprom_data,
 				    valid_checksum));
-		}
 	}
 
 	if ((wm_debug & WM_DEBUG_NVM) != 0) {
@@ -13839,8 +14054,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 +14070,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 +14089,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 +14099,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 +14119,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 +14146,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 +14316,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__));
+		return -1;
+	}
 
 	/* Toggle LANPHYPC */
 	wm_toggle_lanphypc_pch_lpt(sc);
@@ -14131,26 +14386,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 */
@@ -14191,7 +14507,7 @@ wm_igp3_phy_powerdown_workaround_ich8lan
 }
 
 /*
- *  e1000_suspend_workarounds_ich8lan - workarounds needed during S0->Sx
+ *  wm_suspend_workarounds_ich8lan - workarounds needed during S0->Sx
  *  @sc: pointer to the HW structure
  *
  *  During S0 to Sx transition, it is possible the link remains at gig
@@ -14269,23 +14585,94 @@ out:
 	}
 }
 
+/*
+ *  wm_resume_workarounds_pchlan - workarounds needed during Sx->S0
+ *  @sc: 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)
+			return -1;
+
+		/* 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
+			 */
+			rv = 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)
 {
 	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)
@@ -14296,21 +14683,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)
@@ -14319,15 +14710,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);
 }
 
@@ -14500,7 +14892,6 @@ wm_kmrn_lock_loss_workaround_ich8lan(str
 	if (__SHIFTOUT(status, STATUS_SPEED) != STATUS_SPEED_1000)
 		return;
 
-	reg = CSR_READ(sc, WMREG_PHY_CTRL);
 	for (i = 0; i < 10; i++) {
 		/* read twice */
 		reg = mii->mii_readreg(sc->sc_dev, 1, IGP3_KMRN_DIAG);
@@ -14560,7 +14951,7 @@ wm_gig_downshift_workaround_ich8lan(stru
  * XXX should be moved to new PHY driver?
  */
 static void
-wm_hv_phy_workaround_ich8lan(struct wm_softc *sc)
+wm_hv_phy_workarounds_ich8lan(struct wm_softc *sc)
 {
 
 	DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
@@ -14604,11 +14995,54 @@ wm_hv_phy_workaround_ich8lan(struct wm_s
 }
 
 /*
+ *  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.
  */
 static void
-wm_lv_phy_workaround_ich8lan(struct wm_softc *sc)
+wm_lv_phy_workarounds_ich8lan(struct wm_softc *sc)
 {
 
 	DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
@@ -14623,7 +15057,7 @@ wm_lv_phy_workaround_ich8lan(struct wm_s
 }
 
 /**
- *  e1000_k1_workaround_lpt_lp - K1 workaround on Lynxpoint-LP
+ *  wm_k1_workaround_lpt_lp - K1 workaround on Lynxpoint-LP
  *  @link: link up bool flag
  *
  *  When K1 is enabled for 1Gbps, the MAC can miss 2 DMA completion indications
@@ -15166,6 +15600,11 @@ wm_pll_workaround_i210(struct wm_softc *
 	bool wa_done = false;
 	int i;
 
+	/* Get Power Management cap offset */
+	if (pci_get_capability(sc->sc_pc, sc->sc_pcitag, PCI_CAP_PWRMGMT,
+	    &pmreg, NULL) == 0)
+		return;
+
 	/* Save WUC and MDICNFG registers */
 	wuc = CSR_READ(sc, WMREG_WUC);
 	mdicnfg = CSR_READ(sc, WMREG_MDICNFG);
@@ -15177,10 +15616,6 @@ wm_pll_workaround_i210(struct wm_softc *
 		nvmword = INVM_DEFAULT_AL;
 	tmp_nvmword = nvmword | INVM_PLL_WO_VAL;
 
-	/* Get Power Management cap offset */
-	if (pci_get_capability(sc->sc_pc, sc->sc_pcitag, PCI_CAP_PWRMGMT,
-		&pmreg, NULL) == 0)
-		return;
 	for (i = 0; i < WM_MAX_PLL_TRIES; i++) {
 		phyval = wm_gmii_gs40g_readreg(sc->sc_dev, 1,
 		    GS40G_PHY_PLL_FREQ_PAGE | GS40G_PHY_PLL_FREQ_REG);

Index: src/sys/dev/pci/if_wmreg.h
diff -u src/sys/dev/pci/if_wmreg.h:1.98.6.6 src/sys/dev/pci/if_wmreg.h:1.98.6.7
--- src/sys/dev/pci/if_wmreg.h:1.98.6.6	Tue Dec  4 11:21:32 2018
+++ src/sys/dev/pci/if_wmreg.h	Thu Jan 31 06:43:48 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wmreg.h,v 1.98.6.6 2018/12/04 11:21:32 martin Exp $	*/
+/*	$NetBSD: if_wmreg.h,v 1.98.6.7 2019/01/31 06:43:48 martin 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 */
@@ -1195,15 +1195,38 @@ struct livengood_tcpip_ctxdesc {
 #define	WMREG_WUC	0x5800	/* Wakeup Control */
 #define	WUC_APME		0x00000001 /* APM Enable */
 #define	WUC_PME_EN		0x00000002 /* PME Enable */
+#define WUC_PME_STATUS		0x00000004 /* PME Status */
+#define WUC_APMPME		0x00000008 /* Assert PME on APM Wakeup */
+#define WUC_PHY_WAKE		0x00000100 /* if PHY supports wakeup */
 
 #define	WMREG_WUFC	0x5808	/* Wakeup Filter Control */
-#define WUFC_MAG		0x00000002 /* Magic Packet Wakeup Enable */
-#define WUFC_EX			0x00000004 /* Directed Exact Wakeup Enable */
-#define WUFC_MC			0x00000008 /* Directed Multicast Wakeup En */
-#define WUFC_BC			0x00000010 /* Broadcast Wakeup Enable */
-#define WUFC_ARP		0x00000020 /* ARP Request Packet Wakeup En */
-#define WUFC_IPV4		0x00000040 /* Directed IPv4 Packet Wakeup En */
-#define WUFC_IPV6		0x00000080 /* Directed IPv6 Packet Wakeup En */
+#define WUFC_LNKC	__BIT(0)	/* Link Status Change Wakeup Enable */
+#define WUFC_MAG	__BIT(1)	/* Magic Packet Wakeup Enable */
+#define WUFC_EX		__BIT(2)	/* Directed Exact Wakeup Enable */
+#define WUFC_MC		__BIT(3)	/* Directed Multicast Wakeup En */
+#define WUFC_BC		__BIT(4)	/* Broadcast Wakeup Enable */
+#define WUFC_ARPDIR	__BIT(5)	/* ARP Request Packet Wakeup En */
+#define WUFC_IPV4	__BIT(6)	/* Directed IPv4 Packet Wakeup En */
+#define WUFC_IPV6	__BIT(7)	/* Directed IPv6 Packet Wakeup En */
+#define WUFC_NS		__BIT(9)	/* NS Wakeup En */
+#define WUFC_NSDIR	__BIT(10)	/* NS Directed En */
+#define WUFC_ARP	__BIT(11)	/* ARP request En */
+#define WUFC_FLEX_HQ	__BIT(14)	/* Flex Filters Host Queueing En */
+#define WUFC_NOTCO	__BIT(15)	/* ? */
+#define WUFC_FLX	__BITS(23, 16)	/* Flexible Filter [0-7] En */
+#define WUFC_FLXACT	__BITS(27, 24)	/* Flexible Filter [0-3] Action */
+#define WUFC_FW_RST_WK	__BIT(31)	/* Wake on Firmware Reset Assert En */
+
+#define	WMREG_WUS	0x5810	/* Wakeup Status (R/W1C) */
+	/* Bit 30-24 and 15-12 are reserved */
+#define WUS_MNG		__BIT(8)	/* Manageability event */
+#define WUS_FLAGS	"\20"						\
+	"\1LINKC"	"\2MAG"		"\3EX"		"\4MC"		\
+	"\5BC"		"\6ARPDIR"	"\7IPV4"	"\10IPV6"	\
+	"\11MNG"	"\12NS"		"\13NSDIR"	"\14ARP"	\
+	"\21FLX0"	"\22FLX1"	"\23FLX2"	"\24FLX3"	\
+	"\25FLX4"	"\26FLX5"	"\27FLX6"	"\30FLX7"	\
+							"\40FW_RST_WK"
 
 #define WMREG_MRQC	0x5818	/* Multiple Receive Queues Command */
 #define MRQC_DISABLE_RSS	0x00000000

Index: src/sys/dev/pci/if_wmvar.h
diff -u src/sys/dev/pci/if_wmvar.h:1.33.6.3 src/sys/dev/pci/if_wmvar.h:1.33.6.4
--- src/sys/dev/pci/if_wmvar.h:1.33.6.3	Sat Aug 11 14:47:32 2018
+++ src/sys/dev/pci/if_wmvar.h	Thu Jan 31 06:43:48 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wmvar.h,v 1.33.6.3 2018/08/11 14:47:32 martin Exp $	*/
+/*	$NetBSD: if_wmvar.h,v 1.33.6.4 2019/01/31 06:43:48 martin Exp $	*/
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -105,7 +105,7 @@
 	"\15" "PCIX"	"\16" "CSA"	"\17" "PCIE"	"\20" "SGMII"	\
 	"\21" "NEWQUEUE" "\22" "ASF_FIRM" "\23" "ARC_SUBSYS" "\24" "AMT" \
 	"\25" "MANAGE"	"\26" "WOL"	"\27" "EEE"	"\30" "ATTACHED" \
-	"\31" "MDIC_WA"	"\32" "PCS_DIS_AUTONEGO" "\33" "PLLWA" "\40" "CLSEMWA"
+	"\31" "MDIC_WA"	"\32" "PCS_DIS_AUTONEGO" "\33" "PLLWA" "\34" "CLSEMWA"
 
 /*
  * Variations of Intel gigabit Ethernet controller:
@@ -166,17 +166,17 @@ typedef enum {
 	WMPHY_M88,
 	WMPHY_IGP,
 	WMPHY_IGP_2,
-	WMPHY_GG82563,
-	WMPHY_IGP_3,
-	WMPHY_IFE,
-	WMPHY_BM,
-	WMPHY_82577,
-	WMPHY_82578,
-	WMPHY_82579,
-	WMPHY_I217,
-	WMPHY_82580,
+	WMPHY_GG82563,	/* 82563: 80003 */
+	WMPHY_IGP_3,	/* 82566: 82575, 82576, ICH8, ICH9 */
+	WMPHY_IFE,	/* 82562 */
+	WMPHY_BM,	/* 82567: ICH8 ICH9 ICH10 */
+	WMPHY_82577,	/* 82577: PCH */
+	WMPHY_82578,	/* 82578: PCH */
+	WMPHY_82579,	/* 82579: PCH2 */
+	WMPHY_I217,	/* I217:  _LPT, I218: _LPT, I219: _SPT _CNP */
+	WMPHY_82580,	/* 82580: 82580 or I350 */
 	WMPHY_VF,
-	WMPHY_I210
+	WMPHY_I210	/* I210: I210 I211 */
 } wm_phy_type;
 
 

Reply via email to