Module Name:    src
Committed By:   snj
Date:           Fri May  6 18:43:35 UTC 2016

Modified Files:
        src/sys/dev/mii [netbsd-6]: igphy.c ukphy.c
        src/sys/dev/pci [netbsd-6]: if_wm.c if_wmreg.h if_wmvar.h

Log Message:
Pull up following revision(s) (requested by msaitoh in ticket #1366):
        sys/dev/pci/if_wm.c: 1.281, 1.318, 1.320, 1.324-1.332, 1.334, 1.336, 
1.343-1.344, 1.347-1.348, 1.350, 1.376-1.382, 1.386-1.387, 1.389 via patch
        sys/dev/pci/if_wmreg.h: 1.68-1.70, 1.73-1.77, 1.79-1.80, 1.82, 
1.86-1.88 via patch
        sys/dev/pci/if_wmvar.h: 1.22-1.23, 1.25-1.30 via patch
        sys/dev/mii/igphy.c: 1.25
        sys/dev/mii/ukphy.c: 1.48
Sync wm(4) as of if_wm.c rev 1.389 except SERDES, MSI/MSI-X, multiqueue
and NET_MPSAFE:
- Set ICH9 and ICH10's PBA size to 14K if the RX buffer size is more
  than 4096. Almost the same as other OSes.
- For 82576 and newer devices, the PBA register is deleted. Don't write
  PBA for those chips. Also change the calculation of RX packet buffer
  size in new way.
- Print NVM image version and option ROM version.
- Add workaround for I210 Errata 25 and I211 Errata 10 (PLL bug). This
  workaround is required if the NVM image version < 3.25.
- Fix a bug that wm_detach() didn't unmap the FHASH's area. Now
  "drvctl -d wm0" -> "drvctl -r pci0" works on ICH* and PCH*.
- Add workaround for 82574 Errata 25 and 82583 Errata 12 "Dropped RX
  packets" and for 82573 (unknown). Set GCR_L1_ACT_WITHOUT_L0S_RX bit.
  The NVM Image version 2.1.4 and newer have this workaround.
- Check PHY type correctly. This change is required to use igphy(4)
  device correctly.
- Disable LPLU (Low Power Link Up) on D0 state on 82574, 82583 and ICH*
  too.
- Call wm_get_hw_control() correctly. This change fixes a bug that some
  AMT based systems doesn't linkup at 1000BaseT. The problem was
  observed on HP Compaq dc7700. A lot of fixes have been done for wm(4)
  and igphy(4), so now PR#44893 should be fixed.
- Call wm_get_wakeup(sc) before checking WM_F_HAS_AMT. It's required to
  check the existence of AMT correctly.
- Fix a problem that wm_gate_hw_phy_config_ich8lan() isn't called in
  wm_reset() on PCH2.
- Clear WMREG_WUC in wm_reset() if the chip >= 82544. This might fix
  the behavior on suspend/resume.
- Fix logic of wm_check_reset_block() on ICH* and PCH*. This change
  might fix a problem that PHY's read/write functions can't get
  semaphore.
- On ICH8, call wm_gig_downshift_workaround_ich8lan() when link changed
  down.
- Drop PHY_CTRL_GBE_DIS explicitly in wm_lplu_d0_disable() in case BIOS
  sets this bit.
- Fix two bugs in wm_kmrn_lock_loss_workaround_ich8lan(). Now the
  function checks the status correctly but it causes linkdown up to 10
  times, so it's disabled for the time being.
- PR/50527: David Binderman: Fix impossible code. Odd offsets need
  special treatment.
- Fix RAL table's size of PCH2 and PCH_LPT.
- PCH_LPT (and newer device) is required to check FWSM_WLOCK_MAC bit to
  determine the range of the RAL.
- Use sc->sc_itr instead of hard-coded number.
- Rename wm_tbi_check_link() to wm_tbi_tick() because this function
  acts as mii_tick().
- ACK Accelerate Disable in the RFCTL register is not bit 13 but 12.
  No binary change because this definition has not used yet.
- Add ACK data Disable bit's definition (not used yet).
- PHY_CTRL_GBE_DIS is not bit 4 but bit 6. This change has no any
  effect by default because WM_WOL is not defined yet and
  m_kmrn_lock_loss_workaround_ich8lan() is broken.
- Fix wm_check_mng_mode_ich8lan(). This function is used only when
  WM_WOL is defined and it's disabled by default.
- Rename wm_check_reset_block() to wm_phy_resetisblocked() and make it
  returns bool. No functional change.
- Reorder function definitions and macro definitions. No functional
  change.
- Fix comment. Add comment. Update comment.
- KNF.


To generate a diff of this commit:
cvs rdiff -u -r1.21.16.1 -r1.21.16.2 src/sys/dev/mii/igphy.c
cvs rdiff -u -r1.43 -r1.43.14.1 src/sys/dev/mii/ukphy.c
cvs rdiff -u -r1.227.2.18 -r1.227.2.19 src/sys/dev/pci/if_wm.c
cvs rdiff -u -r1.46.2.8 -r1.46.2.9 src/sys/dev/pci/if_wmreg.h
cvs rdiff -u -r1.12.10.6 -r1.12.10.7 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/igphy.c
diff -u src/sys/dev/mii/igphy.c:1.21.16.1 src/sys/dev/mii/igphy.c:1.21.16.2
--- src/sys/dev/mii/igphy.c:1.21.16.1	Sun Nov  9 12:13:15 2014
+++ src/sys/dev/mii/igphy.c	Fri May  6 18:43:34 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: igphy.c,v 1.21.16.1 2014/11/09 12:13:15 martin Exp $	*/
+/*	$NetBSD: igphy.c,v 1.21.16.2 2016/05/06 18:43:34 snj Exp $	*/
 
 /*
  * The Intel copyright applies to the analog register setup, and the
@@ -70,7 +70,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: igphy.c,v 1.21.16.1 2014/11/09 12:13:15 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: igphy.c,v 1.21.16.2 2016/05/06 18:43:34 snj Exp $");
 
 #include "opt_mii.h"
 
@@ -154,6 +154,9 @@ igphyattach(device_t parent, device_t se
 	sc->mii_dev = self;
 	sc->mii_inst = mii->mii_instance;
 	sc->mii_phy = ma->mii_phyno;
+	sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
+	sc->mii_mpd_model = MII_MODEL(ma->mii_id2);
+	sc->mii_mpd_rev = MII_REV(ma->mii_id2);
 	sc->mii_funcs = &igphy_funcs;
 	sc->mii_pdata = mii;
 	sc->mii_flags = ma->mii_flags;

Index: src/sys/dev/mii/ukphy.c
diff -u src/sys/dev/mii/ukphy.c:1.43 src/sys/dev/mii/ukphy.c:1.43.14.1
--- src/sys/dev/mii/ukphy.c:1.43	Sun Jun  6 18:58:22 2010
+++ src/sys/dev/mii/ukphy.c	Fri May  6 18:43:34 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ukphy.c,v 1.43 2010/06/06 18:58:22 pgoyette Exp $	*/
+/*	$NetBSD: ukphy.c,v 1.43.14.1 2016/05/06 18:43:34 snj Exp $	*/
 
 /*-
  * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
@@ -59,7 +59,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ukphy.c,v 1.43 2010/06/06 18:58:22 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ukphy.c,v 1.43.14.1 2016/05/06 18:43:34 snj Exp $");
 
 #include "opt_mii.h"
 
@@ -121,6 +121,9 @@ ukphyattach(device_t parent, device_t se
 	sc->mii_dev = self;
 	sc->mii_inst = mii->mii_instance;
 	sc->mii_phy = ma->mii_phyno;
+	sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
+	sc->mii_mpd_model = MII_MODEL(ma->mii_id2);
+	sc->mii_mpd_rev = MII_REV(ma->mii_id2);
 	sc->mii_funcs = &ukphy_funcs;
 	sc->mii_pdata = mii;
 	sc->mii_flags = ma->mii_flags;

Index: src/sys/dev/pci/if_wm.c
diff -u src/sys/dev/pci/if_wm.c:1.227.2.18 src/sys/dev/pci/if_wm.c:1.227.2.19
--- src/sys/dev/pci/if_wm.c:1.227.2.18	Thu Apr 30 19:53:28 2015
+++ src/sys/dev/pci/if_wm.c	Fri May  6 18:43:34 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wm.c,v 1.227.2.18 2015/04/30 19:53:28 snj Exp $	*/
+/*	$NetBSD: if_wm.c,v 1.227.2.19 2016/05/06 18:43:34 snj Exp $	*/
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -72,11 +72,19 @@
  *
  * TODO (in order of importance):
  *
+ *	- Check XXX'ed comments
+ *	- MSI/MSI-X
+ *	- Disable D0 LPLU on 8257[12356], 82580 and I350.
+ *	- Multi queue
+ *	- EEE (Energy Efficiency Ethernet)
+ *	- Image Unique ID
+ *	- Virtual Function
+ *	- Set LED correctly (based on contents in EEPROM)
  *	- Rework how parameters are loaded from the EEPROM.
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.227.2.18 2015/04/30 19:53:28 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.227.2.19 2016/05/06 18:43:34 snj Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -240,6 +248,10 @@ static uint16_t swfwphysem[] = {
 	SWFW_PHY3_SM
 };
 
+static const uint32_t wm_82580_rxpbs_table[] = {
+	36, 72, 144, 1, 2, 4, 8, 16, 35, 70, 140
+};
+
 /*
  * Software state per device.
  */
@@ -253,6 +265,7 @@ struct wm_softc {
 	bus_size_t sc_ios;		/* I/O space size */
 	bus_space_tag_t sc_flasht;	/* flash registers space tag */
 	bus_space_handle_t sc_flashh;	/* flash registers space handle */
+	bus_size_t sc_flashs;		/* flash registers space size */
 	bus_dma_tag_t sc_dmat;		/* bus DMA tag */
 
 	struct ethercom sc_ethercom;	/* ethernet common data */
@@ -261,7 +274,7 @@ struct wm_softc {
 	pci_chipset_tag_t sc_pc;
 	pcitag_t sc_pcitag;
 	int sc_bus_speed;		/* PCI/PCIX bus speed */
-	int sc_pcixe_capoff;		/* PCI[Xe] capability register offset */
+	int sc_pcixe_capoff;		/* PCI[Xe] capability reg offset */
 
 	const struct wm_product *sc_wmp; /* Pointer to the wm_product entry */
 	uint16_t sc_pcidevid;		/* PCI device ID */
@@ -277,22 +290,21 @@ struct wm_softc {
 	void *sc_ih;			/* interrupt cookie */
 	callout_t sc_tick_ch;		/* tick callout */
 
+	int sc_nvm_ver_major;
+	int sc_nvm_ver_minor;
+	int sc_nvm_ver_build;
 	int sc_nvm_addrbits;		/* NVM address bits */
-	unsigned int sc_nvm_wordsize;		/* NVM word size */
+	unsigned int sc_nvm_wordsize;	/* NVM word size */
 	int sc_ich8_flash_base;
 	int sc_ich8_flash_bank_size;
 	int sc_nvm_k1_enabled;
 
-	/*
-	 * Software state for the transmit and receive descriptors.
-	 */
+	/* Software state for the transmit and receive descriptors. */
 	int sc_txnum;			/* must be a power of two */
 	struct wm_txsoft sc_txsoft[WM_TXQUEUELEN_MAX];
 	struct wm_rxsoft sc_rxsoft[WM_NRXDESC];
 
-	/*
-	 * Control data structures.
-	 */
+	/* Control data structures. */
 	int sc_ntxdesc;			/* must be a power of two */
 	struct wm_control_data_82544 *sc_control_data;
 	bus_dmamap_t sc_cddmamap;	/* control data DMA map */
@@ -532,6 +544,7 @@ static void	wm_get_auto_rd_done(struct w
 static void	wm_lan_init_done(struct wm_softc *);
 static void	wm_get_cfg_done(struct wm_softc *);
 static void	wm_initialize_hardware_bits(struct wm_softc *);
+static uint32_t	wm_rxpbs_adjust_82580(uint32_t);
 static void	wm_reset(struct wm_softc *);
 static int	wm_add_rxbuf(struct wm_softc *, int);
 static void	wm_rxdrain(struct wm_softc *);
@@ -580,6 +593,8 @@ static int	wm_gmii_hv_readreg(device_t, 
 static void	wm_gmii_hv_writereg(device_t, int, int, int);
 static int	wm_gmii_82580_readreg(device_t, int, int);
 static void	wm_gmii_82580_writereg(device_t, int, int, int);
+static int	wm_gmii_gs40g_readreg(device_t, int, int);
+static void	wm_gmii_gs40g_writereg(device_t, int, int, int);
 static void	wm_gmii_statchg(device_t);
 static int	wm_kmrn_readreg(struct wm_softc *, int);
 static void	wm_kmrn_writereg(struct wm_softc *, int, int);
@@ -621,11 +636,17 @@ static int32_t	wm_read_ich8_data(struct 
 static int32_t	wm_read_ich8_byte(struct wm_softc *, uint32_t, uint8_t *);
 static int32_t	wm_read_ich8_word(struct wm_softc *, uint32_t, uint16_t *);
 static int	wm_nvm_read_ich8(struct wm_softc *, int, int, uint16_t *);
+/* iNVM */
+static int	wm_nvm_read_word_invm(struct wm_softc *, uint16_t, uint16_t *);
+static int	wm_nvm_read_invm(struct wm_softc *, int, int, uint16_t *);
 /* Lock, detecting NVM type, validate checksum and read */
 static int	wm_nvm_acquire(struct wm_softc *);
 static void	wm_nvm_release(struct wm_softc *);
 static int	wm_nvm_is_onboard_eeprom(struct wm_softc *);
+static int	wm_nvm_get_flash_presence_i210(struct wm_softc *);
 static int	wm_nvm_validate_checksum(struct wm_softc *);
+static void	wm_nvm_version_invm(struct wm_softc *);
+static void	wm_nvm_version(struct wm_softc *);
 static int	wm_nvm_read(struct wm_softc *, int, int, uint16_t *);
 
 /*
@@ -645,12 +666,14 @@ static void	wm_put_hw_semaphore_82573(st
  * Management mode and power management related subroutines.
  * BMC, AMT, suspend/resume and EEE.
  */
+#ifdef WM_WOL
 static int	wm_check_mng_mode(struct wm_softc *);
 static int	wm_check_mng_mode_ich8lan(struct wm_softc *);
 static int	wm_check_mng_mode_82574(struct wm_softc *);
 static int	wm_check_mng_mode_generic(struct wm_softc *);
+#endif
 static int	wm_enable_mng_pass_thru(struct wm_softc *);
-static int	wm_check_reset_block(struct wm_softc *);
+static bool	wm_phy_resetisblocked(struct wm_softc *);
 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 *, int);
@@ -663,6 +686,9 @@ static void	wm_enable_phy_wakeup(struct 
 static void	wm_igp3_phy_powerdown_workaround_ich8lan(struct wm_softc *);
 static void	wm_enable_wakeup(struct wm_softc *);
 #endif
+/* LPLU (Low Power Link Up) */
+static void	wm_lplu_d0_disable(struct wm_softc *);
+static void	wm_lplu_d0_disable_pch(struct wm_softc *);
 /* EEE */
 static void	wm_set_eee_i350(struct wm_softc *);
 
@@ -678,6 +704,7 @@ static void	wm_k1_gig_workaround_hv(stru
 static void	wm_set_mdio_slow_mode_hv(struct wm_softc *);
 static void	wm_configure_k1_ich8lan(struct wm_softc *, int);
 static void	wm_reset_init_script_82575(struct wm_softc *);
+static void	wm_pll_workaround_i210(struct wm_softc *);
 
 CFATTACH_DECL3_NEW(wm, sizeof(struct wm_softc),
     wm_match, wm_attach, wm_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN);
@@ -1642,9 +1669,7 @@ wm_attach(device_t parent, device_t self
 		goto fail_3;
 	}
 
-	/*
-	 * Create the transmit buffer DMA maps.
-	 */
+	/* Create the transmit buffer DMA maps. */
 	WM_TXQUEUELEN(sc) =
 	    (sc->sc_type == WM_T_82547 || sc->sc_type == WM_T_82547_2) ?
 	    WM_TXQUEUELEN_MAX_82547 : WM_TXQUEUELEN_MAX;
@@ -1659,9 +1684,7 @@ wm_attach(device_t parent, device_t self
 		}
 	}
 
-	/*
-	 * Create the receive buffer DMA maps.
-	 */
+	/* Create the receive buffer DMA maps. */
 	for (i = 0; i < WM_NRXDESC; i++) {
 		if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
 			    MCLBYTES, 0, 0,
@@ -1683,14 +1706,10 @@ wm_attach(device_t parent, device_t self
 	    || (sc->sc_type == WM_T_PCH_LPT))
 		wm_smbustopci(sc);
 
-	/*
-	 * Reset the chip to a known state.
-	 */
+	/* Reset the chip to a known state. */
 	wm_reset(sc);
 
-	/*
-	 * Get some information about the EEPROM.
-	 */
+	/* Get some information about the EEPROM. */
 	switch (sc->sc_type) {
 	case WM_T_82542_2_0:
 	case WM_T_82542_2_1:
@@ -1714,13 +1733,13 @@ wm_attach(device_t parent, device_t self
 			sc->sc_nvm_wordsize = 64;
 			sc->sc_nvm_addrbits = 6;
 		}
-		sc->sc_flags |= WM_F_EEPROM_HANDSHAKE;
+		sc->sc_flags |= WM_F_LOCK_EECD;
 		break;
 	case WM_T_82541:
 	case WM_T_82541_2:
 	case WM_T_82547:
 	case WM_T_82547_2:
-		sc->sc_flags |= WM_F_EEPROM_HANDSHAKE;
+		sc->sc_flags |= WM_F_LOCK_EECD;
 		reg = CSR_READ(sc, WMREG_EECD);
 		if (reg & EECD_EE_TYPE) {
 			/* SPI */
@@ -1742,11 +1761,11 @@ wm_attach(device_t parent, device_t self
 		/* SPI */
 		sc->sc_flags |= WM_F_EEPROM_SPI;
 		wm_nvm_set_addrbits_size_eecd(sc);
-		sc->sc_flags |= WM_F_EEPROM_SEMAPHORE;
-		sc->sc_flags |= WM_F_EEPROM_HANDSHAKE;
+		sc->sc_flags |= WM_F_LOCK_SWSM;
+		sc->sc_flags |= WM_F_LOCK_EECD;
 		break;
 	case WM_T_82573:
-		sc->sc_flags |= WM_F_EEPROM_SEMAPHORE;
+		sc->sc_flags |= WM_F_LOCK_SWSM;
 		/* FALLTHROUGH */
 	case WM_T_82574:
 	case WM_T_82583:
@@ -1769,8 +1788,8 @@ wm_attach(device_t parent, device_t self
 		/* SPI */
 		sc->sc_flags |= WM_F_EEPROM_SPI;
 		wm_nvm_set_addrbits_size_eecd(sc);
-		sc->sc_flags |= WM_F_EEPROM_EERDEEWR | WM_F_SWFW_SYNC
-		    | WM_F_EEPROM_SEMAPHORE;
+		sc->sc_flags |= WM_F_EEPROM_EERDEEWR | WM_F_LOCK_SWFW
+		    | WM_F_LOCK_SWSM;
 		break;
 	case WM_T_ICH8:
 	case WM_T_ICH9:
@@ -1779,11 +1798,11 @@ wm_attach(device_t parent, device_t self
 	case WM_T_PCH2:
 	case WM_T_PCH_LPT:
 		/* FLASH */
-		sc->sc_flags |= WM_F_EEPROM_FLASH | WM_F_SWFWHW_SYNC;
+		sc->sc_flags |= WM_F_EEPROM_FLASH | WM_F_LOCK_EXTCNF;
 		sc->sc_nvm_wordsize = 2048;
 		memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, WM_ICH8_FLASH);
 		if (pci_mapreg_map(pa, WM_ICH8_FLASH, memtype, 0,
-		    &sc->sc_flasht, &sc->sc_flashh, NULL, NULL)) {
+		    &sc->sc_flasht, &sc->sc_flashh, NULL, &sc->sc_flashs)) {
 			aprint_error_dev(sc->sc_dev,
 			    "can't map FLASH registers\n");
 			goto fail_5;
@@ -1800,9 +1819,15 @@ wm_attach(device_t parent, device_t self
 		break;
 	case WM_T_I210:
 	case WM_T_I211:
-		wm_nvm_set_addrbits_size_eecd(sc);
-		sc->sc_flags |= WM_F_EEPROM_FLASH_HW;
-		sc->sc_flags |= WM_F_EEPROM_EERDEEWR | WM_F_SWFW_SYNC;
+		if (wm_nvm_get_flash_presence_i210(sc)) {
+			wm_nvm_set_addrbits_size_eecd(sc);
+			sc->sc_flags |= WM_F_EEPROM_FLASH_HW;
+			sc->sc_flags |= WM_F_EEPROM_EERDEEWR | WM_F_LOCK_SWFW;
+		} else {
+			sc->sc_nvm_wordsize = INVM_SIZE;
+			sc->sc_flags |= WM_F_EEPROM_INVM;
+			sc->sc_flags |= WM_F_LOCK_SWFW;
+		}
 		break;
 	default:
 		break;
@@ -1858,24 +1883,46 @@ wm_attach(device_t parent, device_t self
 	prop_dictionary_set_uint32(dict, "macflags", sc->sc_flags);
 
 	if (sc->sc_flags & WM_F_EEPROM_INVALID)
-		aprint_verbose_dev(sc->sc_dev, "No EEPROM\n");
+		aprint_verbose_dev(sc->sc_dev, "No EEPROM");
 	else {
 		aprint_verbose_dev(sc->sc_dev, "%u words ",
 		    sc->sc_nvm_wordsize);
-		if (sc->sc_flags & WM_F_EEPROM_FLASH_HW) {
-			aprint_verbose("FLASH(HW)\n");
-		} else if (sc->sc_flags & WM_F_EEPROM_FLASH) {
-			aprint_verbose("FLASH\n");
-		} else {
+		if (sc->sc_flags & WM_F_EEPROM_INVM)
+			aprint_verbose("iNVM");
+		else if (sc->sc_flags & WM_F_EEPROM_FLASH_HW)
+			aprint_verbose("FLASH(HW)");
+		else if (sc->sc_flags & WM_F_EEPROM_FLASH)
+			aprint_verbose("FLASH");
+		else {
 			if (sc->sc_flags & WM_F_EEPROM_SPI)
 				eetype = "SPI";
 			else
 				eetype = "MicroWire";
-			aprint_verbose("(%d address bits) %s EEPROM\n",
+			aprint_verbose("(%d address bits) %s EEPROM",
 			    sc->sc_nvm_addrbits, eetype);
 		}
 	}
+	wm_nvm_version(sc);
+	aprint_verbose("\n");
 
+	/* Check for I21[01] PLL workaround */
+	if (sc->sc_type == WM_T_I210)
+		sc->sc_flags |= WM_F_PLL_WA_I210;
+	if ((sc->sc_type == WM_T_I210) && wm_nvm_get_flash_presence_i210(sc)) {
+		/* NVM image release 3.25 has a workaround */
+		if ((sc->sc_nvm_ver_major < 3)
+		    || ((sc->sc_nvm_ver_major == 3)
+			&& (sc->sc_nvm_ver_minor < 25))) {
+			aprint_verbose_dev(sc->sc_dev,
+			    "ROM image version %d.%d is older than 3.25\n",
+			    sc->sc_nvm_ver_major, sc->sc_nvm_ver_minor);
+			sc->sc_flags |= WM_F_PLL_WA_I210;
+		}
+	}
+	if ((sc->sc_flags & WM_F_PLL_WA_I210) != 0)
+		wm_pll_workaround_i210(sc);
+
+	wm_get_wakeup(sc);
 	switch (sc->sc_type) {
 	case WM_T_82571:
 	case WM_T_82572:
@@ -1889,13 +1936,14 @@ wm_attach(device_t parent, device_t self
 	case WM_T_PCH:
 	case WM_T_PCH2:
 	case WM_T_PCH_LPT:
-		if (wm_check_mng_mode(sc) != 0)
+		/* Non-AMT based hardware can now take control from firmware */
+		if ((sc->sc_flags & WM_F_HAS_AMT) == 0)
 			wm_get_hw_control(sc);
 		break;
 	default:
 		break;
 	}
-	wm_get_wakeup(sc);
+
 	/*
 	 * Read the Ethernet address from the EEPROM, if not first found
 	 * in device properties.
@@ -2200,9 +2248,7 @@ wm_attach(device_t parent, device_t self
 		break;
 	}
 
-	/*
-	 * If we're a i82543 or greater, we can support VLANs.
-	 */
+	/* If we're a i82543 or greater, we can support VLANs. */
 	if (sc->sc_type >= WM_T_82543)
 		sc->sc_ethercom.ec_capabilities |=
 		    ETHERCAP_VLAN_MTU | ETHERCAP_VLAN_HWTAGGING;
@@ -2243,9 +2289,7 @@ wm_attach(device_t parent, device_t self
 		ifp->if_capabilities |= IFCAP_TSOv6;
 	}
 
-	/*
-	 * Attach the interface.
-	 */
+	/* Attach the interface. */
 	if_attach(ifp);
 	ether_ifattach(ifp, enaddr);
 	ether_set_ifflags_cb(&sc->sc_ethercom, wm_ifflags_cb);
@@ -2408,11 +2452,14 @@ wm_detach(device_t self, int flags __unu
 		bus_space_unmap(sc->sc_st, sc->sc_sh, sc->sc_ss);
 		sc->sc_ss = 0;
 	}
-
 	if (sc->sc_ios) {
 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
 		sc->sc_ios = 0;
 	}
+	if (sc->sc_flashs) {
+		bus_space_unmap(sc->sc_flasht, sc->sc_flashh, sc->sc_flashs);
+		sc->sc_flashs = 0;
+	}
 
 	return 0;
 }
@@ -4037,8 +4084,12 @@ wm_linkintr_gmii(struct wm_softc *sc, ui
 		__func__));
 
 	if (icr & ICR_LSC) {
-		DPRINTF(WM_DEBUG_LINK,
-		    ("%s: LINK: LSC -> mii_pollstat\n",
+		uint32_t status = CSR_READ(sc, WMREG_STATUS);
+
+		if ((sc->sc_type == WM_T_ICH8) && ((status & STATUS_LU) == 0))
+			wm_gig_downshift_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) {
@@ -4226,7 +4277,7 @@ void
 wm_initialize_hardware_bits(struct wm_softc *sc)
 {
 	uint32_t tarc0, tarc1, reg;
-	
+
 	/* For 82571 variant, 80003 and ICHs */
 	if (((sc->sc_type >= WM_T_82571) && (sc->sc_type <= WM_T_82583))
 	    || (sc->sc_type >= WM_T_80003)) {
@@ -4301,6 +4352,17 @@ wm_initialize_hardware_bits(struct wm_so
 			CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
 
 			/* PCIe Control Register */
+			/*
+			 * 82573 Errata (unknown).
+			 *
+			 * 82574 Errata 25 and 82583 Errata 12
+			 * "Dropped Rx Packets":
+			 *   NVM Image Version 2.1.4 and newer has no this bug.
+			 */
+			reg = CSR_READ(sc, WMREG_GCR);
+			reg |= GCR_L1_ACT_WITHOUT_L0S_RX;
+			CSR_WRITE(sc, WMREG_GCR, reg);
+
 			if ((sc->sc_type == WM_T_82574)
 			    || (sc->sc_type == WM_T_82583)) {
 				/*
@@ -4415,6 +4477,17 @@ wm_initialize_hardware_bits(struct wm_so
 	}
 }
 
+static uint32_t
+wm_rxpbs_adjust_82580(uint32_t val)
+{
+	uint32_t rv = 0;
+
+	if (val < __arraycount(wm_82580_rxpbs_table))
+		rv = wm_82580_rxpbs_table[val];
+
+	return rv;
+}
+
 /*
  * wm_reset:
  *
@@ -4446,21 +4519,9 @@ wm_reset(struct wm_softc *sc)
 	case WM_T_82571:
 	case WM_T_82572:
 	case WM_T_82575:	/* XXX need special handing for jumbo frames */
-	case WM_T_I350:
-	case WM_T_I354:
 	case WM_T_80003:
 		sc->sc_pba = PBA_32K;
 		break;
-	case WM_T_82580:
-		sc->sc_pba = PBA_35K;
-		break;
-	case WM_T_I210:
-	case WM_T_I211:
-		sc->sc_pba = PBA_34K;
-		break;
-	case WM_T_82576:
-		sc->sc_pba = PBA_64K;
-		break;
 	case WM_T_82573:
 		sc->sc_pba = PBA_12K;
 		break;
@@ -4468,6 +4529,19 @@ wm_reset(struct wm_softc *sc)
 	case WM_T_82583:
 		sc->sc_pba = PBA_20K;
 		break;
+	case WM_T_82576:
+		sc->sc_pba = CSR_READ(sc, WMREG_RXPBS);
+		sc->sc_pba &= RXPBS_SIZE_MASK_82576;
+		break;
+	case WM_T_82580:
+	case WM_T_I350:
+	case WM_T_I354:
+		sc->sc_pba = wm_rxpbs_adjust_82580(CSR_READ(sc, WMREG_RXPBS));
+		break;
+	case WM_T_I210:
+	case WM_T_I211:
+		sc->sc_pba = PBA_34K;
+		break;
 	case WM_T_ICH8:
 		/* Workaround for a bit corruption issue in FIFO memory */
 		sc->sc_pba = PBA_8K;
@@ -4475,7 +4549,8 @@ wm_reset(struct wm_softc *sc)
 		break;
 	case WM_T_ICH9:
 	case WM_T_ICH10:
-		sc->sc_pba = PBA_10K;
+		sc->sc_pba = sc->sc_ethercom.ec_if.if_mtu > 4096 ?
+		    PBA_14K : PBA_10K;
 		break;
 	case WM_T_PCH:
 	case WM_T_PCH2:
@@ -4487,7 +4562,13 @@ wm_reset(struct wm_softc *sc)
 		    PBA_40K : PBA_48K;
 		break;
 	}
-	CSR_WRITE(sc, WMREG_PBA, sc->sc_pba);
+	/*
+	 * Only old or non-multiqueue devices have the PBA register
+	 * XXX Need special handling for 82575.
+	 */
+	if (((sc->sc_flags & WM_F_NEWQUEUE) == 0)
+	    || (sc->sc_type == WM_T_82575))
+		CSR_WRITE(sc, WMREG_PBA, sc->sc_pba);
 
 	/* Prevent the PCI-E bus from sticking */
 	if (sc->sc_flags & WM_F_PCIE) {
@@ -4588,17 +4669,16 @@ wm_reset(struct wm_softc *sc)
 	case WM_T_PCH2:
 	case WM_T_PCH_LPT:
 		reg = CSR_READ(sc, WMREG_CTRL) | CTRL_RST;
-		if (wm_check_reset_block(sc) == 0) {
+		if (wm_phy_resetisblocked(sc) == false) {
 			/*
 			 * Gate automatic PHY configuration by hardware on
 			 * non-managed 82579
 			 */
 			if ((sc->sc_type == WM_T_PCH2)
 			    && ((CSR_READ(sc, WMREG_FWSM) & FWSM_FW_VALID)
-				!= 0))
+				== 0))
 				wm_gate_hw_phy_config_ich8lan(sc, 1);
 
-
 			reg |= CTRL_PHY_RESET;
 			phy_reset = 1;
 		}
@@ -4761,7 +4841,7 @@ wm_reset(struct wm_softc *sc)
 	/* reload sc_ctrl */
 	sc->sc_ctrl = CSR_READ(sc, WMREG_CTRL);
 
-	if (sc->sc_type == WM_T_I350)
+	if ((sc->sc_type >= WM_T_I350) && (sc->sc_type <= WM_T_I211))
 		wm_set_eee_i350(sc);
 
 	/* dummy read from WUC */
@@ -4775,10 +4855,13 @@ wm_reset(struct wm_softc *sc)
 	if (sc->sc_type == WM_T_PCH)
 		CSR_WRITE(sc, WMREG_CRC_OFFSET, 0x65656565);
 
-	if ((sc->sc_flags & WM_F_NEWQUEUE) != 0)
+	if (sc->sc_type >= WM_T_82544)
 		CSR_WRITE(sc, WMREG_WUC, 0);
 
 	/* XXX need special handling for 82580 */
+
+	if ((sc->sc_flags & WM_F_PLL_WA_I210) != 0)
+		wm_pll_workaround_i210(sc);
 }
 
 static void
@@ -4850,7 +4933,8 @@ wm_init(struct ifnet *ifp)
 	case WM_T_PCH:
 	case WM_T_PCH2:
 	case WM_T_PCH_LPT:
-		if (wm_check_mng_mode(sc) != 0)
+		/* AMT based hardware can now take control from firmware */
+		if ((sc->sc_flags & WM_F_HAS_AMT) != 0)
 			wm_get_hw_control(sc);
 		break;
 	default:
@@ -4946,8 +5030,10 @@ wm_init(struct ifnet *ifp)
 		} else {
 			CSR_WRITE(sc, WMREG_RDH, 0);
 			CSR_WRITE(sc, WMREG_RDT, 0);
-			CSR_WRITE(sc, WMREG_RDTR, 375 | RDTR_FPD); /* ITR/4 */
-			CSR_WRITE(sc, WMREG_RADV, 375);	/* MUST be same */
+			/* ITR/4 */
+			CSR_WRITE(sc, WMREG_RDTR, (sc->sc_itr / 4) | RDTR_FPD);
+			/* MUST be same */
+			CSR_WRITE(sc, WMREG_RADV, sc->sc_itr);
 		}
 	}
 	for (i = 0; i < WM_NRXDESC; i++) {
@@ -5503,12 +5589,12 @@ wm_nvm_acquire(struct wm_softc *sc)
 	if ((sc->sc_flags & WM_F_EEPROM_FLASH) != 0)
 		return 0;
 
-	if (sc->sc_flags & WM_F_SWFWHW_SYNC) {
+	if (sc->sc_flags & WM_F_LOCK_EXTCNF) {
 		ret = wm_get_swfwhw_semaphore(sc);
-	} else if (sc->sc_flags & WM_F_SWFW_SYNC) {
+	} else if (sc->sc_flags & WM_F_LOCK_SWFW) {
 		/* this will also do wm_get_swsm_semaphore() if needed */
 		ret = wm_get_swfw_semaphore(sc, SWFW_EEP_SM);
-	} else if (sc->sc_flags & WM_F_EEPROM_SEMAPHORE) {
+	} else if (sc->sc_flags & WM_F_LOCK_SWSM) {
 		ret = wm_get_swsm_semaphore(sc);
 	}
 
@@ -5518,7 +5604,7 @@ wm_nvm_acquire(struct wm_softc *sc)
 		return 1;
 	}
 
-	if (sc->sc_flags & WM_F_EEPROM_HANDSHAKE) {
+	if (sc->sc_flags & WM_F_LOCK_EECD) {
 		reg = CSR_READ(sc, WMREG_EECD);
 
 		/* Request EEPROM access. */
@@ -5537,11 +5623,11 @@ wm_nvm_acquire(struct wm_softc *sc)
 			    "could not acquire EEPROM GNT\n");
 			reg &= ~EECD_EE_REQ;
 			CSR_WRITE(sc, WMREG_EECD, reg);
-			if (sc->sc_flags & WM_F_SWFWHW_SYNC)
+			if (sc->sc_flags & WM_F_LOCK_EXTCNF)
 				wm_put_swfwhw_semaphore(sc);
-			if (sc->sc_flags & WM_F_SWFW_SYNC)
+			if (sc->sc_flags & WM_F_LOCK_SWFW)
 				wm_put_swfw_semaphore(sc, SWFW_EEP_SM);
-			else if (sc->sc_flags & WM_F_EEPROM_SEMAPHORE)
+			else if (sc->sc_flags & WM_F_LOCK_SWSM)
 				wm_put_swsm_semaphore(sc);
 			return 1;
 		}
@@ -5564,17 +5650,17 @@ wm_nvm_release(struct wm_softc *sc)
 	if ((sc->sc_flags & WM_F_EEPROM_FLASH) != 0)
 		return;
 
-	if (sc->sc_flags & WM_F_EEPROM_HANDSHAKE) {
+	if (sc->sc_flags & WM_F_LOCK_EECD) {
 		reg = CSR_READ(sc, WMREG_EECD);
 		reg &= ~EECD_EE_REQ;
 		CSR_WRITE(sc, WMREG_EECD, reg);
 	}
 
-	if (sc->sc_flags & WM_F_SWFWHW_SYNC)
+	if (sc->sc_flags & WM_F_LOCK_EXTCNF)
 		wm_put_swfwhw_semaphore(sc);
-	if (sc->sc_flags & WM_F_SWFW_SYNC)
+	if (sc->sc_flags & WM_F_LOCK_SWFW)
 		wm_put_swfw_semaphore(sc, SWFW_EEP_SM);
-	else if (sc->sc_flags & WM_F_EEPROM_SEMAPHORE)
+	else if (sc->sc_flags & WM_F_LOCK_SWSM)
 		wm_put_swsm_semaphore(sc);
 }
 
@@ -5667,7 +5753,7 @@ wm_nvm_read_uwire(struct wm_softc *sc, i
 			delay(2);
 		}
 		/* XXX: end of workaround */
-	
+
 		/* Set CHIP SELECT. */
 		reg |= EECD_CS;
 		CSR_WRITE(sc, WMREG_EECD, reg);
@@ -5768,6 +5854,18 @@ wm_nvm_read_spi(struct wm_softc *sc, int
 	return 0;
 }
 
+static int
+wm_nvm_get_flash_presence_i210(struct wm_softc *sc)
+{
+	uint32_t eec;
+
+	eec = CSR_READ(sc, WMREG_EEC);
+	if ((eec & EEC_FLASH_DETECTED) != 0)
+		return 1;
+
+	return 0;
+}
+
 /*
  * wm_nvm_validate_checksum
  *
@@ -5882,6 +5980,133 @@ wm_poll_eerd_eewr_done(struct wm_softc *
 	return done;
 }
 
+static void
+wm_nvm_version_invm(struct wm_softc *sc)
+{
+	uint32_t dword;
+
+	/*
+	 * Linux's code to decode version is very strange, so we don't
+	 * obey that algorithm and just use word 61 as the document.
+	 * Perhaps it's not perfect though...
+	 *
+	 * Example:
+	 *
+	 *   Word61: 00800030 -> Version 0.6 (I211 spec update notes about 0.6)
+	 */
+	dword = CSR_READ(sc, WM_INVM_DATA_REG(61));
+	dword = __SHIFTOUT(dword, INVM_VER_1);
+	sc->sc_nvm_ver_major = __SHIFTOUT(dword, INVM_MAJOR);
+	sc->sc_nvm_ver_minor = __SHIFTOUT(dword, INVM_MINOR);
+}
+
+static void
+wm_nvm_version(struct wm_softc *sc)
+{
+	uint16_t major, minor, build, patch;
+	uint16_t uid0, uid1;
+	uint16_t nvm_data;
+	uint16_t off;
+	bool check_version = false;
+	bool check_optionrom = false;
+	bool have_build = false;
+
+	/*
+	 * Version format:
+	 *
+	 * XYYZ
+	 * X0YZ
+	 * X0YY
+	 *
+	 * Example:
+	 *
+	 *	82571	0x50a2	5.10.2?	(the spec update notes about 5.6-5.10)
+	 *	82571	0x50a6	5.10.6?
+	 *	82572	0x506a	5.6.10?
+	 *	82572EI	0x5069	5.6.9?
+	 *	82574L	0x1080	1.8.0?	(the spec update notes about 2.1.4)
+	 *		0x2013	2.1.3?
+	 *	82583	0x10a0	1.10.0? (document says it's default vaule)
+	 */
+	wm_nvm_read(sc, NVM_OFF_IMAGE_UID1, 1, &uid1);
+	switch (sc->sc_type) {
+	case WM_T_82571:
+	case WM_T_82572:
+	case WM_T_82574:
+	case WM_T_82583:
+		check_version = true;
+		check_optionrom = true;
+		have_build = true;
+		break;
+	case WM_T_82575:
+	case WM_T_82576:
+	case WM_T_82580:
+		if ((uid1 & NVM_MAJOR_MASK) != NVM_UID_VALID)
+			check_version = true;
+		break;
+	case WM_T_I211:
+		wm_nvm_version_invm(sc);
+		goto printver;
+	case WM_T_I210:
+		if (!wm_nvm_get_flash_presence_i210(sc)) {
+			wm_nvm_version_invm(sc);
+			goto printver;
+		}
+		/* FALLTHROUGH */
+	case WM_T_I350:
+	case WM_T_I354:
+		check_version = true;
+		check_optionrom = true;
+		break;
+	default:
+		return;
+	}
+	if (check_version) {
+		wm_nvm_read(sc, NVM_OFF_VERSION, 1, &nvm_data);
+		major = (nvm_data & NVM_MAJOR_MASK) >> NVM_MAJOR_SHIFT;
+		if (have_build || ((nvm_data & 0x0f00) != 0x0000)) {
+			minor = (nvm_data & NVM_MINOR_MASK) >> NVM_MINOR_SHIFT;
+			build = nvm_data & NVM_BUILD_MASK;
+			have_build = true;
+		} else
+			minor = nvm_data & 0x00ff;
+
+		/* Decimal */
+		minor = (minor / 16) * 10 + (minor % 16);
+		sc->sc_nvm_ver_major = major;
+		sc->sc_nvm_ver_minor = minor;
+
+printver:
+		aprint_verbose(", version %d.%d", sc->sc_nvm_ver_major,
+		    sc->sc_nvm_ver_minor);
+		if (have_build) {
+			sc->sc_nvm_ver_build = build;
+			aprint_verbose(".%d", build);
+		}
+	}
+	if (check_optionrom) {
+		wm_nvm_read(sc, NVM_OFF_COMB_VER_PTR, 1, &off);
+		/* Option ROM Version */
+		if ((off != 0x0000) && (off != 0xffff)) {
+			off += NVM_COMBO_VER_OFF;
+			wm_nvm_read(sc, off + 1, 1, &uid1);
+			wm_nvm_read(sc, off, 1, &uid0);
+			if ((uid0 != 0) && (uid0 != 0xffff)
+			    && (uid1 != 0) && (uid1 != 0xffff)) {
+				/* 16bits */
+				major = uid0 >> 8;
+				build = (uid0 << 8) | (uid1 >> 8);
+				patch = uid1 & 0x00ff;
+				aprint_verbose(", option ROM Version %d.%d.%d",
+				    major, build, patch);
+			}
+		}
+	}
+
+	wm_nvm_read(sc, NVM_OFF_IMAGE_UID0, 1, &uid0);
+	aprint_verbose(", Image Unique ID %08x", (uid1 << 16) | uid0);
+}
+
 /*
  * wm_nvm_read:
  *
@@ -5902,6 +6127,8 @@ wm_nvm_read(struct wm_softc *sc, int wor
 	    || (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))
 		rv = wm_nvm_read_ich8(sc, word, wordcnt, data);
+	else if (sc->sc_flags & WM_F_EEPROM_INVM)
+		rv = wm_nvm_read_invm(sc, word, wordcnt, data);
 	else if (sc->sc_flags & WM_F_EEPROM_EERDEEWR)
 		rv = wm_nvm_read_eerd(sc, word, wordcnt, data);
 	else if (sc->sc_flags & WM_F_EEPROM_SPI)
@@ -6127,7 +6354,7 @@ wm_set_filter(struct wm_softc *sc)
 	struct ether_multistep step;
 	bus_addr_t mta_reg;
 	uint32_t hash, reg, bit;
-	int i, size;
+	int i, size, ralmax;
 
 	if (sc->sc_type >= WM_T_82544)
 		mta_reg = WMREG_CORDOVA_MTA;
@@ -6150,9 +6377,12 @@ wm_set_filter(struct wm_softc *sc)
 	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) || (sc->sc_type == WM_T_PCH2)
-	    || (sc->sc_type == WM_T_PCH_LPT))
+	    || (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)
+		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))
@@ -6162,8 +6392,28 @@ wm_set_filter(struct wm_softc *sc)
 	else
 		size = WM_RAL_TABSIZE;
 	wm_set_ral(sc, CLLADDR(ifp->if_sadl), 0);
-	for (i = 1; i < size; i++)
-		wm_set_ral(sc, NULL, i);
+
+	if (sc->sc_type == WM_T_PCH_LPT) {
+		i = __SHIFTOUT(CSR_READ(sc, WMREG_FWSM), FWSM_WLOCK_MAC);
+		switch (i) {
+		case 0:
+			/* We can use all entries */
+			ralmax = size;
+			break;
+		case 1:
+			/* Only RAR[0] */
+			ralmax = 1;
+			break;
+		default:
+			/* available SHRA + RAR[0] */
+			ralmax = i + 1;
+		}
+	} else
+		ralmax = size;
+	for (i = 1; i < size; i++) {
+		if (i < ralmax)
+			wm_set_ral(sc, NULL, i);
+	}
 
 	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)
@@ -6204,8 +6454,12 @@ wm_set_filter(struct wm_softc *sc)
 		hash = CSR_READ(sc, mta_reg + (reg << 2));
 		hash |= 1U << bit;
 
-		/* XXX Hardware bug?? */
-		if (sc->sc_type == WM_T_82544 && (reg & 0xe) == 1) {
+		if (sc->sc_type == WM_T_82544 && (reg & 1) != 0) {
+			/*
+			 * 82544 Errata 9: Certain register cannot be written
+			 * with particular alignments in PCI-X bus operation
+			 * (FCAH, MTA and VFTA).
+			 */
 			bit = CSR_READ(sc, mta_reg + ((reg - 1) << 2));
 			CSR_WRITE(sc, mta_reg + (reg << 2), hash);
 			CSR_WRITE(sc, mta_reg + ((reg - 1) << 2), bit);
@@ -6707,7 +6961,6 @@ wm_gmii_reset(struct wm_softc *sc)
 	case WM_T_82571:
 	case WM_T_82572:
 	case WM_T_82573:
-	case WM_T_82574:
 	case WM_T_82575:
 	case WM_T_82576:
 	case WM_T_82580:
@@ -6715,10 +6968,13 @@ wm_gmii_reset(struct wm_softc *sc)
 	case WM_T_I354:
 	case WM_T_I210:
 	case WM_T_I211:
-	case WM_T_82583:
 	case WM_T_80003:
 		/* null */
 		break;
+	case WM_T_82574:
+	case WM_T_82583:
+		wm_lplu_d0_disable(sc);
+		break;
 	case WM_T_82541:
 	case WM_T_82547:
 		/* XXX Configure actively LED after PHY reset */
@@ -6751,18 +7007,11 @@ wm_gmii_reset(struct wm_softc *sc)
 		 * in NVM
 		 */
 
-		/* Configure the LCD with the OEM bits in NVM */
-		if ((sc->sc_type == WM_T_PCH) || (sc->sc_type == WM_T_PCH2)
-		    || (sc->sc_type == WM_T_PCH_LPT)) {
-			/*
-			 * Disable LPLU.
-			 * XXX It seems that 82567 has LPLU, too.
-			 */
-			reg = wm_gmii_hv_readreg(sc->sc_dev, 1, HV_OEM_BITS);
-			reg &= ~(HV_OEM_BITS_A1KDIS| HV_OEM_BITS_LPLU);
-			reg |= HV_OEM_BITS_ANEGNOW;
-			wm_gmii_hv_writereg(sc->sc_dev, 1, HV_OEM_BITS, reg);
-		}
+		/* Disable D0 LPLU. */
+		if (sc->sc_type >= WM_T_PCH)	/* PCH* */
+			wm_lplu_d0_disable_pch(sc);
+		else
+			wm_lplu_d0_disable(sc);	/* ICH* */
 		break;
 	default:
 		panic("%s: unknown type\n", __func__);
@@ -6894,19 +7143,24 @@ wm_gmii_mediainit(struct wm_softc *sc, p
 	default:
 		if (((sc->sc_flags & WM_F_SGMII) != 0)
 		    && !wm_sgmii_uses_mdio(sc)){
+			/* SGMII */
 			mii->mii_readreg = wm_sgmii_readreg;
 			mii->mii_writereg = wm_sgmii_writereg;
 		} else if (sc->sc_type >= WM_T_80003) {
+			/* 80003 */
 			mii->mii_readreg = wm_gmii_i80003_readreg;
 			mii->mii_writereg = wm_gmii_i80003_writereg;
 		} else if (sc->sc_type >= WM_T_I210) {
-			mii->mii_readreg = wm_gmii_i82544_readreg;
-			mii->mii_writereg = wm_gmii_i82544_writereg;
+			/* I210 and I211 */
+			mii->mii_readreg = wm_gmii_gs40g_readreg;
+			mii->mii_writereg = wm_gmii_gs40g_writereg;
 		} else if (sc->sc_type >= WM_T_82580) {
+			/* 82580, I350 and I354 */
 			sc->sc_phytype = WMPHY_82580;
 			mii->mii_readreg = wm_gmii_82580_readreg;
 			mii->mii_writereg = wm_gmii_82580_writereg;
 		} else if (sc->sc_type >= WM_T_82544) {
+			/* 82544, 0, [56], [17], 8257[1234] and 82583 */
 			mii->mii_readreg = wm_gmii_i82544_readreg;
 			mii->mii_writereg = wm_gmii_i82544_writereg;
 		} else {
@@ -7007,13 +7261,9 @@ wm_gmii_mediainit(struct wm_softc *sc, p
 		struct mii_softc *child;
 
 		child = LIST_FIRST(&mii->mii_phys);
-		if (device_is_a(child->mii_dev, "igphy")) {
-			struct igphy_softc *isc = (struct igphy_softc *)child;
-
-			model = isc->sc_mii.mii_mpd_model;
-			if (model == MII_MODEL_yyINTEL_I82566)
-				sc->sc_phytype = WMPHY_IGP_3;
-		}
+		model = child->mii_mpd_model;
+		if (model == MII_MODEL_yyINTEL_I82566)
+			sc->sc_phytype = WMPHY_IGP_3;
 
 		ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
 	}
@@ -7734,6 +7984,75 @@ wm_gmii_82580_writereg(device_t self, in
 }
 
 /*
+ * wm_gmii_gs40g_readreg:	[mii interface function]
+ *
+ *	Read a PHY register on the I2100 and I211.
+ * This could be handled by the PHY layer if we didn't have to lock the
+ * ressource ...
+ */
+static int
+wm_gmii_gs40g_readreg(device_t self, int phy, int reg)
+{
+	struct wm_softc *sc = device_private(self);
+	int sem;
+	int page, offset;
+	int rv;
+
+	/* Acquire semaphore */
+	sem = swfwphysem[sc->sc_funcid];
+	if (wm_get_swfw_semaphore(sc, sem)) {
+		aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",
+		    __func__);
+		return 0;
+	}
+
+	/* Page select */
+	page = reg >> GS40G_PAGE_SHIFT;
+	wm_gmii_i82544_writereg(self, phy, GS40G_PAGE_SELECT, page);
+
+	/* Read reg */
+	offset = reg & GS40G_OFFSET_MASK;
+	rv = wm_gmii_i82544_readreg(self, phy, offset);
+
+	wm_put_swfw_semaphore(sc, sem);
+	return rv;
+}
+
+/*
+ * wm_gmii_gs40g_writereg:	[mii interface function]
+ *
+ *	Write a PHY register on the I210 and I211.
+ * This could be handled by the PHY layer if we didn't have to lock the
+ * ressource ...
+ */
+static void
+wm_gmii_gs40g_writereg(device_t self, int phy, int reg, int val)
+{
+	struct wm_softc *sc = device_private(self);
+	int sem;
+	int page, offset;
+
+	/* Acquire semaphore */
+	sem = swfwphysem[sc->sc_funcid];
+	if (wm_get_swfw_semaphore(sc, sem)) {
+		aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",
+		    __func__);
+		return;
+	}
+
+	/* Page select */
+	page = reg >> GS40G_PAGE_SHIFT;
+	wm_gmii_i82544_writereg(self, phy, GS40G_PAGE_SELECT, page);
+
+	/* Write reg */
+	offset = reg & GS40G_OFFSET_MASK;
+	wm_gmii_i82544_writereg(self, phy, offset, val);
+
+	/* Release semaphore */
+	wm_put_swfw_semaphore(sc, sem);
+}
+
+/*
  * wm_gmii_statchg:	[mii interface function]
  *
  *	Callback from MII layer when media changes.
@@ -7807,13 +8126,13 @@ wm_kmrn_readreg(struct wm_softc *sc, int
 {
 	int rv;
 
-	if (sc->sc_flags == WM_F_SWFW_SYNC) {
+	if (sc->sc_flags & WM_F_LOCK_SWFW) {
 		if (wm_get_swfw_semaphore(sc, SWFW_MAC_CSR_SM)) {
 			aprint_error_dev(sc->sc_dev,
 			    "%s: failed to get semaphore\n", __func__);
 			return 0;
 		}
-	} else if (sc->sc_flags == WM_F_SWFWHW_SYNC) {
+	} else if (sc->sc_flags & WM_F_LOCK_EXTCNF) {
 		if (wm_get_swfwhw_semaphore(sc)) {
 			aprint_error_dev(sc->sc_dev,
 			    "%s: failed to get semaphore\n", __func__);
@@ -7829,9 +8148,9 @@ wm_kmrn_readreg(struct wm_softc *sc, int
 
 	rv = CSR_READ(sc, WMREG_KUMCTRLSTA) & KUMCTRLSTA_MASK;
 
-	if (sc->sc_flags == WM_F_SWFW_SYNC)
+	if (sc->sc_flags & WM_F_LOCK_SWFW)
 		wm_put_swfw_semaphore(sc, SWFW_MAC_CSR_SM);
-	else if (sc->sc_flags == WM_F_SWFWHW_SYNC)
+	else if (sc->sc_flags & WM_F_LOCK_EXTCNF)
 		wm_put_swfwhw_semaphore(sc);
 
 	return rv;
@@ -7846,13 +8165,13 @@ static void
 wm_kmrn_writereg(struct wm_softc *sc, int reg, int val)
 {
 
-	if (sc->sc_flags == WM_F_SWFW_SYNC) {
+	if (sc->sc_flags & WM_F_LOCK_SWFW) {
 		if (wm_get_swfw_semaphore(sc, SWFW_MAC_CSR_SM)) {
 			aprint_error_dev(sc->sc_dev,
 			    "%s: failed to get semaphore\n", __func__);
 			return;
 		}
-	} else if (sc->sc_flags == WM_F_SWFWHW_SYNC) {
+	} else if (sc->sc_flags & WM_F_LOCK_EXTCNF) {
 		if (wm_get_swfwhw_semaphore(sc)) {
 			aprint_error_dev(sc->sc_dev,
 			    "%s: failed to get semaphore\n", __func__);
@@ -7864,9 +8183,9 @@ wm_kmrn_writereg(struct wm_softc *sc, in
 	    ((reg << KUMCTRLSTA_OFFSET_SHIFT) & KUMCTRLSTA_OFFSET) |
 	    (val & KUMCTRLSTA_MASK));
 
-	if (sc->sc_flags == WM_F_SWFW_SYNC)
+	if (sc->sc_flags & WM_F_LOCK_SWFW)
 		wm_put_swfw_semaphore(sc, SWFW_MAC_CSR_SM);
-	else if (sc->sc_flags == WM_F_SWFWHW_SYNC)
+	else if (sc->sc_flags & WM_F_LOCK_EXTCNF)
 		wm_put_swfwhw_semaphore(sc);
 }
 
@@ -7895,7 +8214,7 @@ wm_get_swsm_semaphore(struct wm_softc *s
 	int32_t timeout;
 	uint32_t swsm;
 
-	if (sc->sc_flags & WM_F_EEPROM_SEMAPHORE) {
+	if (sc->sc_flags & WM_F_LOCK_SWSM) {
 		/* Get the SW semaphore. */
 		timeout = sc->sc_nvm_wordsize + 1;
 		while (timeout) {
@@ -7958,7 +8277,7 @@ wm_get_swfw_semaphore(struct wm_softc *s
 	int timeout = 200;
 
 	for (timeout = 0; timeout < 200; timeout++) {
-		if (sc->sc_flags & WM_F_EEPROM_SEMAPHORE) {
+		if (sc->sc_flags & WM_F_LOCK_SWSM) {
 			if (wm_get_swsm_semaphore(sc)) {
 				aprint_error_dev(sc->sc_dev,
 				    "%s: failed to get semaphore\n",
@@ -7970,11 +8289,11 @@ wm_get_swfw_semaphore(struct wm_softc *s
 		if ((swfw_sync & (swmask | fwmask)) == 0) {
 			swfw_sync |= swmask;
 			CSR_WRITE(sc, WMREG_SW_FW_SYNC, swfw_sync);
-			if (sc->sc_flags & WM_F_EEPROM_SEMAPHORE)
+			if (sc->sc_flags & WM_F_LOCK_SWSM)
 				wm_put_swsm_semaphore(sc);
 			return 0;
 		}
-		if (sc->sc_flags & WM_F_EEPROM_SEMAPHORE)
+		if (sc->sc_flags & WM_F_LOCK_SWSM)
 			wm_put_swsm_semaphore(sc);
 		delay(5000);
 	}
@@ -7988,14 +8307,14 @@ wm_put_swfw_semaphore(struct wm_softc *s
 {
 	uint32_t swfw_sync;
 
-	if (sc->sc_flags & WM_F_EEPROM_SEMAPHORE) {
+	if (sc->sc_flags & WM_F_LOCK_SWSM) {
 		while (wm_get_swsm_semaphore(sc) != 0)
 			continue;
 	}
 	swfw_sync = CSR_READ(sc, WMREG_SW_FW_SYNC);
 	swfw_sync &= ~(mask << SWFW_SOFT_SHIFT);
 	CSR_WRITE(sc, WMREG_SW_FW_SYNC, swfw_sync);
-	if (sc->sc_flags & WM_F_EEPROM_SEMAPHORE)
+	if (sc->sc_flags & WM_F_LOCK_SWSM)
 		wm_put_swsm_semaphore(sc);
 }
 
@@ -8007,11 +8326,11 @@ wm_get_swfwhw_semaphore(struct wm_softc 
 
 	for (timeout = 0; timeout < 200; timeout++) {
 		ext_ctrl = CSR_READ(sc, WMREG_EXTCNFCTR);
-		ext_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
+		ext_ctrl |= EXTCNFCTR_MDIO_SW_OWNERSHIP;
 		CSR_WRITE(sc, WMREG_EXTCNFCTR, ext_ctrl);
 
 		ext_ctrl = CSR_READ(sc, WMREG_EXTCNFCTR);
-		if (ext_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
+		if (ext_ctrl & EXTCNFCTR_MDIO_SW_OWNERSHIP)
 			return 0;
 		delay(5000);
 	}
@@ -8025,7 +8344,7 @@ wm_put_swfwhw_semaphore(struct wm_softc 
 {
 	uint32_t ext_ctrl;
 	ext_ctrl = CSR_READ(sc, WMREG_EXTCNFCTR);
-	ext_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
+	ext_ctrl &= ~EXTCNFCTR_MDIO_SW_OWNERSHIP;
 	CSR_WRITE(sc, WMREG_EXTCNFCTR, ext_ctrl);
 }
 
@@ -8392,6 +8711,103 @@ wm_read_ich8_word(struct wm_softc *sc, u
 	return status;
 }
 
+/* iNVM */
+
+static int
+wm_nvm_read_word_invm(struct wm_softc *sc, uint16_t address, uint16_t *data)
+{
+	int32_t  rv = 0;
+	uint32_t invm_dword;
+	uint16_t i;
+	uint8_t record_type, word_address;
+
+	for (i = 0; i < INVM_SIZE; i++) {
+		invm_dword = CSR_READ(sc, WM_INVM_DATA_REG(i));
+		/* Get record type */
+		record_type = INVM_DWORD_TO_RECORD_TYPE(invm_dword);
+		if (record_type == INVM_UNINITIALIZED_STRUCTURE)
+			break;
+		if (record_type == INVM_CSR_AUTOLOAD_STRUCTURE)
+			i += INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS;
+		if (record_type == INVM_RSA_KEY_SHA256_STRUCTURE)
+			i += INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS;
+		if (record_type == INVM_WORD_AUTOLOAD_STRUCTURE) {
+			word_address = INVM_DWORD_TO_WORD_ADDRESS(invm_dword);
+			if (word_address == address) {
+				*data = INVM_DWORD_TO_WORD_DATA(invm_dword);
+				rv = 0;
+				break;
+			}
+		}
+	}
+
+	return rv;
+}
+
+static int
+wm_nvm_read_invm(struct wm_softc *sc, int offset, int words, uint16_t *data)
+{
+	int rv = 0;
+	int i;
+
+	for (i = 0; i < words; i++) {
+		switch (offset + i) {
+		case NVM_OFF_MACADDR:
+		case NVM_OFF_MACADDR1:
+		case NVM_OFF_MACADDR2:
+			rv = wm_nvm_read_word_invm(sc, offset + i, &data[i]);
+			if (rv != 0) {
+				data[i] = 0xffff;
+				rv = -1;
+			}
+			break;
+		case NVM_OFF_CFG2:
+			rv = wm_nvm_read_word_invm(sc, offset, data);
+			if (rv != 0) {
+				*data = NVM_INIT_CTRL_2_DEFAULT_I211;
+				rv = 0;
+			}
+			break;
+		case NVM_OFF_CFG4:
+			rv = wm_nvm_read_word_invm(sc, offset, data);
+			if (rv != 0) {
+				*data = NVM_INIT_CTRL_4_DEFAULT_I211;
+				rv = 0;
+			}
+			break;
+		case NVM_OFF_LED_1_CFG:
+			rv = wm_nvm_read_word_invm(sc, offset, data);
+			if (rv != 0) {
+				*data = NVM_LED_1_CFG_DEFAULT_I211;
+				rv = 0;
+			}
+			break;
+		case NVM_OFF_LED_0_2_CFG:
+			rv = wm_nvm_read_word_invm(sc, offset, data);
+			if (rv != 0) {
+				*data = NVM_LED_0_2_CFG_DEFAULT_I211;
+				rv = 0;
+			}
+			break;
+		case NVM_OFF_ID_LED_SETTINGS:
+			rv = wm_nvm_read_word_invm(sc, offset, data);
+			if (rv != 0) {
+				*data = ID_LED_RESERVED_FFFF;
+				rv = 0;
+			}
+			break;
+		default:
+			DPRINTF(WM_DEBUG_NVM,
+			    ("NVM word 0x%02x is not mapped.\n", offset));
+			*data = NVM_RESERVED_WORD;
+			break;
+		}
+	}
+
+	return rv;
+}
+
+#ifdef WM_WOL
 static int
 wm_check_mng_mode(struct wm_softc *sc)
 {
@@ -8432,7 +8848,8 @@ wm_check_mng_mode_ich8lan(struct wm_soft
 
 	fwsm = CSR_READ(sc, WMREG_FWSM);
 
-	if ((fwsm & FWSM_MODE_MASK) == (MNG_ICH_IAMT_MODE << FWSM_MODE_SHIFT))
+	if (((fwsm & FWSM_FW_VALID) != 0)
+	    && (__SHIFTOUT(fwsm, FWSM_MODE) == MNG_ICH_IAMT_MODE))
 		return 1;
 
 	return 0;
@@ -8458,11 +8875,12 @@ wm_check_mng_mode_generic(struct wm_soft
 
 	fwsm = CSR_READ(sc, WMREG_FWSM);
 
-	if ((fwsm & FWSM_MODE_MASK) == (MNG_IAMT_MODE << FWSM_MODE_SHIFT))
+	if (__SHIFTOUT(fwsm, FWSM_MODE) == MNG_IAMT_MODE)
 		return 1;
 
 	return 0;
 }
+#endif /* WM_WOL */
 
 static int
 wm_enable_mng_pass_thru(struct wm_softc *sc)
@@ -8483,8 +8901,7 @@ wm_enable_mng_pass_thru(struct wm_softc 
 		fwsm = CSR_READ(sc, WMREG_FWSM);
 		factps = CSR_READ(sc, WMREG_FACTPS);
 		if (((factps & FACTPS_MNGCG) == 0)
-		    && ((fwsm & FWSM_MODE_MASK)
-			== (MNG_ICH_IAMT_MODE << FWSM_MODE_SHIFT)))
+		    && (__SHIFTOUT(fwsm, FWSM_MODE) == MNG_ICH_IAMT_MODE))
 			return 1;
 	} else if ((sc->sc_type == WM_T_82574) || (sc->sc_type == WM_T_82583)){
 		uint16_t data;
@@ -8504,10 +8921,12 @@ wm_enable_mng_pass_thru(struct wm_softc 
 	return 0;
 }
 
-static int
-wm_check_reset_block(struct wm_softc *sc)
+static bool
+wm_phy_resetisblocked(struct wm_softc *sc)
 {
+	bool blocked = false;
 	uint32_t reg;
+	int i = 0;
 
 	switch (sc->sc_type) {
 	case WM_T_ICH8:
@@ -8516,11 +8935,16 @@ wm_check_reset_block(struct wm_softc *sc
 	case WM_T_PCH:
 	case WM_T_PCH2:
 	case WM_T_PCH_LPT:
-		reg = CSR_READ(sc, WMREG_FWSM);
-		if ((reg & FWSM_RSPCIPHY) != 0)
-			return 0;
-		else
-			return -1;
+		do {
+			reg = CSR_READ(sc, WMREG_FWSM);
+			if ((reg & FWSM_RSPCIPHY) == 0) {
+				blocked = true;
+				delay(10*1000);
+				continue;
+			}
+			blocked = false;
+		} while (blocked && (i++ < 10));
+		return blocked;
 		break;
 	case WM_T_82571:
 	case WM_T_82572:
@@ -8530,16 +8954,16 @@ wm_check_reset_block(struct wm_softc *sc
 	case WM_T_80003:
 		reg = CSR_READ(sc, WMREG_MANC);
 		if ((reg & MANC_BLK_PHY_RST_ON_IDE) != 0)
-			return -1;
+			return true;
 		else
-			return 0;
+			return false;
 		break;
 	default:
 		/* no problem */
 		break;
 	}
 
-	return 0;
+	return false;
 }
 
 static void
@@ -8664,13 +9088,14 @@ wm_check_for_link(struct wm_softc *sc)
 static void
 wm_kmrn_lock_loss_workaround_ich8lan(struct wm_softc *sc)
 {
+#if 0
 	int miistatus, active, i;
 	int reg;
 
 	miistatus = sc->sc_mii.mii_media_status;
 
 	/* If the link is not up, do nothing */
-	if ((miistatus & IFM_ACTIVE) != 0)
+	if ((miistatus & IFM_ACTIVE) == 0)
 		return;
 
 	active = sc->sc_mii.mii_media_active;
@@ -8683,7 +9108,7 @@ wm_kmrn_lock_loss_workaround_ich8lan(str
 		/* read twice */
 		reg = wm_gmii_i80003_readreg(sc->sc_dev, 1, IGP3_KMRN_DIAG);
 		reg = wm_gmii_i80003_readreg(sc->sc_dev, 1, IGP3_KMRN_DIAG);
-		if ((reg & IGP3_KMRN_DIAG_PCS_LOCK_LOSS) != 0)
+		if ((reg & IGP3_KMRN_DIAG_PCS_LOCK_LOSS) == 0)
 			goto out;	/* GOOD! */
 
 		/* Reset the PHY */
@@ -8704,6 +9129,7 @@ wm_kmrn_lock_loss_workaround_ich8lan(str
 
 out:
 	return;
+#endif
 }
 
 /* WOL from S5 stops working */
@@ -8882,7 +9308,7 @@ wm_smbustopci(struct wm_softc *sc)
 
 	fwsm = CSR_READ(sc, WMREG_FWSM);
 	if (((fwsm & FWSM_FW_VALID) == 0)
-	    && ((wm_check_reset_block(sc) == 0))) {
+	    && ((wm_phy_resetisblocked(sc) == false))) {
 		sc->sc_ctrl |= CTRL_LANPHYPC_OVERRIDE;
 		sc->sc_ctrl &= ~CTRL_LANPHYPC_VALUE;
 		CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
@@ -8963,6 +9389,81 @@ wm_reset_init_script_82575(struct wm_sof
 	wm_82575_write_8bit_ctlr_reg(sc, WMREG_SCCTL, 0x10, 0x00);
 }
 
+/*
+ * I210 Errata 25 and I211 Errata 10
+ * Slow System Clock.
+ */
+static void
+wm_pll_workaround_i210(struct wm_softc *sc)
+{
+	uint32_t mdicnfg, wuc;
+	uint32_t reg;
+	pcireg_t pcireg;
+	uint32_t pmreg;
+	uint16_t nvmword, tmp_nvmword;
+	int phyval;
+	bool wa_done = false;
+	int i;
+
+	/* Save WUC and MDICNFG registers */
+	wuc = CSR_READ(sc, WMREG_WUC);
+	mdicnfg = CSR_READ(sc, WMREG_MDICNFG);
+
+	reg = mdicnfg & ~MDICNFG_DEST;
+	CSR_WRITE(sc, WMREG_MDICNFG, reg);
+
+	if (wm_nvm_read(sc, INVM_AUTOLOAD, 1, &nvmword) != 0)
+		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);
+
+		if ((phyval & GS40G_PHY_PLL_UNCONF) != GS40G_PHY_PLL_UNCONF) {
+			break; /* OK */
+		}
+
+		wa_done = true;
+		/* Directly reset the internal PHY */
+		reg = CSR_READ(sc, WMREG_CTRL);
+		CSR_WRITE(sc, WMREG_CTRL, reg | CTRL_PHY_RESET);
+
+		reg = CSR_READ(sc, WMREG_CTRL_EXT);
+		reg |= CTRL_EXT_PHYPDEN | CTRL_EXT_SDLPE;
+		CSR_WRITE(sc, WMREG_CTRL_EXT, reg);
+
+		CSR_WRITE(sc, WMREG_WUC, 0);
+		reg = (INVM_AUTOLOAD << 4) | (tmp_nvmword << 16);
+		CSR_WRITE(sc, WMREG_EEARBC_I210, reg);
+
+		pcireg = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
+		    pmreg + PCI_PMCSR);
+		pcireg |= PCI_PMCSR_STATE_D3;
+		pci_conf_write(sc->sc_pc, sc->sc_pcitag,
+		    pmreg + PCI_PMCSR, pcireg);
+		delay(1000);
+		pcireg &= ~PCI_PMCSR_STATE_D3;
+		pci_conf_write(sc->sc_pc, sc->sc_pcitag,
+		    pmreg + PCI_PMCSR, pcireg);
+
+		reg = (INVM_AUTOLOAD << 4) | (nvmword << 16);
+		CSR_WRITE(sc, WMREG_EEARBC_I210, reg);
+
+		/* Restore WUC register */
+		CSR_WRITE(sc, WMREG_WUC, wuc);
+	}
+
+	/* Restore MDICNFG setting */
+	CSR_WRITE(sc, WMREG_MDICNFG, mdicnfg);
+	if (wa_done)
+		aprint_verbose_dev(sc->sc_dev, "I210 workaround done\n");
+}
+
 static void
 wm_init_manageability(struct wm_softc *sc)
 {
@@ -8979,7 +9480,6 @@ wm_init_manageability(struct wm_softc *s
 			manc |= MANC_EN_MNG2HOST;
 			manc2h |= MANC2H_PORT_623| MANC2H_PORT_624;
 			CSR_WRITE(sc, WMREG_MANC2H, manc2h);
-		
 		}
 
 		CSR_WRITE(sc, WMREG_MANC, manc);
@@ -9022,7 +9522,7 @@ wm_get_wakeup(struct wm_softc *sc)
 	case WM_T_82580:
 	case WM_T_I350:
 	case WM_T_I354:
-		if ((CSR_READ(sc, WMREG_FWSM) & FWSM_MODE_MASK) != 0)
+		if ((CSR_READ(sc, WMREG_FWSM) & FWSM_MODE) != 0)
 			sc->sc_flags |= WM_F_ARC_SUBSYS_VALID;
 		sc->sc_flags |= WM_F_ASF_FIRMWARE_PRES;
 		break;
@@ -9170,6 +9670,29 @@ wm_enable_wakeup(struct wm_softc *sc)
 }
 #endif /* WM_WOL */
 
+/* LPLU */
+
+static void
+wm_lplu_d0_disable(struct wm_softc *sc)
+{
+	uint32_t reg;
+
+	reg = CSR_READ(sc, WMREG_PHY_CTRL);
+	reg &= ~(PHY_CTRL_GBE_DIS | PHY_CTRL_D0A_LPLU);
+	CSR_WRITE(sc, WMREG_PHY_CTRL, reg);
+}
+
+static void
+wm_lplu_d0_disable_pch(struct wm_softc *sc)
+{
+	uint32_t reg;
+
+	reg = wm_gmii_hv_readreg(sc->sc_dev, 1, HV_OEM_BITS);
+	reg &= ~(HV_OEM_BITS_A1KDIS | HV_OEM_BITS_LPLU);
+	reg |= HV_OEM_BITS_ANEGNOW;
+	wm_gmii_hv_writereg(sc->sc_dev, 1, HV_OEM_BITS, reg);
+}
+
 static bool
 wm_suspend(device_t self, const pmf_qual_t *qual)
 {
@@ -9194,8 +9717,10 @@ wm_resume(device_t self, const pmf_qual_
 	return true;
 }
 
+/* EEE */
+
 static void
-wm_set_eee_i350(struct wm_softc * sc)
+wm_set_eee_i350(struct wm_softc *sc)
 {
 	uint32_t ipcnfg, eeer;
 
@@ -9208,6 +9733,7 @@ wm_set_eee_i350(struct wm_softc * sc)
 		    | EEER_LPI_FC);
 	} else {
 		ipcnfg &= ~(IPCNFG_EEE_1G_AN | IPCNFG_EEE_100M_AN);
+		ipcnfg &= ~IPCNFG_10BASE_TE;
 		eeer &= ~(EEER_TX_LPI_EN | EEER_RX_LPI_EN
 		    | EEER_LPI_FC);
 	}

Index: src/sys/dev/pci/if_wmreg.h
diff -u src/sys/dev/pci/if_wmreg.h:1.46.2.8 src/sys/dev/pci/if_wmreg.h:1.46.2.9
--- src/sys/dev/pci/if_wmreg.h:1.46.2.8	Thu Apr 16 06:20:08 2015
+++ src/sys/dev/pci/if_wmreg.h	Fri May  6 18:43:34 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wmreg.h,v 1.46.2.8 2015/04/16 06:20:08 snj Exp $	*/
+/*	$NetBSD: if_wmreg.h,v 1.46.2.9 2016/05/06 18:43:34 snj Exp $	*/
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -315,7 +315,9 @@ struct livengood_tcpip_ctxdesc {
 #define	CTRL_EXT_SPD_BYPS	(1U << 15) /* speed select bypass */
 #define	CTRL_EXT_IPS1		(1U << 16) /* invert power state bit 1 */
 #define	CTRL_EXT_RO_DIS		(1U << 17) /* relaxed ordering disabled */
-#define	CTRL_EXT_DMA_DYN_CLK	(1U << 19) /* DMA Dymamic Gating Enable */
+#define	CTRL_EXT_SDLPE		(1U << 18) /* SerDes Low Power Enable */
+#define	CTRL_EXT_DMA_DYN_CLK	(1U << 19) /* DMA Dynamic Gating Enable */
+#define	CTRL_EXT_PHYPDEN	__BIT(20)
 #define	CTRL_EXT_LINK_MODE_MASK		0x00C00000
 #define	CTRL_EXT_LINK_MODE_GMII		0x00000000
 #define	CTRL_EXT_LINK_MODE_KMRN		0x00000000
@@ -324,7 +326,6 @@ struct livengood_tcpip_ctxdesc {
 #define	CTRL_EXT_LINK_MODE_PCIX_SERDES	0x00800000
 #define	CTRL_EXT_LINK_MODE_TBI		0x00C00000
 #define	CTRL_EXT_LINK_MODE_PCIE_SERDES	0x00C00000
-#define	CTRL_EXT_PHYPDEN	0x00100000
 #define CTRL_EXT_I2C_ENA	0x02000000  /* I2C enable */
 #define	CTRL_EXT_DRV_LOAD	0x10000000
 
@@ -414,6 +415,8 @@ struct livengood_tcpip_ctxdesc {
 
 #define	WM_RAL_TABSIZE		15	/* RAL size for old devices */
 #define	WM_RAL_TABSIZE_ICH8	7	/* RAL size for ICH* and PCH* */
+#define	WM_RAL_TABSIZE_PCH2	5	/* RAL size for PCH2 */
+#define	WM_RAL_TABSIZE_PCH_LPT	12	/* RAL size for PCH_LPT */
 #define	WM_RAL_TABSIZE_82575	16	/* RAL size for 82575 */
 #define	WM_RAL_TABSIZE_82576	24	/* RAL size for 82576 and 82580 */
 #define	WM_RAL_TABSIZE_I350	32	/* RAL size for I350 */
@@ -642,6 +645,7 @@ struct livengood_tcpip_ctxdesc {
 #define EEER_EEER_TX_LPI_STATUS	0x80000000 /* EEER Tx in LPI state */
 #define WMREG_EEE_SU	0x0e34	/* EEE Setup */
 #define WMREG_IPCNFG	0x0e38	/* Internal PHY Configuration */
+#define IPCNFG_10BASE_TE	0x00000002 /* IPCNFG 10BASE-Te low power op. */
 #define IPCNFG_EEE_100M_AN	0x00000004 /* IPCNFG EEE Ena 100M AN */
 #define IPCNFG_EEE_1G_AN	0x00000008 /* IPCNFG EEE Ena 1G AN */
 
@@ -655,14 +659,13 @@ struct livengood_tcpip_ctxdesc {
 #define EXTCNFCTR_MDIO_HW_OWNERSHIP	0x00000040
 #define EXTCNFCTR_GATE_PHY_CFG		0x00000080
 #define EXTCNFCTR_EXT_CNF_POINTER	0x0FFF0000
-#define E1000_EXTCNF_CTRL_SWFLAG	EXTCNFCTR_MDIO_SW_OWNERSHIP
 
 #define	WMREG_PHY_CTRL	0x0f10	/* PHY control */
 #define	PHY_CTRL_SPD_EN		(1 << 0)
 #define	PHY_CTRL_D0A_LPLU	(1 << 1)
 #define	PHY_CTRL_NOND0A_LPLU	(1 << 2)
 #define	PHY_CTRL_NOND0A_GBE_DIS	(1 << 3)
-#define	PHY_CTRL_GBE_DIS	(1 << 4)
+#define	PHY_CTRL_GBE_DIS	(1 << 6)
 
 #define	WMREG_PBA	0x1000	/* Packet Buffer Allocation */
 #define	PBA_BYTE_SHIFT	10		/* KB -> bytes */
@@ -670,6 +673,7 @@ struct livengood_tcpip_ctxdesc {
 #define	PBA_8K		0x0008
 #define	PBA_10K		0x000a
 #define	PBA_12K		0x000c
+#define	PBA_14K		0x000e
 #define	PBA_16K		0x0010		/* 16K, default Tx allocation */
 #define	PBA_20K		0x0014
 #define	PBA_22K		0x0016
@@ -739,6 +743,9 @@ struct livengood_tcpip_ctxdesc {
 #define WMREG_EITR(x)	(0x01680 + (0x4 * (x)))
 #define EITR_ITR_INT_MASK	0x0000ffff
 
+#define	WMREG_RXPBS	0x2404	/* Rx Packet Buffer Size  */
+#define RXPBS_SIZE_MASK_82576	0x0000007F
+
 #define	WMREG_RDFH	0x2410	/* Receive Data FIFO Head */
 #define	WMREG_RDFT	0x2418	/* Receive Data FIFO Tail */
 #define	WMREG_RDFHS	0x2420	/* Receive Data FIFO Head Saved */
@@ -807,7 +814,8 @@ struct livengood_tcpip_ctxdesc {
 #define WMREG_RFCTL	0x5008	/* Receive Filter Control */
 #define WMREG_RFCTL_NFSWDIS	__BIT(6)  /* NFS Write Disable */
 #define WMREG_RFCTL_NFSRDIS	__BIT(7)  /* NFS Read Disable */
-#define WMREG_RFCTL_ACKDIS	__BIT(13) /* ACK Accelerate Disable */
+#define WMREG_RFCTL_ACKDIS	__BIT(12) /* ACK Accelerate Disable */
+#define WMREG_RFCTL_ACKD_DIS	__BIT(13) /* ACK data Disable */
 #define WMREG_RFCTL_IPV6EXDIS	__BIT(16) /* IPv6 Extension Header Disable */
 #define WMREG_RFCTL_NEWIPV6EXDIS __BIT(17) /* New IPv6 Extension Header */
 
@@ -835,7 +843,7 @@ struct livengood_tcpip_ctxdesc {
 #define	MANC_EN_MAC_ADDR_FILTER	0x00100000
 #define	MANC_EN_MNG2HOST	0x00200000
 
-#define	WMREG_MANC2H	0x5860	/* Manaegment Control To Host - RW */
+#define	WMREG_MANC2H	0x5860	/* Management Control To Host - RW */
 #define MANC2H_PORT_623		(1 << 5)
 #define MANC2H_PORT_624		(1 << 6)
 
@@ -850,6 +858,7 @@ struct livengood_tcpip_ctxdesc {
 #define GCR_CMPL_TMOUT_10MS	0x00001000
 #define GCR_CMPL_TMOUT_RESEND	0x00010000
 #define GCR_CAP_VER2		0x00040000
+#define GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
 
 #define WMREG_FACTPS	0x5b30	/* Function Active and Power State to MNG */
 #define FACTPS_MNGCG		0x20000000
@@ -866,12 +875,12 @@ struct livengood_tcpip_ctxdesc {
 #define	SWSM_DRV_LOAD	0x00000008	/* Driver Loaded Bit */
 
 #define	WMREG_FWSM	0x5b54	/* FW Semaphore */
-#define	FWSM_MODE_MASK		0xe
-#define	FWSM_MODE_SHIFT		0x1
+#define	FWSM_MODE		__BITS(1, 3)
 #define	MNG_ICH_IAMT_MODE	0x2	/* PT mode? */
 #define	MNG_IAMT_MODE		0x3
-#define FWSM_RSPCIPHY		0x00000040	/* Reset PHY on PCI reset */
-#define FWSM_FW_VALID		0x00008000 /* FW established a valid mode */
+#define FWSM_RSPCIPHY		__BIT(6)  /* Reset PHY on PCI reset */
+#define FWSM_WLOCK_MAC		__BITS(7, 9)  /* Reset PHY on PCI reset */
+#define FWSM_FW_VALID		__BIT(15) /* FW established a valid mode */
 
 #define	WMREG_SWSM2	0x5b58	/* SW Semaphore 2 */
 #define SWSM2_LOCK		0x00000002 /* Secondary driver semaphore bit */
@@ -890,6 +899,12 @@ struct livengood_tcpip_ctxdesc {
 
 #define WMREG_CRC_OFFSET 0x5f50
 
+#define WMREG_EEC	0x12010
+#define EEC_FLASH_DETECTED (1U << 19)	/* FLASH */
+#define EEC_FLUPD	(1U << 23)	/* Update FLASH */
+
+#define WMREG_EEARBC_I210 0x12024
+
 /*
  * NVM related values.
  *  Microwire, SPI, and flash
@@ -917,18 +932,28 @@ struct livengood_tcpip_ctxdesc {
 #define NVM_SIZE		0x0040
 #define NVM_WORD_SIZE_BASE_SHIFT 6
 
-#define	NVM_OFF_MACADDR		0x0000	/* MAC address offset */
+#define	NVM_OFF_MACADDR		0x0000	/* MAC address offset 0 */
+#define	NVM_OFF_MACADDR1	0x0001	/* MAC address offset 1 */
+#define	NVM_OFF_MACADDR2	0x0002	/* MAC address offset 2 */
 #define NVM_OFF_COMPAT		0x0003
+#define NVM_OFF_ID_LED_SETTINGS	0x0004
+#define NVM_OFF_VERSION		0x0005
 #define	NVM_OFF_CFG1		0x000a	/* config word 1 */
 #define	NVM_OFF_CFG2		0x000f	/* config word 2 */
 #define	NVM_OFF_EEPROM_SIZE	0x0012	/* NVM SIZE */
+#define	NVM_OFF_CFG4		0x0013	/* config word 4 */
 #define	NVM_OFF_CFG3_PORTB	0x0014	/* config word 3 */
 #define NVM_OFF_FUTURE_INIT_WORD1 0x0019
 #define	NVM_OFF_INIT_3GIO_3	0x001a	/* PCIe Initial Configuration Word 3 */
 #define	NVM_OFF_K1_CONFIG	0x001b	/* NVM K1 Config */
+#define	NVM_OFF_LED_1_CFG	0x001c
+#define	NVM_OFF_LED_0_2_CFG	0x001f
 #define	NVM_OFF_SWDPIN		0x0020	/* SWD Pins (Cordova) */
 #define	NVM_OFF_CFG3_PORTA	0x0024	/* config word 3 */
 #define NVM_OFF_ALT_MAC_ADDR_PTR 0x0037	/* to the alternative MAC addresses */
+#define NVM_OFF_COMB_VER_PTR	0x003d
+#define NVM_OFF_IMAGE_UID0	0x0042
+#define NVM_OFF_IMAGE_UID1	0x0043
 
 #define NVM_COMPAT_VALID_CHECKSUM	0x0001
 
@@ -988,6 +1013,54 @@ struct livengood_tcpip_ctxdesc {
  */
 #define NVM_OFF_LAN_FUNC_82580(x)	((x) ? (0x40 + (0x40 * (x))) : 0)
 
+#define NVM_COMBO_VER_OFF	0x0083
+
+#define NVM_MAJOR_MASK		0xf000
+#define NVM_MAJOR_SHIFT		12
+#define NVM_MINOR_MASK		0x0ff0
+#define NVM_MINOR_SHIFT		4
+#define NVM_BUILD_MASK		0x000f
+#define NVM_UID_VALID		0x8000
+
+/* iNVM Registers for i21[01] */
+#define WM_INVM_DATA_REG(reg)	(0x12120 + 4*(reg))
+#define INVM_SIZE			64 /* Number of INVM Data Registers */
+
+/* iNVM default vaule */
+#define NVM_INIT_CTRL_2_DEFAULT_I211	0x7243
+#define NVM_INIT_CTRL_4_DEFAULT_I211	0x00c1
+#define NVM_LED_1_CFG_DEFAULT_I211	0x0184
+#define NVM_LED_0_2_CFG_DEFAULT_I211	0x200c
+#define NVM_RESERVED_WORD		0xffff
+
+#define INVM_DWORD_TO_RECORD_TYPE(dword)	((dword) & 0x7)
+#define INVM_DWORD_TO_WORD_ADDRESS(dword)	(((dword) & 0x0000FE00) >> 9)
+#define INVM_DWORD_TO_WORD_DATA(dword)		(((dword) & 0xFFFF0000) >> 16)
+
+#define INVM_UNINITIALIZED_STRUCTURE		0x0
+#define INVM_WORD_AUTOLOAD_STRUCTURE		0x1
+#define INVM_CSR_AUTOLOAD_STRUCTURE		0x2
+#define INVM_PHY_REGISTER_AUTOLOAD_STRUCTURE	0x3
+#define INVM_RSA_KEY_SHA256_STRUCTURE		0x4
+#define INVM_INVALIDATED_STRUCTURE		0xf
+
+#define INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS	8
+#define INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS	1
+
+#define INVM_DEFAULT_AL		0x202f
+#define INVM_AUTOLOAD		0x0a
+#define INVM_PLL_WO_VAL		0x0010
+
+/* Version and Image Type field */
+#define INVM_VER_1	__BITS(12,3)
+#define INVM_VER_2	__BITS(22,13)
+#define INVM_IMGTYPE	__BITS(28,23)
+#define INVM_MINOR	__BITS(3,0)
+#define INVM_MAJOR	__BITS(9,4)
+
+/* Word definitions for ID LED Settings */
+#define ID_LED_RESERVED_FFFF 0xFFFF
+
 /* ich8 flash control */
 #define ICH_FLASH_COMMAND_TIMEOUT            5000    /* 5000 uSecs - adjusted */
 #define ICH_FLASH_ERASE_TIMEOUT              3000000 /* Up to 3 seconds - worst case */
@@ -1060,6 +1133,13 @@ typedef union nq_txdesc {
 	} nqrx_ctx;
 } __packed nq_txdesc_t;
 
+/* I21[01] PHY related definitions */
+#define GS40G_PAGE_SELECT	0x16
+#define GS40G_PAGE_SHIFT	16
+#define GS40G_OFFSET_MASK	0xffff
+#define GS40G_PHY_PLL_FREQ_PAGE	0xfc0000
+#define GS40G_PHY_PLL_FREQ_REG	0x000e
+#define GS40G_PHY_PLL_UNCONF	0xff
 
 /* Commands for nqtxd_cmdlen and nqtxc_cmd */
 #define	NQTX_CMD_EOP	(1U << 24)	/* end of packet */

Index: src/sys/dev/pci/if_wmvar.h
diff -u src/sys/dev/pci/if_wmvar.h:1.12.10.6 src/sys/dev/pci/if_wmvar.h:1.12.10.7
--- src/sys/dev/pci/if_wmvar.h:1.12.10.6	Thu Apr 30 19:53:28 2015
+++ src/sys/dev/pci/if_wmvar.h	Fri May  6 18:43:34 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wmvar.h,v 1.12.10.6 2015/04/30 19:53:28 snj Exp $	*/
+/*	$NetBSD: if_wmvar.h,v 1.12.10.7 2016/05/06 18:43:34 snj Exp $	*/
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -73,29 +73,46 @@
 
 /* sc_flags */
 #define	WM_F_HAS_MII		0x00000001 /* has MII */
-#define	WM_F_EEPROM_HANDSHAKE	0x00000002 /* requires EEPROM handshake */
-#define	WM_F_EEPROM_SEMAPHORE	0x00000004 /* EEPROM with semaphore */
-#define	WM_F_EEPROM_EERDEEWR	0x00000008 /* EEPROM access via EERD/EEWR */
-#define	WM_F_EEPROM_SPI		0x00000010 /* EEPROM is SPI */
-#define	WM_F_EEPROM_FLASH	0x00000020 /* EEPROM is FLASH */
-#define	WM_F_EEPROM_INVALID	0x00000040 /* EEPROM not present (bad checksum) */
-#define	WM_F_IOH_VALID		0x00000080 /* I/O handle is valid */
-#define	WM_F_BUS64		0x00000100 /* bus is 64-bit */
-#define	WM_F_PCIX		0x00000200 /* bus is PCI-X */
-#define	WM_F_CSA		0x00000400 /* bus is CSA */
-#define	WM_F_PCIE		0x00000800 /* bus is PCI-Express */
-#define WM_F_SWFW_SYNC		0x00001000 /* Software-Firmware synchronisation */
-#define WM_F_SWFWHW_SYNC	0x00002000 /* Software-Firmware synchronisation */
-#define WM_F_SGMII		0x00004000 /* use SGMII */
-#define WM_F_NEWQUEUE		0x00008000 /* chips which has the new queue system */
-#define WM_F_ASF_FIRMWARE_PRES	0x00010000
-#define WM_F_ARC_SUBSYS_VALID	0x00020000
-#define WM_F_HAS_AMT		0x00040000
-#define WM_F_HAS_MANAGE		0x00080000
-#define WM_F_WOL		0x00100000
-#define WM_F_EEE		0x00200000 /* Energy Efficiency Ethernet */
-#define	WM_F_EEPROM_FLASH_HW	0x00400000 /* EEPROM is FLASH */
-#define WM_F_ATTACHED		0x00800000 /* attach() fininsed successfully */
+#define	WM_F_LOCK_EECD		0x00000002 /* Lock using with EECD register */
+#define	WM_F_LOCK_SWSM		0x00000004 /* Lock using with SWSM register */
+#define WM_F_LOCK_SWFW		0x00000008 /* Lock using with SWFW register */
+#define WM_F_LOCK_EXTCNF	0x00000010 /* Lock using with EXTCNF reg. */
+#define	WM_F_EEPROM_EERDEEWR	0x00000020 /* EEPROM access via EERD/EEWR */
+#define	WM_F_EEPROM_SPI		0x00000040 /* EEPROM is SPI */
+#define	WM_F_EEPROM_FLASH	0x00000080 /* EEPROM is FLASH */
+#define	WM_F_EEPROM_FLASH_HW	0x00000100 /* EEPROM is FLASH */
+#define	WM_F_EEPROM_INVALID	0x00000200 /* EEPROM not present (bad cksum) */
+#define	WM_F_IOH_VALID		0x00000400 /* I/O handle is valid */
+#define	WM_F_BUS64		0x00000800 /* bus is 64-bit */
+#define	WM_F_PCIX		0x00001000 /* bus is PCI-X */
+#define	WM_F_CSA		0x00002000 /* bus is CSA */
+#define	WM_F_PCIE		0x00004000 /* bus is PCI-Express */
+#define WM_F_SGMII		0x00008000 /* use SGMII */
+#define WM_F_NEWQUEUE		0x00010000 /* use new queue system */
+#define WM_F_ASF_FIRMWARE_PRES	0x00020000
+#define WM_F_ARC_SUBSYS_VALID	0x00040000
+#define WM_F_HAS_AMT		0x00080000
+#define WM_F_HAS_MANAGE		0x00100000
+#define WM_F_WOL		0x00200000
+#define WM_F_EEE		0x00400000 /* Energy Efficiency Ethernet */
+#define WM_F_ATTACHED		0x00800000 /* attach() finished successfully */
+#define	WM_F_EEPROM_INVM	0x01000000 /* NVM is iNVM */
+#define	WM_F_PLL_WA_I210	0x04000000 /* I21[01] PLL workaround */
+
+/*
+ * Variations of Intel gigabit Ethernet controller:
+ *
+ *  +-- 82542
+ *  |  +-- 82543 - 82544
+ *  |  |  +-- 82540 - 82545 - 82546
+ *  |  |  |  +-- 82541 - 82547
+ *  |  |  |  |  +---------- 82571 - 82572 - 82573 - 82574 - 82583
+ *  |  |  |  |  |  +--------- 82575 - 82576 - 82580 - I350 - I354 - I210 - I211
+ *  |  |  |  |  |  |  +-- 80003
+ *  |  |  |  |  |  |  |  +-- ICH8 - ICH9 - ICH10 - PCH - PCH2 - PCH_LPT
+ *  |  |  |  |  |  |  |  |
+ * -+--+--+--+--+--+--+--+----------------------------------------------->
+ */
 
 typedef enum {
 	WM_T_unknown		= 0,
@@ -125,12 +142,12 @@ typedef enum {
 	WM_T_I210,			/* I210 */
 	WM_T_I211,			/* I211 */
 	WM_T_80003,			/* i80003 */
-	WM_T_ICH8,			/* ICH8 LAN */
+	WM_T_ICH8,			/* ICH8 (I/O Controller Hub) LAN */
 	WM_T_ICH9,			/* ICH9 LAN */
 	WM_T_ICH10,			/* ICH10 LAN */
-	WM_T_PCH,			/* PCH LAN */
+	WM_T_PCH,			/* PCH (Platform Controller Hub) LAN */
 	WM_T_PCH2,			/* PCH2 LAN */
-	WM_T_PCH_LPT,			/* PCH LPT LAN (I21[78]) */
+	WM_T_PCH_LPT,			/* PCH "Lynx Point" LAN (I217, I218) */
 } wm_chip_type;
 
 typedef enum {
@@ -154,5 +171,6 @@ typedef enum {
 #define WM_PHY_CFG_TIMEOUT	100
 #define	WM_ICH8_LAN_INIT_TIMEOUT 1500
 #define	WM_MDIO_OWNERSHIP_TIMEOUT 10
+#define	WM_MAX_PLL_TRIES	5
 
 #endif /* _DEV_PCI_IF_WMVAR_H_ */

Reply via email to