Index: sys/dev/pci/if_wmreg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_wmreg.h,v
retrieving revision 1.93
diff -u -p -r1.93 if_wmreg.h
--- sys/dev/pci/if_wmreg.h	16 Nov 2016 08:56:17 -0000	1.93
+++ sys/dev/pci/if_wmreg.h	18 Nov 2016 09:24:16 -0000
@@ -514,6 +514,12 @@ struct livengood_tcpip_ctxdesc {
 #define IVAR_MISC_TCPTIMER __BITS(0, 7)
 #define IVAR_MISC_OTHER	__BITS(8, 15)
 
+#define WMREG_SVCR	0x00f0
+#define SVCR_OFF_EN	__BIT(0)
+#define SVCR_OFF_MASKINT __BIT(12)
+#define WMREG_SVT	0x00f8
+#define SVT_OFF_HIWAT	__BITS(4, 0)
+
 #define	WMREG_LTRV	0x00f8	/* Latency Tolerance Reporting */
 #define	LTRV_VALUE	__BITS(9, 0)
 #define	LTRV_SCALE	__BITS(12, 10)
@@ -624,6 +630,7 @@ struct livengood_tcpip_ctxdesc {
 #define	WMREG_FCRTH	0x2168	/* Flow Control Rx Threhsold Hi */
 #define	FCRTL_DFLT	0x00004000
 #define	FCRTL_XONE	0x80000000	/* Enable XON frame transmission */
+#define	FCRT_MASK	__BITS(15, 3)
 
 #define	WMREG_FCTTV	0x0170	/* Flow Control Transmit Timer Value */
 #define	FCTTV_DFLT	0x00000600
@@ -864,12 +871,16 @@ struct livengood_tcpip_ctxdesc {
 
 #define	WMREG_TXDCTL(n)		/* Trandmit Descriptor Control */ \
 	(((n) < 4) ? (0x3828 + ((n) * 0x100)) : (0xe028 + ((n) * 0x40)))
-#define	TXDCTL_PTHRESH(x) ((x) << 0)	/* prefetch threshold */
-#define	TXDCTL_HTHRESH(x) ((x) << 8)	/* host threshold */
-#define	TXDCTL_WTHRESH(x) ((x) << 16)	/* write back threshold */
+#define	TXDCTL_PTHRESH_MASK	__BITS(4, 0)	/* prefetch threshold */
+#define	TXDCTL_HTHRESH_MASK	__BITS(12, 8)	/* host threshold */
+#define	TXDCTL_WTHRESH_MASK	__BITS(20, 16)	/* write back threshold */
+#define	TXDCTL_PTHRESH(x)	__SHIFTIN((x), TXDCTL_PTHRESH_MASK)
+#define	TXDCTL_HTHRESH(x)	__SHIFTIN((x), TXDCTL_HTHRESH_MASK)
+#define	TXDCTL_WTHRESH(x)	__SHIFTIN((x), TXDCTL_WTHRESH_MASK)
 /* flags used starting with 82575 ... */
 #define TXDCTL_COUNT_DESC	__BIT(22) /* Enable the counting of desc.
 					   still to be processed. */
+#define TXDCTL_GRAN		__BIT(24) /* Granularity */
 #define TXDCTL_QUEUE_ENABLE  0x02000000 /* Enable specific Tx Queue */
 #define TXDCTL_SWFLSH        0x04000000 /* Tx Desc. write-back flushing */
 #define TXDCTL_PRIORITY      0x08000000
@@ -942,6 +953,11 @@ struct livengood_tcpip_ctxdesc {
 #define WMREG_RFCTL_IPV6EXDIS	__BIT(16) /* IPv6 Extension Header Disable */
 #define WMREG_RFCTL_NEWIPV6EXDIS __BIT(17) /* New IPv6 Extension Header */
 
+#define WMREG_SHRA_BASE	0x5438
+#define WMREG_SHRA_BASE_PCH_LPT 0x5408
+#define WMREG_SHRAL(b, x)	((b) + ((x) << 3))
+#define WMREG_SHRAH(b, x)	(WMREG_SHRAL((b), (x)) + 4)
+
 #define	WMREG_WUC	0x5800	/* Wakeup Control */
 #define	WUC_APME		0x00000001 /* APM Enable */
 #define	WUC_PME_EN		0x00000002 /* PME Enable */
Index: sys/dev/pci/if_wm.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_wm.c,v
retrieving revision 1.451
diff -u -p -r1.451 if_wm.c
--- sys/dev/pci/if_wm.c	18 Nov 2016 06:55:00 -0000	1.451
+++ sys/dev/pci/if_wm.c	18 Nov 2016 09:24:23 -0000
@@ -142,6 +142,8 @@ __KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.
 #include <dev/pci/if_wmreg.h>
 #include <dev/pci/if_wmvar.h>
 
+// #define WM_DEBUG 1
+
 #ifdef WM_DEBUG
 #define	WM_DEBUG_LINK		__BIT(0)
 #define	WM_DEBUG_TX		__BIT(1)
@@ -393,12 +395,22 @@ struct wm_queue {
 	struct wm_rxqueue wmq_rxq;
 };
 
+struct wm_macop {
+	int (*acquire)(struct wm_softc *);
+	void (*release)(struct wm_softc *);
+};
+
 struct wm_phyop {
 	int (*acquire)(struct wm_softc *);
 	void (*release)(struct wm_softc *);
 	int reset_delay_us;
 };
 
+struct wm_nvmop {
+	int (*acquire)(struct wm_softc *);
+	void (*release)(struct wm_softc *);
+};
+
 /*
  * Software state per device.
  */
@@ -514,7 +526,9 @@ struct wm_softc {
 					 */
 	kmutex_t *sc_ich_nvmmtx;	/* ICH/PCH specific NVM mutex */
 
+	struct wm_macop mac;
 	struct wm_phyop phy;
+	struct wm_nvmop nvm;
 };
 
 #define WM_CORE_LOCK(_sc)	if ((_sc)->sc_core_lock) mutex_enter((_sc)->sc_core_lock)
@@ -556,10 +570,55 @@ do {									\
 #define WM_Q_EVCNT_ADD(qname, evname, val)	/* nothing */
 #endif /* !WM_EVENT_COUNTERS */
 
+#if 0
 #define	CSR_READ(sc, reg)						\
 	bus_space_read_4((sc)->sc_st, (sc)->sc_sh, (reg))
 #define	CSR_WRITE(sc, reg, val)						\
 	bus_space_write_4((sc)->sc_st, (sc)->sc_sh, (reg), (val))
+#else
+
+#define WMMAXREGS 0x8000
+struct regtab {
+	int rd;
+	int wr;
+} regtab[16][WMMAXREGS];
+
+uint32_t CSR_READ(struct wm_softc *sc, bus_size_t reg);
+void CSR_WRITE(struct wm_softc *sc, bus_size_t reg, uint32_t val);
+
+uint32_t
+CSR_READ(struct wm_softc *sc, bus_size_t reg)
+{
+	uint32_t val;
+	int index = reg >> 2;
+	if ((reg & 0x00000003) != 0)
+		printf("%s: not aligned? %zx\n", device_xname(sc->sc_dev), reg);
+	if (index >= WMMAXREGS)
+		printf("%s: read offset is too big? %d, %zx\n", device_xname(sc->sc_dev), index, reg);
+	else
+		regtab[device_unit(sc->sc_dev)][index].rd = 1;
+	val = bus_space_read_4((sc)->sc_st, (sc)->sc_sh, (reg));
+	if (reg == WMREG_CTRL)
+		printf("%s: CTRL == %08x\n", device_xname(sc->sc_dev), val);
+	return val;
+}
+
+void
+CSR_WRITE(struct wm_softc *sc, bus_size_t reg, uint32_t val)
+{
+
+	int index = reg >> 2;
+	if ((reg & 0x00000003) != 0)
+		printf("%s: not aligned? %zx\n", device_xname(sc->sc_dev), reg);
+	if (index >= WMMAXREGS)
+		printf("%s: write offset is too big? %d, %zx\n", device_xname(sc->sc_dev), index, reg);
+	else
+		regtab[device_unit(sc->sc_dev)][index].wr = 1;
+	if (reg == WMREG_CTRL)
+		printf("%s: CTRL <- %08x\n", device_xname(sc->sc_dev), val);
+	bus_space_write_4((sc)->sc_st, (sc)->sc_sh, (reg), (val));
+}
+#endif
 #define	CSR_WRITE_FLUSH(sc)						\
 	(void) CSR_READ((sc), WMREG_STATUS)
 
@@ -814,6 +873,10 @@ static int	wm_get_swfw_semaphore(struct 
 static void	wm_put_swfw_semaphore(struct wm_softc *, uint16_t);
 static int	wm_get_phy_82575(struct wm_softc *);
 static void	wm_put_phy_82575(struct wm_softc *);
+#if 0
+static int	wm_get_nvm_82575(struct wm_softc *);
+static void	wm_put_nvm_82575(struct wm_softc *);
+#endif
 static int	wm_get_swfwhw_semaphore(struct wm_softc *); /* For 574/583 */
 static void	wm_put_swfwhw_semaphore(struct wm_softc *);
 static int	wm_get_swflag_ich8lan(struct wm_softc *);	/* For PHY */
@@ -870,6 +933,12 @@ static void	wm_toggle_lanphypc_pch_lpt(s
 static int	wm_platform_pm_pch_lpt(struct wm_softc *, bool);
 static void	wm_pll_workaround_i210(struct wm_softc *);
 
+// #define WM_DUMP 1
+
+#ifdef WM_DUMP
+static void	wm_regdump(struct wm_softc *);
+#endif
+
 CFATTACH_DECL3_NEW(wm, sizeof(struct wm_softc),
     wm_match, wm_attach, wm_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN);
 
@@ -1389,7 +1458,7 @@ static const struct wm_product {
 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I218_LM3,
 	  "I218 LM Ethernet Connection",
 	  WM_T_PCH_LPT,		WMP_F_COPPER },
-#if 0
+#if 1
 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I219_V,
 	  "I219 V Ethernet Connection",
 	  WM_T_PCH_SPT,		WMP_F_COPPER },
@@ -1633,8 +1702,8 @@ wm_attach(device_t parent, device_t self
 	sc->sc_type = wmp->wmp_type;
 
 	/* Set default function pointers */
-	sc->phy.acquire = wm_get_null;
-	sc->phy.release = wm_put_null;
+	sc->mac.acquire = sc->phy.acquire = sc->nvm.acquire = wm_get_null;
+	sc->mac.release = sc->phy.release = sc->nvm.release = wm_put_null;
 	sc->phy.reset_delay_us = (sc->sc_type >= WM_T_82571) ? 100 : 10000;
 
 	if (sc->sc_type < WM_T_82543) {
@@ -1991,6 +2060,7 @@ alloc_retry:
 	case WM_T_82571:
 	case WM_T_82572:
 		/* SPI */
+		/* XXX nvm_82571 and SWSM_SMBI + SWSM_SWSESMBI */
 		sc->sc_flags |= WM_F_EEPROM_SPI;
 		wm_nvm_set_addrbits_size_eecd(sc);
 		sc->sc_flags |= WM_F_LOCK_EECD | WM_F_LOCK_SWSM;
@@ -2007,9 +2077,9 @@ alloc_retry:
 		} else {
 			sc->sc_flags |= WM_F_LOCK_EXTCNF;
 			/* Both PHY and NVM use the same semaphore. */
-			sc->phy.acquire
+			sc->phy.acquire = sc->nvm.acquire
 			    = wm_get_swfwhw_semaphore;
-			sc->phy.release
+			sc->phy.release = sc->nvm.release
 			    = wm_put_swfwhw_semaphore;
 		}
 		if (wm_nvm_is_onboard_eeprom(sc) == 0) {
@@ -2031,6 +2101,10 @@ alloc_retry:
 		/* SPI */
 		sc->sc_flags |= WM_F_EEPROM_SPI;
 		wm_nvm_set_addrbits_size_eecd(sc);
+		/*
+		 * XXX SWFW_SYNC + EECD check + nvm_generic
+		 * XXX 80003 should be separated?
+		 */
 		sc->sc_flags |= WM_F_EEPROM_EERDEEWR | WM_F_LOCK_SWFW
 		    | WM_F_LOCK_SWSM;
 		sc->phy.acquire = wm_get_phy_82575;
@@ -2639,6 +2713,10 @@ alloc_retry:
 
 	sc->sc_flags |= WM_F_ATTACHED;
  out:
+#ifdef WM_DUMP
+	printf("XXX end of wm_attach()\n");
+	wm_regdump(sc);
+#endif
 	return;
 }
 
@@ -2648,6 +2726,9 @@ wm_detach(device_t self, int flags __unu
 {
 	struct wm_softc *sc = device_private(self);
 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+#if 0
+	int num, found, first;
+#endif
 	int i;
 
 	if ((sc->sc_flags & WM_F_ATTACHED) == 0)
@@ -2694,6 +2775,10 @@ wm_detach(device_t self, int flags __unu
 
 	wm_free_txrx_queues(sc);
 
+#ifdef WM_DUMP
+	printf("XXX in wm_detach()\n");
+	wm_regdump(sc);
+#endif
 	/* Unmap the registers */
 	if (sc->sc_ss) {
 		bus_space_unmap(sc->sc_st, sc->sc_sh, sc->sc_ss);
@@ -2715,6 +2800,29 @@ wm_detach(device_t self, int flags __unu
 	if (sc->sc_ich_nvmmtx)
 		mutex_obj_free(sc->sc_ich_nvmmtx);
 
+#if 0
+	printf("%s:\n", device_xname(sc->sc_dev));
+
+	/* Dump r/w table */
+	num = 0;
+	found = 0;
+	first = -1;
+	for (i = 0; i < WMMAXREGS; i++) {
+		if ((regtab[device_unit(sc->sc_dev)][i].rd != 0)
+		    || (regtab[device_unit(sc->sc_dev)][i].wr != 0)){
+ 			num++;
+			if (found == 0)
+				first = i;
+			found = 1;
+		} else {
+			if (found == 1)
+				printf("%04x, %d\n", first << 2, i - first);
+			found = 0;
+		}
+	}
+	printf("r/w = %d, last = %x\n", num, first << 2);
+#endif
+
 	return 0;
 }
 
@@ -2757,6 +2865,10 @@ wm_watchdog(struct ifnet *ifp)
 		wm_watchdog_txq(ifp, txq);
 	}
 
+#ifdef WM_DUMP
+	printf("XXX before wm_init() in wm_watchdog()\n");
+	wm_regdump(sc);
+#endif	
 	/* Reset the interface. */
 	(void) wm_init(ifp);
 
@@ -3068,7 +3180,8 @@ wm_read_mac_addr(struct wm_softc *sc, ui
 		break;
 	}
 
-	if (wm_nvm_read(sc, offset, sizeof(myea) / sizeof(myea[0]), myea) != 0)
+	if (wm_nvm_read(sc, offset, sizeof(myea) / sizeof(myea[0]),
+	    myea) != 0)
 		goto bad;
 
 	enaddr[0] = myea[0] & 0xff;
@@ -3087,7 +3200,7 @@ wm_read_mac_addr(struct wm_softc *sc, ui
 
 	return 0;
 
- bad:
+bad:
 	return -1;
 }
 
@@ -3100,25 +3213,60 @@ static void
 wm_set_ral(struct wm_softc *sc, const uint8_t *enaddr, int idx)
 {
 	uint32_t ral_lo, ral_hi;
+	bus_size_t off;
 
 	if (enaddr != NULL) {
 		ral_lo = enaddr[0] | (enaddr[1] << 8) | (enaddr[2] << 16) |
 		    (enaddr[3] << 24);
 		ral_hi = enaddr[4] | (enaddr[5] << 8);
-		ral_hi |= RAL_AV;
 	} else {
 		ral_lo = 0;
 		ral_hi = 0;
 	}
 
-	if (sc->sc_type >= WM_T_82544) {
+	if ((ral_lo != 0) || (ral_hi != 0))
+		ral_hi |= RAL_AV;
+
+	switch (sc->sc_type) {
+	case WM_T_82542_2_0:
+	case WM_T_82542_2_1:
+	case WM_T_82543:
+		/* Very old */
+		CSR_WRITE(sc, WMREG_RAL_LO(WMREG_RAL_BASE, idx), ral_lo);
+		CSR_WRITE_FLUSH(sc);
+		CSR_WRITE(sc, WMREG_RAL_HI(WMREG_RAL_BASE, idx), ral_hi);
+		CSR_WRITE_FLUSH(sc);
+		break;
+	case WM_T_PCH2:
+	case WM_T_PCH_LPT:
+	case WM_T_PCH_SPT:
+		if (idx == 0) {
+			CSR_WRITE(sc,
+			    WMREG_RAL_LO(WMREG_CORDOVA_RAL_BASE, idx), ral_lo);
+			CSR_WRITE_FLUSH(sc);
+			CSR_WRITE(sc,
+			    WMREG_RAL_HI(WMREG_CORDOVA_RAL_BASE, idx), ral_hi);
+			CSR_WRITE_FLUSH(sc);
+			break;
+		}
+		if (sc->sc_type == WM_T_PCH2)
+			off = WMREG_SHRA_BASE;
+		else
+			off = WMREG_SHRA_BASE_PCH_LPT;
+		
+		CSR_WRITE(sc, WMREG_SHRAL(off, idx - 1), ral_lo);
+		CSR_WRITE_FLUSH(sc);
+		CSR_WRITE(sc, WMREG_SHRAH(off, idx - 1), ral_hi);
+		CSR_WRITE_FLUSH(sc);
+		break;
+	default:		
+		/* Generic */
 		CSR_WRITE(sc, WMREG_RAL_LO(WMREG_CORDOVA_RAL_BASE, idx),
 		    ral_lo);
+		CSR_WRITE_FLUSH(sc);
 		CSR_WRITE(sc, WMREG_RAL_HI(WMREG_CORDOVA_RAL_BASE, idx),
 		    ral_hi);
-	} else {
-		CSR_WRITE(sc, WMREG_RAL_LO(WMREG_RAL_BASE, idx), ral_lo);
-		CSR_WRITE(sc, WMREG_RAL_HI(WMREG_RAL_BASE, idx), ral_hi);
+		CSR_WRITE_FLUSH(sc);
 	}
 }
 
@@ -3293,6 +3441,8 @@ wm_set_filter(struct wm_softc *sc)
 	sc->sc_rctl |= RCTL_MPE;
 
  setit:
+	DPRINTF(WM_DEBUG_INIT, ("%s: %s exit\n",
+		device_xname(sc->sc_dev), __func__));
 	CSR_WRITE(sc, WMREG_RCTL, sc->sc_rctl);
 }
 
@@ -3910,10 +4060,16 @@ wm_reset(struct wm_softc *sc)
 		    PBA_14K : PBA_10K;
 		break;
 	case WM_T_PCH:
+		sc->sc_pba = PBA_26K;
+		break;
 	case WM_T_PCH2:
 	case WM_T_PCH_LPT:
 	case WM_T_PCH_SPT:
+#if 1
+		sc->sc_pba = PBA_14K;
+#else
 		sc->sc_pba = PBA_26K;
+#endif
 		break;
 	default:
 		sc->sc_pba = sc->sc_ethercom.ec_if.if_mtu > 8192 ?
@@ -3974,6 +4130,7 @@ wm_reset(struct wm_softc *sc)
 	/* Must acquire the MDIO ownership before MAC reset */
 	switch (sc->sc_type) {
 	case WM_T_82573:
+		/* XXX 82573 and others should be different */
 	case WM_T_82574:
 	case WM_T_82583:
 		error = wm_get_hw_semaphore_82573(sc);
@@ -4804,8 +4961,10 @@ wm_init_locked(struct ifnet *ifp)
 	}
 
 	error = wm_init_txrx_queues(sc);
-	if (error)
+	if (error) {
+		printf("XXX wm_init_txrx_queues() failed\n");
 		goto out;
+	}
 
 	/*
 	 * Clear out the VLAN table -- we don't use it (yet).
@@ -4833,6 +4992,7 @@ wm_init_locked(struct ifnet *ifp)
 		CSR_WRITE(sc, WMREG_FCT, ETHERTYPE_FLOWCONTROL);
 	}
 
+	KASSERT(sc->sc_pba);
 	sc->sc_fcrtl = FCRTL_DFLT;
 	if (sc->sc_type < WM_T_82543) {
 		CSR_WRITE(sc, WMREG_OLD_FCRTH, FCRTH_DFLT);
@@ -4840,6 +5000,10 @@ wm_init_locked(struct ifnet *ifp)
 	} else {
 		CSR_WRITE(sc, WMREG_FCRTH, FCRTH_DFLT);
 		CSR_WRITE(sc, WMREG_FCRTL, sc->sc_fcrtl);
+		CSR_WRITE(sc, WMREG_FCRTH,
+		    ((sc->sc_pba << PBA_BYTE_SHIFT) * 9 / 10) & FCRT_MASK);
+		CSR_WRITE(sc, WMREG_FCRTL,
+		    ((sc->sc_pba << PBA_BYTE_SHIFT) * 8 / 10) & FCRT_MASK);
 	}
 
 	if (sc->sc_type == WM_T_80003)
@@ -4908,6 +5072,20 @@ wm_init_locked(struct ifnet *ifp)
 		reg |= RXCSUM_IPV6OFL | RXCSUM_TUOFL;
 	CSR_WRITE(sc, WMREG_RXCSUM, reg);
 
+	/* Disable Relax Ordering on some chips */
+	if ((sc->sc_pcidevid == PCI_PRODUCT_INTEL_82546GB_QUAD_COPPER)
+	    || (sc->sc_pcidevid == PCI_PRODUCT_INTEL_82546GB_QUAD_COPPER_KSP3)
+	    || sc->sc_type >= WM_T_ICH8) {
+		reg = CSR_READ(sc, WMREG_CTRL_EXT);
+		reg |= CTRL_EXT_RO_DIS;
+		CSR_WRITE(sc, WMREG_CTRL_EXT, reg);
+	}
+
+	if (sc->sc_type >= WM_T_ICH8) {
+		reg = CSR_READ(sc, WMREG_GCR);
+		/* XXX Check _set_pcie_no_snoop() */
+	}
+
 	/* Set up MSI-X */
 	if (sc->sc_nintrs > 1) {
 		uint32_t ivar;
@@ -5236,6 +5414,12 @@ wm_init_locked(struct ifnet *ifp)
 	if (error)
 		log(LOG_ERR, "%s: interface not running\n",
 		    device_xname(sc->sc_dev));
+	DPRINTF(WM_DEBUG_INIT, ("%s: %s exit\n",
+		device_xname(sc->sc_dev), __func__));
+#ifdef WM_DUMP
+	printf("XXX end of wm_init_locked()\n");
+	wm_regdump(sc);
+#endif
 	return error;
 }
 
@@ -5875,6 +6059,7 @@ static void
 wm_init_tx_regs(struct wm_softc *sc, struct wm_queue *wmq,
     struct wm_txqueue *txq)
 {
+	uint32_t reg;
 
 	DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
 		device_xname(sc->sc_dev), __func__));
@@ -5895,15 +6080,17 @@ wm_init_tx_regs(struct wm_softc *sc, str
 		CSR_WRITE(sc, WMREG_TDLEN(qid), WM_TXDESCS_SIZE(txq));
 		CSR_WRITE(sc, WMREG_TDH(qid), 0);
 
-		if ((sc->sc_flags & WM_F_NEWQUEUE) != 0)
+		if ((sc->sc_flags & WM_F_NEWQUEUE) != 0) {
 			/*
 			 * Don't write TDT before TCTL.EN is set.
 			 * See the document.
 			 */
 			CSR_WRITE(sc, WMREG_TXDCTL(qid), TXDCTL_QUEUE_ENABLE
 			    | TXDCTL_PTHRESH(0) | TXDCTL_HTHRESH(0)
-			    | TXDCTL_WTHRESH(0));
-		else {
+			    | TXDCTL_WTHRESH(0));	
+
+			reg = CSR_READ(sc, WMREG_TXDCTL(qid));
+		} else {
 			/* ITR / 4 */
 			CSR_WRITE(sc, WMREG_TIDV, sc->sc_itr / 4);
 			if (sc->sc_type >= WM_T_82540) {
@@ -5912,8 +6099,32 @@ wm_init_tx_regs(struct wm_softc *sc, str
 			}
 
 			CSR_WRITE(sc, WMREG_TDT(qid), 0);
-			CSR_WRITE(sc, WMREG_TXDCTL(qid), TXDCTL_PTHRESH(0) |
-			    TXDCTL_HTHRESH(0) | TXDCTL_WTHRESH(0));
+			reg = CSR_READ(sc, WMREG_TXDCTL(qid));
+			if (sc->sc_type >= WM_T_82540) {
+				reg &= ~TXDCTL_WTHRESH_MASK;
+				reg |= TXDCTL_GRAN | TXDCTL_WTHRESH(1);
+			}
+			if (sc->sc_type >= WM_T_82571)
+				reg |= TXDCTL_COUNT_DESC;
+
+			if (sc->sc_type >= WM_T_ICH8) {
+				reg &= ~TXDCTL_PTHRESH_MASK;
+				reg |= TXDCTL_PTHRESH(0x1f); /* MAX */
+			}
+			if (sc->sc_type >= WM_T_82571) {
+				/* XXX not for 82573 and 82583? */
+				reg &= ~TXDCTL_HTHRESH_MASK;
+				reg |= TXDCTL_HTHRESH(0x01);
+			}
+
+			CSR_WRITE(sc, WMREG_TXDCTL(qid), reg);
+			/*
+			 * For both queues.
+			 * 80003, 82571, 82572, ICH, PCH
+			 * Not for 82574, 82583
+			 */
+			if (sc->sc_type >= WM_T_82571)
+				CSR_WRITE(sc, WMREG_TXDCTL(1), reg);
 		}
 	}
 }
@@ -7568,11 +7779,11 @@ wm_linkintr_gmii(struct wm_softc *sc, ui
 				delay(200*1000); /* XXX too big */
 
 				/* Link stall fix for link up */
-				wm_gmii_hv_writereg(sc->sc_dev, 1,
+				wm_gmii_hv_writereg(sc->sc_dev, 2,
 				    HV_MUX_DATA_CTRL,
 				    HV_MUX_DATA_CTRL_GEN_TO_MAC
 				    | HV_MUX_DATA_CTRL_FORCE_SPEED);
-				wm_gmii_hv_writereg(sc->sc_dev, 1,
+				wm_gmii_hv_writereg(sc->sc_dev, 2,
 				    HV_MUX_DATA_CTRL,
 				    HV_MUX_DATA_CTRL_GEN_TO_MAC);
 			}
@@ -8990,6 +9201,8 @@ wm_gmii_hv_readreg(device_t self, int ph
 
 	DPRINTF(WM_DEBUG_GMII, ("%s: %s called\n",
 		device_xname(sc->sc_dev), __func__));
+//	printf("%s: reg %d, read page %d, reg2 %d\n", __func__, reg, page, regnum);
+
 	if (sc->phy.acquire(sc)) {
 		aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",
 		    __func__);
@@ -9010,6 +9223,7 @@ wm_gmii_hv_readreg_locked(device_t self,
 	int rv;
 
 	phy = (page >= HV_INTC_FC_PAGE_START) ? 1 : phy;
+//	printf("%s: reg %d, read page %d, reg2 %d\n", __func__, reg, page, regnum);
 
 	/* Page 800 works differently than the rest so it has its own func */
 	if (page == BM_WUC_PAGE) {
@@ -9026,9 +9240,11 @@ wm_gmii_hv_readreg_locked(device_t self,
 		return 0;
 	}
 
-	if (regnum > BME1000_MAX_MULTI_PAGE_REG) {
-		wm_gmii_mdic_writereg(self, 1, MII_IGPHY_PAGE_SELECT,
-		    page << BME1000_PAGE_SHIFT);
+	{
+		if (regnum > BME1000_MAX_MULTI_PAGE_REG) {
+			wm_gmii_mdic_writereg(self, 1, MII_IGPHY_PAGE_SELECT,
+			    page << BME1000_PAGE_SHIFT);
+		}
 	}
 
 	rv = wm_gmii_mdic_readreg(self, phy, regnum & MII_ADDRMASK);
@@ -9055,7 +9271,6 @@ wm_gmii_hv_writereg(device_t self, int p
 		    __func__);
 		return;
 	}
-
 	wm_gmii_hv_writereg_locked(self, phy, reg, val);
 	sc->phy.release(sc);
 }
@@ -9068,6 +9283,7 @@ wm_gmii_hv_writereg_locked(device_t self
 	uint16_t regnum = BM_PHY_REG_NUM(reg);
 
 	phy = (page >= HV_INTC_FC_PAGE_START) ? 1 : phy;
+//	printf("%s: reg %d, write page %d, reg2 %d\n", __func__, reg, page, regnum);
 
 	/* Page 800 works differently than the rest so it has its own func */
 	if (page == BM_WUC_PAGE) {
@@ -11091,6 +11307,7 @@ wm_nvm_release(struct wm_softc *sc)
 		CSR_WRITE(sc, WMREG_EECD, reg);
 	}
 
+	/* XXX msaitoh 2016/09/12 */
 	if (sc->sc_type >= WM_T_ICH8) {
 		wm_put_nvm_ich8lan(sc);
 	} else if (sc->sc_flags & WM_F_LOCK_EXTCNF)
@@ -11548,6 +11765,18 @@ wm_put_phy_82575(struct wm_softc *sc)
 	return wm_put_swfw_semaphore(sc, swfwphysem[sc->sc_funcid]);
 }
 
+#if 0
+static int
+wm_get_nvm_82575(struct wm_softc *sc)
+{
+}
+
+static void
+wm_put_nvm_82575(struct wm_softc *sc)
+{
+}
+#endif
+
 static int
 wm_get_swfwhw_semaphore(struct wm_softc *sc)
 {
@@ -11677,6 +11906,11 @@ wm_get_hw_semaphore_82573(struct wm_soft
 	int i = 0;
 	uint32_t reg;
 
+#if 0
+	check the difference between  wm_get_hw_semaphore_82573
+	    and wm_get_swfwhw_semaphore
+#endif
+	
 	DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n",
 		device_xname(sc->sc_dev), __func__));
 
@@ -11800,7 +12034,8 @@ wm_enable_mng_pass_thru(struct wm_softc 
 {
 	uint32_t manc, fwsm, factps;
 
-	if ((sc->sc_flags & WM_F_ASF_FIRMWARE_PRES) == 0)
+	if ((sc->sc_type < WM_T_80003)
+	    && (sc->sc_flags & WM_F_ASF_FIRMWARE_PRES) == 0)
 		return 0;
 
 	manc = CSR_READ(sc, WMREG_MANC);
@@ -11960,8 +12195,10 @@ wm_smbustopci(struct wm_softc *sc)
 	switch (sc->sc_type) {
 	case WM_T_PCH_LPT:
 	case WM_T_PCH_SPT:
-		if (wm_phy_is_accessible_pchlan(sc))
+		if (wm_phy_is_accessible_pchlan(sc)) {
+			printf("%s: WA isn't required (1)\n", __func__);
 			break;
+		}
 
 		reg = CSR_READ(sc, WMREG_CTRL_EXT);
 		reg |= CTRL_EXT_FORCE_SMBUS;
@@ -11973,8 +12210,10 @@ wm_smbustopci(struct wm_softc *sc)
 		delay(50 * 1000);
 		/* FALLTHROUGH */
 	case WM_T_PCH2:
-		if (wm_phy_is_accessible_pchlan(sc) == true)
+		if (wm_phy_is_accessible_pchlan(sc) == true) {
+			printf("%s: WA isn't required (2)\n", __func__);
 			break;
+		}
 		/* FALLTHROUGH */
 	case WM_T_PCH:
 		if ((sc->sc_type == WM_T_PCH))
@@ -11989,8 +12228,10 @@ wm_smbustopci(struct wm_softc *sc)
 		wm_toggle_lanphypc_pch_lpt(sc);
 
 		if (sc->sc_type >= WM_T_PCH_LPT) {
-			if (wm_phy_is_accessible_pchlan(sc) == true)
+			if (wm_phy_is_accessible_pchlan(sc) == true) {
+				printf("%s: WA isn't required (3)\n", __func__);
 				break;
+			}
 
 			reg = CSR_READ(sc, WMREG_CTRL_EXT);
 			reg &= ~CTRL_EXT_FORCE_SMBUS;
@@ -12113,7 +12354,7 @@ wm_get_wakeup(struct wm_softc *sc)
 	if (wm_enable_mng_pass_thru(sc) != 0)
 		sc->sc_flags |= WM_F_HAS_MANAGE;
 
-#ifdef WM_DEBUG
+#if 1 /* def WM_DEBUG */
 	printf("\n");
 	if ((sc->sc_flags & WM_F_HAS_AMT) != 0)
 		printf("HAS_AMT,");
@@ -12431,6 +12672,8 @@ wm_set_eee_i350(struct wm_softc *sc)
 	CSR_READ(sc, WMREG_EEER); /* XXX flush? */
 }
 
+/* XXX wm_set_eee_pchlan */
+
 /*
  * Workarounds (mainly PHY related).
  * Basically, PHY's workarounds are in the PHY drivers.
@@ -12557,6 +12800,11 @@ wm_lv_phy_workaround_ich8lan(struct wm_s
 	KASSERT(sc->sc_type == WM_T_PCH2);
 
 	wm_set_mdio_slow_mode_hv(sc);
+#if 0 /* notyet */
+	sc->phy.acquire(sc);
+	/* XXX write emi regs */
+	sc->phy.release(sc);
+#endif
 }
 
 static int
@@ -12574,10 +12822,10 @@ wm_k1_gig_workaround_hv(struct wm_softc 
 		k1_enable = 0;
 
 		/* Link stall fix for link up */
-		wm_gmii_hv_writereg_locked(sc->sc_dev, 1, IGP3_KMRN_DIAG, 0x0100);
+		wm_gmii_hv_writereg_locked(sc->sc_dev, 2, IGP3_KMRN_DIAG, 0x0100);
 	} else {
 		/* Link stall fix for link down */
-		wm_gmii_hv_writereg_locked(sc->sc_dev, 1, IGP3_KMRN_DIAG, 0x4100);
+		wm_gmii_hv_writereg_locked(sc->sc_dev, 2, IGP3_KMRN_DIAG, 0x4100);
 	}
 
 	wm_configure_k1_ich8lan(sc, k1_enable);
@@ -12591,8 +12839,8 @@ wm_set_mdio_slow_mode_hv(struct wm_softc
 {
 	uint32_t reg;
 
-	reg = wm_gmii_hv_readreg(sc->sc_dev, 1, HV_KMRN_MODE_CTRL);
-	wm_gmii_hv_writereg(sc->sc_dev, 1, HV_KMRN_MODE_CTRL,
+	reg = wm_gmii_hv_readreg(sc->sc_dev, 2, HV_KMRN_MODE_CTRL);
+	wm_gmii_hv_writereg(sc->sc_dev, 2, HV_KMRN_MODE_CTRL,
 	    reg | HV_KMRN_MDIO_SLOW);
 }
 
@@ -12708,7 +12956,10 @@ wm_phy_is_accessible_pchlan(struct wm_so
 			continue;
 		break;
 	}
+	printf("XXX %s: i = %d\n", __func__, i);
+	printf("XXX id1 = 0x%04hx, id2 = 0x%04hx\n", id1, id2);
 	if (!MII_INVALIDID(id1) && !MII_INVALIDID(id2)) {
+		printf("XXX GOTO OUT\n");
 		goto out;
 	}
 
@@ -12719,6 +12970,7 @@ wm_phy_is_accessible_pchlan(struct wm_so
 		id2 = wm_gmii_hv_readreg(sc->sc_dev, 2, MII_PHYIDR2);
 		sc->phy.acquire(sc);
 	}
+	printf("XXX id1 = 0x%04hx, id2 = 0x%04hx\n", id1, id2);
 	if (MII_INVALIDID(id1) || MII_INVALIDID(id2)) {
 		printf("XXX return with false\n");
 		return false;
@@ -12727,6 +12979,7 @@ out:
 	if ((sc->sc_type == WM_T_PCH_LPT) || (sc->sc_type == WM_T_PCH_SPT)) {
 		/* Only unforce SMBus if ME is not active */
 		if ((CSR_READ(sc, WMREG_FWSM) & FWSM_FW_VALID) == 0) {
+			printf("XXX %s: FW isn't valid\n", __func__);
 			/* Unforce SMBus mode in PHY */
 			reg = wm_gmii_hv_readreg_locked(sc->sc_dev, 2,
 			    CV_SMB_CTRL);
@@ -12777,9 +13030,22 @@ wm_toggle_lanphypc_pch_lpt(struct wm_sof
 		    && i--);
 
 		delay(30 * 1000);
+		printf("%s: i = %d\n", __func__, i);
 	}
 }
 
+static uint64_t
+wm_ltr2ns(uint16_t ltr)
+{
+	uint32_t value, scale;
+
+	/* Determine the latency in nsec based on the LTR value & scale */
+	value = ltr & LTRV_VALUE;
+	scale = __SHIFTOUT(ltr, LTRV_SCALE);
+
+	return value * (1 << (scale * LTRV_SCALE_MAX));
+}
+
 static int
 wm_platform_pm_pch_lpt(struct wm_softc *sc, bool link)
 {
@@ -12788,12 +13054,14 @@ wm_platform_pm_pch_lpt(struct wm_softc *
 	uint32_t rxa;
 	uint16_t scale = 0, lat_enc = 0;
 	int64_t lat_ns, value;
+	int32_t obff_hwm = 0;
 	
 	DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
 		device_xname(sc->sc_dev), __func__));
 
 	if (link) {
 		pcireg_t preg;
+		uint16_t speed = 0;
 		uint16_t max_snoop, max_nosnoop, max_ltr_enc;
 
 		rxa = CSR_READ(sc, WMREG_PBA) & PBA_RXA_MASK;
@@ -12813,7 +13081,6 @@ wm_platform_pm_pch_lpt(struct wm_softc *
 			lat_ns = 0;
 		else {
 			uint32_t status;
-			uint16_t speed;
 
 			status = CSR_READ(sc, WMREG_STATUS);
 			switch (__SHIFTOUT(status, STATUS_SPEED)) {
@@ -12855,12 +13122,46 @@ wm_platform_pm_pch_lpt(struct wm_softc *
 
 		if (lat_enc > max_ltr_enc) {
 			lat_enc = max_ltr_enc;
+			lat_ns = wm_ltr2ns(max_ltr_enc);
+		}
+
+		if (lat_ns) {
+			lat_ns *= speed * 1000;
+			lat_ns /= 8;
+			lat_ns /= 1000000000;
+			obff_hwm = (int32_t)(rxa - lat_ns);
+		}
+		if ((obff_hwm < 0) || (obff_hwm > SVT_OFF_HIWAT)) {
+			printf("%s: Invalid invalid high water mark %d\n",
+			    device_xname(sc->sc_dev), obff_hwm);
 		}
 	}
-	/* Snoop and No-Snoop latencies the same */
+	/* Set Snoop and No-Snoop latencies the same */
 	reg |= lat_enc | __SHIFTIN(lat_enc, LTRV_NONSNOOP);
 	CSR_WRITE(sc, WMREG_LTRV, reg);
 
+	/* Set OBFF high water mark */
+	reg = CSR_READ(sc, WMREG_SVT) & ~SVT_OFF_HIWAT;
+	printf("XXX msk SVT = %08x\n", reg);
+	reg |= obff_hwm;
+	printf("XXX SVT hwm = %08x\n", obff_hwm);
+	printf("XXX new SVT = %08x\n", reg);
+	CSR_WRITE(sc, WMREG_SVT, reg);
+	printf("XXX new SVT = %08x\n", CSR_READ(sc, WMREG_SVT));
+
+	printf("XXX old SVCR = %08x\n", CSR_READ(sc, WMREG_SVCR));
+	/* Enable OBFF */
+	reg = CSR_READ(sc, WMREG_SVCR);
+	reg |= SVCR_OFF_EN;
+	/*
+	  Always unblock interrupts to the CPU even when the system is
+	  * in OBFF mode. This ensures that small round-robin traffic
+	  * (like ping) does not get dropped or experience long latency.
+	  */
+	reg |= SVCR_OFF_MASKINT;
+	CSR_WRITE(sc, WMREG_SVCR, reg);
+	printf("XXX new SVCR = %08x\n", CSR_READ(sc, WMREG_SVCR));
+
 	return 0;
 }
 
@@ -12938,3 +13239,251 @@ wm_pll_workaround_i210(struct wm_softc *
 	if (wa_done)
 		aprint_verbose_dev(sc->sc_dev, "I210 workaround done\n");
 }
+
+#ifdef WM_DUMP
+static uint32_t wmregs[] = {
+	0x0000,
+	0x0004,
+	0x0008,
+	0x0010,
+	0x0014,
+	0x0018,
+	0x0020,
+	0x0024,
+	0x0028,
+	0x002c,
+	0x0030,
+	0x0034,
+	0x0038,
+	0x003c,
+	0x00c0,
+	0x00c4,
+	0x00c8,
+	0x00d0,
+	0x00d8,
+	0x00e4,
+	0x00f0,
+	0x00f4,
+	0x0100,
+	0x0170,
+	0x0178,
+	0x0180,
+	0x0400,
+	0x0404,
+	0x0410,
+	0x0600,
+	0x0800,
+	0x08d8,
+	0x08f0,
+	0x0c00,
+	0x0c40,
+	0x0c80,
+	0x0c88,
+	0x0e00,
+	0x0e04,
+	0x0e10,
+	0x0e30,
+	0x0e34,
+	0x0e38,
+	0x0f00,
+	0x0f08,
+	0x0f10,
+	0x0f14,
+	0x0f18,
+	0x0f28,
+	0x0f34,
+	0x0f3c,
+	0x1000,
+	0x1008,
+	0x100c,
+	0x1010,
+	0x1028,
+	0x102c,
+	0x103c,
+	0x1100,
+	0x1500,
+	0x1514,
+	0x1520,
+	0x1524,
+	0x1528,
+	0x152c,
+	0x1530,
+	0x1600,
+	0x1680,
+	0x1700,
+	0x1740,
+	0x2160,
+	0x2168,
+	0x2170,
+	0x2404,
+	0x2508,
+	0x2514,
+	0x2800,
+	0x2804,
+	0x2808,
+	0x280c,
+	0x2810,
+	0x2818,
+	0x2820,
+	0x2828,
+	0x282c,
+	0x3004,
+	0x3410,
+	0x3418,
+	0x3420,
+	0x3428,
+	0x3430,
+	0x3500,
+	0x3550,
+	0x3800,
+	0x3804,
+	0x3808,
+	0x3810,
+	0x3818,
+	0x3820,
+	0x3828,
+	0x382c,
+	0x3840,
+	0x3928,
+	0x3940,
+	0x3f24,
+	0x4000,
+	0x4004,
+	0x4008,
+	0x400c,
+	0x4010,
+	0x4014,
+	0x4018,
+	0x401c,
+	0x4020,
+	0x4028,
+	0x402c,
+	0x4034,
+	0x4038,
+	0x403c,
+	0x4040,
+	0x4044,
+	0x4048,
+	0x404c,
+	0x4050,
+	0x4054,
+	0x4058,
+	0x405c,
+	0x4060,
+	0x4064,
+	0x4068,
+	0x406c,
+	0x4070,
+	0x4074,
+	0x4078,
+	0x407c,
+	0x4080,
+	0x4088,
+	0x408c,
+	0x4090,
+	0x4094,
+	0x40a0,
+	0x40a4,
+	0x40a8,
+	0x40ac,
+	0x40b0,
+	0x40b4,
+	0x40b8,
+	0x40bc,
+	0x40c0,
+	0x40c4,
+	0x40c8,
+	0x40cc,
+	0x40d8,
+	0x40dc,
+	0x40e0,
+	0x40e4,
+	0x40e8,
+	0x40ec,
+	0x40f0,
+	0x40f4,
+	0x40f8,
+	0x40fc,
+	0x4100,
+	0x4104,
+	0x4108,
+	0x410c,
+	0x4110,
+	0x4118,
+	0x411c,
+	0x4120,
+	0x4124,
+	0x4128,
+	0x412c,
+	0x4130,
+	0x4134,
+	0x4138,
+	0x4200,
+	0x4208,
+	0x420c,
+	0x4218,
+	0x421c,
+	0x4224,
+	0x4228,
+	0x5000,
+	0x5004,
+	0x5008,
+	0x5200,
+	0x5400,
+	0x5404,
+	0x5438,
+	0x543c,
+	0x5600,
+	0x5800,
+	0x5808,
+	0x5818,
+	0x581c,
+	0x5820,
+	0x5860,
+	0x5acc,
+	0x5b00,
+	0x5b30,
+//	0x5b50,
+	0x5b54,
+	0x5b58,
+	0x5b5c,
+	0x5b64,
+	0x5bb8,
+	0x5bbc,
+	0x5c00,
+	0x5dd0,
+	0x5f00,
+	0x5f04,
+	0x5f40,
+	0x5f50,
+	0x8110,
+	0x8800,
+	0x8f00,
+	0x8f40,
+	0xa000,
+	0xa018,
+	0x10010,
+	0x10014,
+	0x10018,
+	0x10034,
+	0x10038,
+	0x12018,
+	0x12024,
+	0x12120,
+};
+
+static void
+wm_regdump(struct wm_softc *sc)
+{
+	int i;
+	int last = 100;
+
+	printf("%s:\n", device_xname(sc->sc_dev));
+	for (i = 0; i < __arraycount(wmregs); i++) {
+		if (wmregs[i] == last)
+			printf("same %05x\n", wmregs[i]);
+		printf("%05x: %08x\n", wmregs[i], CSR_READ(sc, wmregs[i]));
+		last = wmregs[i];
+	}
+}
+#endif
