git: 2723a9c67ce0 - stable/15 - ixgbe: Correct Wake-on-LAN configuration

From: Kevin Bowling <kbowling_at_FreeBSD.org>
Date: Fri, 18 Sep 2026 00:12:15 UTC
The branch stable/15 has been updated by kbowling:

URL: https://cgit.FreeBSD.org/src/commit/?id=2723a9c67ce05de0957da89a3a9e2afec7f3df6b

commit 2723a9c67ce05de0957da89a3a9e2afec7f3df6b
Author:     Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-10 16:01:13 +0000
Commit:     Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-09-18 00:12:04 +0000

    ixgbe: Correct Wake-on-LAN configuration
    
    Wake-on-LAN capability was inferred from NVM bits on every MAC even
    though 82599 support is board and sometimes port specific.  Private
    sysctls formed a second policy interface, and the driver neither
    coordinated the controller wake source with PCI PME nor reliably
    rebuilt address filters erased by the stop-time reset.
    
    Use the standard ifconfig wake capabilities.  Derive support from the
    82599 board and port matrix or the X540-and-newer NVM capability.
    Require D3hot PME support, and use the NVM APME bit only to select the
    initial magic-packet policy after initializing the LAN function number.
    
    Snapshot requested filters before the terminal stop so shared reset and
    PHY code sees the active wake policy.  After reset, restore RAR0, the
    multicast table, receive filtering, and the optical laser before arming
    WUFC, WUC, and PCI PME.  Remove device wake sources before clearing PCI
    PME on detach, resume, and when wake is disabled.  Clear autonomous APM
    so ifconfig remains authoritative.
    
    Treat X550EM low-power-link-up failure as best effort and allow shutdown
    to continue after a wake-programming error.
    
    The 82599, X540, X550, and E610 datasheets document the standard ACPI
    wake filters used here; the E610 ACPI path includes magic-packet wake.
    
    Validated on a dual-port E610.  Both ports completed three direct-D3
    cycles covering wake disabled and magic-packet wake armed.  A system S3
    cycle woke through ix0 with WUS 0x00000002 (magic packet).  Link and
    traffic recovered after each transition.
    
    Note that many add-in cards in this family do not support WoL; LOM and
    OCP cards are more likely.  The E610 as tested does.
    
    Sponsored by:   Dirk-Willem van Gulik from Web Weaving (E610 hardware)
    Sponsored by:   BBOX.io
    
    (cherry picked from commit c004384343bece0b984cfe3520ec077ef2483e1f)
---
 share/man/man4/ix.4    |  20 ++-
 sys/dev/ixgbe/if_ix.c  | 367 ++++++++++++++++++++++++++++---------------------
 sys/dev/ixgbe/if_ixv.c |   7 +-
 sys/dev/ixgbe/ixgbe.h  |   5 +-
 4 files changed, 235 insertions(+), 164 deletions(-)

diff --git a/share/man/man4/ix.4 b/share/man/man4/ix.4
index 9b6fcfe6dfd2..ed3bf4bb4d3e 100644
--- a/share/man/man4/ix.4
+++ b/share/man/man4/ix.4
@@ -29,7 +29,7 @@
 .\"
 .\" * Other names and brands may be claimed as the property of others.
 .\"
-.Dd August 28, 2026
+.Dd September 2, 2026
 .Dt IX 4
 .Os
 .Sh NAME
@@ -73,6 +73,24 @@ The identification LED for each port is controlled through its
 .Pa /dev/led/ix*
 device node.
 .Pp
+On adapters and ports that expose PCI power-management wake, the driver
+supports the
+.Cm wol_magic ,
+.Cm wol_ucast ,
+and
+.Cm wol_mcast
+capabilities shown by
+.Xr ifconfig 8 .
+The NVM APME setting selects whether magic-packet wake is enabled by default
+without hiding wake modes that the hardware and board support.
+Waking the system from an ACPI sleep state also requires enabling the
+corresponding device wake source when it is exposed, for example:
+.Bd -literal -offset indent
+sysctl dev.ix.0.wake=1
+.Ed
+The interface wake capabilities select the controller packet filters; they do
+not enable the ACPI wake source.
+.Pp
 For questions related to hardware requirements,
 refer to the documentation supplied with your Intel 10GbE adapter.
 All hardware requirements listed apply to use with
diff --git a/sys/dev/ixgbe/if_ix.c b/sys/dev/ixgbe/if_ix.c
index 95a11338fb43..2524c5caeb60 100644
--- a/sys/dev/ixgbe/if_ix.c
+++ b/sys/dev/ixgbe/if_ix.c
@@ -223,7 +223,7 @@ static void ixgbe_enable_queue(struct ixgbe_softc *, u32);
 static void ixgbe_disable_queue(struct ixgbe_softc *, u32);
 static void ixgbe_add_device_sysctls(if_ctx_t);
 static int  ixgbe_allocate_pci_resources(if_ctx_t);
-static int  ixgbe_setup_low_power_mode(if_ctx_t);
+static int  ixgbe_setup_low_power_mode(if_ctx_t, bool);
 
 static void ixgbe_config_dmac(struct ixgbe_softc *);
 static void ixgbe_configure_ivars(struct ixgbe_softc *);
@@ -249,7 +249,9 @@ static void ixgbe_update_stats_counters(struct ixgbe_softc *);
 static void ixgbe_config_link(if_ctx_t);
 static void ixgbe_get_slot_info(struct ixgbe_softc *);
 static void ixgbe_fw_mode_timer(void *);
-static void ixgbe_check_wol_support(struct ixgbe_softc *);
+static void ixgbe_configure_wakeup(if_ctx_t);
+static void ixgbe_configure_wakeup_mta(if_ctx_t);
+static void ixgbe_prepare_wakeup(if_ctx_t, bool);
 static void ixgbe_enable_rx_drop(struct ixgbe_softc *);
 static void ixgbe_disable_rx_drop(struct ixgbe_softc *);
 
@@ -284,8 +286,6 @@ static int  ixgbe_sysctl_rdt_handler(SYSCTL_HANDLER_ARGS);
 static int  ixgbe_sysctl_tdt_handler(SYSCTL_HANDLER_ARGS);
 static int  ixgbe_sysctl_tdh_handler(SYSCTL_HANDLER_ARGS);
 static int  ixgbe_sysctl_eee_state(SYSCTL_HANDLER_ARGS);
-static int  ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS);
-static int  ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS);
 static int  ixgbe_sysctl_tso_tcp_flags_mask(SYSCTL_HANDLER_ARGS);
 
 static int  ixgbe_sysctl_debug_dump_set_clusters(SYSCTL_HANDLER_ARGS);
@@ -1167,9 +1167,6 @@ ixgbe_if_attach_pre(if_ctx_t ctx)
 
 	ixgbe_init_device_features(sc);
 
-	/* Enable WoL (if supported) */
-	ixgbe_check_wol_support(sc);
-
 	/* Verify adapter fan is still functional (if applicable) */
 	if (sc->feat_en & IXGBE_FEATURE_FAN_FAIL) {
 		u32 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
@@ -1288,6 +1285,7 @@ ixgbe_if_attach_pre(if_ctx_t ctx)
 	scctx->isc_txrx = &ixgbe_txrx;
 
 	scctx->isc_capabilities = scctx->isc_capenable = IXGBE_CAPS;
+	ixgbe_configure_wakeup(ctx);
 
 	return (0);
 
@@ -1405,33 +1403,93 @@ err:
 } /* ixgbe_if_attach_post */
 
 /************************************************************************
- * ixgbe_check_wol_support
- *
- *   Checks whether the adapter's ports are capable of
- *   Wake On LAN by reading the adapter's NVM.
+ * ixgbe_configure_wakeup
  *
- *   Sets each port's hw->wol_enabled value depending
- *   on the value read here.
+ *   Advertise the wake modes supported by this board and port.  The NVM
+ *   APME setting selects the initial magic-packet policy.
  ************************************************************************/
 static void
-ixgbe_check_wol_support(struct ixgbe_softc *sc)
+ixgbe_configure_wakeup(if_ctx_t ctx)
 {
+	struct ixgbe_softc *sc = iflib_get_softc(ctx);
+	if_softc_ctx_t scctx = iflib_get_softc_ctx(ctx);
 	struct ixgbe_hw *hw = &sc->hw;
+	device_t dev = iflib_get_dev(ctx);
 	u16 dev_caps = 0;
+	u16 subdevice_id;
+	u16 wol_cap;
+	bool apme, supported;
+
+	supported = false;
+	subdevice_id = hw->subsystem_device_id;
+	if (hw->mac.ops.set_lan_id != NULL)
+		hw->mac.ops.set_lan_id(hw);
+
+	/* X540 and newer advertise per-port WoL support in the NVM. */
+	if (hw->mac.type >= ixgbe_mac_X540) {
+		if (ixgbe_get_device_caps(hw, &dev_caps) == IXGBE_SUCCESS) {
+			wol_cap = dev_caps & IXGBE_DEVICE_CAPS_WOL_MASK;
+			if (wol_cap == IXGBE_DEVICE_CAPS_WOL_PORT0_1 ||
+			    (wol_cap == IXGBE_DEVICE_CAPS_WOL_PORT0 &&
+			    hw->bus.func == 0))
+				supported = true;
+		}
+	} else if (hw->mac.type == ixgbe_mac_82599EB) {
+		/* 82599 WoL support is board and, in some cases, port specific. */
+		switch (hw->device_id) {
+		case IXGBE_DEV_ID_82599_SFP:
+			switch (subdevice_id) {
+			case IXGBE_SUBDEV_ID_82599_560FLR:
+			case IXGBE_SUBDEV_ID_82599_LOM_SNAP6:
+			case IXGBE_SUBDEV_ID_82599_SFP_WOL0:
+			case IXGBE_SUBDEV_ID_82599_SFP_2OCP:
+				supported = hw->bus.func == 0;
+				break;
+			case IXGBE_SUBDEV_ID_82599_SP_560FLR:
+			case IXGBE_SUBDEV_ID_82599_SFP:
+			case IXGBE_SUBDEV_ID_82599_RNDC:
+			case IXGBE_SUBDEV_ID_82599_ECNA_DP:
+			case IXGBE_SUBDEV_ID_82599_SFP_1OCP:
+			case IXGBE_SUBDEV_ID_82599_SFP_LOM_OEM1:
+			case IXGBE_SUBDEV_ID_82599_SFP_LOM_OEM2:
+				supported = true;
+				break;
+			default:
+				break;
+			}
+			break;
+		case IXGBE_DEV_ID_82599EN_SFP:
+			supported =
+			    subdevice_id == IXGBE_SUBDEV_ID_82599EN_SFP_OCP1;
+			break;
+		case IXGBE_DEV_ID_82599_COMBO_BACKPLANE:
+			supported =
+			    subdevice_id != IXGBE_SUBDEV_ID_82599_KX4_KR_MEZZ;
+			break;
+		case IXGBE_DEV_ID_82599_KX4:
+			supported = true;
+			break;
+		default:
+			break;
+		}
+	}
+	if (!pci_has_pme(dev, PCI_POWERSTATE_D3_HOT))
+		supported = false;
+	apme = supported &&
+	    (IXGBE_READ_REG(hw, IXGBE_GRC_BY_MAC(hw)) & IXGBE_GRC_APME) != 0;
 
-	/* Find out WoL support for port */
-	sc->wol_support = hw->wol_enabled = 0;
-	ixgbe_get_device_caps(hw, &dev_caps);
-	if ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0_1) ||
-	    ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0) &&
-	     hw->bus.func == 0))
-		sc->wol_support = hw->wol_enabled = 1;
-
-	/* Save initial wake up filter configuration */
-	sc->wufc = IXGBE_READ_REG(hw, IXGBE_WUFC);
+	scctx->isc_capabilities &= ~IFCAP_WOL;
+	scctx->isc_capenable &= ~IFCAP_WOL;
+	if (supported) {
+		scctx->isc_capabilities |= IFCAP_WOL;
+		if (apme)
+			scctx->isc_capenable |= IFCAP_WOL_MAGIC;
+	}
 
-	return;
-} /* ixgbe_check_wol_support */
+	/* hw->wol_enabled describes the policy active in hardware, not support. */
+	hw->wol_enabled = false;
+	sc->wol_filters = 0;
+} /* ixgbe_configure_wakeup */
 
 /************************************************************************
  * ixgbe_setup_interface
@@ -3755,19 +3813,6 @@ ixgbe_add_device_sysctls(if_ctx_t ctx)
 		    sc, 0, ixgbe_sysctl_dmac,
 		    "I", "DMA Coalesce");
 
-	/* for WoL-capable devices */
-	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) {
-		SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "wol_enable",
-		    CTLTYPE_INT | CTLFLAG_RW, sc, 0,
-		    ixgbe_sysctl_wol_enable, "I",
-		    "Enable/Disable Wake on LAN");
-
-		SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "wufc",
-		    CTLTYPE_U32 | CTLFLAG_RW,
-		    sc, 0, ixgbe_sysctl_wufc,
-		    "I", "Enable/Disable Wake Up Filters");
-	}
-
 	/* for X552/X557-AT devices */
 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) {
 		struct sysctl_oid *phy_node;
@@ -3860,7 +3905,7 @@ ixgbe_if_detach(if_ctx_t ctx)
 
 	sc->iov_recovery_stop = true;
 
-	ixgbe_setup_low_power_mode(ctx);
+	ixgbe_setup_low_power_mode(ctx, false);
 
 	/* let hardware know driver is unloading */
 	ctrl_ext = IXGBE_READ_REG(&sc->hw, IXGBE_CTRL_EXT);
@@ -3881,64 +3926,144 @@ ixgbe_if_detach(if_ctx_t ctx)
 	return (0);
 } /* ixgbe_if_detach */
 
+static void
+ixgbe_prepare_wakeup(if_ctx_t ctx, bool arm_wake)
+{
+	struct ixgbe_softc *sc = iflib_get_softc(ctx);
+	struct ixgbe_hw *hw = &sc->hw;
+	if_t ifp = iflib_get_ifp(ctx);
+	int enabled;
+	u32 wufc;
+
+	enabled = arm_wake ?
+	    if_getcapenable(ifp) & if_getcapabilities(ifp) & IFCAP_WOL : 0;
+	wufc = 0;
+	if ((enabled & IFCAP_WOL_MAGIC) != 0)
+		wufc |= IXGBE_WUFC_MAG;
+	if ((enabled & IFCAP_WOL_UCAST) != 0)
+		wufc |= IXGBE_WUFC_EX;
+	if ((enabled & IFCAP_WOL_MCAST) != 0)
+		wufc |= IXGBE_WUFC_MC;
+	sc->wol_filters = wufc;
+	hw->wol_enabled = wufc != 0;
+
+	/* X550EM 10GBASE-T requires PHY reset suppression during the stop. */
+	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T &&
+	    hw->phy.ops.enter_lplu != NULL)
+		hw->phy.reset_disable = true;
+}
+
+static u_int
+ixgbe_wakeup_mta_apply(void *arg, struct sockaddr_dl *sdl, u_int idx __unused)
+{
+	struct ixgbe_hw *hw = arg;
+
+	ixgbe_set_mta(hw, LLADDR(sdl));
+	return (1);
+}
+
+/* Restore multicast hashes needed by directed and multicast-magic wake. */
+static void
+ixgbe_configure_wakeup_mta(if_ctx_t ctx)
+{
+	struct ixgbe_softc *sc = iflib_get_softc(ctx);
+	struct ixgbe_hw *hw = &sc->hw;
+	u_int i, mcnt;
+
+	bzero(hw->mac.mta_shadow, sizeof(hw->mac.mta_shadow));
+	hw->addr_ctrl.mta_in_use = 0;
+	mcnt = if_foreach_llmaddr(iflib_get_ifp(ctx),
+	    ixgbe_wakeup_mta_apply, hw);
+	hw->addr_ctrl.num_mc_addrs = mcnt;
+	for (i = 0; i < hw->mac.mcft_size; i++)
+		IXGBE_WRITE_REG_ARRAY(hw, IXGBE_MTA(0), i,
+		    hw->mac.mta_shadow[i]);
+	IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL,
+	    (hw->addr_ctrl.mta_in_use != 0 ? IXGBE_MCSTCTRL_MFE : 0) |
+	    hw->mac.mc_filter_type);
+}
+
 /************************************************************************
  * ixgbe_setup_low_power_mode - LPLU/WoL preparation
  *
  *   Prepare the adapter/port for LPLU and/or WoL
  ************************************************************************/
 static int
-ixgbe_setup_low_power_mode(if_ctx_t ctx)
+ixgbe_setup_low_power_mode(if_ctx_t ctx, bool arm_wake)
 {
 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
 	struct ixgbe_hw *hw = &sc->hw;
 	device_t dev = iflib_get_dev(ctx);
+	u32 fctrl, grc, wufc;
 	s32 error = 0;
 
-	if (!hw->wol_enabled)
-		ixgbe_set_phy_power(hw, false);
+	/* Snapshot wake policy before the terminal stop clears hardware state. */
+	ixgbe_prepare_wakeup(ctx, arm_wake);
+	wufc = sc->wol_filters;
+	ixgbe_if_stop(ctx);
 
 	/* Limit power management flow to X550EM baseT */
 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T &&
 	    hw->phy.ops.enter_lplu) {
-		/* Turn off support for APM wakeup. (Using ACPI instead) */
-		IXGBE_WRITE_REG(hw, IXGBE_GRC_BY_MAC(hw),
-		    IXGBE_READ_REG(hw, IXGBE_GRC_BY_MAC(hw)) & ~(u32)2);
-
-		/*
-		 * Clear Wake Up Status register to prevent any previous
-		 * wakeup events from waking us up immediately after we
-		 * suspend.
-		 */
-		IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff);
-
-		/*
-		 * Program the Wakeup Filter Control register with user filter
-		 * settings
-		 */
-		IXGBE_WRITE_REG(hw, IXGBE_WUFC, sc->wufc);
-
-		/* Enable wakeups and power management in Wakeup Control */
-		IXGBE_WRITE_REG(hw, IXGBE_WUC,
-		    IXGBE_WUC_WKEN | IXGBE_WUC_PME_EN);
-
-		/* X550EM baseT adapters need a special LPLU flow */
-		hw->phy.reset_disable = true;
-		ixgbe_if_stop(ctx);
+		/* X550EM baseT adapters need a special LPLU flow. */
 		error = hw->phy.ops.enter_lplu(hw);
 		if (error)
 			device_printf(dev, "Error entering LPLU: %d\n",
 			    error);
 		hw->phy.reset_disable = false;
-	} else {
-		/* Just stop for other adapters */
-		ixgbe_if_stop(ctx);
+		error = 0;
 	}
 
 	/* Disable the 82599 link only when actually entering D3. */
 	if (hw->mac.type == ixgbe_mac_82599EB)
 		ixgbe_stop_mac_link_on_d3_82599(hw);
 
-	return error;
+	/*
+	 * Make ifconfig's ACPI policy authoritative.  All supported families,
+	 * including E610, implement the standard filters in WUFC; leaving the
+	 * NVM-selected APM path enabled would permit an unrequested magic wake.
+	 */
+	if (hw->mac.type != ixgbe_mac_82598EB) {
+		grc = IXGBE_READ_REG(hw, IXGBE_GRC_BY_MAC(hw));
+		IXGBE_WRITE_REG(hw, IXGBE_GRC_BY_MAC(hw),
+		    grc & ~IXGBE_GRC_APME);
+	}
+	IXGBE_WRITE_REG(hw, IXGBE_WUFC, 0);
+	IXGBE_WRITE_REG(hw, IXGBE_WUC, 0);
+	IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff);
+	pci_clear_pme(dev);
+	if (wufc != 0) {
+		bcopy(if_getlladdr(iflib_get_ifp(ctx)), hw->mac.addr,
+		    IXGBE_ETH_LENGTH_OF_ADDRESS);
+		error = ixgbe_set_rar(hw, 0, hw->mac.addr, sc->pool,
+		    IXGBE_RAH_AV);
+		if (error != IXGBE_SUCCESS) {
+			device_printf(dev,
+			    "Could not restore unicast wake address: %d\n", error);
+			sc->wol_filters = 0;
+			hw->wol_enabled = false;
+			goto no_wake;
+		}
+
+		/* 82599 SFP+ ports need the laser for an optical wake packet. */
+		ixgbe_enable_tx_laser(hw);
+
+		/* Rebuild address filtering erased by the terminal reset. */
+		ixgbe_configure_wakeup_mta(ctx);
+		fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
+		fctrl |= IXGBE_FCTRL_BAM | IXGBE_FCTRL_MPE;
+		IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
+
+		IXGBE_WRITE_REG(hw, IXGBE_WUFC, wufc);
+		IXGBE_WRITE_REG(hw, IXGBE_WUC,
+		    IXGBE_WUC_WKEN | IXGBE_WUC_PME_EN);
+		pci_enable_pme(dev);
+		return (0);
+	}
+
+no_wake:
+	ixgbe_set_phy_power(hw, false);
+	return (error == IXGBE_SUCCESS ? 0 : EIO);
 } /* ixgbe_setup_low_power_mode */
 
 /************************************************************************
@@ -3951,9 +4076,11 @@ ixgbe_if_shutdown(if_ctx_t ctx)
 
 	INIT_DEBUGOUT("ixgbe_shutdown: begin");
 
-	error = ixgbe_setup_low_power_mode(ctx);
-
-	return (error);
+	error = ixgbe_setup_low_power_mode(ctx, true);
+	if (error != 0)
+		device_printf(iflib_get_dev(ctx),
+		    "Wake configuration failed during shutdown: %d\n", error);
+	return (0);
 } /* ixgbe_if_shutdown */
 
 /************************************************************************
@@ -3968,7 +4095,7 @@ ixgbe_if_suspend(if_ctx_t ctx)
 
 	INIT_DEBUGOUT("ixgbe_suspend: begin");
 
-	error = ixgbe_setup_low_power_mode(ctx);
+	error = ixgbe_setup_low_power_mode(ctx, true);
 
 	return (error);
 } /* ixgbe_if_suspend */
@@ -3993,10 +4120,18 @@ ixgbe_if_resume(if_ctx_t ctx)
 	wus = IXGBE_READ_REG(hw, IXGBE_WUS);
 	if (wus)
 		device_printf(dev, "Woken up by (WUS): %#010x\n",
-		    IXGBE_READ_REG(hw, IXGBE_WUS));
-	IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff);
-	/* And clear WUFC until next low-power transition */
+		    wus);
+	/* Remove every device wake source before clearing PCI PME. */
 	IXGBE_WRITE_REG(hw, IXGBE_WUFC, 0);
+	if (hw->mac.type != ixgbe_mac_82598EB)
+		IXGBE_WRITE_REG(hw, IXGBE_GRC_BY_MAC(hw),
+		    IXGBE_READ_REG(hw, IXGBE_GRC_BY_MAC(hw)) &
+		    ~IXGBE_GRC_APME);
+	IXGBE_WRITE_REG(hw, IXGBE_WUC, 0);
+	IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff);
+	pci_clear_pme(dev);
+	hw->wol_enabled = false;
+	sc->wol_filters = 0;
 
 	/*
 	 * Required after D3->D0 transition;
@@ -5871,82 +6006,6 @@ ixgbe_sysctl_power_state(SYSCTL_HANDLER_ARGS)
 } /* ixgbe_sysctl_power_state */
 #endif
 
-/************************************************************************
- * ixgbe_sysctl_wol_enable
- *
- *   Sysctl to enable/disable the WoL capability,
- *   if supported by the adapter.
- *
- *   Values:
- *     0 - disabled
- *     1 - enabled
- ************************************************************************/
-static int
-ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS)
-{
-	struct ixgbe_softc  *sc = (struct ixgbe_softc *)arg1;
-	struct ixgbe_hw *hw = &sc->hw;
-	int new_wol_enabled;
-	int error = 0;
-
-	new_wol_enabled = hw->wol_enabled;
-	error = sysctl_handle_int(oidp, &new_wol_enabled, 0, req);
-	if ((error) || (req->newptr == NULL))
-		return (error);
-	new_wol_enabled = !!(new_wol_enabled);
-	if (new_wol_enabled == hw->wol_enabled)
-		return (0);
-
-	if (new_wol_enabled > 0 && !sc->wol_support)
-		return (ENODEV);
-	else
-		hw->wol_enabled = new_wol_enabled;
-
-	return (0);
-} /* ixgbe_sysctl_wol_enable */
-
-/************************************************************************
- * ixgbe_sysctl_wufc - Wake Up Filter Control
- *
- *   Sysctl to enable/disable the types of packets that the
- *   adapter will wake up on upon receipt.
- *   Flags:
- *     0x1  - Link Status Change
- *     0x2  - Magic Packet
- *     0x4  - Direct Exact
- *     0x8  - Directed Multicast
- *     0x10 - Broadcast
- *     0x20 - ARP/IPv4 Request Packet
- *     0x40 - Direct IPv4 Packet
- *     0x80 - Direct IPv6 Packet
- *
- *   Settings not listed above will cause the sysctl to return an error.
- ************************************************************************/
-static int
-ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS)
-{
-	struct ixgbe_softc *sc = (struct ixgbe_softc *)arg1;
-	int error = 0;
-	u32 new_wufc;
-
-	new_wufc = sc->wufc;
-
-	error = sysctl_handle_32(oidp, &new_wufc, 0, req);
-	if ((error) || (req->newptr == NULL))
-		return (error);
-	if (new_wufc == sc->wufc)
-		return (0);
-
-	if (new_wufc & 0xffffff00)
-		return (EINVAL);
-
-	new_wufc &= 0xff;
-	new_wufc |= (0xffffff & sc->wufc);
-	sc->wufc = new_wufc;
-
-	return (0);
-} /* ixgbe_sysctl_wufc */
-
 #ifdef IXGBE_DEBUG
 /************************************************************************
  * ixgbe_sysctl_print_rss_config
diff --git a/sys/dev/ixgbe/if_ixv.c b/sys/dev/ixgbe/if_ixv.c
index 391e38f218f2..29a83aad9af2 100644
--- a/sys/dev/ixgbe/if_ixv.c
+++ b/sys/dev/ixgbe/if_ixv.c
@@ -532,13 +532,8 @@ ixv_if_attach_pre(if_ctx_t ctx)
 
 	scctx->isc_txrx = &ixgbe_txrx;
 
-	/*
-	 * Tell the upper layer(s) we support everything the PF
-	 * driver does except...
-	 *   Wake-on-LAN
-	 */
+	/* We support everything the PF does; VFs do not do WoL. */
 	scctx->isc_capabilities = IXGBE_CAPS;
-	scctx->isc_capabilities ^= IFCAP_WOL;
 	scctx->isc_capenable = scctx->isc_capabilities;
 	atomic_store_rel_32(&sc->vf_mbx_ready, mailbox_ready);
 	callout_init(&sc->vf_mbx_retry, 1);
diff --git a/sys/dev/ixgbe/ixgbe.h b/sys/dev/ixgbe/ixgbe.h
index 405d5b5daf14..c91f829e5b5f 100644
--- a/sys/dev/ixgbe/ixgbe.h
+++ b/sys/dev/ixgbe/ixgbe.h
@@ -217,7 +217,7 @@
 #define IXGBE_CAPS (IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6 | IFCAP_TSO | \
 		    IFCAP_LRO | IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWTSO | \
 		    IFCAP_VLAN_HWCSUM | IFCAP_JUMBO_MTU | IFCAP_VLAN_MTU | \
-		    IFCAP_VLAN_HWFILTER | IFCAP_WOL)
+		    IFCAP_VLAN_HWFILTER)
 
 #ifndef DEVMETHOD_END
 #define DEVMETHOD_END	{ NULL, NULL }
@@ -451,8 +451,7 @@ struct ixgbe_softc {
 	u32			ledctl_default;
 
 	/* Power management-related */
-	bool			wol_support;
-	u32			wufc;
+	u32			wol_filters;
 
 	/* Mbuf cluster size */
 	u32			rx_mbuf_sz;