Module Name:    src
Committed By:   martin
Date:           Wed Aug  5 17:22:46 UTC 2020

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

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

        sys/dev/pci/if_wm.c                     1.655-1.658, 1.660,
                                                1.662, 1.664-1.668,
                                                1.671-1.674, 1.678,
                                                1.680-1.685 via patch
        sys/dev/pci/if_wmreg.c                  1.118-1.119 via patch
        sys/dev/pci/if_wmvar.c                  1.45 via patch
        sys/dev/mii/igphy.c                     1.35-1.36 via patch
        sys/dev/mii/igphyreg.h                  1.12-1.13
        sys/dev/mii/makphy.c                    1.66 via patch
        sys/dev/mii/makphyreg.h                 1.11

- Add SFP support. Module insertion/removal is not supported yet.
  Currently, SFP detection is only done in the driver's attach phase.
- Detect the Media Auto Sense feature. Not supported yet.
- Fix SFF_SFP_ETH_FLAGS_100FX. It's not 0x10 but 0x20.
- Add extra delay in wm_serdes_power_up_link_82575().
- Add Intel I219 LM10-LM15 and V10-V14.
- wm(4) can use workqueue as deferred Rx/Tx handler).
  Set hw.wm*.txrx_workqueue=1 to use workqueue instead of softint.
  The default value of hw.wm*.txrx_workqueue is 0 which use softint
  as before.
- Unset RSS UDP flags like ixg(4) and other OSes. To handle IP
  fragmented UDP, first packet and second packet should be processed
  in the same Rx queue.
- It's useless to not to set PCI_PMCSR_PME_STS bit when writing because
  the bit is W1C. Instead, always write PCI_PMCSR_PME_STS bit to clear
  in case it's already set.
- Actually writing always the checksum offload context descriptor
  makes the HW do extra processing, avoid doing that if possible.
- Fix a bug that the WMREG_EEARBC_I210 register is incorrectly set if
  the system uses iNVM.
- "wmX: 0" on 82542 is difficult to understand, so don't print it.
- Explicitly cast from uint16_t to uint32_t before shifting 16bit left
  when printing Image Unique ID to avoid undefined behavior.
- Set if_baudrate for non-MII device.
- Rename some macros and function.
- KNF. Add comment.


To generate a diff of this commit:
cvs rdiff -u -r1.26.10.1 -r1.26.10.2 src/sys/dev/mii/igphy.c
cvs rdiff -u -r1.10 -r1.10.8.1 src/sys/dev/mii/igphyreg.h
cvs rdiff -u -r1.42.8.4 -r1.42.8.5 src/sys/dev/mii/makphy.c
cvs rdiff -u -r1.6.20.2 -r1.6.20.3 src/sys/dev/mii/makphyreg.h
cvs rdiff -u -r1.508.4.38 -r1.508.4.39 src/sys/dev/pci/if_wm.c
cvs rdiff -u -r1.98.6.11 -r1.98.6.12 src/sys/dev/pci/if_wmreg.h
cvs rdiff -u -r1.33.6.5 -r1.33.6.6 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.26.10.1 src/sys/dev/mii/igphy.c:1.26.10.2
--- src/sys/dev/mii/igphy.c:1.26.10.1	Tue Aug  1 23:33:18 2017
+++ src/sys/dev/mii/igphy.c	Wed Aug  5 17:22:46 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: igphy.c,v 1.26.10.1 2017/08/01 23:33:18 snj Exp $	*/
+/*	$NetBSD: igphy.c,v 1.26.10.2 2020/08/05 17:22:46 martin 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.26.10.1 2017/08/01 23:33:18 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: igphy.c,v 1.26.10.2 2020/08/05 17:22:46 martin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_mii.h"
@@ -274,7 +274,7 @@ igphy_load_dspcode(struct mii_softc *sc)
 
 	delay(20000);
 
-	PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000);
+	PHY_WRITE(sc, IGPHY_PAGE_SELECT, 0x0000);
 	PHY_WRITE(sc, 0x0000, 0x0140);
 
 	delay(5000);
@@ -282,7 +282,7 @@ igphy_load_dspcode(struct mii_softc *sc)
 	for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++)
 		IGPHY_WRITE(sc, code[i].reg, code[i].val);
 
-	PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000);
+	PHY_WRITE(sc, IGPHY_PAGE_SELECT, 0x0000);
 	PHY_WRITE(sc, 0x0000, 0x3300);
 
 	delay(20000);
@@ -327,9 +327,9 @@ igphy_reset(struct mii_softc *sc)
 	}
 
 	if (igsc->sc_mactype == WM_T_82547) {
-		fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_SPARE_FUSE_STATUS);
+		fused = IGPHY_READ(sc, IGPHY_ANALOG_SPARE_FUSE_STATUS);
 		if ((fused & ANALOG_SPARE_FUSE_ENABLED) == 0) {
-			fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_FUSE_STATUS);
+			fused = IGPHY_READ(sc, IGPHY_ANALOG_FUSE_STATUS);
 
 			fine = fused & ANALOG_FUSE_FINE_MASK;
 			coarse = fused & ANALOG_FUSE_COARSE_MASK;
@@ -344,12 +344,12 @@ igphy_reset(struct mii_softc *sc)
 			    (fine & ANALOG_FUSE_FINE_MASK) |
 			    (coarse & ANALOG_FUSE_COARSE_MASK);
 
-			IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_CONTROL, fused);
-			IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_BYPASS,
+			IGPHY_WRITE(sc, IGPHY_ANALOG_FUSE_CONTROL, fused);
+			IGPHY_WRITE(sc, IGPHY_ANALOG_FUSE_BYPASS,
 			    ANALOG_FUSE_ENABLE_SW_CONTROL);
 		}
 	}
-	PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000);
+	PHY_WRITE(sc, IGPHY_PAGE_SELECT, 0x0000);
 }
 
 
@@ -385,14 +385,14 @@ igphy_service(struct mii_softc *sc, stru
 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
 			break;
 
-		reg = PHY_READ(sc, MII_IGPHY_PORT_CTRL);
+		reg = PHY_READ(sc, IGPHY_PORT_CTRL);
 		if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
 			reg |= PSCR_AUTO_MDIX;
 			reg &= ~PSCR_FORCE_MDI_MDIX;
-			PHY_WRITE(sc, MII_IGPHY_PORT_CTRL, reg);
+			PHY_WRITE(sc, IGPHY_PORT_CTRL, reg);
 		} else {
 			reg &= ~(PSCR_AUTO_MDIX | PSCR_FORCE_MDI_MDIX);
-			PHY_WRITE(sc, MII_IGPHY_PORT_CTRL, reg);
+			PHY_WRITE(sc, IGPHY_PORT_CTRL, reg);
 		}
 
 		mii_phy_setmedia(sc);
@@ -435,9 +435,9 @@ igphy_status(struct mii_softc *sc)
 	mii->mii_media_status = IFM_AVALID;
 	mii->mii_media_active = IFM_ETHER;
 
-	pssr = PHY_READ(sc, MII_IGPHY_PORT_STATUS);
+	pssr = PHY_READ(sc, IGPHY_PORT_STATUS);
 
-	if (pssr & PSSR_LINK_UP)
+	if (pssr & IGPHY_PSSR_LINK_UP)
 		mii->mii_media_status |= IFM_ACTIVE;
 
 	bmcr = PHY_READ(sc, MII_BMCR);
@@ -461,19 +461,19 @@ igphy_status(struct mii_softc *sc)
 			mii->mii_media_active |= IFM_NONE;
 			return;
 		}
-		switch (pssr & PSSR_SPEED_MASK) {
-		case PSSR_SPEED_1000MBPS:
+		switch (pssr & IGPHY_PSSR_SPEED_MASK) {
+		case IGPHY_PSSR_SPEED_1000MBPS:
 			mii->mii_media_active |= IFM_1000_T;
 			gtsr = PHY_READ(sc, MII_100T2SR);
 			if (gtsr & GTSR_MS_RES)
 				mii->mii_media_active |= IFM_ETH_MASTER;
 			break;
 
-		case PSSR_SPEED_100MBPS:
+		case IGPHY_PSSR_SPEED_100MBPS:
 			mii->mii_media_active |= IFM_100_TX;
 			break;
 
-		case PSSR_SPEED_10MBPS:
+		case IGPHY_PSSR_SPEED_10MBPS:
 			mii->mii_media_active |= IFM_10_T;
 			break;
 
@@ -483,7 +483,7 @@ igphy_status(struct mii_softc *sc)
 			return;
 		}
 
-		if (pssr & PSSR_FULL_DUPLEX)
+		if (pssr & IGPHY_PSSR_FULL_DUPLEX)
 			mii->mii_media_active |=
 			    IFM_FDX | mii_phy_flowstatus(sc);
 		else

Index: src/sys/dev/mii/igphyreg.h
diff -u src/sys/dev/mii/igphyreg.h:1.10 src/sys/dev/mii/igphyreg.h:1.10.8.1
--- src/sys/dev/mii/igphyreg.h:1.10	Mon Nov  7 08:57:43 2016
+++ src/sys/dev/mii/igphyreg.h	Wed Aug  5 17:22:46 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: igphyreg.h,v 1.10 2016/11/07 08:57:43 msaitoh Exp $	*/
+/*	$NetBSD: igphyreg.h,v 1.10.8.1 2020/08/05 17:22:46 martin Exp $	*/
 
 /*******************************************************************************
 
@@ -43,7 +43,7 @@
  */
 
 /* IGP01E1000 Specific Port Config Register - R/W */
-#define MII_IGPHY_PORT_CONFIG		0x10 /* PHY specific config register */
+#define IGPHY_PORT_CONFIG		0x10 /* PHY specific config register */
 #define PSCFR_AUTO_MDIX_PAR_DETECT	0x0010
 #define PSCFR_PRE_EN			0x0020
 #define PSCFR_SMART_SPEED		0x0080
@@ -52,22 +52,22 @@
 #define PSCFR_DISABLE_TRANSMIT		0x2000
 
 /* IGP01E1000 Specific Port Status Register - R/O */
-#define MII_IGPHY_PORT_STATUS		0x11
-#define PSSR_AUTONEG_FAILED		0x0001 /* RO LH SC */
-#define PSSR_POLARITY_REVERSED		0x0002
-#define PSSR_CABLE_LENGTH		0x007C
-#define PSSR_FULL_DUPLEX		0x0200
-#define PSSR_LINK_UP			0x0400
-#define PSSR_MDIX			0x0800
-#define PSSR_SPEED_MASK			0xC000 /* speed bits mask */
-#define PSSR_SPEED_10MBPS		0x4000
-#define PSSR_SPEED_100MBPS		0x8000
-#define PSSR_SPEED_1000MBPS		0xC000
-#define PSSR_CABLE_LENGTH_SHIFT 	0x0002 /* shift right 2 */
-#define PSSR_MDIX_SHIFT			0x000B /* shift right 11 */
+#define IGPHY_PORT_STATUS		0x11
+#define IGPHY_PSSR_AUTONEG_FAILED	0x0001 /* RO LH SC */
+#define IGPHY_PSSR_POLARITY_REVERSED	0x0002
+#define IGPHY_PSSR_CABLE_LENGTH		0x007C
+#define IGPHY_PSSR_FULL_DUPLEX		0x0200
+#define IGPHY_PSSR_LINK_UP		0x0400
+#define IGPHY_PSSR_MDIX			0x0800
+#define IGPHY_PSSR_SPEED_MASK		0xC000 /* speed bits mask */
+#define IGPHY_PSSR_SPEED_10MBPS		0x4000
+#define IGPHY_PSSR_SPEED_100MBPS	0x8000
+#define IGPHY_PSSR_SPEED_1000MBPS	0xC000
+#define IGPHY_PSSR_CABLE_LENGTH_SHIFT 	0x0002 /* shift right 2 */
+#define IGPHY_PSSR_MDIX_SHIFT		0x000B /* shift right 11 */
 
 /* IGP01E1000 Specific Port Control Register - R/W */
-#define MII_IGPHY_PORT_CTRL		0x12
+#define IGPHY_PORT_CTRL			0x12
 #define PSCR_TP_LOOPBACK		0x0010
 #define PSCR_CORRECT_NC_SCMBLR		0x0200
 #define PSCR_TEN_CRS_SELECT		0x0400
@@ -76,7 +76,7 @@
 #define PSCR_FORCE_MDI_MDIX 		0x2000 /* 0-MDI, 1-MDIX */
 
 /* IGP01E1000 Specific Port Link Health Register */
-#define MII_IGPHY_LINK_HEALTH		0x13
+#define IGPHY_LINK_HEALTH		0x13
 #define PLHR_VALID_CHANNEL_A		0x0001
 #define PLHR_VALID_CHANNEL_B		0x0002
 #define PLHR_VALID_CHANNEL_C		0x0004
@@ -96,61 +96,61 @@
 #define GMII_SPD			0x20 /* Enable SPD */
 
 /* IGP01E1000 Channel Quality Register */
-#define MII_IGPHY_CHANNEL_QUALITY	0x15
+#define IGPHY_CHANNEL_QUALITY		0x15
 #define MSE_CHANNEL_A			0x000F
 #define MSE_CHANNEL_B			0x00F0
 #define MSE_CHANNEL_C			0x0F00
 #define MSE_CHANNEL_D			0xF000
 
 /* IGP01E1000 Power Management */
-#define MII_IGPHY_POWER_MGMT		0x19
+#define IGPHY_POWER_MGMT		0x19
 #define PMR_SPD_EN			0x0001
 #define PMR_D0_LPLU			0x0002
 #define PMR_D3_LPLU			0x0004
 #define PMR_DIS_1000			0x0040
 
-#define MII_IGPHY_PAGE_SELECT		0x1F
+#define IGPHY_PAGE_SELECT		0x1F
 #define IGPHY_MAXREGADDR		0x1F
 #define IGPHY_PAGEMASK			(~IGPHY_MAXREGADDR)
 
 /* IGP01E1000 AGC Registers - stores the cable length values*/
-#define MII_IGPHY_AGC_A			0x1172
-#define MII_IGPHY_AGC_PARAM_A		0x1171
-#define MII_IGPHY_AGC_B			0x1272
-#define MII_IGPHY_AGC_PARAM_B		0x1271
-#define MII_IGPHY_AGC_C			0x1472
-#define MII_IGPHY_AGC_PARAM_C		0x1471
-#define MII_IGPHY_AGC_D			0x1872
-#define MII_IGPHY_AGC_PARAM_D		0x1871
+#define IGPHY_AGC_A			0x1172
+#define IGPHY_AGC_PARAM_A		0x1171
+#define IGPHY_AGC_B			0x1272
+#define IGPHY_AGC_PARAM_B		0x1271
+#define IGPHY_AGC_C			0x1472
+#define IGPHY_AGC_PARAM_C		0x1471
+#define IGPHY_AGC_D			0x1872
+#define IGPHY_AGC_PARAM_D		0x1871
 #define AGC_LENGTH_SHIFT		7  /* Coarse - 13:11, Fine - 10:7 */
 #define AGC_LENGTH_TABLE_SIZE		128
 #define AGC_RANGE			10
 
 /* IGP01E1000 DSP Reset Register */
-#define MII_IGPHY_DSP_RESET		0x1F33
-#define MII_IGPHY_DSP_SET		0x1F71
-#define MII_IGPHY_DSP_FFE		0x1F35
-#define MII_IGPHY_CHANNEL_NUM		4
-#define MII_IGPHY_EDAC_MU_INDEX		0xC000
-#define MII_IGPHY_EDAC_SIGN_EXT_9_BITS	0x8000
-#define MII_IGPHY_ANALOG_TX_STATE	0x2890
-#define MII_IGPHY_ANALOG_CLASS_A	0x2000
-#define MII_IGPHY_FORCE_ANALOG_ENABLE	0x0004
-#define MII_IGPHY_DSP_FFE_CM_CP		0x0069
-#define MII_IGPHY_DSP_FFE_DEFAULT	0x002A
+#define IGPHY_DSP_RESET			0x1F33
+#define IGPHY_DSP_SET			0x1F71
+#define IGPHY_DSP_FFE			0x1F35
+#define IGPHY_CHANNEL_NUM		4
+#define IGPHY_EDAC_MU_INDEX		0xC000
+#define IGPHY_EDAC_SIGN_EXT_9_BITS	0x8000
+#define IGPHY_ANALOG_TX_STATE		0x2890
+#define IGPHY_ANALOG_CLASS_A		0x2000
+#define IGPHY_FORCE_ANALOG_ENABLE	0x0004
+#define IGPHY_DSP_FFE_CM_CP		0x0069
+#define IGPHY_DSP_FFE_DEFAULT		0x002A
 
 /* IGP01E1000 PCS Initialization register - stores the polarity status */
-#define MII_IGPHY_PCS_INIT_REG		0x00B4
-#define MII_IGPHY_PCS_CTRL_REG		0x00B5
+#define IGPHY_PCS_INIT_REG		0x00B4
+#define IGPHY_PCS_CTRL_REG		0x00B5
 
-#define MII_IGPHY_ANALOG_REGS_PAGE	0x20C0
+#define IGPHY_ANALOG_REGS_PAGE		0x20C0
 #define PHY_POLARITY_MASK		0x0078
 
 /* IGP01E1000 Analog Register */
-#define MII_IGPHY_ANALOG_SPARE_FUSE_STATUS	0x20D1
-#define MII_IGPHY_ANALOG_FUSE_STATUS		0x20D0
-#define MII_IGPHY_ANALOG_FUSE_CONTROL		0x20DC
-#define MII_IGPHY_ANALOG_FUSE_BYPASS		0x20DE
+#define IGPHY_ANALOG_SPARE_FUSE_STATUS	0x20D1
+#define IGPHY_ANALOG_FUSE_STATUS	0x20D0
+#define IGPHY_ANALOG_FUSE_CONTROL	0x20DC
+#define IGPHY_ANALOG_FUSE_BYPASS	0x20DE
 #define ANALOG_FUSE_POLY_MASK		0xF000
 #define ANALOG_FUSE_FINE_MASK		0x0F80
 #define ANALOG_FUSE_COARSE_MASK		0x0070
@@ -177,12 +177,12 @@
 
 
 #define IGPHY_READ(sc, reg) \
-    (PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, (reg) & ~0x1f), \
+	(PHY_WRITE(sc, IGPHY_PAGE_SELECT, (reg) & ~0x1f),		      \
      PHY_READ(sc, (reg) & 0x1f))
 
 #define IGPHY_WRITE(sc, reg, val) \
     do { \
-	PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, (reg) & ~0x1f); \
+	PHY_WRITE(sc, IGPHY_PAGE_SELECT, (reg) & ~0x1f); \
 	PHY_WRITE(sc, (reg) & 0x1f, val); \
     } while (/*CONSTCOND*/0)
 

Index: src/sys/dev/mii/makphy.c
diff -u src/sys/dev/mii/makphy.c:1.42.8.4 src/sys/dev/mii/makphy.c:1.42.8.5
--- src/sys/dev/mii/makphy.c:1.42.8.4	Tue Jan 28 09:34:29 2020
+++ src/sys/dev/mii/makphy.c	Wed Aug  5 17:22:46 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: makphy.c,v 1.42.8.4 2020/01/28 09:34:29 martin Exp $	*/
+/*	$NetBSD: makphy.c,v 1.42.8.5 2020/08/05 17:22:46 martin Exp $	*/
 
 /*-
  * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
@@ -59,7 +59,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: makphy.c,v 1.42.8.4 2020/01/28 09:34:29 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: makphy.c,v 1.42.8.5 2020/08/05 17:22:46 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -469,7 +469,7 @@ makphy_status(struct mii_softc *sc)
 	/* XXX FIXME: Use different page for Fiber on newer chips */
 	pssr = PHY_READ(sc, MAKPHY_PSSR);
 
-	if (pssr & PSSR_LINK)
+	if (pssr & MAKPHY_PSSR_LINK)
 		mii->mii_media_status |= IFM_ACTIVE;
 
 	if (bmcr & BMCR_LOOP)
@@ -486,13 +486,13 @@ makphy_status(struct mii_softc *sc)
 		 * Check Speed and Duplex Resolved bit.
 		 * Note that this bit is always 1 when autonego is not enabled.
 		 */
-		if (!(pssr & PSSR_RESOLVED)) {
+		if (!(pssr & MAKPHY_PSSR_RESOLVED)) {
 			/* Erg, still trying, I guess... */
 			mii->mii_media_active |= IFM_NONE;
 			return;
 		}
 	} else {
-		if ((pssr & PSSR_LINK) == 0) {
+		if ((pssr & MAKPHY_PSSR_LINK) == 0) {
 			mii->mii_media_active |= IFM_NONE;
 			return;
 		}
@@ -520,10 +520,10 @@ makphy_status(struct mii_softc *sc)
 		/* Fiber/Copper auto select mode */
 
 		pssr = PHY_READ(sc, MAKPHY_PSSR);
-		if ((pssr & PSSR_RESOLUTION_FIBER) == 0)
+		if ((pssr & MAKPHY_PSSR_RESOLUTION_FIBER) == 0)
 			goto copper;
 
-		switch (PSSR_SPEED_get(pssr)) {
+		switch (MAKPHY_PSSR_SPEED_get(pssr)) {
 		case SPEED_1000:
 			mii->mii_media_active |= IFM_1000_SX;
 			break;
@@ -537,7 +537,7 @@ makphy_status(struct mii_softc *sc)
 		}
 	} else {
 copper:
-		switch (PSSR_SPEED_get(pssr)) {
+		switch (MAKPHY_PSSR_SPEED_get(pssr)) {
 		case SPEED_1000:
 			mii->mii_media_active |= IFM_1000_T;
 			break;
@@ -554,7 +554,7 @@ copper:
 		}
 	}
 
-	if (pssr & PSSR_DUPLEX)
+	if (pssr & MAKPHY_PSSR_DUPLEX)
 		mii->mii_media_active |= mii_phy_flowstatus(sc) | IFM_FDX;
 	else
 		mii->mii_media_active |= IFM_HDX;

Index: src/sys/dev/mii/makphyreg.h
diff -u src/sys/dev/mii/makphyreg.h:1.6.20.2 src/sys/dev/mii/makphyreg.h:1.6.20.3
--- src/sys/dev/mii/makphyreg.h:1.6.20.2	Tue Jan 28 09:34:29 2020
+++ src/sys/dev/mii/makphyreg.h	Wed Aug  5 17:22:46 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: makphyreg.h,v 1.6.20.2 2020/01/28 09:34:29 martin Exp $	*/
+/*	$NetBSD: makphyreg.h,v 1.6.20.3 2020/08/05 17:22:46 martin Exp $	*/
 
 /*-
  * Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -92,15 +92,15 @@
 #define	MSCR_ENHANCED_SGMII	0x0004	/* Enhanced SGMII */
 
 #define	MAKPHY_PSSR		0x11	/* PHY specific status register */
-#define	PSSR_JABBER		(1U << 0)   /* jabber indication */
-#define	PSSR_POLARITY		(1U << 1)   /* polarity indiciation */
-#define	PSSR_MDIX		(1U << 6)   /* 1 = MIDX, 0 = MDI */
-#define	PSSR_CABLE_LENGTH_get(x) (((x) >> 7) & 0x3)
-#define	PSSR_LINK		(1U << 10)  /* link indication */
-#define	PSSR_RESOLVED		(1U << 11)  /* speed and duplex resolved */
-#define	PSSR_PAGE_RECEIVED	(1U << 12)  /* page received */
-#define	PSSR_DUPLEX		(1U << 13)  /* 1 = FDX */
-#define	PSSR_SPEED_get(x)	(((x) >> 14) & 0x3)
+#define	MAKPHY_PSSR_JABBER	(1U << 0)   /* jabber indication */
+#define	MAKPHY_PSSR_POLARITY	(1U << 1)   /* polarity indiciation */
+#define	MAKPHY_PSSR_MDIX	(1U << 6)   /* 1 = MIDX, 0 = MDI */
+#define	MAKPHY_PSSR_CABLE_LENGTH_get(x) (((x) >> 7) & 0x3)
+#define	MAKPHY_PSSR_LINK	(1U << 10)  /* link indication */
+#define	MAKPHY_PSSR_RESOLVED	(1U << 11)  /* speed and duplex resolved */
+#define	MAKPHY_PSSR_PAGE_RECEIVED (1U << 12)  /* page received */
+#define	MAKPHY_PSSR_DUPLEX	(1U << 13)  /* 1 = FDX */
+#define	MAKPHY_PSSR_SPEED_get(x) (((x) >> 14) & 0x3)
 
 #define	SPEED_10		0
 #define	SPEED_100		1
@@ -108,10 +108,10 @@
 #define	SPEED_reserved		3
 
 /* For 88E1112 */
-#define	PSSR_RESOLUTION_FIBER	(1U << 7)   /*
-					     * Fiber/Copper resolution
-					     * 1 = Fiber, 0 = Copper
-					     */
+#define	MAKPHY_PSSR_RESOLUTION_FIBER (1U << 7) /*
+						* Fiber/Copper resolution
+						* 1 = Fiber, 0 = Copper
+						*/
 
 #define	MAKPHY_IE		0x12	/* Interrupt enable */
 #define	IE_JABBER		(1U << 0)   /* jabber indication */

Index: src/sys/dev/pci/if_wm.c
diff -u src/sys/dev/pci/if_wm.c:1.508.4.38 src/sys/dev/pci/if_wm.c:1.508.4.39
--- src/sys/dev/pci/if_wm.c:1.508.4.38	Fri Jan 24 18:43:35 2020
+++ src/sys/dev/pci/if_wm.c	Wed Aug  5 17:22:45 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wm.c,v 1.508.4.38 2020/01/24 18:43:35 martin Exp $	*/
+/*	$NetBSD: if_wm.c,v 1.508.4.39 2020/08/05 17:22:45 martin Exp $	*/
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -82,7 +82,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.508.4.38 2020/01/24 18:43:35 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.508.4.39 2020/08/05 17:22:45 martin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_net_mpsafe.h"
@@ -105,6 +105,8 @@ __KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.
 #include <sys/interrupt.h>
 #include <sys/cpu.h>
 #include <sys/pcq.h>
+#include <sys/sysctl.h>
+#include <sys/workqueue.h>
 
 #include <sys/rndsource.h>
 
@@ -136,6 +138,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.
 #include <dev/mii/igphyvar.h>
 #include <dev/mii/inbmphyreg.h>
 #include <dev/mii/ihphyreg.h>
+#include <dev/mii/makphyreg.h>
 
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
@@ -155,7 +158,6 @@ __KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.
 #define	WM_DEBUG_LOCK		__BIT(7)
 int	wm_debug = WM_DEBUG_TX | WM_DEBUG_RX | WM_DEBUG_LINK | WM_DEBUG_GMII
     | WM_DEBUG_MANAGE | WM_DEBUG_NVM | WM_DEBUG_INIT | WM_DEBUG_LOCK;
-
 #define	DPRINTF(x, y)	do { if (wm_debug & (x)) printf y; } while (0)
 #else
 #define	DPRINTF(x, y)	__nothing
@@ -163,11 +165,17 @@ int	wm_debug = WM_DEBUG_TX | WM_DEBUG_RX
 
 #ifdef NET_MPSAFE
 #define WM_MPSAFE	1
-#define CALLOUT_FLAGS	CALLOUT_MPSAFE
+#define WM_CALLOUT_FLAGS	CALLOUT_MPSAFE
+#define WM_SOFTINT_FLAGS	SOFTINT_MPSAFE
+#define WM_WORKQUEUE_FLAGS	WQ_PERCPU | WQ_MPSAFE
 #else
-#define CALLOUT_FLAGS	0
+#define WM_CALLOUT_FLAGS	0
+#define WM_SOFTINT_FLAGS	0
+#define WM_WORKQUEUE_FLAGS	WQ_PERCPU
 #endif
 
+#define WM_WORKQUEUE_PRI PRI_SOFTNET
+
 /*
  * This device driver's max interrupt numbers.
  */
@@ -373,6 +381,12 @@ struct wm_txqueue {
 	bool txq_sending;
 	time_t txq_lastsent;
 
+	/* Checksum flags used for previous packet */
+	uint32_t 	txq_last_hw_cmd;
+	uint8_t 	txq_last_hw_fields;
+	uint16_t	txq_last_hw_ipcs;
+	uint16_t	txq_last_hw_tucs;
+
 	uint32_t txq_packets;		/* for AIM */
 	uint32_t txq_bytes;		/* for AIM */
 #ifdef WM_EVENT_COUNTERS
@@ -397,6 +411,7 @@ struct wm_txqueue {
 	WM_Q_EVCNT_DEFINE(txq, toomanyseg)  /* Pkt dropped(toomany DMA segs) */
 	WM_Q_EVCNT_DEFINE(txq, defrag)	    /* m_defrag() */
 	WM_Q_EVCNT_DEFINE(txq, underrun)    /* Tx underrun */
+	WM_Q_EVCNT_DEFINE(txq, skipcontext) /* Tx skip wring cksum context */
 
 	char txq_txseg_evcnt_names[WM_NTXSEGS][sizeof("txqXXtxsegXXX")];
 	struct evcnt txq_ev_txseg[WM_NTXSEGS]; /* Tx packets w/ N segments */
@@ -456,6 +471,8 @@ struct wm_queue {
 	struct wm_txqueue wmq_txq;
 	struct wm_rxqueue wmq_rxq;
 
+	bool wmq_txrx_use_workqueue;
+	struct work wmq_cookie;
 	void *wmq_si;
 	krndsource_t rnd_source;	/* random source */
 };
@@ -466,6 +483,7 @@ struct wm_phyop {
 	int (*readreg_locked)(device_t, int, int, uint16_t *);
 	int (*writereg_locked)(device_t, int, int, uint16_t);
 	int reset_delay_us;
+	bool no_errprint;
 };
 
 struct wm_nvmop {
@@ -506,6 +524,7 @@ struct wm_softc {
 	wm_chip_type sc_type;		/* MAC type */
 	int sc_rev;			/* MAC revision */
 	wm_phy_type sc_phytype;		/* PHY type */
+	uint8_t sc_sfptype;		/* SFP type */
 	uint32_t sc_mediatype;		/* Media type (Copper, Fiber, SERDES)*/
 #define	WM_MEDIATYPE_UNKNOWN		0x00
 #define	WM_MEDIATYPE_FIBER		0x01
@@ -548,6 +567,8 @@ struct wm_softc {
 	u_int sc_tx_intr_process_limit;	/* Tx proc. repeat limit in H/W intr */
 	u_int sc_rx_process_limit;	/* Rx proc. repeat limit in softint */
 	u_int sc_rx_intr_process_limit;	/* Rx proc. repeat limit in H/W intr */
+	struct workqueue *sc_queue_wq;
+	bool sc_txrx_use_workqueue;
 
 	int sc_affinity_offset;
 
@@ -563,6 +584,8 @@ struct wm_softc {
 	struct evcnt sc_ev_rx_macctl;	/* Rx Unsupported */
 #endif /* WM_EVENT_COUNTERS */
 
+	struct sysctllog *sc_sysctllog;
+
 	/* This variable are used only on the 82547. */
 	callout_t sc_txfifo_ch;		/* Tx FIFO stall work-around timer */
 
@@ -734,11 +757,12 @@ static void	wm_init_rss(struct wm_softc 
 static void	wm_adjust_qnum(struct wm_softc *, int);
 static inline bool	wm_is_using_msix(struct wm_softc *);
 static inline bool	wm_is_using_multiqueue(struct wm_softc *);
-static int	wm_softint_establish(struct wm_softc *, int, int);
+static int	wm_softint_establish_queue(struct wm_softc *, int, int);
 static int	wm_setup_legacy(struct wm_softc *);
 static int	wm_setup_msix(struct wm_softc *);
 static int	wm_init(struct ifnet *);
 static int	wm_init_locked(struct ifnet *);
+static void	wm_init_sysctls(struct wm_softc *);
 static void	wm_unset_stopping_flags(struct wm_softc *);
 static void	wm_set_stopping_flags(struct wm_softc *);
 static void	wm_stop(struct ifnet *, int);
@@ -771,7 +795,7 @@ static int	wm_alloc_txrx_queues(struct w
 static void	wm_free_txrx_queues(struct wm_softc *);
 static int	wm_init_txrx_queues(struct wm_softc *);
 /* Start */
-static int	wm_tx_offload(struct wm_softc *, struct wm_txqueue *,
+static void	wm_tx_offload(struct wm_softc *, struct wm_txqueue *,
     struct wm_txsoft *, uint32_t *, uint8_t *);
 static inline int	wm_select_txqueue(struct ifnet *, struct mbuf *);
 static void	wm_start(struct ifnet *);
@@ -780,7 +804,7 @@ static int	wm_transmit(struct ifnet *, s
 static void	wm_transmit_locked(struct ifnet *, struct wm_txqueue *);
 static void	wm_send_common_locked(struct ifnet *, struct wm_txqueue *,
     bool);
-static int	wm_nq_tx_offload(struct wm_softc *, struct wm_txqueue *,
+static void	wm_nq_tx_offload(struct wm_softc *, struct wm_txqueue *,
     struct wm_txsoft *, uint32_t *, uint32_t *, bool *);
 static void	wm_nq_start(struct ifnet *);
 static void	wm_nq_start_locked(struct ifnet *);
@@ -790,6 +814,7 @@ static void	wm_nq_send_common_locked(str
     bool);
 static void	wm_deferred_start_locked(struct wm_txqueue *);
 static void	wm_handle_queue(void *);
+static void	wm_handle_queue_work(struct work *, void *);
 /* Interrupt */
 static bool	wm_txeof(struct wm_txqueue *, u_int);
 static bool	wm_rxeof(struct wm_rxqueue *, u_int);
@@ -855,6 +880,7 @@ static int	wm_kmrn_writereg(struct wm_so
 static int	wm_kmrn_writereg_locked(struct wm_softc *, int, uint16_t);
 /* SGMII */
 static bool	wm_sgmii_uses_mdio(struct wm_softc *);
+static void	wm_sgmii_sfp_preconfig(struct wm_softc *);
 static int	wm_sgmii_readreg(device_t, int, int);
 static void	wm_sgmii_writereg(device_t, int, int, int);
 /* TBI related */
@@ -1173,23 +1199,23 @@ static const struct wm_product {
 
 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82571GB_QUAD_COPPER,
 	  "Intel PRO/1000 PT Quad Port Server Adapter",
-	  WM_T_82571,		WMP_F_COPPER, },
+	  WM_T_82571,		WMP_F_COPPER },
 
 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82571PT_QUAD_COPPER,
 	  "Intel Gigabit PT Quad Port Server ExpressModule",
-	  WM_T_82571,		WMP_F_COPPER, },
+	  WM_T_82571,		WMP_F_COPPER },
 
 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82571EB_DUAL_SERDES,
 	  "Intel 82571EB Dual Gigabit Ethernet (SERDES)",
-	  WM_T_82571,		WMP_F_SERDES, },
+	  WM_T_82571,		WMP_F_SERDES },
 
 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82571EB_QUAD_SERDES,
 	  "Intel 82571EB Quad Gigabit Ethernet (SERDES)",
-	  WM_T_82571,		WMP_F_SERDES, },
+	  WM_T_82571,		WMP_F_SERDES },
 
 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82571EB_QUAD_FIBER,
 	  "Intel 82571EB Quad 1000baseX Ethernet",
-	  WM_T_82571,		WMP_F_FIBER, },
+	  WM_T_82571,		WMP_F_FIBER },
 
 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82572EI_COPPER,
 	  "Intel i82572EI 1000baseT Ethernet",
@@ -1543,6 +1569,24 @@ static const struct wm_product {
 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I219_LM9,
 	  "I219 LM Ethernet Connection",
 	  WM_T_PCH_CNP,		WMP_F_COPPER },
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I219_LM10,
+	  "I219 LM Ethernet Connection",
+	  WM_T_PCH_CNP,		WMP_F_COPPER },
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I219_LM11,
+	  "I219 LM Ethernet Connection",
+	  WM_T_PCH_CNP,		WMP_F_COPPER },
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I219_LM12,
+	  "I219 LM Ethernet Connection",
+	  WM_T_PCH_SPT,		WMP_F_COPPER },
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I219_LM13,
+	  "I219 LM Ethernet Connection",
+	  WM_T_PCH_CNP,		WMP_F_COPPER },
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I219_LM14,
+	  "I219 LM Ethernet Connection",
+	  WM_T_PCH_CNP,		WMP_F_COPPER },
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I219_LM15,
+	  "I219 LM Ethernet Connection",
+	  WM_T_PCH_CNP,		WMP_F_COPPER },
 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I219_V,
 	  "I219 V Ethernet Connection",
 	  WM_T_PCH_SPT,		WMP_F_COPPER },
@@ -1567,6 +1611,21 @@ static const struct wm_product {
 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I219_V9,
 	  "I219 V Ethernet Connection",
 	  WM_T_PCH_CNP,		WMP_F_COPPER },
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I219_V10,
+	  "I219 V Ethernet Connection",
+	  WM_T_PCH_CNP,		WMP_F_COPPER },
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I219_V11,
+	  "I219 V Ethernet Connection",
+	  WM_T_PCH_CNP,		WMP_F_COPPER },
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I219_V12,
+	  "I219 V Ethernet Connection",
+	  WM_T_PCH_SPT,		WMP_F_COPPER },
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I219_V13,
+	  "I219 V Ethernet Connection",
+	  WM_T_PCH_CNP,		WMP_F_COPPER },
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I219_V14,
+	  "I219 V Ethernet Connection",
+	  WM_T_PCH_CNP,		WMP_F_COPPER },
 	{ 0,			0,
 	  NULL,
 	  0,			0 },
@@ -1763,6 +1822,7 @@ wm_attach(device_t parent, device_t self
 	prop_number_t pn;
 	uint8_t enaddr[ETHER_ADDR_LEN];
 	char buf[256];
+	char wqname[MAXCOMLEN];
 	uint16_t cfg1, cfg2, swdpin, nvmword;
 	pcireg_t preg, memtype;
 	uint16_t eeprom_data, apme_mask;
@@ -1771,7 +1831,7 @@ wm_attach(device_t parent, device_t self
 	uint32_t reg;
 
 	sc->sc_dev = self;
-	callout_init(&sc->sc_tick_ch, CALLOUT_FLAGS);
+	callout_init(&sc->sc_tick_ch, WM_CALLOUT_FLAGS);
 	sc->sc_core_stopping = false;
 
 	wmp = wm_lookup(pa);
@@ -1996,6 +2056,16 @@ alloc_retry:
 		}
 	}
 
+	snprintf(wqname, sizeof(wqname), "%sTxRx", device_xname(sc->sc_dev));
+	error = workqueue_create(&sc->sc_queue_wq, wqname,
+	    wm_handle_queue_work, sc, WM_WORKQUEUE_PRI, IPL_NET,
+	    WM_WORKQUEUE_FLAGS);
+	if (error) {
+		aprint_error_dev(sc->sc_dev,
+		    "unable to create workqueue\n");
+		goto out;
+	}
+
 	/*
 	 * Check the function ID (unit number of the chip).
 	 */
@@ -2025,7 +2095,7 @@ alloc_retry:
 		aprint_verbose_dev(sc->sc_dev,
 		    "Communication Streaming Architecture\n");
 		if (sc->sc_type == WM_T_82547) {
-			callout_init(&sc->sc_txfifo_ch, CALLOUT_FLAGS);
+			callout_init(&sc->sc_txfifo_ch, WM_CALLOUT_FLAGS);
 			callout_setfunc(&sc->sc_txfifo_ch,
 			    wm_82547_txfifo_stall, sc);
 			aprint_verbose_dev(sc->sc_dev,
@@ -2593,11 +2663,22 @@ alloc_retry:
 		break;
 	}
 
-	if ((sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576)) {
-		/* Check NVM for autonegotiation */
+	if (sc->sc_type >= WM_T_82575) {
 		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;
+			aprint_debug_dev(sc->sc_dev, "COMPAT = %hx\n",
+			    nvmword);
+			if ((sc->sc_type == WM_T_82575) ||
+			    (sc->sc_type == WM_T_82576)) {
+				/* Check NVM for autonegotiation */
+				if ((nvmword & NVM_COMPAT_SERDES_FORCE_MODE)
+				    != 0)
+					sc->sc_flags |= WM_F_PCS_DIS_AUTONEGO;
+			}
+			if ((sc->sc_type == WM_T_82575) ||
+			    (sc->sc_type == WM_T_I350)) {
+				if (nvmword & NVM_COMPAT_MAS_EN(sc->sc_funcid))
+					sc->sc_flags |= WM_F_MAS;
+			}
 		}
 	}
 
@@ -2705,12 +2786,12 @@ alloc_retry:
 		link_mode = reg & CTRL_EXT_LINK_MODE_MASK;
 		switch (link_mode) {
 		case CTRL_EXT_LINK_MODE_1000KX:
-			aprint_verbose_dev(sc->sc_dev, "1000KX\n");
+			aprint_normal_dev(sc->sc_dev, "1000KX\n");
 			sc->sc_mediatype = WM_MEDIATYPE_SERDES;
 			break;
 		case CTRL_EXT_LINK_MODE_SGMII:
 			if (wm_sgmii_uses_mdio(sc)) {
-				aprint_verbose_dev(sc->sc_dev,
+				aprint_normal_dev(sc->sc_dev,
 				    "SGMII(MDIO)\n");
 				sc->sc_flags |= WM_F_SGMII;
 				sc->sc_mediatype = WM_MEDIATYPE_COPPER;
@@ -2725,6 +2806,8 @@ alloc_retry:
 				    == CTRL_EXT_LINK_MODE_SGMII) {
 					sc->sc_mediatype = WM_MEDIATYPE_COPPER;
 					sc->sc_flags |= WM_F_SGMII;
+					aprint_verbose_dev(sc->sc_dev,
+					    "SGMII\n");
 				} else {
 					sc->sc_mediatype = WM_MEDIATYPE_SERDES;
 					aprint_verbose_dev(sc->sc_dev,
@@ -2733,25 +2816,26 @@ alloc_retry:
 				break;
 			}
 			if (sc->sc_mediatype == WM_MEDIATYPE_SERDES)
-				aprint_verbose_dev(sc->sc_dev, "SERDES\n");
+				aprint_normal_dev(sc->sc_dev, "SERDES(SFP)\n");
+			else if (sc->sc_mediatype == WM_MEDIATYPE_COPPER) {
+				aprint_normal_dev(sc->sc_dev, "SGMII(SFP)\n");
+				sc->sc_flags |= WM_F_SGMII;
+			}
+			/* Do not change link mode for 100BaseFX */
+			if (sc->sc_sfptype == SFF_SFP_ETH_FLAGS_100FX)
+				break;
 
 			/* Change current link mode setting */
 			reg &= ~CTRL_EXT_LINK_MODE_MASK;
-			switch (sc->sc_mediatype) {
-			case WM_MEDIATYPE_COPPER:
+			if (sc->sc_mediatype == WM_MEDIATYPE_COPPER)
 				reg |= CTRL_EXT_LINK_MODE_SGMII;
-				break;
-			case WM_MEDIATYPE_SERDES:
+			else
 				reg |= CTRL_EXT_LINK_MODE_PCIE_SERDES;
-				break;
-			default:
-				break;
-			}
 			CSR_WRITE(sc, WMREG_CTRL_EXT, reg);
 			break;
 		case CTRL_EXT_LINK_MODE_GMII:
 		default:
-			aprint_verbose_dev(sc->sc_dev, "Copper\n");
+			aprint_normal_dev(sc->sc_dev, "Copper\n");
 			sc->sc_mediatype = WM_MEDIATYPE_COPPER;
 			break;
 		}
@@ -2762,6 +2846,10 @@ alloc_retry:
 		else
 			reg &= ~CTRL_EXT_I2C_ENA;
 		CSR_WRITE(sc, WMREG_CTRL_EXT, reg);
+		if ((sc->sc_flags & WM_F_SGMII) != 0) {
+			wm_gmii_setup_phytype(sc, 0, 0);
+			wm_reset_mdicnfg_82580(sc);
+		}
 	} else if (sc->sc_type < WM_T_82543 ||
 	    (CSR_READ(sc, WMREG_STATUS) & STATUS_TBIMODE) != 0) {
 		if (sc->sc_mediatype == WM_MEDIATYPE_COPPER) {
@@ -2776,8 +2864,10 @@ alloc_retry:
 			sc->sc_mediatype = WM_MEDIATYPE_COPPER;
 		}
 	}
-	snprintb(buf, sizeof(buf), WM_FLAGS, sc->sc_flags);
-	aprint_verbose_dev(sc->sc_dev, "%s\n", buf);
+	if (sc->sc_flags != 0) {
+		snprintb(buf, sizeof(buf), WM_FLAGS, sc->sc_flags);
+		aprint_verbose_dev(sc->sc_dev, "%s\n", buf);
+	}
 
 	/* Set device properties (macflags) */
 	prop_dictionary_set_uint32(dict, "macflags", sc->sc_flags);
@@ -2948,6 +3038,10 @@ alloc_retry:
 	    NULL, xname, "rx_macctl");
 #endif /* WM_EVENT_COUNTERS */
 
+	sc->sc_txrx_use_workqueue = false;
+
+	wm_init_sysctls(sc);
+
 	if (pmf_device_register(self, wm_suspend, wm_resume))
 		pmf_class_network_register(self, ifp);
 	else
@@ -2974,6 +3068,8 @@ wm_detach(device_t self, int flags __unu
 
 	pmf_device_deregister(self);
 
+	sysctl_teardown(&sc->sc_sysctllog);
+
 #ifdef WM_EVENT_COUNTERS
 	evcnt_detach(&sc->sc_ev_linkintr);
 
@@ -3018,6 +3114,9 @@ wm_detach(device_t self, int flags __unu
 	}
 	pci_intr_release(sc->sc_pc, sc->sc_intrs, sc->sc_nintrs);
 
+	/* wm_stop() ensure workqueue is stopped. */
+	workqueue_destroy(sc->sc_queue_wq);
+
 	for (i = 0; i < sc->sc_nqueues; i++)
 		softint_disestablish(sc->sc_queue[i].wmq_si);
 
@@ -4153,7 +4252,7 @@ wm_init_lcd_from_nvm(struct wm_softc *sc
 		if (wm_nvm_read(sc, (word_addr + i * 2 + 1), 1, &reg_addr) !=0)
 			goto release;
 
-		if (reg_addr == MII_IGPHY_PAGE_SELECT)
+		if (reg_addr == IGPHY_PAGE_SELECT)
 			phy_page = reg_data;
 
 		reg_addr &= IGPHY_MAXREGADDR;
@@ -5175,8 +5274,11 @@ wm_init_rss(struct wm_softc *sc)
 	 */
 	mrqc |= (MRQC_RSS_FIELD_IPV4 | MRQC_RSS_FIELD_IPV4_TCP);
 	mrqc |= (MRQC_RSS_FIELD_IPV6 | MRQC_RSS_FIELD_IPV6_TCP);
+#if 0
 	mrqc |= (MRQC_RSS_FIELD_IPV4_UDP | MRQC_RSS_FIELD_IPV6_UDP);
-	mrqc |= (MRQC_RSS_FIELD_IPV6_UDP_EX | MRQC_RSS_FIELD_IPV6_TCP_EX);
+	mrqc |= MRQC_RSS_FIELD_IPV6_UDP_EX;
+#endif
+	mrqc |= MRQC_RSS_FIELD_IPV6_TCP_EX;
 
 	CSR_WRITE(sc, WMREG_MRQC, mrqc);
 }
@@ -5281,22 +5383,19 @@ wm_is_using_multiqueue(struct wm_softc *
 }
 
 static int
-wm_softint_establish(struct wm_softc *sc, int qidx, int intr_idx)
+wm_softint_establish_queue(struct wm_softc *sc, int qidx, int intr_idx)
 {
 	struct wm_queue *wmq = &sc->sc_queue[qidx];
+
 	wmq->wmq_id = qidx;
 	wmq->wmq_intr_idx = intr_idx;
-	wmq->wmq_si = softint_establish(SOFTINT_NET
-#ifdef WM_MPSAFE
-	    | SOFTINT_MPSAFE
-#endif
-	    , wm_handle_queue, wmq);
+	wmq->wmq_si = softint_establish(SOFTINT_NET | WM_SOFTINT_FLAGS,
+	    wm_handle_queue, wmq);
 	if (wmq->wmq_si != NULL)
 		return 0;
 
 	aprint_error_dev(sc->sc_dev, "unable to establish queue[%d] handler\n",
 	    wmq->wmq_id);
-
 	pci_intr_disestablish(sc->sc_pc, sc->sc_ihs[wmq->wmq_intr_idx]);
 	sc->sc_ihs[wmq->wmq_intr_idx] = NULL;
 	return ENOMEM;
@@ -5336,7 +5435,7 @@ wm_setup_legacy(struct wm_softc *sc)
 	aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr);
 	sc->sc_nintrs = 1;
 
-	return wm_softint_establish(sc, 0, 0);
+	return wm_softint_establish_queue(sc, 0, 0);
 }
 
 static int
@@ -5414,7 +5513,7 @@ wm_setup_msix(struct wm_softc *sc)
 			    "for TX and RX interrupting at %s\n", intrstr);
 		}
 		sc->sc_ihs[intr_idx] = vih;
-		if (wm_softint_establish(sc, qidx, intr_idx) != 0)
+		if (wm_softint_establish_queue(sc, qidx, intr_idx) != 0)
 			goto fail;
 		txrx_established++;
 		intr_idx++;
@@ -5608,6 +5707,40 @@ out:
 #endif
 }
 
+static void
+wm_init_sysctls(struct wm_softc *sc)
+{
+	struct sysctllog **log;
+	const struct sysctlnode *rnode, *cnode;
+	int rv;
+	const char *dvname;
+
+	log = &sc->sc_sysctllog;
+	dvname = device_xname(sc->sc_dev);
+
+	rv = sysctl_createv(log, 0, NULL, &rnode,
+	    0, CTLTYPE_NODE, dvname,
+	    SYSCTL_DESCR("wm information and settings"),
+	    NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL);
+	if (rv != 0)
+		goto err;
+
+	rv = sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE,
+	    CTLTYPE_BOOL, "txrx_workqueue", SYSCTL_DESCR("Use workqueue for packet processing"),
+	    NULL, 0, &sc->sc_txrx_use_workqueue, 0, CTL_CREATE, CTL_EOL);
+	if (rv != 0)
+		goto teardown;
+
+	return;
+
+teardown:
+	sysctl_teardown(log);
+err:
+	sc->sc_sysctllog = NULL;
+	device_printf(sc->sc_dev, "%s: sysctl_createv failed, rv = %d\n",
+	    __func__, rv);
+}
+
 /*
  * wm_init:		[ifnet interface function]
  *
@@ -5631,7 +5764,7 @@ wm_init_locked(struct ifnet *ifp)
 {
 	struct wm_softc *sc = ifp->if_softc;
 	int i, j, trynum, error = 0;
-	uint32_t reg;
+	uint32_t reg, sfp_mask = 0;
 
 	DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
 		device_xname(sc->sc_dev), __func__));
@@ -5701,6 +5834,7 @@ wm_init_locked(struct ifnet *ifp)
 			reg &= ~GCR_NO_SNOOP_ALL;
 		CSR_WRITE(sc, WMREG_GCR, reg);
 	}
+
 	if ((sc->sc_type >= WM_T_ICH8)
 	    || (sc->sc_pcidevid == PCI_PRODUCT_INTEL_82546GB_QUAD_COPPER)
 	    || (sc->sc_pcidevid == PCI_PRODUCT_INTEL_82546GB_QUAD_COPPER_KSP3)) {
@@ -5750,6 +5884,11 @@ wm_init_locked(struct ifnet *ifp)
 	if (error)
 		goto out;
 
+	if (((sc->sc_flags & WM_F_SGMII) == 0) &&
+	    (sc->sc_mediatype == WM_MEDIATYPE_SERDES) &&
+	    (sc->sc_type >= WM_T_82575))
+		wm_serdes_power_up_link_82575(sc);
+
 	/* Clear out the VLAN table -- we don't use it (yet). */
 	CSR_WRITE(sc, WMREG_VET, 0);
 	if ((sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I354))
@@ -5983,6 +6122,13 @@ wm_init_locked(struct ifnet *ifp)
 	/* Set up the interrupt registers. */
 	CSR_WRITE(sc, WMREG_IMC, 0xffffffffU);
 
+	/* Enable SFP module insertion interrupt if it's required */
+	if ((sc->sc_flags & WM_F_SFP) != 0) {
+		sc->sc_ctrl |= CTRL_EXTLINK_EN;
+		CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
+		sfp_mask = ICR_GPI(0);
+	}
+
 	if (wm_is_using_msix(sc)) {
 		uint32_t mask;
 		struct wm_queue *wmq;
@@ -6019,12 +6165,14 @@ wm_init_locked(struct ifnet *ifp)
 			CSR_WRITE(sc, WMREG_EIAC, mask);
 			CSR_WRITE(sc, WMREG_EIAM, mask);
 			CSR_WRITE(sc, WMREG_EIMS, mask);
-			CSR_WRITE(sc, WMREG_IMS, ICR_LSC);
+
+			/* For other interrupts */
+			CSR_WRITE(sc, WMREG_IMS, ICR_LSC | sfp_mask);
 			break;
 		}
 	} else {
 		sc->sc_icr = ICR_TXDW | ICR_LSC | ICR_RXSEQ | ICR_RXDMT0 |
-		    ICR_RXO | ICR_RXT0;
+		    ICR_RXO | ICR_RXT0 | sfp_mask;
 		CSR_WRITE(sc, WMREG_IMS, sc->sc_icr);
 	}
 
@@ -6205,6 +6353,16 @@ wm_stop(struct ifnet *ifp, int disable)
 	WM_CORE_LOCK(sc);
 	wm_stop_locked(ifp, disable);
 	WM_CORE_UNLOCK(sc);
+
+	/*
+	 * After wm_set_stopping_flags(), it is guaranteed
+	 * wm_handle_queue_work() does not call workqueue_enqueue().
+	 * However, workqueue_wait() cannot call in wm_stop_locked()
+	 * because it can sleep...
+	 * so, call workqueue_wait() here.
+	 */
+	for (int i = 0; i < sc->sc_nqueues; i++)
+		workqueue_wait(sc->sc_queue_wq, &sc->sc_queue[i].wmq_cookie);
 }
 
 static void
@@ -6720,6 +6878,7 @@ wm_alloc_txrx_queues(struct wm_softc *sc
 		WM_Q_MISC_EVCNT_ATTACH(txq, toomanyseg, txq, i, xname);
 		WM_Q_MISC_EVCNT_ATTACH(txq, defrag, txq, i, xname);
 		WM_Q_MISC_EVCNT_ATTACH(txq, underrun, txq, i, xname);
+		WM_Q_MISC_EVCNT_ATTACH(txq, skipcontext, txq, i, xname);
 #endif /* WM_EVENT_COUNTERS */
 
 		tx_done++;
@@ -6852,6 +7011,7 @@ wm_free_txrx_queues(struct wm_softc *sc)
 		WM_Q_EVCNT_DETACH(txq, toomanyseg, txq, i);
 		WM_Q_EVCNT_DETACH(txq, defrag, txq, i);
 		WM_Q_EVCNT_DETACH(txq, underrun, txq, i);
+		WM_Q_EVCNT_DETACH(txq, skipcontext, txq, i);
 #endif /* WM_EVENT_COUNTERS */
 
 		/* Drain txq_interq */
@@ -7137,7 +7297,7 @@ wm_init_txrx_queues(struct wm_softc *sc)
  *	Set up TCP/IP checksumming parameters for the
  *	specified packet.
  */
-static int
+static void
 wm_tx_offload(struct wm_softc *sc, struct wm_txqueue *txq,
     struct wm_txsoft *txs, uint32_t *cmdp, uint8_t *fieldsp)
 {
@@ -7167,9 +7327,12 @@ wm_tx_offload(struct wm_softc *sc, struc
 
 	default:
 		/* Don't support this protocol or encapsulation. */
+ 		txq->txq_last_hw_cmd = txq->txq_last_hw_fields = 0;
+ 		txq->txq_last_hw_ipcs = 0;
+ 		txq->txq_last_hw_tucs = 0;
 		*fieldsp = 0;
 		*cmdp = 0;
-		return 0;
+		return;
 	}
 
 	if ((m0->m_pkthdr.csum_flags &
@@ -7306,13 +7469,51 @@ wm_tx_offload(struct wm_softc *sc, struc
 		    WTX_TCPIP_TUCSE(0) /* Rest of packet */;
 	}
 
+	*cmdp = cmd;
+	*fieldsp = fields;
+
 	/*
 	 * We don't have to write context descriptor for every packet
 	 * except for 82574. For 82574, we must write context descriptor
 	 * for every packet when we use two descriptor queues.
-	 * It would be overhead to write context descriptor for every packet,
-	 * however it does not cause problems.
-	 */
+	 *
+	 * The 82574L can only remember the *last* context used
+	 * regardless of queue that it was use for.  We cannot reuse
+	 * contexts on this hardware platform and must generate a new
+	 * context every time.  82574L hardware spec, section 7.2.6,
+	 * second note.
+	 */
+	if (sc->sc_nqueues < 2) {
+		/*
+	 	 *
+	  	 * Setting up new checksum offload context for every
+		 * frames takes a lot of processing time for hardware.
+		 * This also reduces performance a lot for small sized
+		 * frames so avoid it if driver can use previously
+		 * configured checksum offload context.
+		 * For TSO, in theory we can use the same TSO context only if
+		 * frame is the same type(IP/TCP) and the same MSS. However
+		 * checking whether a frame has the same IP/TCP structure is
+		 * hard thing so just ignore that and always restablish a
+		 * new TSO context.
+	  	 */
+		if ((m0->m_pkthdr.csum_flags & (M_CSUM_TSOv4 | M_CSUM_TSOv6))
+		    == 0) {
+			if (txq->txq_last_hw_cmd == cmd &&
+			    txq->txq_last_hw_fields == fields &&
+			    txq->txq_last_hw_ipcs == (ipcs & 0xffff) &&
+			    txq->txq_last_hw_tucs == (tucs & 0xffff)) {
+				WM_Q_EVCNT_INCR(txq, skipcontext);
+				return;
+			}
+		}
+
+	 	txq->txq_last_hw_cmd = cmd;
+ 		txq->txq_last_hw_fields = fields;
+ 		txq->txq_last_hw_ipcs = (ipcs & 0xffff);
+		txq->txq_last_hw_tucs = (tucs & 0xffff);
+	}
+
 	/* Fill in the context descriptor. */
 	t = (struct livengood_tcpip_ctxdesc *)
 	    &txq->txq_descs[txq->txq_next];
@@ -7324,11 +7525,6 @@ wm_tx_offload(struct wm_softc *sc, struc
 
 	txq->txq_next = WM_NEXTTX(txq, txq->txq_next);
 	txs->txs_ndesc++;
-
-	*cmdp = cmd;
-	*fieldsp = fields;
-
-	return 0;
 }
 
 static inline int
@@ -7610,13 +7806,10 @@ retry:
 		    (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, txq, txs, &cksumcmd,
-					  &cksumfields) != 0) {
-				/* Error message already displayed. */
-				bus_dmamap_unload(sc->sc_dmat, dmamap);
-				continue;
-			}
+			wm_tx_offload(sc, txq, txs, &cksumcmd, &cksumfields);
 		} else {
+ 			txq->txq_last_hw_cmd = txq->txq_last_hw_fields = 0;
+ 			txq->txq_last_hw_ipcs = txq->txq_last_hw_tucs = 0;
 			cksumcmd = 0;
 			cksumfields = 0;
 		}
@@ -7751,7 +7944,7 @@ retry:
  *	Set up TCP/IP checksumming parameters for the
  *	specified packet, for NEWQUEUE devices
  */
-static int
+static void
 wm_nq_tx_offload(struct wm_softc *sc, struct wm_txqueue *txq,
     struct wm_txsoft *txs, uint32_t *cmdlenp, uint32_t *fieldsp, bool *do_csum)
 {
@@ -7781,7 +7974,7 @@ wm_nq_tx_offload(struct wm_softc *sc, st
 	default:
 		/* Don't support this protocol or encapsulation. */
 		*do_csum = false;
-		return 0;
+		return;
 	}
 	*do_csum = true;
 	*cmdlenp = NQTX_DTYP_D | NQTX_CMD_DEXT | NQTX_CMD_IFCS;
@@ -7947,7 +8140,6 @@ wm_nq_tx_offload(struct wm_softc *sc, st
 	DPRINTF(WM_DEBUG_TX, ("\t0x%08x%08x\n", mssidx, cmdc));
 	txq->txq_next = WM_NEXTTX(txq, txq->txq_next);
 	txs->txs_ndesc++;
-	return 0;
 }
 
 /*
@@ -8184,12 +8376,8 @@ retry:
 		    (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, txq, txs, &cmdlen, &fields,
-			    &do_csum) != 0) {
-				/* Error message already displayed. */
-				bus_dmamap_unload(sc->sc_dmat, dmamap);
-				continue;
-			}
+			wm_nq_tx_offload(sc, txq, txs, &cmdlen, &fields,
+			    &do_csum);
 		} else {
 			do_csum = false;
 			cmdlen = 0;
@@ -8225,7 +8413,7 @@ retry:
 			    htole64(dmamap->dm_segs[0].ds_addr);
 			KASSERT((dmamap->dm_segs[0].ds_len & cmdlen) == 0);
 			txq->txq_nq_descs[nexttx].nqtx_data.nqtxd_cmdlen =
-			    htole32(dmamap->dm_segs[0].ds_len | cmdlen );
+			    htole32(dmamap->dm_segs[0].ds_len | cmdlen);
 			txq->txq_nq_descs[nexttx].nqtx_data.nqtxd_fields =
 			    htole32(fields);
 			DPRINTF(WM_DEBUG_TX,
@@ -9186,6 +9374,17 @@ wm_linkintr(struct wm_softc *sc, uint32_
 		wm_linkintr_tbi(sc, icr);
 }
 
+
+static inline void
+wm_sched_handle_queue(struct wm_softc *sc, struct wm_queue *wmq)
+{
+
+	if (wmq->wmq_txrx_use_workqueue)
+		workqueue_enqueue(sc->sc_queue_wq, &wmq->wmq_cookie, curcpu());
+	else
+		softint_schedule(wmq->wmq_si);
+}
+
 /*
  * wm_intr_legacy:
  *
@@ -9270,6 +9469,8 @@ wm_intr_legacy(void *arg)
 			WM_EVCNT_INCR(&sc->sc_ev_linkintr);
 			wm_linkintr(sc, icr);
 		}
+		if ((icr & ICR_GPI(0)) != 0)
+			device_printf(sc->sc_dev, "got module interrupt\n");
 
 		WM_CORE_UNLOCK(sc);
 
@@ -9285,7 +9486,8 @@ wm_intr_legacy(void *arg)
 
 	if (handled) {
 		/* Try to get more packets going. */
-		softint_schedule(wmq->wmq_si);
+		wmq->wmq_txrx_use_workqueue = sc->sc_txrx_use_workqueue;
+		wm_sched_handle_queue(sc, wmq);
 	}
 
 	return handled;
@@ -9388,9 +9590,10 @@ wm_txrxintr_msix(void *arg)
 	if (rndval != 0)
 		rnd_add_uint32(&sc->sc_queue[wmq->wmq_id].rnd_source, rndval);
 
-	if (txmore || rxmore)
-		softint_schedule(wmq->wmq_si);
-	else
+	if (txmore || rxmore) {
+		wmq->wmq_txrx_use_workqueue = sc->sc_txrx_use_workqueue;
+		wm_sched_handle_queue(sc, wmq);
+	} else
 		wm_txrxintr_enable(wmq);
 
 	return 1;
@@ -9426,12 +9629,24 @@ wm_handle_queue(void *arg)
 	rxmore = wm_rxeof(rxq, rxlimit);
 	mutex_exit(rxq->rxq_lock);
 
-	if (txmore || rxmore)
-		softint_schedule(wmq->wmq_si);
-	else
+	if (txmore || rxmore) {
+		wmq->wmq_txrx_use_workqueue = sc->sc_txrx_use_workqueue;
+		wm_sched_handle_queue(sc, wmq);
+	} else
 		wm_txrxintr_enable(wmq);
 }
 
+static void
+wm_handle_queue_work(struct work *wk, void *context)
+{
+	struct wm_queue *wmq = container_of(wk, struct wm_queue, wmq_cookie);
+
+	/*
+	 * "enqueued flag" is not required here.
+	 */
+	wm_handle_queue(wmq);
+}
+
 /*
  * wm_linkintr_msix:
  *
@@ -9457,6 +9672,8 @@ wm_linkintr_msix(void *arg)
 		WM_EVCNT_INCR(&sc->sc_ev_linkintr);
 		wm_linkintr(sc, ICR_LSC);
 	}
+	if ((reg & ICR_GPI(0)) != 0)
+		device_printf(sc->sc_dev, "got module interrupt\n");
 
 	/*
 	 * XXX 82574 MSI-X mode workaround
@@ -9728,10 +9945,18 @@ wm_gmii_setup_phytype(struct wm_softc *s
 	uint16_t doubt_phytype = WMPHY_UNKNOWN;
 	mii_readreg_t new_readreg;
 	mii_writereg_t new_writereg;
+	bool dodiag = true;
 
 	DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
 		device_xname(sc->sc_dev), __func__));
 
+	/*
+	 * 1000BASE-T SFP uses SGMII and the first asumed PHY type is always
+	 * incorrect. So don't print diag output when it's 2nd call.
+	 */
+	if ((sc->sc_sfptype != 0) && (phy_oui == 0) && (phy_model == 0))
+		dodiag = false;
+
 	if (mii->mii_readreg == NULL) {
 		/*
 		 *  This is the first call of this function. For ICH and PCH
@@ -9848,16 +10073,20 @@ wm_gmii_setup_phytype(struct wm_softc *s
 		default:
 			break;
 		}
-		if (new_phytype == WMPHY_UNKNOWN)
-			aprint_verbose_dev(dev,
-			    "%s: unknown PHY model. OUI=%06x, model=%04x\n",
-			    __func__, phy_oui, phy_model);
 
-		if ((sc->sc_phytype != WMPHY_UNKNOWN)
-		    && (sc->sc_phytype != new_phytype )) {
-			aprint_error_dev(dev, "Previously assumed PHY type(%u)"
-			    "was incorrect. PHY type from PHY ID = %u\n",
-			    sc->sc_phytype, new_phytype);
+		if (dodiag) {
+			if (new_phytype == WMPHY_UNKNOWN)
+				aprint_verbose_dev(dev,
+				    "%s: Unknown PHY model. OUI=%06x, "
+				    "model=%04x\n", __func__, phy_oui,
+				    phy_model);
+
+			if ((sc->sc_phytype != WMPHY_UNKNOWN)
+			    && (sc->sc_phytype != new_phytype)) {
+				aprint_error_dev(dev, "Previously assumed PHY "
+				    "type(%u) was incorrect. PHY type from PHY"
+				    "ID = %u\n", sc->sc_phytype, new_phytype);
+			}
 		}
 	}
 
@@ -9926,22 +10155,26 @@ wm_gmii_setup_phytype(struct wm_softc *s
 	}
 
 	/* Diag output */
-	if (doubt_phytype != WMPHY_UNKNOWN)
-		aprint_error_dev(dev, "Assumed new PHY type was "
-		    "incorrect. old = %u, new = %u\n", sc->sc_phytype,
-		    new_phytype);
-	else if ((sc->sc_phytype != WMPHY_UNKNOWN)
-	    && (sc->sc_phytype != new_phytype ))
-		aprint_error_dev(dev, "Previously assumed PHY type(%u)"
-		    "was incorrect. New PHY type = %u\n",
-		    sc->sc_phytype, new_phytype);
-
-	if ((mii->mii_readreg != NULL) && (new_phytype == WMPHY_UNKNOWN))
-		aprint_error_dev(dev, "PHY type is still unknown.\n");
-
-	if ((mii->mii_readreg != NULL) && (mii->mii_readreg != new_readreg))
-		aprint_error_dev(dev, "Previously assumed PHY read/write "
-		    "function was incorrect.\n");
+	if (dodiag) {
+		if (doubt_phytype != WMPHY_UNKNOWN)
+			aprint_error_dev(dev, "Assumed new PHY type was "
+			    "incorrect. old = %u, new = %u\n", sc->sc_phytype,
+			    new_phytype);
+		else if ((sc->sc_phytype != WMPHY_UNKNOWN)
+		    && (sc->sc_phytype != new_phytype))
+			aprint_error_dev(dev, "Previously assumed PHY type(%u)"
+			    "was incorrect. New PHY type = %u\n",
+			    sc->sc_phytype, new_phytype);
+
+		if ((mii->mii_readreg != NULL) &&
+		    (new_phytype == WMPHY_UNKNOWN))
+			aprint_error_dev(dev, "PHY type is still unknown.\n");
+
+		if ((mii->mii_readreg != NULL) &&
+		    (mii->mii_readreg != new_readreg))
+			aprint_error_dev(dev, "Previously assumed PHY "
+			    "read/write function was incorrect.\n");
+	}
 
 	/* Update now */
 	sc->sc_phytype = new_phytype;
@@ -9994,7 +10227,6 @@ wm_get_phy_id_82575(struct wm_softc *sc)
 	return phyid;
 }
 
-
 /*
  * wm_gmii_mediainit:
  *
@@ -10006,7 +10238,6 @@ wm_gmii_mediainit(struct wm_softc *sc, p
 	device_t dev = sc->sc_dev;
 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
 	struct mii_data *mii = &sc->sc_mii;
-	uint32_t reg;
 
 	DPRINTF(WM_DEBUG_GMII, ("%s: %s called\n",
 		device_xname(sc->sc_dev), __func__));
@@ -10019,15 +10250,6 @@ wm_gmii_mediainit(struct wm_softc *sc, p
 	else
 		sc->sc_tipg = TIPG_1000T_DFLT;
 
-	/* XXX Not for I354? FreeBSD's e1000_82575.c doesn't include it */
-	if ((sc->sc_type == WM_T_82580)
-	    || (sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I210)
-	    || (sc->sc_type == WM_T_I211)) {
-		reg = CSR_READ(sc, WMREG_PHPM);
-		reg &= ~PHPM_GO_LINK_D;
-		CSR_WRITE(sc, WMREG_PHPM, reg);
-	}
-
 	/*
 	 * Let the chip set speed/duplex on its own based on
 	 * signals from the PHY.
@@ -10054,6 +10276,9 @@ wm_gmii_mediainit(struct wm_softc *sc, p
 	ifmedia_init(&mii->mii_media, IFM_IMASK, wm_gmii_mediachange,
 	    wm_gmii_mediastatus);
 
+	/* Setup internal SGMII PHY for SFP */
+	wm_sgmii_sfp_preconfig(sc);
+
 	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)
@@ -10080,11 +10305,19 @@ wm_gmii_mediainit(struct wm_softc *sc, p
 				CSR_WRITE_FLUSH(sc);
 				delay(300*1000); /* XXX too long */
 
-				/* From 1 to 8 */
+				/*
+				 * From 1 to 8.
+				 *
+				 * I2C access fails with I2C register's ERROR
+				 * bit set, so prevent error message while
+				 * scanning.
+				 */
+				sc->phy.no_errprint = true;
 				for (i = 1; i < 8; i++)
 					mii_attach(sc->sc_dev, &sc->sc_mii,
 					    0xffffffff, i, MII_OFFSET_ANY,
 					    MIIF_DOPAUSE);
+				sc->phy.no_errprint = false;
 
 				/* Restore previous sfp cage power state */
 				CSR_WRITE(sc, WMREG_CTRL_EXT, ctrl_ext);
@@ -10153,6 +10386,7 @@ wm_gmii_mediachange(struct ifnet *ifp)
 {
 	struct wm_softc *sc = ifp->if_softc;
 	struct ifmedia_entry *ife = sc->sc_mii.mii_media.ifm_cur;
+	uint32_t reg;
 	int rc;
 
 	DPRINTF(WM_DEBUG_GMII, ("%s: %s called\n",
@@ -10160,6 +10394,15 @@ wm_gmii_mediachange(struct ifnet *ifp)
 	if ((ifp->if_flags & IFF_UP) == 0)
 		return 0;
 
+	/* XXX Not for I354? FreeBSD's e1000_82575.c doesn't include it */
+	if ((sc->sc_type == WM_T_82580)
+	    || (sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I210)
+	    || (sc->sc_type == WM_T_I211)) {
+		reg = CSR_READ(sc, WMREG_PHPM);
+		reg &= ~PHPM_GO_LINK_D;
+		CSR_WRITE(sc, WMREG_PHPM, reg);
+	}
+
 	/* Disable D0 LPLU. */
 	wm_lplu_d0_disable(sc);
 
@@ -10193,8 +10436,18 @@ wm_gmii_mediachange(struct ifnet *ifp)
 	}
 	CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
 	CSR_WRITE_FLUSH(sc);
+
+	if ((sc->sc_type >= WM_T_82575) && (sc->sc_type <= WM_T_I211))
+		wm_serdes_mediachange(ifp);
+
 	if (sc->sc_type <= WM_T_82543)
 		wm_gmii_reset(sc);
+	else if ((sc->sc_type >= WM_T_82575) && (sc->sc_type <= WM_T_I211)
+	    && ((sc->sc_flags & WM_F_SGMII) != 0)) {
+		/* allow time for SFP cage time to power up phy */
+		delay(300 * 1000);
+		wm_gmii_reset(sc);
+	}
 
 	if ((rc = mii_mediachg(&sc->sc_mii)) == ENXIO)
 		return 0;
@@ -10464,7 +10717,7 @@ wm_gmii_i82544_readreg_locked(device_t d
 		case WMPHY_IGP:
 		case WMPHY_IGP_2:
 		case WMPHY_IGP_3:
-			wm_gmii_mdic_writereg(dev, phy, MII_IGPHY_PAGE_SELECT,
+			wm_gmii_mdic_writereg(dev, phy, IGPHY_PAGE_SELECT,
 			    reg);
 			break;
 		default:
@@ -10510,7 +10763,7 @@ wm_gmii_i82544_writereg_locked(device_t 
 		case WMPHY_IGP:
 		case WMPHY_IGP_2:
 		case WMPHY_IGP_3:
-			wm_gmii_mdic_writereg(dev, phy, MII_IGPHY_PAGE_SELECT,
+			wm_gmii_mdic_writereg(dev, phy, IGPHY_PAGE_SELECT,
 			    reg);
 			break;
 		default:
@@ -10666,7 +10919,7 @@ wm_gmii_bm_readreg(device_t dev, int phy
 		if ((phy == 1) && (sc->sc_type != WM_T_82574)
 		    && (sc->sc_type != WM_T_82583))
 			wm_gmii_mdic_writereg(dev, phy,
-			    MII_IGPHY_PAGE_SELECT, page << BME1000_PAGE_SHIFT);
+			    IGPHY_PAGE_SELECT, page << BME1000_PAGE_SHIFT);
 		else
 			wm_gmii_mdic_writereg(dev, phy,
 			    BME1000_PHY_PAGE_SELECT, page);
@@ -10713,7 +10966,7 @@ wm_gmii_bm_writereg(device_t dev, int ph
 		if ((phy == 1) && (sc->sc_type != WM_T_82574)
 		    && (sc->sc_type != WM_T_82583))
 			wm_gmii_mdic_writereg(dev, phy,
-			    MII_IGPHY_PAGE_SELECT, page << BME1000_PAGE_SHIFT);
+			    IGPHY_PAGE_SELECT, page << BME1000_PAGE_SHIFT);
 		else
 			wm_gmii_mdic_writereg(dev, phy,
 			    BME1000_PHY_PAGE_SELECT, page);
@@ -10747,7 +11000,7 @@ wm_enable_phy_wakeup_reg_access_bm(devic
 	/* All page select, port ctrl and wakeup registers use phy address 1 */
 
 	/* Select Port Control Registers page */
-	wm_gmii_mdic_writereg(dev, 1, MII_IGPHY_PAGE_SELECT,
+	wm_gmii_mdic_writereg(dev, 1, IGPHY_PAGE_SELECT,
 	    BM_PORT_CTRL_PAGE << IGP3_PAGE_SHIFT);
 
 	/* Read WUCE and save it */
@@ -10765,7 +11018,7 @@ wm_enable_phy_wakeup_reg_access_bm(devic
 	/* Select Host Wakeup Registers page - caller now able to write
 	 * registers on the Wakeup registers page
 	 */
-	wm_gmii_mdic_writereg(dev, 1, MII_IGPHY_PAGE_SELECT,
+	wm_gmii_mdic_writereg(dev, 1, IGPHY_PAGE_SELECT,
 	    BM_WUC_PAGE << IGP3_PAGE_SHIFT);
 
 	return 0;
@@ -10793,7 +11046,7 @@ wm_disable_phy_wakeup_reg_access_bm(devi
 		return -1;
 
 	/* Select Port Control Registers page */
-	wm_gmii_mdic_writereg(dev, 1, MII_IGPHY_PAGE_SELECT,
+	wm_gmii_mdic_writereg(dev, 1, IGPHY_PAGE_SELECT,
 	    BM_PORT_CTRL_PAGE << IGP3_PAGE_SHIFT);
 
 	/* Restore 769.17 to its original value */
@@ -10935,7 +11188,7 @@ wm_gmii_hv_readreg_locked(device_t dev, 
 		page = 0;
 
 	if (regnum > BME1000_MAX_MULTI_PAGE_REG) {
-		wm_gmii_mdic_writereg(dev, 1, MII_IGPHY_PAGE_SELECT,
+		wm_gmii_mdic_writereg(dev, 1, IGPHY_PAGE_SELECT,
 		    page << BME1000_PAGE_SHIFT);
 	}
 
@@ -11020,7 +11273,7 @@ wm_gmii_hv_writereg_locked(device_t dev,
 		}
 
 		if (regnum > BME1000_MAX_MULTI_PAGE_REG) {
-			wm_gmii_mdic_writereg(dev, 1, MII_IGPHY_PAGE_SELECT,
+			wm_gmii_mdic_writereg(dev, 1, IGPHY_PAGE_SELECT,
 			    page << BME1000_PAGE_SHIFT);
 		}
 	}
@@ -11337,6 +11590,38 @@ wm_sgmii_uses_mdio(struct wm_softc *sc)
 	return ismdio;
 }
 
+/* Setup internal SGMII PHY for SFP */
+static void
+wm_sgmii_sfp_preconfig(struct wm_softc *sc)
+{
+	uint16_t id1, id2, phyreg;
+	int i, rv;
+
+	if (((sc->sc_flags & WM_F_SGMII) == 0)
+	    || ((sc->sc_flags & WM_F_SFP) == 0))
+		return;
+
+	for (i = 0; i < MII_NPHY; i++) {
+		sc->phy.no_errprint = true;
+		rv = sc->phy.readreg_locked(sc->sc_dev, i, MII_PHYIDR1, &id1);
+		if (rv != 0)
+			continue;
+		rv = sc->phy.readreg_locked(sc->sc_dev, i, MII_PHYIDR2, &id2);
+		if (rv != 0)
+			continue;
+		if (MII_OUI(id1, id2) != MII_OUI_xxMARVELL)
+			continue;
+		sc->phy.no_errprint = false;
+
+		sc->phy.readreg_locked(sc->sc_dev, i, MAKPHY_ESSR, &phyreg);
+		phyreg &= ~(ESSR_SER_ANEG_BYPASS | ESSR_HWCFG_MODE);
+		phyreg |= ESSR_SGMII_WOC_COPPER;
+		sc->phy.writereg_locked(sc->sc_dev, i, MAKPHY_ESSR, phyreg);
+		break;
+	}
+
+}
+
 /*
  * wm_sgmii_readreg:	[mii interface function]
  *
@@ -11349,7 +11634,7 @@ wm_sgmii_readreg(device_t dev, int phy, 
 {
 	struct wm_softc *sc = device_private(dev);
 	uint32_t i2ccmd;
-	int i, rv;
+	int i, rv = 0;
 
 	if (sc->phy.acquire(sc)) {
 		device_printf(dev, "%s: failed to get semaphore\n", __func__);
@@ -11367,13 +11652,20 @@ wm_sgmii_readreg(device_t dev, int phy, 
 		if (i2ccmd & I2CCMD_READY)
 			break;
 	}
-	if ((i2ccmd & I2CCMD_READY) == 0)
+	if ((i2ccmd & I2CCMD_READY) == 0) {
 		device_printf(dev, "I2CCMD Read did not complete\n");
-	if ((i2ccmd & I2CCMD_ERROR) != 0)
-		device_printf(dev, "I2CCMD Error bit set\n");
+		goto out;
+	}
+	if ((i2ccmd & I2CCMD_ERROR) != 0) {
+		if (!sc->phy.no_errprint)
+			device_printf(dev, "%s: I2CCMD Error bit set\n",
+				__func__);
+		goto out;
+	}
 
 	rv = ((i2ccmd >> 8) & 0x00ff) | ((i2ccmd << 8) & 0xff00);
 
+out:
 	sc->phy.release(sc);
 	return rv;
 }
@@ -11413,7 +11705,7 @@ wm_sgmii_writereg(device_t dev, int phy,
 	if ((i2ccmd & I2CCMD_READY) == 0)
 		device_printf(dev, "I2CCMD Write did not complete\n");
 	if ((i2ccmd & I2CCMD_ERROR) != 0)
-		device_printf(dev, "I2CCMD Error bit set\n");
+		device_printf(dev, "%s: I2CCMD Error bit set\n", __func__);
 
 	sc->phy.release(sc);
 }
@@ -11459,6 +11751,7 @@ wm_tbi_mediainit(struct wm_softc *sc)
 	sc->sc_mii.mii_ifp = ifp;
 	sc->sc_ethercom.ec_mii = &sc->sc_mii;
 
+	ifp->if_baudrate = IF_Gbps(1);
 	if (((sc->sc_type >= WM_T_82575) && (sc->sc_type <= WM_T_I211))
 	    && (sc->sc_mediatype == WM_MEDIATYPE_SERDES))
 		ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK,
@@ -11506,6 +11799,31 @@ do {									\
 		/* Only 82545 is LX (XXX except SFP) */
 		ADD("1000baseLX", IFM_1000_LX, ANAR_X_HD);
 		ADD("1000baseLX-FDX", IFM_1000_LX | IFM_FDX, ANAR_X_FD);
+	} else if (sc->sc_sfptype != 0) {
+		/* XXX wm(4) fiber/serdes don't use ifm_data */
+		switch (sc->sc_sfptype) {
+		default:
+		case SFF_SFP_ETH_FLAGS_1000SX:
+			ADD("1000baseSX", IFM_1000_SX, ANAR_X_HD);
+			ADD("1000baseSX-FDX", IFM_1000_SX | IFM_FDX, ANAR_X_FD);
+			break;
+		case SFF_SFP_ETH_FLAGS_1000LX:
+			ADD("1000baseLX", IFM_1000_LX, ANAR_X_HD);
+			ADD("1000baseLX-FDX", IFM_1000_LX | IFM_FDX, ANAR_X_FD);
+			break;
+		case SFF_SFP_ETH_FLAGS_1000CX:
+			ADD("1000baseCX", IFM_1000_CX, ANAR_X_HD);
+			ADD("1000baseCX-FDX", IFM_1000_CX | IFM_FDX, ANAR_X_FD);
+			break;
+		case SFF_SFP_ETH_FLAGS_1000T:
+			ADD("1000baseT", IFM_1000_T, 0);
+			ADD("1000baseT-FDX", IFM_1000_T | IFM_FDX, 0);
+			break;
+		case SFF_SFP_ETH_FLAGS_100FX:
+			ADD("100baseFX", IFM_100_FX, ANAR_TX);
+			ADD("100baseFX-FDX", IFM_100_FX | IFM_FDX, ANAR_TX_FD);
+			break;
+		}
 	} else {
 		ADD("1000baseSX", IFM_1000_SX, ANAR_X_HD);
 		ADD("1000baseSX-FDX", IFM_1000_SX | IFM_FDX, ANAR_X_FD);
@@ -11823,14 +12141,19 @@ wm_serdes_power_up_link_82575(struct wm_
 	    && ((sc->sc_flags & WM_F_SGMII) == 0))
 		return;
 
+	/* Enable PCS to turn on link */
 	reg = CSR_READ(sc, WMREG_PCS_CFG);
 	reg |= PCS_CFG_PCS_EN;
 	CSR_WRITE(sc, WMREG_PCS_CFG, reg);
 
+	/* Power up the laser */
 	reg = CSR_READ(sc, WMREG_CTRL_EXT);
 	reg &= ~CTRL_EXT_SWDPIN(3);
 	CSR_WRITE(sc, WMREG_CTRL_EXT, reg);
+
+	/* Flush the write to verify completion */
 	CSR_WRITE_FLUSH(sc);
+	delay(1000);
 }
 
 static int
@@ -11840,23 +12163,37 @@ wm_serdes_mediachange(struct ifnet *ifp)
 	bool pcs_autoneg = true; /* XXX */
 	uint32_t ctrl_ext, pcs_lctl, reg;
 
+	if ((sc->sc_mediatype != WM_MEDIATYPE_SERDES)
+	    && ((sc->sc_flags & WM_F_SGMII) == 0))
+		return 0;
+
 	/* 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);
+	/* Power on the sfp cage if present */
+	ctrl_ext = CSR_READ(sc, WMREG_CTRL_EXT);
+	ctrl_ext &= ~CTRL_EXT_SWDPIN(3);
+	ctrl_ext |= CTRL_EXT_I2C_ENA;
+	CSR_WRITE(sc, WMREG_CTRL_EXT, ctrl_ext);
 
 	sc->sc_ctrl |= CTRL_SLU;
 
-	if ((sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576))
+	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);
+		reg = CSR_READ(sc, WMREG_CONNSW);
+		reg |= CONNSW_ENRGSRC;
+		CSR_WRITE(sc, WMREG_CONNSW, reg);
+	}
+
 	pcs_lctl = CSR_READ(sc, WMREG_PCS_LCTL);
 	switch (ctrl_ext & CTRL_EXT_LINK_MODE_MASK) {
 	case CTRL_EXT_LINK_MODE_SGMII:
+		/* SGMII mode lets the phy handle forcing speed/duplex */
 		pcs_autoneg = true;
+		/* Autoneg time out should be disabled for SGMII mode */
 		pcs_lctl &= ~PCS_LCTL_AN_TIMEOUT;
 		break;
 	case CTRL_EXT_LINK_MODE_1000KX:
@@ -11870,14 +12207,23 @@ wm_serdes_mediachange(struct ifnet *ifp)
 		}
 		sc->sc_ctrl |= CTRL_SPEED_1000 | CTRL_FRCSPD | CTRL_FD
 		    | CTRL_FRCFDX;
+
+		/* Set speed of 1000/Full if speed/duplex is forced */
 		pcs_lctl |= PCS_LCTL_FSV_1000 | PCS_LCTL_FDV_FULL;
 	}
 	CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
 
+	pcs_lctl &= ~(PCS_LCTL_AN_ENABLE | PCS_LCTL_FLV_LINK_UP |
+	    PCS_LCTL_FSD | PCS_LCTL_FORCE_LINK);
+
 	if (pcs_autoneg) {
+		/* Set PCS register for autoneg */
 		pcs_lctl |= PCS_LCTL_AN_ENABLE | PCS_LCTL_AN_RESTART;
+
+		/* Disable force flow control for autoneg */
 		pcs_lctl &= ~PCS_LCTL_FORCE_FC;
 
+		/* Configure flow control advertisement for autoneg */
 		reg = CSR_READ(sc, WMREG_PCS_ANADV);
 		reg &= ~(TXCW_ASYM_PAUSE | TXCW_SYM_PAUSE);
 		reg |= TXCW_ASYM_PAUSE | TXCW_SYM_PAUSE;
@@ -11887,7 +12233,6 @@ wm_serdes_mediachange(struct ifnet *ifp)
 
 	CSR_WRITE(sc, WMREG_PCS_LCTL, pcs_lctl);
 
-
 	return 0;
 }
 
@@ -11938,6 +12283,7 @@ wm_serdes_mediastatus(struct ifnet *ifp,
 			break;
 		}
 	}
+	ifp->if_baudrate = ifmedia_baudrate(ifmr->ifm_active);
 	if ((reg & PCS_LSTS_FDX) != 0)
 		ifmr->ifm_active |= IFM_FDX;
 	else
@@ -12084,7 +12430,7 @@ wm_sfp_get_media_type(struct wm_softc *s
 		    "Module/Connector soldered to board\n");
 		break;
 	case SFF_SFP_ID_SFP:
-		aprint_normal_dev(sc->sc_dev, "SFP\n");
+		sc->sc_flags |= WM_F_SFP;
 		break;
 	case SFF_SFP_ID_UNKNOWN:
 		goto out;
@@ -12096,6 +12442,7 @@ wm_sfp_get_media_type(struct wm_softc *s
 	if (rv != 0)
 		goto out;
 
+	sc->sc_sfptype = val;
 	if ((val & (SFF_SFP_ETH_FLAGS_1000SX | SFF_SFP_ETH_FLAGS_1000LX)) != 0)
 		mediatype = WM_MEDIATYPE_SERDES;
 	else if ((val & SFF_SFP_ETH_FLAGS_1000T) != 0) {
@@ -12104,6 +12451,10 @@ wm_sfp_get_media_type(struct wm_softc *s
 	} else if ((val & SFF_SFP_ETH_FLAGS_100FX) != 0) {
 		sc->sc_flags |= WM_F_SGMII;
 		mediatype = WM_MEDIATYPE_SERDES;
+	} else {
+		device_printf(sc->sc_dev, "%s: unknown media type? (0x%hhx)\n",
+		    __func__, sc->sc_sfptype);
+		sc->sc_sfptype = 0; /* XXX unknown */
 	}
 
 out:
@@ -13005,6 +13356,13 @@ wm_nvm_read_invm(struct wm_softc *sc, in
 				rv = -1;
 			}
 			break;
+		case NVM_OFF_CFG1: /* == INVM_AUTOLOAD */
+			rv = wm_nvm_read_word_invm(sc, offset, data);
+			if (rv != 0) {
+				*data = INVM_DEFAULT_AL;
+				rv = 0;
+			}
+			break;
 		case NVM_OFF_CFG2:
 			rv = wm_nvm_read_word_invm(sc, offset, data);
 			if (rv != 0) {
@@ -13320,7 +13678,8 @@ printver:
 	}
 
 	if (have_uid && (wm_nvm_read(sc, NVM_OFF_IMAGE_UID0, 1, &uid0) == 0))
-		aprint_verbose(", Image Unique ID %08x", (uid1 << 16) | uid0);
+		aprint_verbose(", Image Unique ID %08x",
+		    ((uint32_t)uid1 << 16) | uid0);
 }
 
 /*
@@ -14757,12 +15116,13 @@ wm_enable_wakeup(struct wm_softc *sc)
 pme:
 	/* Request PME */
 	pmode = pci_conf_read(sc->sc_pc, sc->sc_pcitag, pmreg + PCI_PMCSR);
+	pmode |= PCI_PMCSR_PME_STS; /* in case it's already set (W1C) */
 	if ((rv == 0) && (sc->sc_flags & WM_F_WOL) != 0) {
 		/* For WOL */
-		pmode |= PCI_PMCSR_PME_STS | PCI_PMCSR_PME_EN;
+		pmode |= PCI_PMCSR_PME_EN;
 	} else {
 		/* Disable WOL */
-		pmode &= ~(PCI_PMCSR_PME_STS | PCI_PMCSR_PME_EN);
+		pmode &= ~PCI_PMCSR_PME_EN;
 	}
 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, pmreg + PCI_PMCSR, pmode);
 }
@@ -14846,9 +15206,9 @@ wm_lplu_d0_disable(struct wm_softc *sc)
 	case WM_T_82573:
 	case WM_T_82575:
 	case WM_T_82576:
-		reg = mii->mii_readreg(sc->sc_dev, 1, MII_IGPHY_POWER_MGMT);
+		reg = mii->mii_readreg(sc->sc_dev, 1, IGPHY_POWER_MGMT);
 		reg &= ~PMR_D0_LPLU;
-		mii->mii_writereg(sc->sc_dev, 1, MII_IGPHY_POWER_MGMT, reg);
+		mii->mii_writereg(sc->sc_dev, 1, IGPHY_POWER_MGMT, reg);
 		break;
 	case WM_T_82580:
 	case WM_T_I350:
@@ -15030,7 +15390,7 @@ wm_hv_phy_workarounds_ich8lan(struct wm_
 
 	/* Select page 0 */
 	sc->phy.acquire(sc);
-	wm_gmii_mdic_writereg(sc->sc_dev, 1, MII_IGPHY_PAGE_SELECT, 0);
+	wm_gmii_mdic_writereg(sc->sc_dev, 1, IGPHY_PAGE_SELECT, 0);
 	sc->phy.release(sc);
 
 	/*
@@ -15633,6 +15993,8 @@ wm_platform_pm_pch_lpt(struct wm_softc *
 /*
  * I210 Errata 25 and I211 Errata 10
  * Slow System Clock.
+ *
+ * Note that this function is called on both FLASH and iNVM case on NetBSD.
  */
 static void
 wm_pll_workaround_i210(struct wm_softc *sc)
@@ -15658,8 +16020,13 @@ wm_pll_workaround_i210(struct wm_softc *
 	reg = mdicnfg & ~MDICNFG_DEST;
 	CSR_WRITE(sc, WMREG_MDICNFG, reg);
 
-	if (wm_nvm_read(sc, INVM_AUTOLOAD, 1, &nvmword) != 0)
+	if (wm_nvm_read(sc, INVM_AUTOLOAD, 1, &nvmword) != 0) {
+		/*
+		 * The default value of the Initialization Control Word 1
+		 * is the same on both I210's FLASH_HW and I21[01]'s iNVM.
+		 */
 		nvmword = INVM_DEFAULT_AL;
+	}
 	tmp_nvmword = nvmword | INVM_PLL_WO_VAL;
 
 	for (i = 0; i < WM_MAX_PLL_TRIES; i++) {

Index: src/sys/dev/pci/if_wmreg.h
diff -u src/sys/dev/pci/if_wmreg.h:1.98.6.11 src/sys/dev/pci/if_wmreg.h:1.98.6.12
--- src/sys/dev/pci/if_wmreg.h:1.98.6.11	Fri Jan 24 18:43:35 2020
+++ src/sys/dev/pci/if_wmreg.h	Wed Aug  5 17:22:46 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wmreg.h,v 1.98.6.11 2020/01/24 18:43:35 martin Exp $	*/
+/*	$NetBSD: if_wmreg.h,v 1.98.6.12 2020/08/05 17:22:46 martin Exp $	*/
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -694,7 +694,7 @@ struct livengood_tcpip_ctxdesc {
 #define	ICR_RXT0	(1U << 7)	/* Rx ring 0 timer */
 #define	ICR_MDAC	(1U << 9)	/* MDIO access complete */
 #define	ICR_RXCFG	(1U << 10)	/* Receiving /C/ */
-#define	ICR_GPI(x)	(1U << (x))	/* general purpose interrupts */
+#define	ICR_GPI(x)	__BIT(11+(x))	/* general purpose interrupts */
 #define	ICR_RXQ(x)	__BIT(20+(x))	/* 82574: Rx queue x interrupt x=0,1 */
 #define	ICR_TXQ(x)	__BIT(22+(x))	/* 82574: Tx queue x interrupt x=0,1 */
 #define	ICR_OTHER	__BIT(24)	/* 82574: Other interrupt */
@@ -1474,6 +1474,7 @@ struct livengood_tcpip_ctxdesc {
 #define	NVM_CFG2_MNGM_NCSI	1
 #define	NVM_CFG2_MNGM_PT	2
 
+#define	NVM_COMPAT_MAS_EN(x)		__BIT(x) /* Media Auto Sense Enable */
 #define	NVM_COMPAT_SERDES_FORCE_MODE	__BIT(14) /* Don't use autonego */
 
 #define NVM_FUTURE_INIT_WORD1_VALID_CHECKSUM	0x0040
@@ -1618,7 +1619,8 @@ struct livengood_tcpip_ctxdesc {
 #define SFF_SFP_ETH_FLAGS_1000LX	0x02
 #define SFF_SFP_ETH_FLAGS_1000CX	0x04
 #define SFF_SFP_ETH_FLAGS_1000T		0x08
-#define SFF_SFP_ETH_FLAGS_100FX		0x10
+#define SFF_SFP_ETH_FLAGS_100LX		0x10
+#define SFF_SFP_ETH_FLAGS_100FX		0x20
 
 /* I21[01] PHY related definitions */
 #define GS40G_PAGE_SELECT	0x16

Index: src/sys/dev/pci/if_wmvar.h
diff -u src/sys/dev/pci/if_wmvar.h:1.33.6.5 src/sys/dev/pci/if_wmvar.h:1.33.6.6
--- src/sys/dev/pci/if_wmvar.h:1.33.6.5	Thu Mar  7 17:11:53 2019
+++ src/sys/dev/pci/if_wmvar.h	Wed Aug  5 17:22:46 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wmvar.h,v 1.33.6.5 2019/03/07 17:11:53 martin Exp $	*/
+/*	$NetBSD: if_wmvar.h,v 1.33.6.6 2020/08/05 17:22:46 martin Exp $	*/
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -97,6 +97,8 @@
 #define	WM_F_PCS_DIS_AUTONEGO	0x02000000 /* PCS Disable Autonego */
 #define	WM_F_PLL_WA_I210	0x04000000 /* I21[01] PLL workaround */
 #define	WM_F_WA_I210_CLSEM	0x08000000 /* I21[01] Semaphore workaround */
+#define	WM_F_SFP		0x10000000 /* SFP */
+#define	WM_F_MAS		0x20000000 /* Media Auto Sense */
 
 #define WM_FLAGS "\20" \
 	"\1" "HAS_MII"	"\2" "LOCK_EECD" "\3" "_B02"	"\4" "_B03"	\
@@ -105,7 +107,8 @@
 	"\15" "PCIX"	"\16" "CSA"	"\17" "PCIE"	"\20" "SGMII"	\
 	"\21" "NEWQUEUE" "\22" "ASF_FIRM" "\23" "ARC_SUBSYS" "\24" "AMT" \
 	"\25" "MANAGE"	"\26" "WOL"	"\27" "EEE"	"\30" "ATTACHED" \
-	"\31" "MDIC_WA"	"\32" "PCS_DIS_AUTONEGO" "\33" "PLLWA" "\34" "CLSEMWA"
+	"\31" "MDIC_WA"	"\32" "PCS_DIS_AUTONEGO" "\33" "PLLWA" "\34" "CLSEMWA" \
+	"\35" "SFP"	"\36" "MAS"
 
 /*
  * Variations of Intel gigabit Ethernet controller:

Reply via email to