Module Name:    src
Committed By:   snj
Date:           Fri Feb 26 22:08:17 UTC 2016

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

Log Message:
Pull up following revision(s) (requested by msaitoh in ticket #1102):
        sys/dev/mii/igphy.c: 1.25
        sys/dev/mii/ukphy.c: 1.48
        sys/dev/pci/if_wm.c: revisions 1.308, 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.389 via patch
        sys/dev/pci/if_wmreg.h: revisions 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: revisions 1.22-1.23, 1.25-1.30 via patch
Sync wm(4) as of if_wm.c rev 1.389 except MSI/MSI-X, multiqueue and NET_MPSAFE:
- Add C2000 KX and 2.5G support.
- 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.
- Fix a lot of bugs to make 82575 and newer SERDES based systems work.
- 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
  "drvct -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.23 -r1.23.2.1 src/sys/dev/mii/igphy.c
cvs rdiff -u -r1.46 -r1.46.8.1 src/sys/dev/mii/ukphy.c
cvs rdiff -u -r1.289.2.8 -r1.289.2.9 src/sys/dev/pci/if_wm.c
cvs rdiff -u -r1.60.2.4 -r1.60.2.5 src/sys/dev/pci/if_wmreg.h
cvs rdiff -u -r1.19.2.3 -r1.19.2.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/igphy.c
diff -u src/sys/dev/mii/igphy.c:1.23 src/sys/dev/mii/igphy.c:1.23.2.1
--- src/sys/dev/mii/igphy.c:1.23	Mon Jun 16 16:48:16 2014
+++ src/sys/dev/mii/igphy.c	Fri Feb 26 22:08:17 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: igphy.c,v 1.23 2014/06/16 16:48:16 msaitoh Exp $	*/
+/*	$NetBSD: igphy.c,v 1.23.2.1 2016/02/26 22:08:17 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.23 2014/06/16 16:48:16 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: igphy.c,v 1.23.2.1 2016/02/26 22:08:17 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.46 src/sys/dev/mii/ukphy.c:1.46.8.1
--- src/sys/dev/mii/ukphy.c:1.46	Tue Jun 11 16:18:48 2013
+++ src/sys/dev/mii/ukphy.c	Fri Feb 26 22:08:17 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ukphy.c,v 1.46 2013/06/11 16:18:48 msaitoh Exp $	*/
+/*	$NetBSD: ukphy.c,v 1.46.8.1 2016/02/26 22:08:17 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.46 2013/06/11 16:18:48 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ukphy.c,v 1.46.8.1 2016/02/26 22:08:17 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.289.2.8 src/sys/dev/pci/if_wm.c:1.289.2.9
--- src/sys/dev/pci/if_wm.c:1.289.2.8	Wed Jun 10 16:43:51 2015
+++ src/sys/dev/pci/if_wm.c	Fri Feb 26 22:08:17 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wm.c,v 1.289.2.8 2015/06/10 16:43:51 snj Exp $	*/
+/*	$NetBSD: if_wm.c,v 1.289.2.9 2016/02/26 22:08:17 snj Exp $	*/
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -75,13 +75,16 @@
  *	- Check XXX'ed comments
  *	- EEE (Energy Efficiency Ethernet)
  *	- MSI/MSI-X
+ *	- Multi queue
+ *	- Image Unique ID
+ *	- Disable D0 LPLU on 8257[12356], 82580 and I350.
  *	- 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.289.2.8 2015/06/10 16:43:51 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.289.2.9 2016/02/26 22:08:17 snj Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -249,6 +252,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.
  */
@@ -262,6 +269,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 */
@@ -291,8 +299,11 @@ struct wm_softc {
 	callout_t sc_tick_ch;		/* tick callout */
 	bool sc_stopping;
 
+	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;
@@ -334,7 +345,7 @@ struct wm_softc {
 	struct evcnt sc_ev_txtsopain;	/* painful header manip. for TSO */
 
 	struct evcnt sc_ev_txseg[WM_NTXSEGS]; /* Tx packets w/ N segments */
-	struct evcnt sc_ev_txdrop;	/* Tx packets dropped (too many segs) */
+	struct evcnt sc_ev_txdrop;	/* Tx packets dropped(too many segs) */
 
 	struct evcnt sc_ev_tu;		/* Tx underrun */
 
@@ -384,8 +395,8 @@ struct wm_softc {
 	uint32_t sc_pba;		/* prototype PBA register */
 
 	int sc_tbi_linkup;		/* TBI link status */
-	int sc_tbi_anegticks;		/* autonegotiation ticks */
-	int sc_tbi_ticks;		/* tbi ticks */
+	int sc_tbi_serdes_anegticks;	/* autonegotiation ticks */
+	int sc_tbi_serdes_ticks;	/* tbi ticks */
 
 	int sc_mchash_type;		/* multicast filter offset */
 
@@ -518,7 +529,7 @@ do {									\
 	__rxd->wrx_status = 0;						\
 	__rxd->wrx_errors = 0;						\
 	__rxd->wrx_special = 0;						\
-	WM_CDRXSYNC((sc), (x), BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); \
+	WM_CDRXSYNC((sc), (x), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); \
 									\
 	CSR_WRITE((sc), (sc)->sc_rdt_reg, (x));				\
 } while (/*CONSTCOND*/0)
@@ -562,6 +573,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 *);
@@ -586,6 +598,7 @@ static void	wm_txintr(struct wm_softc *)
 static void	wm_rxintr(struct wm_softc *);
 static void	wm_linkintr_gmii(struct wm_softc *, uint32_t);
 static void	wm_linkintr_tbi(struct wm_softc *, uint32_t);
+static void	wm_linkintr_serdes(struct wm_softc *, uint32_t);
 static void	wm_linkintr(struct wm_softc *, uint32_t);
 static int	wm_intr(void *);
 
@@ -593,12 +606,14 @@ static int	wm_intr(void *);
  * Media related.
  * GMII, SGMII, TBI, SERDES and SFP.
  */
+/* Common */
+static void	wm_tbi_serdes_set_linkled(struct wm_softc *);
 /* GMII related */
 static void	wm_gmii_reset(struct wm_softc *);
 static int	wm_get_phy_id_82575(struct wm_softc *);
 static void	wm_gmii_mediainit(struct wm_softc *, pci_product_id_t);
-static void	wm_gmii_mediastatus(struct ifnet *, struct ifmediareq *);
 static int	wm_gmii_mediachange(struct ifnet *);
+static void	wm_gmii_mediastatus(struct ifnet *, struct ifmediareq *);
 static void	wm_i82543_mii_sendbits(struct wm_softc *, uint32_t, int);
 static uint32_t	wm_i82543_mii_recvbits(struct wm_softc *);
 static int	wm_gmii_i82543_readreg(device_t, int, int);
@@ -614,6 +629,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(struct ifnet *);
 static int	wm_kmrn_readreg(struct wm_softc *, int);
 static void	wm_kmrn_writereg(struct wm_softc *, int, int);
@@ -622,12 +639,16 @@ static bool	wm_sgmii_uses_mdio(struct wm
 static int	wm_sgmii_readreg(device_t, int, int);
 static void	wm_sgmii_writereg(device_t, int, int, int);
 /* TBI related */
-static int	wm_check_for_link(struct wm_softc *);
 static void	wm_tbi_mediainit(struct wm_softc *);
-static void	wm_tbi_mediastatus(struct ifnet *, struct ifmediareq *);
 static int	wm_tbi_mediachange(struct ifnet *);
-static void	wm_tbi_set_linkled(struct wm_softc *);
-static void	wm_tbi_check_link(struct wm_softc *);
+static void	wm_tbi_mediastatus(struct ifnet *, struct ifmediareq *);
+static int	wm_check_for_link(struct wm_softc *);
+static void	wm_tbi_tick(struct wm_softc *);
+/* SERDES related */
+static void	wm_serdes_power_up_link_82575(struct wm_softc *);
+static int	wm_serdes_mediachange(struct ifnet *);
+static void	wm_serdes_mediastatus(struct ifnet *, struct ifmediareq *);
+static void	wm_serdes_tick(struct wm_softc *);
 /* SFP related */
 static int	wm_sfp_read_data_byte(struct wm_softc *, uint16_t, uint8_t *);
 static uint32_t	wm_sfp_get_media_type(struct wm_softc *);
@@ -667,6 +688,8 @@ static void	wm_nvm_release(struct wm_sof
 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 *);
 
 /*
@@ -686,12 +709,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);
@@ -704,6 +729,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 *);
 
@@ -719,6 +747,8 @@ 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_reset_mdicnfg_82580(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);
@@ -1168,9 +1198,18 @@ static const struct wm_product {
 	  "I350 Gigabit Connection",
 	  WM_T_I350,		WMP_F_COPPER },
 
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_C2000_1000KX,
+	  "I354 Gigabit Ethernet (KX)",
+	  WM_T_I354,		WMP_F_SERDES },
+
 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_C2000_SGMII,
-	  "I354 Gigabit Connection",
+	  "I354 Gigabit Ethernet (SGMII)",
+	  WM_T_I354,		WMP_F_COPPER },
+
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_C2000_25GBE,
+	  "I354 Gigabit Ethernet (2.5G)",
 	  WM_T_I354,		WMP_F_COPPER },
+
 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I210_T1,
 	  "I210-T1 Ethernet Server Adapter",
 	  WM_T_I210,		WMP_F_COPPER },
@@ -1348,7 +1387,7 @@ wm_attach(device_t parent, device_t self
 	prop_data_t ea;
 	prop_number_t pn;
 	uint8_t enaddr[ETHER_ADDR_LEN];
-	uint16_t cfg1, cfg2, swdpin, io3;
+	uint16_t cfg1, cfg2, swdpin, nvmword;
 	pcireg_t preg, memtype;
 	uint16_t eeprom_data, apme_mask;
 	bool force_clear_smbi;
@@ -1378,7 +1417,7 @@ wm_attach(device_t parent, device_t self
 		sc->sc_dmat = pa->pa_dmat;
 
 	sc->sc_pcidevid = PCI_PRODUCT(pa->pa_id);
-	sc->sc_rev = PCI_REVISION(pci_conf_read(pc, pa->pa_tag, PCI_CLASS_REG));
+	sc->sc_rev = PCI_REVISION(pci_conf_read(pc, pa->pa_tag,PCI_CLASS_REG));
 	pci_aprint_devinfo_fancy(pa, "Ethernet controller", wmp->wmp_name, 1);
 
 	sc->sc_type = wmp->wmp_type;
@@ -1580,11 +1619,9 @@ wm_attach(device_t parent, device_t self
 				pcix_sts = pci_conf_read(pa->pa_pc, pa->pa_tag,
 				    sc->sc_pcixe_capoff + PCIX_STATUS);
 
-				bytecnt =
-				    (pcix_cmd & PCIX_CMD_BYTECNT_MASK) >>
+				bytecnt = (pcix_cmd & PCIX_CMD_BYTECNT_MASK) >>
 				    PCIX_CMD_BYTECNT_SHIFT;
-				maxb =
-				    (pcix_sts & PCIX_STATUS_MAXB_MASK) >>
+				maxb = (pcix_sts & PCIX_STATUS_MAXB_MASK) >>
 				    PCIX_STATUS_MAXB_SHIFT;
 				if (bytecnt > maxb) {
 					aprint_verbose_dev(sc->sc_dev,
@@ -1808,20 +1845,19 @@ wm_attach(device_t parent, device_t self
 		/* FLASH */
 		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);
+		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;
 		}
 		reg = ICH8_FLASH_READ32(sc, ICH_FLASH_GFPREG);
 		sc->sc_ich8_flash_base = (reg & ICH_GFPREG_BASE_MASK) *
-						ICH_FLASH_SECTOR_SIZE;
+		    ICH_FLASH_SECTOR_SIZE;
 		sc->sc_ich8_flash_bank_size =
 		    ((reg >> 16) & ICH_GFPREG_BASE_MASK) + 1;
-		sc->sc_ich8_flash_bank_size -=
-		    (reg & ICH_GFPREG_BASE_MASK);
+		sc->sc_ich8_flash_bank_size -= (reg & ICH_GFPREG_BASE_MASK);
 		sc->sc_ich8_flash_bank_size *= ICH_FLASH_SECTOR_SIZE;
 		sc->sc_ich8_flash_bank_size /= 2 * sizeof(uint16_t);
 		break;
@@ -1834,7 +1870,7 @@ wm_attach(device_t parent, device_t self
 		} else {
 			sc->sc_nvm_wordsize = INVM_SIZE;
 			sc->sc_flags |= WM_F_EEPROM_INVM;
-			sc->sc_flags |= WM_F_EEPROM_EERDEEWR | WM_F_LOCK_SWFW;
+			sc->sc_flags |= WM_F_LOCK_SWFW;
 		}
 		break;
 	default:
@@ -1891,26 +1927,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_INVM)
-			aprint_verbose("iNVM\n");
+			aprint_verbose("iNVM");
 		else if (sc->sc_flags & WM_F_EEPROM_FLASH_HW)
-			aprint_verbose("FLASH(HW)\n");
+			aprint_verbose("FLASH(HW)");
 		else if (sc->sc_flags & WM_F_EEPROM_FLASH)
-			aprint_verbose("FLASH\n");
+			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:
@@ -1924,13 +1980,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.
@@ -2028,6 +2085,14 @@ wm_attach(device_t parent, device_t self
 		printf("WOL\n");
 #endif
 
+	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) {
+			if ((nvmword & NVM_COMPAT_SERDES_FORCE_MODE) != 0)
+				sc->sc_flags |= WM_F_PCS_DIS_AUTONEGO;
+		}
+	}
+
 	/*
 	 * XXX need special handling for some multiple port cards
 	 * to disable a paticular port.
@@ -2049,17 +2114,34 @@ wm_attach(device_t parent, device_t self
 
 	if (cfg1 & NVM_CFG1_ILOS)
 		sc->sc_ctrl |= CTRL_ILOS;
-	if (sc->sc_type >= WM_T_82544) {
-		sc->sc_ctrl |=
-		    ((swdpin >> NVM_SWDPIN_SWDPIO_SHIFT) & 0xf) <<
-		    CTRL_SWDPIO_SHIFT;
-		sc->sc_ctrl |=
-		    ((swdpin >> NVM_SWDPIN_SWDPIN_SHIFT) & 0xf) <<
-		    CTRL_SWDPINS_SHIFT;
-	} else {
-		sc->sc_ctrl |=
-		    ((cfg1 >> NVM_CFG1_SWDPIO_SHIFT) & 0xf) <<
-		    CTRL_SWDPIO_SHIFT;
+
+	/*
+	 * XXX
+	 * This code isn't correct because pin 2 and 3 are located
+	 * in different position on newer chips. Check all datasheet.
+	 *
+	 * Until resolve this problem, check if a chip < 82580
+	 */
+	if (sc->sc_type <= WM_T_82580) {
+		if (sc->sc_type >= WM_T_82544) {
+			sc->sc_ctrl |=
+			    ((swdpin >> NVM_SWDPIN_SWDPIO_SHIFT) & 0xf) <<
+			    CTRL_SWDPIO_SHIFT;
+			sc->sc_ctrl |=
+			    ((swdpin >> NVM_SWDPIN_SWDPIN_SHIFT) & 0xf) <<
+			    CTRL_SWDPINS_SHIFT;
+		} else {
+			sc->sc_ctrl |=
+			    ((cfg1 >> NVM_CFG1_SWDPIO_SHIFT) & 0xf) <<
+			    CTRL_SWDPIO_SHIFT;
+		}
+	}
+
+	/* XXX For other than 82580? */
+	if (sc->sc_type == WM_T_82580) {
+		wm_nvm_read(sc, NVM_OFF_CFG3_PORTA, 1, &nvmword);
+		if (nvmword & __BIT(13))
+			sc->sc_ctrl |= CTRL_ILOS;
 	}
 
 #if 0
@@ -2237,8 +2319,8 @@ wm_attach(device_t parent, device_t self
 	switch (sc->sc_type) {
 	case WM_T_82573:
 		/* XXX limited to 9234 if ASPM is disabled */
-		wm_nvm_read(sc, NVM_OFF_INIT_3GIO_3, 1, &io3);
-		if ((io3 & NVM_3GIO_3_ASPM_MASK) != 0)
+		wm_nvm_read(sc, NVM_OFF_INIT_3GIO_3, 1, &nvmword);
+		if ((nvmword & NVM_3GIO_3_ASPM_MASK) != 0)
 			sc->sc_ethercom.ec_capabilities |= ETHERCAP_JUMBO_MTU;
 		break;
 	case WM_T_82571:
@@ -2502,11 +2584,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;
+	}
 
 	if (sc->sc_tx_lock)
 		mutex_obj_free(sc->sc_tx_lock);
@@ -2637,8 +2722,11 @@ 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)
+	    && (sc->sc_mediatype == WM_MEDIATYPE_SERDES))
+		wm_serdes_tick(sc);
 	else
-		wm_tbi_check_link(sc);
+		wm_tbi_tick(sc);
 
 out:
 	WM_TX_UNLOCK(sc);
@@ -2663,7 +2751,7 @@ wm_ifflags_cb(struct ethercom *ec)
 	if (change != 0)
 		sc->sc_if_flags = ifp->if_flags;
 
-	if ((change & ~(IFF_CANTCHANGE|IFF_DEBUG)) != 0) {
+	if ((change & ~(IFF_CANTCHANGE | IFF_DEBUG)) != 0) {
 		rc = ENETRESET;
 		goto out;
 	}
@@ -2934,7 +3022,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, max;
 
 	if (sc->sc_type >= WM_T_82544)
 		mta_reg = WMREG_CORDOVA_MTA;
@@ -2957,9 +3045,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))
@@ -2969,8 +3060,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 */
+			max = size;
+			break;
+		case 1:
+			/* Only RAR[0] */
+			max = 1;
+			break;
+		default:
+			/* available SHRA + RAR[0] */
+			max = i + 1;
+		}
+	} else
+		max = size;
+	for (i = 1; i < size; i++) {
+		if (i < max)
+			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)
@@ -3011,8 +3122,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);
@@ -3231,7 +3346,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)) {
@@ -3306,6 +3421,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)) {
 				/*
@@ -3420,6 +3546,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:
  *
@@ -3451,21 +3588,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;
@@ -3473,6 +3598,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;
@@ -3480,7 +3618,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:
@@ -3492,7 +3631,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) {
@@ -3593,17 +3738,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;
 		}
@@ -3731,9 +3875,7 @@ wm_reset(struct wm_softc *sc)
 	switch (sc->sc_type) {
 	case WM_T_82575:
 	case WM_T_82576:
-#if 0 /* XXX */
 	case WM_T_82580:
-#endif
 	case WM_T_I350:
 	case WM_T_I354:
 	case WM_T_ICH8:
@@ -3741,11 +3883,7 @@ wm_reset(struct wm_softc *sc)
 		if ((CSR_READ(sc, WMREG_EECD) & EECD_EE_PRES) == 0) {
 			/* Not found */
 			sc->sc_flags |= WM_F_EEPROM_INVALID;
-			if ((sc->sc_type == WM_T_82575)
-			    || (sc->sc_type == WM_T_82576)
-			    || (sc->sc_type == WM_T_82580)
-			    || (sc->sc_type == WM_T_I350)
-			    || (sc->sc_type == WM_T_I354))
+			if (sc->sc_type == WM_T_82575)
 				wm_reset_init_script_82575(sc);
 		}
 		break;
@@ -3780,10 +3918,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 */
+	wm_reset_mdicnfg_82580(sc);
+
+	if ((sc->sc_flags & WM_F_PLL_WA_I210) != 0)
+		wm_pll_workaround_i210(sc);
 }
 
 /*
@@ -3817,7 +3958,7 @@ wm_add_rxbuf(struct wm_softc *sc, int id
 
 	m->m_len = m->m_pkthdr.len = m->m_ext.ext_size;
 	error = bus_dmamap_load_mbuf(sc->sc_dmat, rxs->rxs_dmamap, m,
-	    BUS_DMA_READ|BUS_DMA_NOWAIT);
+	    BUS_DMA_READ | BUS_DMA_NOWAIT);
 	if (error) {
 		/* XXX XXX XXX */
 		aprint_error_dev(sc->sc_dev,
@@ -3931,7 +4072,8 @@ wm_init_locked(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:
@@ -3948,7 +4090,7 @@ wm_init_locked(struct ifnet *ifp)
 	/* Initialize the transmit descriptor ring. */
 	memset(sc->sc_txdescs, 0, WM_TXDESCSIZE(sc));
 	WM_CDTXSYNC(sc, 0, WM_NTXDESC(sc),
-	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 	sc->sc_txfree = WM_NTXDESC(sc);
 	sc->sc_txnext = 0;
 
@@ -4027,8 +4169,10 @@ wm_init_locked(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++) {
@@ -4120,8 +4264,7 @@ wm_init_locked(struct ifnet *ifp)
 			 */
 			wm_kmrn_writereg(sc, KUMCTRLSTA_OFFSET_TIMEOUTS,
 			    0xFFFF);
-			val = wm_kmrn_readreg(sc,
-			    KUMCTRLSTA_OFFSET_INB_PARAM);
+			val = wm_kmrn_readreg(sc, KUMCTRLSTA_OFFSET_INB_PARAM);
 			val |= 0x3F;
 			wm_kmrn_writereg(sc,
 			    KUMCTRLSTA_OFFSET_INB_PARAM, val);
@@ -4452,7 +4595,7 @@ wm_tx_offload(struct wm_softc *sc, struc
 	}
 
 	if ((m0->m_pkthdr.csum_flags &
-	    (M_CSUM_TSOv4|M_CSUM_UDPv4|M_CSUM_TCPv4)) != 0) {
+	    (M_CSUM_TSOv4 | M_CSUM_UDPv4 | M_CSUM_TCPv4)) != 0) {
 		iphl = M_CSUM_DATA_IPv4_IPHL(m0->m_pkthdr.csum_data);
 	} else {
 		iphl = M_CSUM_DATA_IPv6_HL(m0->m_pkthdr.csum_data);
@@ -4555,7 +4698,7 @@ wm_tx_offload(struct wm_softc *sc, struc
 	ipcs = WTX_TCPIP_IPCSS(offset) |
 	    WTX_TCPIP_IPCSO(offset + offsetof(struct ip, ip_sum)) |
 	    WTX_TCPIP_IPCSE(ipcse);
-	if (m0->m_pkthdr.csum_flags & (M_CSUM_IPv4|M_CSUM_TSOv4)) {
+	if (m0->m_pkthdr.csum_flags & (M_CSUM_IPv4 | M_CSUM_TSOv4)) {
 		WM_EVCNT_INCR(&sc->sc_ev_txipsum);
 		fields |= WTX_IXSM;
 	}
@@ -4563,7 +4706,7 @@ wm_tx_offload(struct wm_softc *sc, struc
 	offset += iphl;
 
 	if (m0->m_pkthdr.csum_flags &
-	    (M_CSUM_TCPv4|M_CSUM_UDPv4|M_CSUM_TSOv4)) {
+	    (M_CSUM_TCPv4 | M_CSUM_UDPv4 | M_CSUM_TSOv4)) {
 		WM_EVCNT_INCR(&sc->sc_ev_txtusum);
 		fields |= WTX_TXSM;
 		tucs = WTX_TCPIP_TUCSS(offset) |
@@ -4571,7 +4714,7 @@ wm_tx_offload(struct wm_softc *sc, struc
 		    M_CSUM_DATA_IPv4_OFFSET(m0->m_pkthdr.csum_data)) |
 		    WTX_TCPIP_TUCSE(0) /* rest of packet */;
 	} else if ((m0->m_pkthdr.csum_flags &
-	    (M_CSUM_TCPv6|M_CSUM_UDPv6|M_CSUM_TSOv6)) != 0) {
+	    (M_CSUM_TCPv6 | M_CSUM_UDPv6 | M_CSUM_TSOv6)) != 0) {
 		WM_EVCNT_INCR(&sc->sc_ev_txtusum6);
 		fields |= WTX_TXSM;
 		tucs = WTX_TCPIP_TUCSS(offset) |
@@ -4751,7 +4894,7 @@ wm_start_locked(struct ifnet *ifp)
 
 	KASSERT(WM_TX_LOCKED(sc));
 
-	if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
+	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
 		return;
 
 	/* Remember the previous number of free descriptors. */
@@ -4903,9 +5046,9 @@ wm_start_locked(struct ifnet *ifp)
 
 		/* Set up offload parameters for this packet. */
 		if (m0->m_pkthdr.csum_flags &
-		    (M_CSUM_TSOv4|M_CSUM_TSOv6|
-		    M_CSUM_IPv4|M_CSUM_TCPv4|M_CSUM_UDPv4|
-		    M_CSUM_TCPv6|M_CSUM_UDPv6)) {
+		    (M_CSUM_TSOv4 | M_CSUM_TSOv6 |
+		    M_CSUM_IPv4 | M_CSUM_TCPv4 | M_CSUM_UDPv4 |
+		    M_CSUM_TCPv6 | M_CSUM_UDPv6)) {
 			if (wm_tx_offload(sc, txs, &cksumcmd,
 					  &cksumfields) != 0) {
 				/* Error message already displayed. */
@@ -4939,21 +5082,19 @@ wm_start_locked(struct ifnet *ifp)
 				 * write-backs in TSO mode.  Append a
 				 * 4-byte sentinel descriptor.
 				 */
-				if (use_tso &&
-				    seg == dmamap->dm_nsegs - 1 &&
+				if (use_tso && seg == dmamap->dm_nsegs - 1 &&
 				    curlen > 8)
 					curlen -= 4;
 
 				wm_set_dma_addr(
-				    &sc->sc_txdescs[nexttx].wtx_addr,
-				    curaddr);
-				sc->sc_txdescs[nexttx].wtx_cmdlen =
-				    htole32(cksumcmd | curlen);
-				sc->sc_txdescs[nexttx].wtx_fields.wtxu_status =
-				    0;
-				sc->sc_txdescs[nexttx].wtx_fields.wtxu_options =
-				    cksumfields;
-				sc->sc_txdescs[nexttx].wtx_fields.wtxu_vlan = 0;
+				    &sc->sc_txdescs[nexttx].wtx_addr, curaddr);
+				sc->sc_txdescs[nexttx].wtx_cmdlen
+				    = htole32(cksumcmd | curlen);
+				sc->sc_txdescs[nexttx].wtx_fields.wtxu_status
+				    = 0;
+				sc->sc_txdescs[nexttx].wtx_fields.wtxu_options
+				    = cksumfields;
+				sc->sc_txdescs[nexttx].wtx_fields.wtxu_vlan =0;
 				lasttx = nexttx;
 
 				DPRINTF(WM_DEBUG_TX,
@@ -4996,7 +5137,7 @@ wm_start_locked(struct ifnet *ifp)
 
 		/* Sync the descriptors we're using. */
 		WM_CDTXSYNC(sc, sc->sc_txnext, txs->txs_ndesc,
-		    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 
 		/* Give the packet to the chip. */
 		CSR_WRITE(sc, sc->sc_tdt_reg, nexttx);
@@ -5022,7 +5163,8 @@ wm_start_locked(struct ifnet *ifp)
 	if (m0 != NULL) {
 		ifp->if_flags |= IFF_OACTIVE;
 		WM_EVCNT_INCR(&sc->sc_ev_txdrop);
-		DPRINTF(WM_DEBUG_TX, ("%s: TX: error after IFQ_DEQUEUE\n", __func__));
+		DPRINTF(WM_DEBUG_TX, ("%s: TX: error after IFQ_DEQUEUE\n",
+			__func__));
 		m_freem(m0);
 	}
 
@@ -5084,7 +5226,7 @@ wm_nq_tx_offload(struct wm_softc *sc, st
 	KASSERT((offset & ~NQTXC_VLLEN_MACLEN_MASK) == 0);
 
 	if ((m0->m_pkthdr.csum_flags &
-	    (M_CSUM_TSOv4|M_CSUM_UDPv4|M_CSUM_TCPv4|M_CSUM_IPv4)) != 0) {
+	    (M_CSUM_TSOv4 | M_CSUM_UDPv4 | M_CSUM_TCPv4 | M_CSUM_IPv4)) != 0) {
 		iphl = M_CSUM_DATA_IPv4_IPHL(m0->m_pkthdr.csum_data);
 	} else {
 		iphl = M_CSUM_DATA_IPv6_HL(m0->m_pkthdr.csum_data);
@@ -5264,7 +5406,7 @@ wm_nq_start_locked(struct ifnet *ifp)
 
 	KASSERT(WM_TX_LOCKED(sc));
 
-	if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
+	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
 		return;
 
 	sent = false;
@@ -5310,7 +5452,7 @@ wm_nq_start_locked(struct ifnet *ifp)
 		 * buffer.
 		 */
 		error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m0,
-		    BUS_DMA_WRITE|BUS_DMA_NOWAIT);
+		    BUS_DMA_WRITE | BUS_DMA_NOWAIT);
 		if (error) {
 			if (error == EFBIG) {
 				WM_EVCNT_INCR(&sc->sc_ev_txdrop);
@@ -5379,9 +5521,9 @@ wm_nq_start_locked(struct ifnet *ifp)
 		/* Set up offload parameters for this packet. */
 		uint32_t cmdlen, fields, dcmdlen;
 		if (m0->m_pkthdr.csum_flags &
-		    (M_CSUM_TSOv4|M_CSUM_TSOv6|
-		    M_CSUM_IPv4|M_CSUM_TCPv4|M_CSUM_UDPv4|
-		    M_CSUM_TCPv6|M_CSUM_UDPv6)) {
+		    (M_CSUM_TSOv4 | M_CSUM_TSOv6 |
+		    M_CSUM_IPv4 | M_CSUM_TCPv4 | M_CSUM_UDPv4 |
+		    M_CSUM_TCPv6 | M_CSUM_UDPv6)) {
 			if (wm_nq_tx_offload(sc, txs, &cmdlen, &fields,
 			    &do_csum) != 0) {
 				/* Error message already displayed. */
@@ -5416,7 +5558,7 @@ wm_nq_start_locked(struct ifnet *ifp)
 				sc->sc_txdescs[nexttx].wtx_fields.wtxu_vlan =
 				    htole16(VLAN_TAG_VALUE(mtag) & 0xffff);
 			} else {
-				sc->sc_txdescs[nexttx].wtx_fields.wtxu_vlan = 0;
+				sc->sc_txdescs[nexttx].wtx_fields.wtxu_vlan =0;
 			}
 			dcmdlen = 0;
 		} else {
@@ -5483,7 +5625,7 @@ wm_nq_start_locked(struct ifnet *ifp)
 
 		/* Sync the descriptors we're using. */
 		WM_CDTXSYNC(sc, sc->sc_txnext, txs->txs_ndesc,
-		    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 
 		/* Give the packet to the chip. */
 		CSR_WRITE(sc, sc->sc_tdt_reg, nexttx);
@@ -5510,7 +5652,8 @@ wm_nq_start_locked(struct ifnet *ifp)
 	if (m0 != NULL) {
 		ifp->if_flags |= IFF_OACTIVE;
 		WM_EVCNT_INCR(&sc->sc_ev_txdrop);
-		DPRINTF(WM_DEBUG_TX, ("%s: TX: error after IFQ_DEQUEUE\n", __func__));
+		DPRINTF(WM_DEBUG_TX, ("%s: TX: error after IFQ_DEQUEUE\n",
+			__func__));
 		m_freem(m0);
 	}
 
@@ -5553,11 +5696,11 @@ wm_txintr(struct wm_softc *sc)
 	     i = WM_NEXTTXS(sc, i), sc->sc_txsfree++) {
 		txs = &sc->sc_txsoft[i];
 
-		DPRINTF(WM_DEBUG_TX,
-		    ("%s: TX: checking job %d\n", device_xname(sc->sc_dev), i));
+		DPRINTF(WM_DEBUG_TX, ("%s: TX: checking job %d\n",
+			device_xname(sc->sc_dev), i));
 
 		WM_CDTXSYNC(sc, txs->txs_firstdesc, txs->txs_ndesc,
-		    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
 
 		status =
 		    sc->sc_txdescs[txs->txs_lastdesc].wtx_fields.wtxu_status;
@@ -5583,7 +5726,7 @@ wm_txintr(struct wm_softc *sc)
 			WM_EVCNT_INCR(&sc->sc_ev_tu);
 #endif /* WM_EVENT_COUNTERS */
 
-		if (status & (WTX_ST_EC|WTX_ST_LC)) {
+		if (status & (WTX_ST_EC | WTX_ST_LC)) {
 			ifp->if_oerrors++;
 			if (status & WTX_ST_LC)
 				log(LOG_WARNING, "%s: late collision\n",
@@ -5773,9 +5916,7 @@ wm_rxintr(struct wm_softc *sc)
 		 */
 		/* XXXX should check for i350 and i354 */
 		if ((status & WRX_ST_VP) != 0) {
-			VLAN_INPUT_TAG(ifp, m,
-			    le16toh(vlantag),
-			    continue);
+			VLAN_INPUT_TAG(ifp, m, le16toh(vlantag), continue);
 		}
 
 		/* Set up checksum info for this packet. */
@@ -5841,8 +5982,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) {
@@ -5873,8 +6018,7 @@ wm_linkintr_gmii(struct wm_softc *sc, ui
 					 * fiber?
 					 * Shoud not enter here.
 					 */
-					printf("unknown media (%x)\n",
-					    active);
+					printf("unknown media (%x)\n", active);
 					break;
 				}
 				if (active & IFM_FDX)
@@ -5907,8 +6051,7 @@ wm_linkintr_gmii(struct wm_softc *sc, ui
 			}
 		}
 	} else if (icr & ICR_RXSEQ) {
-		DPRINTF(WM_DEBUG_LINK,
-		    ("%s: LINK Receive sequence error\n",
+		DPRINTF(WM_DEBUG_LINK, ("%s: LINK Receive sequence error\n",
 			device_xname(sc->sc_dev)));
 	}
 }
@@ -5958,7 +6101,8 @@ wm_linkintr_tbi(struct wm_softc *sc, uin
 			    device_xname(sc->sc_dev)));
 			sc->sc_tbi_linkup = 0;
 		}
-		wm_tbi_set_linkled(sc);
+		/* Update LED */
+		wm_tbi_serdes_set_linkled(sc);
 	} else if (icr & ICR_RXSEQ) {
 		DPRINTF(WM_DEBUG_LINK,
 		    ("%s: LINK: Receive sequence error\n",
@@ -5967,6 +6111,76 @@ wm_linkintr_tbi(struct wm_softc *sc, uin
 }
 
 /*
+ * wm_linkintr_serdes:
+ *
+ *	Helper; handle link interrupts for TBI mode.
+ */
+static void
+wm_linkintr_serdes(struct wm_softc *sc, uint32_t icr)
+{
+	struct mii_data *mii = &sc->sc_mii;
+	struct ifmedia_entry *ife = sc->sc_mii.mii_media.ifm_cur;
+	uint32_t pcs_adv, pcs_lpab, reg;
+
+	DPRINTF(WM_DEBUG_LINK, ("%s: %s:\n", device_xname(sc->sc_dev),
+		__func__));
+
+	if (icr & ICR_LSC) {
+		/* Check PCS */
+		reg = CSR_READ(sc, WMREG_PCS_LSTS);
+		if ((reg & PCS_LSTS_LINKOK) != 0) {
+			mii->mii_media_status |= IFM_ACTIVE;
+			sc->sc_tbi_linkup = 1;
+		} else {
+			mii->mii_media_status |= IFM_NONE;
+			sc->sc_tbi_linkup = 0;
+			wm_tbi_serdes_set_linkled(sc);
+			return;
+		}
+		mii->mii_media_active |= IFM_1000_SX;
+		if ((reg & PCS_LSTS_FDX) != 0)
+			mii->mii_media_active |= IFM_FDX;
+		else
+			mii->mii_media_active |= IFM_HDX;
+		if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
+			/* Check flow */
+			reg = CSR_READ(sc, WMREG_PCS_LSTS);
+			if ((reg & PCS_LSTS_AN_COMP) == 0) {
+				DPRINTF(WM_DEBUG_LINK,
+				    ("XXX LINKOK but not ACOMP\n"));
+				return;
+			}
+			pcs_adv = CSR_READ(sc, WMREG_PCS_ANADV);
+			pcs_lpab = CSR_READ(sc, WMREG_PCS_LPAB);
+			DPRINTF(WM_DEBUG_LINK,
+			    ("XXX AN result %08x, %08x\n", pcs_adv, pcs_lpab));
+			if ((pcs_adv & TXCW_SYM_PAUSE)
+			    && (pcs_lpab & TXCW_SYM_PAUSE)) {
+				mii->mii_media_active |= IFM_FLOW
+				    | IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE;
+			} else if (((pcs_adv & TXCW_SYM_PAUSE) == 0)
+			    && (pcs_adv & TXCW_ASYM_PAUSE)
+			    && (pcs_lpab & TXCW_SYM_PAUSE)
+			    && (pcs_lpab & TXCW_ASYM_PAUSE))
+				mii->mii_media_active |= IFM_FLOW
+				    | IFM_ETH_TXPAUSE;
+			else if ((pcs_adv & TXCW_SYM_PAUSE)
+			    && (pcs_adv & TXCW_ASYM_PAUSE)
+			    && ((pcs_lpab & TXCW_SYM_PAUSE) == 0)
+			    && (pcs_lpab & TXCW_ASYM_PAUSE))
+				mii->mii_media_active |= IFM_FLOW
+				    | IFM_ETH_RXPAUSE;
+		}
+		/* Update LED */
+		wm_tbi_serdes_set_linkled(sc);
+	} else {
+		DPRINTF(WM_DEBUG_LINK,
+		    ("%s: LINK: Receive sequence error\n",
+		    device_xname(sc->sc_dev)));
+	}
+}
+
+/*
  * wm_linkintr:
  *
  *	Helper; handle link interrupts.
@@ -5977,6 +6191,9 @@ 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))
+		wm_linkintr_serdes(sc, icr);
 	else
 		wm_linkintr_tbi(sc, icr);
 }
@@ -6010,11 +6227,11 @@ wm_intr(void *arg)
 		handled = 1;
 
 #if defined(WM_DEBUG) || defined(WM_EVENT_COUNTERS)
-		if (icr & (ICR_RXDMT0|ICR_RXT0)) {
+		if (icr & (ICR_RXDMT0 | ICR_RXT0)) {
 			DPRINTF(WM_DEBUG_RX,
 			    ("%s: RX: got Rx intr 0x%08x\n",
 			    device_xname(sc->sc_dev),
-			    icr & (ICR_RXDMT0|ICR_RXT0)));
+			    icr & (ICR_RXDMT0 | ICR_RXT0)));
 			WM_EVCNT_INCR(&sc->sc_ev_rxintr);
 		}
 #endif
@@ -6033,7 +6250,7 @@ wm_intr(void *arg)
 #endif
 		wm_txintr(sc);
 
-		if (icr & (ICR_LSC|ICR_RXSEQ)) {
+		if (icr & (ICR_LSC | ICR_RXSEQ)) {
 			WM_EVCNT_INCR(&sc->sc_ev_linkintr);
 			wm_linkintr(sc, icr);
 		}
@@ -6061,6 +6278,28 @@ wm_intr(void *arg)
  * GMII, SGMII, TBI (and SERDES)
  */
 
+/* Common */
+
+/*
+ * wm_tbi_serdes_set_linkled:
+ *
+ *	Update the link LED on TBI and SERDES devices.
+ */
+static void
+wm_tbi_serdes_set_linkled(struct wm_softc *sc)
+{
+
+	if (sc->sc_tbi_linkup)
+		sc->sc_ctrl |= CTRL_SWDPIN(0);
+	else
+		sc->sc_ctrl &= ~CTRL_SWDPIN(0);
+
+	/* 82540 or newer devices are active low */
+	sc->sc_ctrl ^= (sc->sc_type >= WM_T_82540) ? CTRL_SWDPIN(0) : 0;
+
+	CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
+}
+
 /* GMII related */
 
 /*
@@ -6258,7 +6497,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:
@@ -6266,10 +6504,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 */
@@ -6302,18 +6543,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__);
@@ -6445,19 +6679,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 {
@@ -6546,8 +6785,8 @@ wm_gmii_mediainit(struct wm_softc *sc, p
 
 	if (LIST_FIRST(&mii->mii_phys) == NULL) {
 		/* Any PHY wasn't find */
-		ifmedia_add(&mii->mii_media, IFM_ETHER|IFM_NONE, 0, NULL);
-		ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_NONE);
+		ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL);
+		ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE);
 		sc->sc_phytype = WMPHY_NONE;
 	} else {
 		/*
@@ -6558,34 +6797,15 @@ 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);
 	}
 }
 
 /*
- * wm_gmii_mediastatus:	[ifmedia interface function]
- *
- *	Get the current interface media status on a 1000BASE-T device.
- */
-static void
-wm_gmii_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
-{
-	struct wm_softc *sc = ifp->if_softc;
-
-	ether_mediastatus(ifp, ifmr);
-	ifmr->ifm_active = (ifmr->ifm_active & ~IFM_ETH_FMASK)
-	    | sc->sc_flowflags;
-}
-
-/*
  * wm_gmii_mediachange:	[ifmedia interface function]
  *
  *	Set hardware to newly-selected media on a 1000BASE-T device.
@@ -6634,6 +6854,21 @@ wm_gmii_mediachange(struct ifnet *ifp)
 	return rc;
 }
 
+/*
+ * wm_gmii_mediastatus:	[ifmedia interface function]
+ *
+ *	Get the current interface media status on a 1000BASE-T device.
+ */
+static void
+wm_gmii_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+	struct wm_softc *sc = ifp->if_softc;
+
+	ether_mediastatus(ifp, ifmr);
+	ifmr->ifm_active = (ifmr->ifm_active & ~IFM_ETH_FMASK)
+	    | sc->sc_flowflags;
+}
+
 #define	MDI_IO		CTRL_SWDPIN(2)
 #define	MDI_DIR		CTRL_SWDPIO(2)	/* host -> PHY */
 #define	MDI_CLK		CTRL_SWDPIN(3)
@@ -6644,7 +6879,7 @@ wm_i82543_mii_sendbits(struct wm_softc *
 	uint32_t i, v;
 
 	v = CSR_READ(sc, WMREG_CTRL);
-	v &= ~(MDI_IO|MDI_CLK|(CTRL_SWDPIO_MASK << CTRL_SWDPIO_SHIFT));
+	v &= ~(MDI_IO | MDI_CLK | (CTRL_SWDPIO_MASK << CTRL_SWDPIO_SHIFT));
 	v |= MDI_DIR | CTRL_SWDPIO(3);
 
 	for (i = 1 << (nbits - 1); i != 0; i >>= 1) {
@@ -6670,7 +6905,7 @@ wm_i82543_mii_recvbits(struct wm_softc *
 	uint32_t v, i, data = 0;
 
 	v = CSR_READ(sc, WMREG_CTRL);
-	v &= ~(MDI_IO|MDI_CLK|(CTRL_SWDPIO_MASK << CTRL_SWDPIO_SHIFT));
+	v &= ~(MDI_IO | MDI_CLK | (CTRL_SWDPIO_MASK << CTRL_SWDPIO_SHIFT));
 	v |= CTRL_SWDPIO(3);
 
 	CSR_WRITE(sc, WMREG_CTRL, v);
@@ -6725,8 +6960,7 @@ wm_gmii_i82543_readreg(device_t self, in
 	    (MII_COMMAND_READ << 10) | (MII_COMMAND_START << 12), 14);
 	rv = wm_i82543_mii_recvbits(sc) & 0xffff;
 
-	DPRINTF(WM_DEBUG_GMII,
-	    ("%s: GMII: read phy %d reg %d -> 0x%04x\n",
+	DPRINTF(WM_DEBUG_GMII, ("%s: GMII: read phy %d reg %d -> 0x%04x\n",
 	    device_xname(sc->sc_dev), phy, reg, rv));
 
 	return rv;
@@ -6920,8 +7154,8 @@ wm_gmii_bm_readreg(device_t self, int ph
 
 	if (reg > BME1000_MAX_MULTI_PAGE_REG) {
 		if (phy == 1)
-			wm_gmii_i82544_writereg(self, phy, MII_IGPHY_PAGE_SELECT,
-			    reg);
+			wm_gmii_i82544_writereg(self, phy,
+			    MII_IGPHY_PAGE_SELECT, reg);
 		else
 			wm_gmii_i82544_writereg(self, phy,
 			    GG82563_PHY_PAGE_SELECT,
@@ -6955,8 +7189,8 @@ wm_gmii_bm_writereg(device_t self, int p
 
 	if (reg > BME1000_MAX_MULTI_PAGE_REG) {
 		if (phy == 1)
-			wm_gmii_i82544_writereg(self, phy, MII_IGPHY_PAGE_SELECT,
-			    reg);
+			wm_gmii_i82544_writereg(self, phy,
+			    MII_IGPHY_PAGE_SELECT, reg);
 		else
 			wm_gmii_i82544_writereg(self, phy,
 			    GG82563_PHY_PAGE_SELECT,
@@ -7167,6 +7401,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.
@@ -7425,106 +7728,35 @@ wm_sgmii_writereg(device_t self, int phy
 
 /* TBI related */
 
-/* XXX Currently TBI only */
-static int
-wm_check_for_link(struct wm_softc *sc)
+/*
+ * wm_tbi_mediainit:
+ *
+ *	Initialize media for use on 1000BASE-X devices.
+ */
+static void
+wm_tbi_mediainit(struct wm_softc *sc)
 {
-	struct ifmedia_entry *ife = sc->sc_mii.mii_media.ifm_cur;
-	uint32_t rxcw;
-	uint32_t ctrl;
-	uint32_t status;
-	uint32_t sig;
+	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+	const char *sep = "";
 
-	if (sc->sc_mediatype == WM_MEDIATYPE_SERDES) {
-		sc->sc_tbi_linkup = 1;
-		return 0;
-	}
+	if (sc->sc_type < WM_T_82543)
+		sc->sc_tipg = TIPG_WM_DFLT;
+	else
+		sc->sc_tipg = TIPG_LG_DFLT;
 
-	rxcw = CSR_READ(sc, WMREG_RXCW);
-	ctrl = CSR_READ(sc, WMREG_CTRL);
-	status = CSR_READ(sc, WMREG_STATUS);
-
-	sig = (sc->sc_type > WM_T_82544) ? CTRL_SWDPIN(1) : 0;
-
-	DPRINTF(WM_DEBUG_LINK, ("%s: %s: sig = %d, status_lu = %d, rxcw_c = %d\n",
-		device_xname(sc->sc_dev), __func__,
-		((ctrl & CTRL_SWDPIN(1)) == sig),
-		((status & STATUS_LU) != 0),
-		((rxcw & RXCW_C) != 0)
-		    ));
-
-	/*
-	 * SWDPIN   LU RXCW
-	 *      0    0    0
-	 *      0    0    1	(should not happen)
-	 *      0    1    0	(should not happen)
-	 *      0    1    1	(should not happen)
-	 *      1    0    0	Disable autonego and force linkup
-	 *      1    0    1	got /C/ but not linkup yet
-	 *      1    1    0	(linkup)
-	 *      1    1    1	If IFM_AUTO, back to autonego
-	 *
-	 */
-	if (((ctrl & CTRL_SWDPIN(1)) == sig)
-	    && ((status & STATUS_LU) == 0)
-	    && ((rxcw & RXCW_C) == 0)) {
-		DPRINTF(WM_DEBUG_LINK, ("%s: force linkup and fullduplex\n",
-			__func__));
-		sc->sc_tbi_linkup = 0;
-		/* Disable auto-negotiation in the TXCW register */
-		CSR_WRITE(sc, WMREG_TXCW, (sc->sc_txcw & ~TXCW_ANE));
-
-		/*
-		 * Force link-up and also force full-duplex.
-		 *
-		 * NOTE: CTRL was updated TFCE and RFCE automatically,
-		 * so we should update sc->sc_ctrl
-		 */
-		sc->sc_ctrl = ctrl | CTRL_SLU | CTRL_FD;
-		CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
-	} else if (((status & STATUS_LU) != 0)
-	    && ((rxcw & RXCW_C) != 0)
-	    && (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO)) {
-		sc->sc_tbi_linkup = 1;
-		DPRINTF(WM_DEBUG_LINK, ("%s: go back to autonego\n",
-			__func__));
-		CSR_WRITE(sc, WMREG_TXCW, sc->sc_txcw);
-		CSR_WRITE(sc, WMREG_CTRL, (ctrl & ~CTRL_SLU));
-	} else if (((ctrl & CTRL_SWDPIN(1)) == sig)
-	    && ((rxcw & RXCW_C) != 0)) {
-		DPRINTF(WM_DEBUG_LINK, ("/C/"));
-	} else {
-		DPRINTF(WM_DEBUG_LINK, ("%s: %x,%x,%x\n", __func__, rxcw, ctrl,
-			status));
-	}
-
-	return 0;
-}
-
-/*
- * wm_tbi_mediainit:
- *
- *	Initialize media for use on 1000BASE-X devices.
- */
-static void
-wm_tbi_mediainit(struct wm_softc *sc)
-{
-	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
-	const char *sep = "";
-
-	if (sc->sc_type < WM_T_82543)
-		sc->sc_tipg = TIPG_WM_DFLT;
-	else
-		sc->sc_tipg = TIPG_LG_DFLT;
-
-	sc->sc_tbi_anegticks = 5;
+	sc->sc_tbi_serdes_anegticks = 5;
 
 	/* Initialize our media structures */
 	sc->sc_mii.mii_ifp = ifp;
-
 	sc->sc_ethercom.ec_mii = &sc->sc_mii;
-	ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK, wm_tbi_mediachange,
-	    wm_tbi_mediastatus);
+
+	if ((sc->sc_type >= WM_T_82575)
+	    && (sc->sc_mediatype == WM_MEDIATYPE_SERDES))
+		ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK,
+		    wm_serdes_mediachange, wm_serdes_mediastatus);
+	else
+		ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK,
+		    wm_tbi_mediachange, wm_tbi_mediastatus);
 
 	/*
 	 * SWD Pins:
@@ -7533,7 +7765,11 @@ wm_tbi_mediainit(struct wm_softc *sc)
 	 *	1 = Loss Of Signal (input)
 	 */
 	sc->sc_ctrl |= CTRL_SWDPIO(0);
-	sc->sc_ctrl &= ~CTRL_SWDPIO(1);
+
+	/* XXX Perhaps this is only for TBI */
+	if (sc->sc_mediatype != WM_MEDIATYPE_SERDES)
+		sc->sc_ctrl &= ~CTRL_SWDPIO(1);
+
 	if (sc->sc_mediatype == WM_MEDIATYPE_SERDES)
 		sc->sc_ctrl &= ~CTRL_LRST;
 
@@ -7542,7 +7778,7 @@ wm_tbi_mediainit(struct wm_softc *sc)
 #define	ADD(ss, mm, dd)							\
 do {									\
 	aprint_normal("%s%s", sep, ss);					\
-	ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|(mm), (dd), NULL);	\
+	ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER | (mm), (dd), NULL); \
 	sep = ", ";							\
 } while (/*CONSTCOND*/0)
 
@@ -7551,12 +7787,12 @@ do {									\
 	/* Only 82545 is LX */
 	if (sc->sc_type == WM_T_82545) {
 		ADD("1000baseLX", IFM_1000_LX, ANAR_X_HD);
-		ADD("1000baseLX-FDX", IFM_1000_LX|IFM_FDX, ANAR_X_FD);
+		ADD("1000baseLX-FDX", IFM_1000_LX | IFM_FDX, ANAR_X_FD);
 	} else {
 		ADD("1000baseSX", IFM_1000_SX, ANAR_X_HD);
-		ADD("1000baseSX-FDX", IFM_1000_SX|IFM_FDX, ANAR_X_FD);
+		ADD("1000baseSX-FDX", IFM_1000_SX | IFM_FDX, ANAR_X_FD);
 	}
-	ADD("auto", IFM_AUTO, ANAR_X_FD|ANAR_X_HD);
+	ADD("auto", IFM_AUTO, ANAR_X_FD | ANAR_X_HD);
 	aprint_normal("\n");
 
 #undef ADD
@@ -7565,43 +7801,6 @@ do {									\
 }
 
 /*
- * wm_tbi_mediastatus:	[ifmedia interface function]
- *
- *	Get the current interface media status on a 1000BASE-X device.
- */
-static void
-wm_tbi_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
-{
-	struct wm_softc *sc = ifp->if_softc;
-	uint32_t ctrl, status;
-
-	ifmr->ifm_status = IFM_AVALID;
-	ifmr->ifm_active = IFM_ETHER;
-
-	status = CSR_READ(sc, WMREG_STATUS);
-	if ((status & STATUS_LU) == 0) {
-		ifmr->ifm_active |= IFM_NONE;
-		return;
-	}
-
-	ifmr->ifm_status |= IFM_ACTIVE;
-	/* Only 82545 is LX */
-	if (sc->sc_type == WM_T_82545)
-		ifmr->ifm_active |= IFM_1000_LX;
-	else
-		ifmr->ifm_active |= IFM_1000_SX;
-	if (CSR_READ(sc, WMREG_STATUS) & STATUS_FD)
-		ifmr->ifm_active |= IFM_FDX;
-	else
-		ifmr->ifm_active |= IFM_HDX;
-	ctrl = CSR_READ(sc, WMREG_CTRL);
-	if (ctrl & CTRL_RFCE)
-		ifmr->ifm_active |= IFM_FLOW | IFM_ETH_RXPAUSE;
-	if (ctrl & CTRL_TFCE)
-		ifmr->ifm_active |= IFM_FLOW | IFM_ETH_TXPAUSE;
-}
-
-/*
  * wm_tbi_mediachange:	[ifmedia interface function]
  *
  *	Set hardware to newly-selected media on a 1000BASE-X device.
@@ -7614,15 +7813,16 @@ wm_tbi_mediachange(struct ifnet *ifp)
 	uint32_t status;
 	int i;
 
-	if (sc->sc_mediatype == WM_MEDIATYPE_SERDES)
-		return 0;
+	if (sc->sc_mediatype == WM_MEDIATYPE_SERDES) {
+		/* XXX need some work for >= 82571 and < 82575 */
+		if (sc->sc_type < WM_T_82575)
+			return 0;
+	}
 
 	if ((sc->sc_type == WM_T_82571) || (sc->sc_type == WM_T_82572)
 	    || (sc->sc_type >= WM_T_82575))
 		CSR_WRITE(sc, WMREG_SCTL, SCTL_DISABLE_SERDES_LOOPBACK);
 
-	/* XXX power_up_serdes_link_82575() */
-
 	sc->sc_ctrl &= ~CTRL_LRST;
 	sc->sc_txcw = TXCW_ANE;
 	if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO)
@@ -7706,49 +7906,141 @@ wm_tbi_mediachange(struct ifnet *ifp)
 		sc->sc_tbi_linkup = 0;
 	}
 
-	wm_tbi_set_linkled(sc);
+	wm_tbi_serdes_set_linkled(sc);
 
 	return 0;
 }
 
 /*
- * wm_tbi_set_linkled:
+ * wm_tbi_mediastatus:	[ifmedia interface function]
  *
- *	Update the link LED on 1000BASE-X devices.
+ *	Get the current interface media status on a 1000BASE-X device.
  */
 static void
-wm_tbi_set_linkled(struct wm_softc *sc)
+wm_tbi_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
 {
+	struct wm_softc *sc = ifp->if_softc;
+	uint32_t ctrl, status;
 
-	if (sc->sc_tbi_linkup)
-		sc->sc_ctrl |= CTRL_SWDPIN(0);
+	ifmr->ifm_status = IFM_AVALID;
+	ifmr->ifm_active = IFM_ETHER;
+
+	status = CSR_READ(sc, WMREG_STATUS);
+	if ((status & STATUS_LU) == 0) {
+		ifmr->ifm_active |= IFM_NONE;
+		return;
+	}
+
+	ifmr->ifm_status |= IFM_ACTIVE;
+	/* Only 82545 is LX */
+	if (sc->sc_type == WM_T_82545)
+		ifmr->ifm_active |= IFM_1000_LX;
 	else
-		sc->sc_ctrl &= ~CTRL_SWDPIN(0);
+		ifmr->ifm_active |= IFM_1000_SX;
+	if (CSR_READ(sc, WMREG_STATUS) & STATUS_FD)
+		ifmr->ifm_active |= IFM_FDX;
+	else
+		ifmr->ifm_active |= IFM_HDX;
+	ctrl = CSR_READ(sc, WMREG_CTRL);
+	if (ctrl & CTRL_RFCE)
+		ifmr->ifm_active |= IFM_FLOW | IFM_ETH_RXPAUSE;
+	if (ctrl & CTRL_TFCE)
+		ifmr->ifm_active |= IFM_FLOW | IFM_ETH_TXPAUSE;
+}
 
-	/* 82540 or newer devices are active low */
-	sc->sc_ctrl ^= (sc->sc_type >= WM_T_82540) ? CTRL_SWDPIN(0) : 0;
+/* XXX TBI only */
+static int
+wm_check_for_link(struct wm_softc *sc)
+{
+	struct ifmedia_entry *ife = sc->sc_mii.mii_media.ifm_cur;
+	uint32_t rxcw;
+	uint32_t ctrl;
+	uint32_t status;
+	uint32_t sig;
 
-	CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
+	if (sc->sc_mediatype == WM_MEDIATYPE_SERDES) {
+		/* XXX need some work for >= 82571 */
+		if (sc->sc_type >= WM_T_82571) {
+			sc->sc_tbi_linkup = 1;
+			return 0;
+		}
+	}
+
+	rxcw = CSR_READ(sc, WMREG_RXCW);
+	ctrl = CSR_READ(sc, WMREG_CTRL);
+	status = CSR_READ(sc, WMREG_STATUS);
+
+	sig = (sc->sc_type > WM_T_82544) ? CTRL_SWDPIN(1) : 0;
+
+	DPRINTF(WM_DEBUG_LINK,
+	    ("%s: %s: sig = %d, status_lu = %d, rxcw_c = %d\n",
+		device_xname(sc->sc_dev), __func__,
+		((ctrl & CTRL_SWDPIN(1)) == sig),
+		((status & STATUS_LU) != 0), ((rxcw & RXCW_C) != 0)));
+
+	/*
+	 * SWDPIN   LU RXCW
+	 *      0    0    0
+	 *      0    0    1	(should not happen)
+	 *      0    1    0	(should not happen)
+	 *      0    1    1	(should not happen)
+	 *      1    0    0	Disable autonego and force linkup
+	 *      1    0    1	got /C/ but not linkup yet
+	 *      1    1    0	(linkup)
+	 *      1    1    1	If IFM_AUTO, back to autonego
+	 *
+	 */
+	if (((ctrl & CTRL_SWDPIN(1)) == sig)
+	    && ((status & STATUS_LU) == 0)
+	    && ((rxcw & RXCW_C) == 0)) {
+		DPRINTF(WM_DEBUG_LINK, ("%s: force linkup and fullduplex\n",
+			__func__));
+		sc->sc_tbi_linkup = 0;
+		/* Disable auto-negotiation in the TXCW register */
+		CSR_WRITE(sc, WMREG_TXCW, (sc->sc_txcw & ~TXCW_ANE));
+
+		/*
+		 * Force link-up and also force full-duplex.
+		 *
+		 * NOTE: CTRL was updated TFCE and RFCE automatically,
+		 * so we should update sc->sc_ctrl
+		 */
+		sc->sc_ctrl = ctrl | CTRL_SLU | CTRL_FD;
+		CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
+	} else if (((status & STATUS_LU) != 0)
+	    && ((rxcw & RXCW_C) != 0)
+	    && (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO)) {
+		sc->sc_tbi_linkup = 1;
+		DPRINTF(WM_DEBUG_LINK, ("%s: go back to autonego\n",
+			__func__));
+		CSR_WRITE(sc, WMREG_TXCW, sc->sc_txcw);
+		CSR_WRITE(sc, WMREG_CTRL, (ctrl & ~CTRL_SLU));
+	} else if (((ctrl & CTRL_SWDPIN(1)) == sig)
+	    && ((rxcw & RXCW_C) != 0)) {
+		DPRINTF(WM_DEBUG_LINK, ("/C/"));
+	} else {
+		DPRINTF(WM_DEBUG_LINK, ("%s: %x,%x,%x\n", __func__, rxcw, ctrl,
+			status));
+	}
+
+	return 0;
 }
 
 /*
- * wm_tbi_check_link:
+ * wm_tbi_tick:
  *
- *	Check the link on 1000BASE-X devices.
+ *	Check the link on TBI devices.
+ *	This function acts as mii_tick().
  */
 static void
-wm_tbi_check_link(struct wm_softc *sc)
+wm_tbi_tick(struct wm_softc *sc)
 {
-	struct ifmedia_entry *ife = sc->sc_mii.mii_media.ifm_cur;
+	struct mii_data *mii = &sc->sc_mii;
+	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
 	uint32_t status;
 
 	KASSERT(WM_TX_LOCKED(sc));
 
-	if (sc->sc_mediatype == WM_MEDIATYPE_SERDES) {
-		sc->sc_tbi_linkup = 1;
-		return;
-	}
-
 	status = CSR_READ(sc, WMREG_STATUS);
 
 	/* XXX is this needed? */
@@ -7767,36 +8059,227 @@ wm_tbi_check_link(struct wm_softc *sc)
 			device_xname(sc->sc_dev),
 			(status & STATUS_FD) ? "FDX" : "HDX"));
 		sc->sc_tbi_linkup = 1;
+		sc->sc_tbi_serdes_ticks = 0;
 	}
 
-	if ((sc->sc_ethercom.ec_if.if_flags & IFF_UP)
-	    && ((status & STATUS_LU) == 0)) {
+	if ((sc->sc_ethercom.ec_if.if_flags & IFF_UP) == 0)
+		goto setled;
+
+	if ((status & STATUS_LU) == 0) {
 		sc->sc_tbi_linkup = 0;
-		if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
-			/* If the timer expired, retry autonegotiation */
-			if (++sc->sc_tbi_ticks >= sc->sc_tbi_anegticks) {
-				DPRINTF(WM_DEBUG_LINK, ("EXPIRE\n"));
-				sc->sc_tbi_ticks = 0;
-				/*
-				 * Reset the link, and let autonegotiation do
-				 * its thing
-				 */
-				sc->sc_ctrl |= CTRL_LRST;
-				CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
-				CSR_WRITE_FLUSH(sc);
-				delay(1000);
-				sc->sc_ctrl &= ~CTRL_LRST;
-				CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
-				CSR_WRITE_FLUSH(sc);
-				delay(1000);
-				CSR_WRITE(sc, WMREG_TXCW,
-				    sc->sc_txcw & ~TXCW_ANE);
-				CSR_WRITE(sc, WMREG_TXCW, sc->sc_txcw);
-			}
+		/* If the timer expired, retry autonegotiation */
+		if ((IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO)
+		    && (++sc->sc_tbi_serdes_ticks
+			>= sc->sc_tbi_serdes_anegticks)) {
+			DPRINTF(WM_DEBUG_LINK, ("EXPIRE\n"));
+			sc->sc_tbi_serdes_ticks = 0;
+			/*
+			 * Reset the link, and let autonegotiation do
+			 * its thing
+			 */
+			sc->sc_ctrl |= CTRL_LRST;
+			CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
+			CSR_WRITE_FLUSH(sc);
+			delay(1000);
+			sc->sc_ctrl &= ~CTRL_LRST;
+			CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
+			CSR_WRITE_FLUSH(sc);
+			delay(1000);
+			CSR_WRITE(sc, WMREG_TXCW,
+			    sc->sc_txcw & ~TXCW_ANE);
+			CSR_WRITE(sc, WMREG_TXCW, sc->sc_txcw);
+		}
+	}
+
+setled:
+	wm_tbi_serdes_set_linkled(sc);
+}
+
+/* SERDES related */
+static void
+wm_serdes_power_up_link_82575(struct wm_softc *sc)
+{
+	uint32_t reg;
+
+	if ((sc->sc_mediatype != WM_MEDIATYPE_SERDES)
+	    && ((sc->sc_flags & WM_F_SGMII) == 0))
+		return;
+
+	reg = CSR_READ(sc, WMREG_PCS_CFG);
+	reg |= PCS_CFG_PCS_EN;
+	CSR_WRITE(sc, WMREG_PCS_CFG, reg);
+
+	reg = CSR_READ(sc, WMREG_CTRL_EXT);
+	reg &= ~CTRL_EXT_SWDPIN(3);
+	CSR_WRITE(sc, WMREG_CTRL_EXT, reg);
+	CSR_WRITE_FLUSH(sc);
+}
+
+static int
+wm_serdes_mediachange(struct ifnet *ifp)
+{
+	struct wm_softc *sc = ifp->if_softc;
+	bool pcs_autoneg = true; /* XXX */
+	uint32_t ctrl_ext, pcs_lctl, reg;
+
+	/* XXX Currently, this function is not called on 8257[12] */
+	if ((sc->sc_type == WM_T_82571) || (sc->sc_type == WM_T_82572)
+	    || (sc->sc_type >= WM_T_82575))
+		CSR_WRITE(sc, WMREG_SCTL, SCTL_DISABLE_SERDES_LOOPBACK);
+
+	wm_serdes_power_up_link_82575(sc);
+
+	sc->sc_ctrl |= CTRL_SLU;
+
+	if ((sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576))
+		sc->sc_ctrl |= CTRL_SWDPIN(0) | CTRL_SWDPIN(1);
+
+	ctrl_ext = CSR_READ(sc, WMREG_CTRL_EXT);
+	pcs_lctl = CSR_READ(sc, WMREG_PCS_LCTL);
+	switch (ctrl_ext & CTRL_EXT_LINK_MODE_MASK) {
+	case CTRL_EXT_LINK_MODE_SGMII:
+		pcs_autoneg = true;
+		pcs_lctl &= ~PCS_LCTL_AN_TIMEOUT;
+		break;
+	case CTRL_EXT_LINK_MODE_1000KX:
+		pcs_autoneg = false;
+		/* FALLTHROUGH */
+	default:
+		if ((sc->sc_type == WM_T_82575)
+		    || (sc->sc_type == WM_T_82576)) {
+			if ((sc->sc_flags & WM_F_PCS_DIS_AUTONEGO) != 0)
+				pcs_autoneg = false;
+		}
+		sc->sc_ctrl |= CTRL_SPEED_1000 | CTRL_FRCSPD | CTRL_FD
+		    | CTRL_FRCFDX;
+		pcs_lctl |= PCS_LCTL_FSV_1000 | PCS_LCTL_FDV_FULL;
+	}
+	CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
+
+	if (pcs_autoneg) {
+		pcs_lctl |= PCS_LCTL_AN_ENABLE | PCS_LCTL_AN_RESTART;
+		pcs_lctl &= ~PCS_LCTL_FORCE_FC;
+
+		reg = CSR_READ(sc, WMREG_PCS_ANADV);
+		reg &= ~(TXCW_ASYM_PAUSE | TXCW_SYM_PAUSE);
+		reg |= TXCW_ASYM_PAUSE | TXCW_SYM_PAUSE;
+		CSR_WRITE(sc, WMREG_PCS_ANADV, reg);
+	} else
+		pcs_lctl |= PCS_LCTL_FSD | PCS_LCTL_FORCE_FC;
+
+	CSR_WRITE(sc, WMREG_PCS_LCTL, pcs_lctl);
+
+
+	return 0;
+}
+
+static void
+wm_serdes_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+	struct wm_softc *sc = ifp->if_softc;
+	struct mii_data *mii = &sc->sc_mii;
+	struct ifmedia_entry *ife = sc->sc_mii.mii_media.ifm_cur;
+	uint32_t pcs_adv, pcs_lpab, reg;
+
+	ifmr->ifm_status = IFM_AVALID;
+	ifmr->ifm_active = IFM_ETHER;
+
+	/* Check PCS */
+	reg = CSR_READ(sc, WMREG_PCS_LSTS);
+	if ((reg & PCS_LSTS_LINKOK) == 0) {
+		ifmr->ifm_active |= IFM_NONE;
+		sc->sc_tbi_linkup = 0;
+		goto setled;
+	}
+
+	sc->sc_tbi_linkup = 1;
+	ifmr->ifm_status |= IFM_ACTIVE;
+	ifmr->ifm_active |= IFM_1000_SX; /* XXX */
+	if ((reg & PCS_LSTS_FDX) != 0)
+		ifmr->ifm_active |= IFM_FDX;
+	else
+		ifmr->ifm_active |= IFM_HDX;
+	mii->mii_media_active &= ~IFM_ETH_FMASK;
+	if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
+		/* Check flow */
+		reg = CSR_READ(sc, WMREG_PCS_LSTS);
+		if ((reg & PCS_LSTS_AN_COMP) == 0) {
+			DPRINTF(WM_DEBUG_LINK, ("XXX LINKOK but not ACOMP\n"));
+			goto setled;
+		}
+		pcs_adv = CSR_READ(sc, WMREG_PCS_ANADV);
+		pcs_lpab = CSR_READ(sc, WMREG_PCS_LPAB);
+		DPRINTF(WM_DEBUG_LINK,
+		    ("XXX AN result(2) %08x, %08x\n", pcs_adv, pcs_lpab));
+		if ((pcs_adv & TXCW_SYM_PAUSE)
+		    && (pcs_lpab & TXCW_SYM_PAUSE)) {
+			mii->mii_media_active |= IFM_FLOW
+			    | IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE;
+		} else if (((pcs_adv & TXCW_SYM_PAUSE) == 0)
+		    && (pcs_adv & TXCW_ASYM_PAUSE)
+		    && (pcs_lpab & TXCW_SYM_PAUSE)
+		    && (pcs_lpab & TXCW_ASYM_PAUSE)) {
+			mii->mii_media_active |= IFM_FLOW
+			    | IFM_ETH_TXPAUSE;
+		} else if ((pcs_adv & TXCW_SYM_PAUSE)
+		    && (pcs_adv & TXCW_ASYM_PAUSE)
+		    && ((pcs_lpab & TXCW_SYM_PAUSE) == 0)
+		    && (pcs_lpab & TXCW_ASYM_PAUSE)) {
+			mii->mii_media_active |= IFM_FLOW
+			    | IFM_ETH_RXPAUSE;
+		} else {
+		}
+	}
+	ifmr->ifm_active = (ifmr->ifm_active & ~IFM_ETH_FMASK)
+	    | (mii->mii_media_active & IFM_ETH_FMASK);
+setled:
+	wm_tbi_serdes_set_linkled(sc);
+}
+
+/*
+ * wm_serdes_tick:
+ *
+ *	Check the link on serdes devices.
+ */
+static void
+wm_serdes_tick(struct wm_softc *sc)
+{
+	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+	struct mii_data *mii = &sc->sc_mii;
+	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+	uint32_t reg;
+
+	KASSERT(WM_TX_LOCKED(sc));
+
+	mii->mii_media_status = IFM_AVALID;
+	mii->mii_media_active = IFM_ETHER;
+
+	/* Check PCS */
+	reg = CSR_READ(sc, WMREG_PCS_LSTS);
+	if ((reg & PCS_LSTS_LINKOK) != 0) {
+		mii->mii_media_status |= IFM_ACTIVE;
+		sc->sc_tbi_linkup = 1;
+		sc->sc_tbi_serdes_ticks = 0;
+		mii->mii_media_active |= IFM_1000_SX; /* XXX */
+		if ((reg & PCS_LSTS_FDX) != 0)
+			mii->mii_media_active |= IFM_FDX;
+		else
+			mii->mii_media_active |= IFM_HDX;
+	} else {
+		mii->mii_media_status |= IFM_NONE;
+		sc->sc_tbi_linkup = 0;
+		    /* If the timer expired, retry autonegotiation */
+		if ((IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO)
+		    && (++sc->sc_tbi_serdes_ticks
+			>= sc->sc_tbi_serdes_anegticks)) {
+			DPRINTF(WM_DEBUG_LINK, ("EXPIRE\n"));
+			sc->sc_tbi_serdes_ticks = 0;
+			/* XXX */
+			wm_serdes_mediachange(ifp);
 		}
 	}
 
-	wm_tbi_set_linkled(sc);
+	wm_tbi_serdes_set_linkled(sc);
 }
 
 /* SFP related */
@@ -7984,7 +8467,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);
@@ -8095,7 +8578,7 @@ wm_nvm_ready_spi(struct wm_softc *sc)
 			break;
 	}
 	if (usec >= SPI_MAX_RETRIES) {
-		aprint_error_dev(sc->sc_dev, "EEPROM failed to become ready\n");
+		aprint_error_dev(sc->sc_dev,"EEPROM failed to become ready\n");
 		return 1;
 	}
 	return 0;
@@ -8534,7 +9017,7 @@ wm_nvm_read_word_invm(struct wm_softc *s
 	uint8_t record_type, word_address;
 
 	for (i = 0; i < INVM_SIZE; i++) {
-		invm_dword = CSR_READ(sc, E1000_INVM_DATA_REG(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)
@@ -8619,7 +9102,7 @@ wm_nvm_read_invm(struct wm_softc *sc, in
 	return rv;
 }
 
-/* Lock, detecting NVM type, validate checksum and read */
+/* Lock, detecting NVM type, validate checksum, version and read */
 
 /*
  * wm_nvm_acquire:
@@ -8816,6 +9299,133 @@ wm_nvm_validate_checksum(struct wm_softc
 	return 0;
 }
 
+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:
  *
@@ -8896,7 +9506,8 @@ wm_get_swsm_semaphore(struct wm_softc *s
 	}
 
 	if (timeout == 0) {
-		aprint_error_dev(sc->sc_dev, "could not acquire SWSM SWESMBI\n");
+		aprint_error_dev(sc->sc_dev,
+		    "could not acquire SWSM SWESMBI\n");
 		/* Release semaphores */
 		wm_put_swsm_semaphore(sc);
 		return 1;
@@ -8972,11 +9583,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);
 	}
@@ -8989,8 +9600,9 @@ static void
 wm_put_swfwhw_semaphore(struct wm_softc *sc)
 {
 	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);
 }
 
@@ -9036,6 +9648,7 @@ wm_put_hw_semaphore_82573(struct wm_soft
  * BMC, AMT, suspend/resume and EEE.
  */
 
+#ifdef WM_WOL
 static int
 wm_check_mng_mode(struct wm_softc *sc)
 {
@@ -9076,7 +9689,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;
@@ -9102,11 +9716,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)
@@ -9127,8 +9742,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;
@@ -9148,10 +9762,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:
@@ -9160,11 +9776,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:
@@ -9174,16 +9795,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
@@ -9255,7 +9876,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);
@@ -9291,7 +9912,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);
@@ -9334,7 +9954,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;
@@ -9519,6 +10139,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);
+}
+
 /* EEE */
 
 static void
@@ -9555,13 +10198,14 @@ wm_set_eee_i350(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;
@@ -9574,7 +10218,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 */
@@ -9595,6 +10239,7 @@ wm_kmrn_lock_loss_workaround_ich8lan(str
 
 out:
 	return;
+#endif
 }
 
 /* WOL from S5 stops working */
@@ -9757,3 +10402,104 @@ wm_reset_init_script_82575(struct wm_sof
 	wm_82575_write_8bit_ctlr_reg(sc, WMREG_SCCTL, 0x14, 0x00);
 	wm_82575_write_8bit_ctlr_reg(sc, WMREG_SCCTL, 0x10, 0x00);
 }
+
+static void
+wm_reset_mdicnfg_82580(struct wm_softc *sc)
+{
+	uint32_t reg;
+	uint16_t nvmword;
+	int rv;
+
+	if ((sc->sc_flags & WM_F_SGMII) == 0)
+		return;
+
+	rv = wm_nvm_read(sc, NVM_OFF_LAN_FUNC_82580(sc->sc_funcid)
+	    + NVM_OFF_CFG3_PORTA, 1, &nvmword);
+	if (rv != 0) {
+		aprint_error_dev(sc->sc_dev, "%s: failed to read NVM\n",
+		    __func__);
+		return;
+	}
+
+	reg = CSR_READ(sc, WMREG_MDICNFG);
+	if (nvmword & NVM_CFG3_PORTA_EXT_MDIO)
+		reg |= MDICNFG_DEST;
+	if (nvmword & NVM_CFG3_PORTA_COM_MDIO)
+		reg |= MDICNFG_COM_MDIO;
+	CSR_WRITE(sc, WMREG_MDICNFG, reg);
+}
+
+/*
+ * 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");
+}

Index: src/sys/dev/pci/if_wmreg.h
diff -u src/sys/dev/pci/if_wmreg.h:1.60.2.4 src/sys/dev/pci/if_wmreg.h:1.60.2.5
--- src/sys/dev/pci/if_wmreg.h:1.60.2.4	Wed Jun 10 16:43:51 2015
+++ src/sys/dev/pci/if_wmreg.h	Fri Feb 26 22:08:17 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wmreg.h,v 1.60.2.4 2015/06/10 16:43:51 snj Exp $	*/
+/*	$NetBSD: if_wmreg.h,v 1.60.2.5 2016/02/26 22:08:17 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 */
@@ -656,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 */
@@ -671,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
@@ -740,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 */
@@ -797,6 +803,28 @@ struct livengood_tcpip_ctxdesc {
 #define WMREG_TLPIC	0x4148	/* EEE Tx LPI Count */
 #define WMREG_RLPIC	0x414c	/* EEE Rx LPI Count */
 
+#define	WMREG_PCS_CFG	0x4200	/* PCS Configuration */
+#define	PCS_CFG_PCS_EN	__BIT(3)
+
+#define	WMREG_PCS_LCTL	0x4208	/* PCS Link Control */
+#define	PCS_LCTL_FSV_1000 __BIT(2)	/* AN Timeout Enable */
+#define	PCS_LCTL_FDV_FULL __BIT(3)	/* AN Timeout Enable */
+#define	PCS_LCTL_FSD __BIT(4)	/* AN Timeout Enable */
+#define	PCS_LCTL_FORCE_FC __BIT(7)	/* AN Timeout Enable */
+#define	PCS_LCTL_AN_ENABLE __BIT(16)	/* AN Timeout Enable */
+#define	PCS_LCTL_AN_RESTART __BIT(17)	/* AN Timeout Enable */
+#define	PCS_LCTL_AN_TIMEOUT __BIT(18)	/* AN Timeout Enable */
+
+#define	WMREG_PCS_LSTS	0x420c	/* PCS Link Status */
+#define PCS_LSTS_LINKOK	__BIT(0)
+#define PCS_LSTS_SPEED_100  __BIT(1)
+#define PCS_LSTS_SPEED_1000 __BIT(2)
+#define PCS_LSTS_FDX	__BIT(3)
+#define PCS_LSTS_AN_COMP __BIT(16)
+
+#define	WMREG_PCS_ANADV	0x4218	/* AN Advertsement */
+#define	WMREG_PCS_LPAB	0x421c	/* Link Partnet Ability */
+
 #define	WMREG_RXCSUM	0x5000	/* Receive Checksum register */
 #define	RXCSUM_PCSS	0x000000ff	/* Packet Checksum Start */
 #define	RXCSUM_IPOFL	(1U << 8)	/* IP checksum offload */
@@ -808,7 +836,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 */
 
@@ -836,7 +865,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)
 
@@ -851,6 +880,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
@@ -867,12 +897,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 */
@@ -895,6 +925,7 @@ struct livengood_tcpip_ctxdesc {
 #define EEC_FLASH_DETECTED (1U << 19)	/* FLASH */
 #define EEC_FLUPD	(1U << 23)	/* Update FLASH */
 
+#define WMREG_EEARBC_I210 0x12024
 
 /*
  * NVM related values.
@@ -928,6 +959,7 @@ struct livengood_tcpip_ctxdesc {
 #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 */
@@ -941,6 +973,9 @@ struct livengood_tcpip_ctxdesc {
 #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
 
@@ -980,6 +1015,8 @@ struct livengood_tcpip_ctxdesc {
 #define	NVM_CFG2_MNGM_NCSI	1
 #define	NVM_CFG2_MNGM_PT	2
 
+#define	NVM_COMPAT_SERDES_FORCE_MODE	__BIT(14) /* Don't use autonego */
+
 #define NVM_FUTURE_INIT_WORD1_VALID_CHECKSUM	0x0040
 
 #define	NVM_K1_CONFIG_ENABLE	0x01
@@ -991,6 +1028,8 @@ struct livengood_tcpip_ctxdesc {
 #define NVM_3GIO_3_ASPM_MASK	(0x3 << 2)	/* Active State PM Support */
 
 #define NVM_CFG3_APME		(1U << 10)	
+#define NVM_CFG3_PORTA_EXT_MDIO	(1U << 2)	/* External MDIO Interface */
+#define NVM_CFG3_PORTA_COM_MDIO	(1U << 3)	/* MDIO Interface is shared */
 
 #define	NVM_OFF_MACADDR_82571(x)	(3 * (x))
 
@@ -1000,8 +1039,17 @@ 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 E1000_INVM_DATA_REG(reg)	(0x12120 + 4*(reg))
+#define WM_INVM_DATA_REG(reg)	(0x12120 + 4*(reg))
 #define INVM_SIZE			64 /* Number of INVM Data Registers */
 
 /* iNVM default vaule */
@@ -1020,11 +1068,22 @@ struct livengood_tcpip_ctxdesc {
 #define INVM_CSR_AUTOLOAD_STRUCTURE		0x2
 #define INVM_PHY_REGISTER_AUTOLOAD_STRUCTURE	0x3
 #define INVM_RSA_KEY_SHA256_STRUCTURE		0x4
-#define INVM_INVALIDATED_STRUCTURE		0x5
+#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
 
@@ -1098,6 +1157,13 @@ struct livengood_tcpip_ctxdesc {
 #define SFF_SFP_ETH_FLAGS_1000T		0x08
 #define SFF_SFP_ETH_FLAGS_100FX		0x10
 
+/* 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
 
 /* advanced TX descriptor for 82575 and newer */
 typedef union nq_txdesc {

Index: src/sys/dev/pci/if_wmvar.h
diff -u src/sys/dev/pci/if_wmvar.h:1.19.2.3 src/sys/dev/pci/if_wmvar.h:1.19.2.4
--- src/sys/dev/pci/if_wmvar.h:1.19.2.3	Tue May 19 05:09:02 2015
+++ src/sys/dev/pci/if_wmvar.h	Fri Feb 26 22:08:17 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wmvar.h,v 1.19.2.3 2015/05/19 05:09:02 snj Exp $	*/
+/*	$NetBSD: if_wmvar.h,v 1.19.2.4 2016/02/26 22:08:17 snj Exp $	*/
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -95,8 +95,25 @@
 #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() fininsed successfully */
+#define WM_F_ATTACHED		0x00800000 /* attach() finished successfully */
 #define	WM_F_EEPROM_INVM	0x01000000 /* NVM is iNVM */
+#define	WM_F_PCS_DIS_AUTONEGO	0x02000000 /* PCS Disable Autonego */
+#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,
@@ -126,12 +143,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 {
@@ -155,5 +172,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