git: 9ea7beb173b8 - main - ixv: Add Hyper-V virtual function support
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 15 Sep 2026 02:06:40 UTC
The branch main has been updated by kbowling:
URL: https://cgit.FreeBSD.org/src/commit/?id=9ea7beb173b8b5c77663ee0f86b32cc76f20357f
commit 9ea7beb173b8b5c77663ee0f86b32cc76f20357f
Author: Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-09-07 03:34:50 +0000
Commit: Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-09-15 02:05:00 +0000
ixv: Add Hyper-V virtual function support
Hyper-V does not expose the normal Intel PF/VF mailbox.
Import the Hyper-V operation overrides from DPDK and complete its reset
callback with the configuration-space mechanism submitted by Microsoft.
Route ixv operations through the operation table, use mailbox API 1.0,
and limit this environment to one queue pair.
Claim the 82599, X540, X550, X550EM-X, and X550EM-A Hyper-V device IDs
listed by DPDK. Select the same path for the E610 Hyper-V subdevice
identity defined there.
For E610/Linkville, read the emulated VFLINKS-format status from PCI
configuration space at offset 0x209. Older families retain the MMIO
VFLINKS path.
Treat receive-mode changes as host-owned no-ops and do not retry VLAN
operations that Hyper-V permanently rejects. Limit the Hyper-V 82599
MTU to 1504 because its VF does not implement the X540 RLPML field.
Use mailbox reset indications only to refresh cached Hyper-V link state.
Hyper-V does not provide the mailbox handshake required to treat that
indication as a request for an iflib reinitialization.
Tested on 82599 and E610 (with a followup commit) with Windows Server
2025 Hyper-V.
PR: 232472, 239849
Obtained from: DPDK (shared code)
Sponsored by: BBOX.io
Co-authored-by: Wei Hu <weh@microsoft.com>
---
share/man/man4/ixv.4 | 11 +-
sys/conf/files | 2 +
sys/dev/ixgbe/if_ixv.c | 134 ++++++++++++++-------
sys/dev/ixgbe/ixgbe_hv_vf.c | 277 ++++++++++++++++++++++++++++++++++++++++++++
sys/dev/ixgbe/ixgbe_hv_vf.h | 12 ++
sys/dev/ixgbe/ixgbe_osdep.c | 8 +-
sys/dev/ixgbe/ixgbe_osdep.h | 4 +
sys/modules/ixv/Makefile | 1 +
8 files changed, 406 insertions(+), 43 deletions(-)
diff --git a/share/man/man4/ixv.4 b/share/man/man4/ixv.4
index 6acc41737294..907ff30103ec 100644
--- a/share/man/man4/ixv.4
+++ b/share/man/man4/ixv.4
@@ -28,7 +28,7 @@
.\" NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
.\" SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd August 15, 2026
+.Dd September 6, 2026
.Dt IXV 4
.Os
.Sh NAME
@@ -60,7 +60,8 @@ guest.
.Pp
The driver supports jumbo frames, MSI-X, receive-side scaling,
TCP segmentation offload, checksum offload, and VLAN hardware offload.
-The maximum supported MTU is 9710 bytes.
+The maximum supported MTU is 9710 bytes, except that an 82599 VF on
+Hyper-V is limited to 1504 bytes.
.Pp
The physical-function driver controls the resources and policy presented to
the virtual function.
@@ -70,6 +71,12 @@ MSI-X vectors.
Requests to change the MAC address, VLAN membership, or receive mode may be
rejected by physical-function policy.
.Pp
+On Hyper-V, the host provides reset and assigned-address information through
+PCI configuration space instead of the Intel PF/VF mailbox.
+The driver uses one queue pair in this environment.
+MAC address, VLAN, multicast filter, and receive mode policies remain under
+host control.
+.Pp
The virtual function cannot configure the physical media.
Only automatic media selection is supported, and reported link state and
speed are supplied by the physical function or virtual-function hardware.
diff --git a/sys/conf/files b/sys/conf/files
index a195d93cb169..c10592263caa 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -2348,6 +2348,8 @@ dev/ixgbe/ixgbe_common.c optional ix inet | ixv inet \
compile-with "${NORMAL_C} -I$S/dev/ixgbe"
dev/ixgbe/ixgbe_fw_logging.c optional ix inet | ixv inet \
compile-with "${NORMAL_C} -I$S/dev/ixgbe"
+dev/ixgbe/ixgbe_hv_vf.c optional ixv inet \
+ compile-with "${NORMAL_C} -I$S/dev/ixgbe"
dev/ixgbe/ixgbe_mbx.c optional ix inet | ixv inet \
compile-with "${NORMAL_C} -I$S/dev/ixgbe"
dev/ixgbe/ixgbe_vf.c optional ix inet | ixv inet \
diff --git a/sys/dev/ixgbe/if_ixv.c b/sys/dev/ixgbe/if_ixv.c
index 8405ac1aa8f9..a5e8a9b39de1 100644
--- a/sys/dev/ixgbe/if_ixv.c
+++ b/sys/dev/ixgbe/if_ixv.c
@@ -37,6 +37,7 @@
#include "opt_rss.h"
#include "ixgbe.h"
+#include "ixgbe_hv_vf.h"
#include "ifdi_if.h"
#include <net/netmap.h>
@@ -74,14 +75,27 @@ static const pci_vendor_info_t ixv_vendor_info_array[] =
{
PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_VF,
"Intel(R) X520 82599 Virtual Function"),
+ PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_VF_HV,
+ "Intel(R) X520 82599 Hyper-V Virtual Function"),
PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540_VF,
"Intel(R) X540 Virtual Function"),
+ PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540_VF_HV,
+ "Intel(R) X540 Hyper-V Virtual Function"),
PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550_VF,
"Intel(R) X550 Virtual Function"),
+ PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550_VF_HV,
+ "Intel(R) X550 Hyper-V Virtual Function"),
PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_VF,
"Intel(R) X552 Virtual Function"),
+ PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_VF_HV,
+ "Intel(R) X552 Hyper-V Virtual Function"),
PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_VF,
"Intel(R) X553 Virtual Function"),
+ PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_VF_HV,
+ "Intel(R) X553 Hyper-V Virtual Function"),
+ PVID_OEM(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_E610_VF, 0,
+ IXGBE_SUBDEV_ID_E610_VF_HV, 0,
+ "Intel(R) E610 Hyper-V Virtual Function"),
PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_E610_VF,
"Intel(R) E610 Virtual Function"),
/* required last entry */
@@ -92,7 +106,6 @@ static const pci_vendor_info_t ixv_vendor_info_array[] =
* Function prototypes
************************************************************************/
static void *ixv_register(device_t);
-static int ixv_probe(device_t);
static int ixv_if_attach_pre(if_ctx_t);
static int ixv_if_attach_post(if_ctx_t);
static int ixv_if_detach(if_ctx_t);
@@ -104,6 +117,7 @@ static int ixv_if_rx_queues_alloc(if_ctx_t, caddr_t *, uint64_t *, int,
int);
static void ixv_if_queues_free(if_ctx_t);
static void ixv_identify_hardware(if_ctx_t);
+static bool ixv_is_hyperv(const struct ixgbe_hw *);
static void ixv_init_device_features(struct ixgbe_softc *);
static int ixv_allocate_pci_resources(if_ctx_t);
static void ixv_free_pci_resources(if_ctx_t);
@@ -133,6 +147,7 @@ static void ixv_initialize_receive_units(if_ctx_t);
static void ixv_initialize_rss_mapping(struct ixgbe_softc *);
static void ixv_setup_vlan_support(if_ctx_t);
+static bool ixv_vlan_error_retryable(s32);
static void ixv_vlan_retry_add(struct ixgbe_softc *, u16);
static void ixv_vlan_retry_clear(struct ixgbe_softc *, u16);
static bool ixv_vlan_retry_pending(const struct ixgbe_softc *);
@@ -168,7 +183,7 @@ static int ixv_msix_mbx(void *);
static device_method_t ixv_methods[] = {
/* Device interface */
DEVMETHOD(device_register, ixv_register),
- DEVMETHOD(device_probe, ixv_probe),
+ DEVMETHOD(device_probe, iflib_device_probe),
DEVMETHOD(device_attach, iflib_device_attach),
DEVMETHOD(device_detach, iflib_device_detach),
DEVMETHOD(device_shutdown, iflib_device_shutdown),
@@ -257,16 +272,6 @@ ixv_register(device_t dev)
return (&ixv_sctx_init);
}
-static int
-ixv_probe(device_t dev)
-{
- if (pci_get_device(dev) == IXGBE_DEV_ID_E610_VF &&
- pci_get_subdevice(dev) == IXGBE_SUBDEV_ID_E610_VF_HV)
- return (ENXIO);
-
- return (iflib_device_probe(dev));
-}
-
/************************************************************************
* ixv_if_tx_queues_alloc
************************************************************************/
@@ -457,9 +462,12 @@ ixv_if_attach_pre(if_ctx_t ctx)
sc->vf_link_poll_tick = device_get_unit(dev) % IXV_LINK_POLL_TICKS;
/* Initialize the shared code */
- error = ixgbe_init_ops_vf(hw);
+ if (ixv_is_hyperv(hw))
+ error = ixgbevf_hv_init_ops_vf(hw);
+ else
+ error = ixgbe_init_ops_vf(hw);
if (error) {
- device_printf(dev, "ixgbe_init_ops_vf() failed!\n");
+ device_printf(dev, "VF shared-code initialization failed\n");
error = EIO;
goto err_out;
}
@@ -603,10 +611,16 @@ ixv_if_mtu_set(if_ctx_t ctx, uint32_t mtu)
{
struct ixgbe_softc *sc = iflib_get_softc(ctx);
if_t ifp = iflib_get_ifp(ctx);
+ uint32_t max_mtu;
int error = 0;
IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)");
- if (mtu > IXGBE_MAX_FRAME_SIZE - IXGBE_MTU_HDR) {
+ max_mtu = IXGBE_MAX_FRAME_SIZE - IXGBE_MTU_HDR;
+ /* The 82599 VF cannot enforce the X540 RLPML field. */
+ if (ixv_is_hyperv(&sc->hw) &&
+ sc->hw.mac.type == ixgbe_mac_82599_vf)
+ max_mtu = ETHERMTU + ETHER_CRC_LEN;
+ if (mtu > max_mtu) {
error = EINVAL;
} else {
if_setmtu(ifp, mtu);
@@ -1071,12 +1085,12 @@ ixv_negotiate_api(struct ixgbe_softc *sc)
};
int i = 0;
- if (hw->mac.type == ixgbe_mac_E610_vf &&
- ixgbevf_negotiate_api_version(hw, ixgbe_mbox_api_16) == 0)
+ if (hw->mac.type == ixgbe_mac_E610_vf && !ixv_is_hyperv(hw) &&
+ hw->mac.ops.negotiate_api_version(hw, ixgbe_mbox_api_16) == 0)
return (0);
while (mbx_api[i] != ixgbe_mbox_api_unknown) {
- if (ixgbevf_negotiate_api_version(hw, mbx_api[i]) == 0)
+ if (hw->mac.ops.negotiate_api_version(hw, mbx_api[i]) == 0)
return (0);
i++;
}
@@ -1097,22 +1111,26 @@ ixv_queue_limit(struct ixgbe_softc *sc, bool mailbox_ready)
int admin_vectors, limit, msix_vectors;
hw = &sc->hw;
- /* Preserve the current family limit as the mailbox fallback. */
- switch (hw->mac.type) {
- case ixgbe_mac_82599_vf:
- case ixgbe_mac_X540_vf:
- limit = 1;
- break;
- case ixgbe_mac_X550_vf:
- case ixgbe_mac_X550EM_x_vf:
- case ixgbe_mac_X550EM_a_vf:
- limit = 2;
- break;
- case ixgbe_mac_E610_vf:
+ if (ixv_is_hyperv(hw)) {
limit = 1;
- break;
- default:
- return (1);
+ } else {
+ /* Preserve the current family limit as the mailbox fallback. */
+ switch (hw->mac.type) {
+ case ixgbe_mac_82599_vf:
+ case ixgbe_mac_X540_vf:
+ limit = 1;
+ break;
+ case ixgbe_mac_X550_vf:
+ case ixgbe_mac_X550EM_x_vf:
+ case ixgbe_mac_X550EM_a_vf:
+ limit = 2;
+ break;
+ case ixgbe_mac_E610_vf:
+ limit = 1;
+ break;
+ default:
+ return (1);
+ }
}
/* Replace the fallback with the queue grant reported by the PF. */
@@ -1162,7 +1180,7 @@ ixv_update_xcast_mode(struct ixgbe_softc *sc, int flags)
mode = IXGBEVF_XCAST_MODE_MULTI;
else
mode = IXGBEVF_XCAST_MODE_NONE;
- return (ixgbevf_update_xcast_mode(&sc->hw, mode));
+ return (sc->hw.mac.ops.update_xcast_mode(&sc->hw, mode));
}
static int
@@ -1306,7 +1324,13 @@ ixv_if_update_admin_status(if_ctx_t ctx)
if (sc->hw.mac.type != ixgbe_mac_E610_vf ||
sc->hw.api_version != ixgbe_mbox_api_16)
check_link = true;
- reset_seen = ixgbe_check_for_rst(&sc->hw, 0) == IXGBE_SUCCESS;
+ /*
+ * Hyper-V uses this indication only to invalidate cached VFLINKS
+ * state; it does not expose the mailbox handshake needed to turn it
+ * into a driver reset. Its check_link operation samples the bit.
+ */
+ reset_seen = !ixv_is_hyperv(&sc->hw) &&
+ ixgbe_check_for_rst(&sc->hw, 0) == IXGBE_SUCCESS;
if (reset_seen)
sc->hw.mac.get_link_status = true;
if (check_link) {
@@ -1442,18 +1466,23 @@ ixv_identify_hardware(if_ctx_t ctx)
/* A subset of set_mac_type */
switch (hw->device_id) {
case IXGBE_DEV_ID_82599_VF:
+ case IXGBE_DEV_ID_82599_VF_HV:
hw->mac.type = ixgbe_mac_82599_vf;
break;
case IXGBE_DEV_ID_X540_VF:
+ case IXGBE_DEV_ID_X540_VF_HV:
hw->mac.type = ixgbe_mac_X540_vf;
break;
case IXGBE_DEV_ID_X550_VF:
+ case IXGBE_DEV_ID_X550_VF_HV:
hw->mac.type = ixgbe_mac_X550_vf;
break;
case IXGBE_DEV_ID_X550EM_X_VF:
+ case IXGBE_DEV_ID_X550EM_X_VF_HV:
hw->mac.type = ixgbe_mac_X550EM_x_vf;
break;
case IXGBE_DEV_ID_X550EM_A_VF:
+ case IXGBE_DEV_ID_X550EM_A_VF_HV:
hw->mac.type = ixgbe_mac_X550EM_a_vf;
break;
case IXGBE_DEV_ID_E610_VF:
@@ -1466,6 +1495,24 @@ ixv_identify_hardware(if_ctx_t ctx)
}
} /* ixv_identify_hardware */
+static bool
+ixv_is_hyperv(const struct ixgbe_hw *hw)
+{
+ switch (hw->device_id) {
+ case IXGBE_DEV_ID_82599_VF_HV:
+ case IXGBE_DEV_ID_X540_VF_HV:
+ case IXGBE_DEV_ID_X550_VF_HV:
+ case IXGBE_DEV_ID_X550EM_X_VF_HV:
+ case IXGBE_DEV_ID_X550EM_A_VF_HV:
+ return (true);
+ case IXGBE_DEV_ID_E610_VF:
+ return (hw->subsystem_device_id ==
+ IXGBE_SUBDEV_ID_E610_VF_HV);
+ default:
+ return (false);
+ }
+}
+
/************************************************************************
* ixv_if_msix_intr_assign - Setup MSI-X Interrupt resources and handlers
************************************************************************/
@@ -1854,7 +1901,7 @@ ixv_initialize_receive_units(if_ctx_t ctx)
IXGBE_WRITE_REG(hw, IXGBE_VFPSRTYPE, psrtype);
/* Tell PF our max_frame size */
- if (ixgbevf_rlpml_set_vf(hw, sc->max_frame_size) != 0) {
+ if (hw->mac.ops.set_rlpml(hw, sc->max_frame_size) != 0) {
device_printf(sc->dev,
"There is a problem with the PF setup. It is likely the"
" receive unit for this VF will not function correctly."
@@ -1954,6 +2001,12 @@ ixv_initialize_receive_units(if_ctx_t ctx)
/************************************************************************
* VF VLAN mailbox retry helpers
************************************************************************/
+static bool
+ixv_vlan_error_retryable(s32 error)
+{
+ return (error != IXGBE_ERR_FEATURE_NOT_SUPPORTED);
+}
+
static void
ixv_vlan_retry_add(struct ixgbe_softc *sc, u16 vid)
{
@@ -2051,7 +2104,7 @@ ixv_vlan_retry_tick(struct ixgbe_softc *sc)
attempts++;
enable = (sc->shadow_vfta[vid >> 5] & bit) != 0;
error = hw->mac.ops.set_vfta(hw, vid, 0, enable, false);
- if (error != IXGBE_SUCCESS)
+ if (error != IXGBE_SUCCESS && ixv_vlan_error_retryable(error))
break;
ixv_vlan_retry_clear(sc, vid);
}
@@ -2109,7 +2162,8 @@ ixv_setup_vlan_support(if_ctx_t ctx)
false);
else
error = IXGBE_ERR_MBX;
- if (error != IXGBE_SUCCESS) {
+ if (error != IXGBE_SUCCESS &&
+ ixv_vlan_error_retryable(error)) {
ixv_vlan_retry_add(sc, vid);
restore_failures++;
} else
@@ -2150,7 +2204,7 @@ ixv_if_register_vlan(if_ctx_t ctx, u16 vtag)
return;
error = sc->hw.mac.ops.set_vfta(&sc->hw, vtag, 0, true, false);
- if (error != IXGBE_SUCCESS) {
+ if (error != IXGBE_SUCCESS && ixv_vlan_error_retryable(error)) {
ixv_vlan_retry_add(sc, vtag);
if (!pending)
device_printf(sc->dev,
@@ -2184,7 +2238,7 @@ ixv_if_unregister_vlan(if_ctx_t ctx, u16 vtag)
return;
error = sc->hw.mac.ops.set_vfta(&sc->hw, vtag, 0, false, false);
- if (error != IXGBE_SUCCESS) {
+ if (error != IXGBE_SUCCESS && ixv_vlan_error_retryable(error)) {
ixv_vlan_retry_add(sc, vtag);
if (!pending)
device_printf(sc->dev,
diff --git a/sys/dev/ixgbe/ixgbe_hv_vf.c b/sys/dev/ixgbe/ixgbe_hv_vf.c
new file mode 100644
index 000000000000..6ce994ff06f1
--- /dev/null
+++ b/sys/dev/ixgbe/ixgbe_hv_vf.c
@@ -0,0 +1,277 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2001-2024 Intel Corporation
+ */
+
+#include "ixgbe_common.h"
+#include "ixgbe_vf.h"
+#include "ixgbe_hv_vf.h"
+
+/* Reading these PCI configuration bytes resets a VF on Hyper-V. */
+#define IXGBE_HV_RESET_OFFSET 0x201
+
+/* E610 exposes VFLINKS in four emulated PCI configuration bytes. */
+#define IXGBE_HV_LINK_STATUS_OFFSET 0x209
+#define IXGBE_HV_LINK_STATUS_SIZE 4
+
+/**
+ * ixgbevf_hv_update_mc_addr_list_vf - Hyper-V variant - just a stub.
+ * @hw: unused
+ * @mc_addr_list: unused
+ * @mc_addr_count: unused
+ * @next: unused
+ * @clear: unused
+ */
+static s32
+ixgbevf_hv_update_mc_addr_list_vf(struct ixgbe_hw *hw, u8 *mc_addr_list,
+ u32 mc_addr_count, ixgbe_mc_addr_itr next, bool clear)
+{
+ UNREFERENCED_5PARAMETER(hw, mc_addr_list, mc_addr_count, next, clear);
+
+ return (IXGBE_ERR_FEATURE_NOT_SUPPORTED);
+}
+
+/**
+ * ixgbevf_hv_update_xcast_mode - Leave receive-mode policy to Hyper-V
+ * @hw: unused
+ * @xcast_mode: unused
+ */
+static s32
+ixgbevf_hv_update_xcast_mode(struct ixgbe_hw *hw, int xcast_mode)
+{
+ UNREFERENCED_2PARAMETER(hw, xcast_mode);
+
+ return (IXGBE_SUCCESS);
+}
+
+/**
+ * ixgbevf_hv_set_vfta_vf - Hyper-V variant - just a stub.
+ * @hw: unused
+ * @vlan: unused
+ * @vind: unused
+ * @vlan_on: unused
+ * @vlvf_bypass: unused
+ */
+static s32
+ixgbevf_hv_set_vfta_vf(struct ixgbe_hw *hw, u32 vlan, u32 vind,
+ bool vlan_on, bool vlvf_bypass)
+{
+ UNREFERENCED_5PARAMETER(hw, vlan, vind, vlan_on, vlvf_bypass);
+
+ return (IXGBE_ERR_FEATURE_NOT_SUPPORTED);
+}
+
+static s32
+ixgbevf_hv_set_uc_addr_vf(struct ixgbe_hw *hw, u32 index, u8 *addr)
+{
+ UNREFERENCED_3PARAMETER(hw, index, addr);
+
+ return (IXGBE_ERR_FEATURE_NOT_SUPPORTED);
+}
+
+/**
+ * ixgbevf_hv_reset_hw_vf - Reset through the Hyper-V PCI side channel
+ * @hw: pointer to hardware structure
+ *
+ * Hyper-V returns the permanent VF address when the guest reads six bytes
+ * beginning at offset 0x201 in PCI configuration space. The reads also
+ * perform the host-side VF reset handshake.
+ */
+static s32
+ixgbevf_hv_reset_hw_vf(struct ixgbe_hw *hw)
+{
+ int i;
+
+ hw->api_version = ixgbe_mbox_api_10;
+ for (i = 0; i < IXGBE_ETH_LENGTH_OF_ADDRESS; i++)
+ hw->mac.perm_addr[i] = IXGBE_READ_PCIE_BYTE(hw,
+ IXGBE_HV_RESET_OFFSET + i);
+ if (ixgbe_validate_mac_addr(hw->mac.perm_addr) != IXGBE_SUCCESS)
+ return (IXGBE_ERR_INVALID_MAC_ADDR);
+
+ return (IXGBE_SUCCESS);
+}
+
+/**
+ * ixgbevf_hv_set_rar_vf - Hyper-V variant - just a stub.
+ * @hw: unused
+ * @index: unused
+ * @addr: unused
+ * @vmdq: unused
+ * @enable_addr: unused
+ */
+static s32
+ixgbevf_hv_set_rar_vf(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq,
+ u32 enable_addr)
+{
+ UNREFERENCED_5PARAMETER(hw, index, addr, vmdq, enable_addr);
+
+ return (IXGBE_ERR_FEATURE_NOT_SUPPORTED);
+}
+
+static u32
+ixgbevf_hv_read_links(struct ixgbe_hw *hw)
+{
+ u32 links_reg;
+ int i;
+
+ if (hw->mac.type != ixgbe_mac_E610_vf)
+ return (IXGBE_READ_REG(hw, IXGBE_VFLINKS));
+
+ links_reg = 0;
+ for (i = 0; i < IXGBE_HV_LINK_STATUS_SIZE; i++)
+ links_reg |= (u32)IXGBE_READ_PCIE_BYTE(hw,
+ IXGBE_HV_LINK_STATUS_OFFSET + i) << (i * NBBY);
+ return (links_reg);
+}
+
+/**
+ * ixgbevf_hv_check_mac_link_vf - Check link without mailbox communication
+ * @hw: pointer to hardware structure
+ * @speed: pointer to link speed
+ * @link_up: true is link is up, false otherwise
+ * @autoneg_wait_to_complete: unused
+ */
+static s32
+ixgbevf_hv_check_mac_link_vf(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
+ bool *link_up, bool autoneg_wait_to_complete)
+{
+ struct ixgbe_mbx_info *mbx = &hw->mbx;
+ struct ixgbe_mac_info *mac = &hw->mac;
+ u32 links_reg;
+
+ UNREFERENCED_1PARAMETER(autoneg_wait_to_complete);
+
+ /* If we were hit with a reset, drop the cached link state. */
+ if (!mbx->ops[0].check_for_rst(hw, 0) || !mbx->timeout)
+ mac->get_link_status = true;
+ if (!mac->get_link_status)
+ goto out;
+
+ links_reg = ixgbevf_hv_read_links(hw);
+ if (!(links_reg & IXGBE_LINKS_UP))
+ goto out;
+
+ /* Link status can take up to 500 usec to settle on 82599. */
+ if (mac->type == ixgbe_mac_82599_vf) {
+ int i;
+
+ for (i = 0; i < 5; i++) {
+ usec_delay(100);
+ links_reg = ixgbevf_hv_read_links(hw);
+ if (!(links_reg & IXGBE_LINKS_UP))
+ goto out;
+ }
+ }
+
+ switch (links_reg & IXGBE_LINKS_SPEED_82599) {
+ case IXGBE_LINKS_SPEED_10G_82599:
+ *speed = IXGBE_LINK_SPEED_10GB_FULL;
+ if (hw->mac.type >= ixgbe_mac_X550_vf &&
+ (links_reg & IXGBE_LINKS_SPEED_NON_STD) != 0)
+ *speed = IXGBE_LINK_SPEED_2_5GB_FULL;
+ break;
+ case IXGBE_LINKS_SPEED_1G_82599:
+ *speed = IXGBE_LINK_SPEED_1GB_FULL;
+ break;
+ case IXGBE_LINKS_SPEED_100_82599:
+ *speed = IXGBE_LINK_SPEED_100_FULL;
+ if ((hw->mac.type == ixgbe_mac_X550_vf ||
+ hw->mac.type == ixgbe_mac_E610_vf) &&
+ (links_reg & IXGBE_LINKS_SPEED_NON_STD) != 0)
+ *speed = IXGBE_LINK_SPEED_5GB_FULL;
+ break;
+ case IXGBE_LINKS_SPEED_10_X550EM_A:
+ *speed = IXGBE_LINK_SPEED_UNKNOWN;
+ if (hw->mac.type >= ixgbe_mac_X550_vf)
+ *speed = IXGBE_LINK_SPEED_10_FULL;
+ break;
+ default:
+ *speed = IXGBE_LINK_SPEED_UNKNOWN;
+ }
+
+ mac->get_link_status = false;
+
+out:
+ *link_up = !mac->get_link_status;
+ return (IXGBE_SUCCESS);
+}
+
+/**
+ * ixgbevf_hv_get_link_state_vf - Hyper-V has no mailbox link policy
+ * @hw: unused
+ * @link_state: unused
+ */
+static s32
+ixgbevf_hv_get_link_state_vf(struct ixgbe_hw *hw, bool *link_state)
+{
+ UNREFERENCED_2PARAMETER(hw, link_state);
+
+ return (IXGBE_ERR_FEATURE_NOT_SUPPORTED);
+}
+
+/**
+ * ixgbevf_hv_set_rlpml_vf - Set the maximum receive packet length
+ * @hw: pointer to hardware structure
+ * @max_size: maximum frame size
+ */
+static s32
+ixgbevf_hv_set_rlpml_vf(struct ixgbe_hw *hw, u16 max_size)
+{
+ u32 reg;
+
+ /* RLPML is not implemented by the 82599 VF. */
+ if (hw->mac.type == ixgbe_mac_82599_vf)
+ return (IXGBE_SUCCESS);
+
+ reg = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(0));
+ reg &= ~IXGBE_RXDCTL_RLPMLMASK;
+ reg |= ((max_size + 4) & IXGBE_RXDCTL_RLPMLMASK) |
+ IXGBE_RXDCTL_RLPML_EN;
+ IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(0), reg);
+
+ return (IXGBE_SUCCESS);
+}
+
+/**
+ * ixgbevf_hv_negotiate_api_version_vf - Negotiate the Hyper-V API version
+ * @hw: pointer to hardware structure
+ * @api: requested API version
+ */
+static int
+ixgbevf_hv_negotiate_api_version_vf(struct ixgbe_hw *hw, int api)
+{
+ if (api != ixgbe_mbox_api_10)
+ return (IXGBE_ERR_INVALID_ARGUMENT);
+
+ hw->api_version = api;
+ return (IXGBE_SUCCESS);
+}
+
+/**
+ * ixgbevf_hv_init_ops_vf - Initialize Hyper-V VF operations
+ * @hw: pointer to hardware structure
+ */
+s32
+ixgbevf_hv_init_ops_vf(struct ixgbe_hw *hw)
+{
+ s32 status;
+
+ status = ixgbe_init_ops_vf(hw);
+ if (status != IXGBE_SUCCESS)
+ return (status);
+
+ hw->mac.ops.reset_hw = ixgbevf_hv_reset_hw_vf;
+ hw->mac.ops.check_link = ixgbevf_hv_check_mac_link_vf;
+ hw->mac.ops.negotiate_api_version =
+ ixgbevf_hv_negotiate_api_version_vf;
+ hw->mac.ops.set_rar = ixgbevf_hv_set_rar_vf;
+ hw->mac.ops.update_mc_addr_list =
+ ixgbevf_hv_update_mc_addr_list_vf;
+ hw->mac.ops.update_xcast_mode = ixgbevf_hv_update_xcast_mode;
+ hw->mac.ops.get_link_state = ixgbevf_hv_get_link_state_vf;
+ hw->mac.ops.set_uc_addr = ixgbevf_hv_set_uc_addr_vf;
+ hw->mac.ops.set_vfta = ixgbevf_hv_set_vfta_vf;
+ hw->mac.ops.set_rlpml = ixgbevf_hv_set_rlpml_vf;
+
+ return (IXGBE_SUCCESS);
+}
diff --git a/sys/dev/ixgbe/ixgbe_hv_vf.h b/sys/dev/ixgbe/ixgbe_hv_vf.h
new file mode 100644
index 000000000000..dd2e1eee4e9c
--- /dev/null
+++ b/sys/dev/ixgbe/ixgbe_hv_vf.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2001-2020 Intel Corporation
+ */
+
+#ifndef _IXGBE_HV_VF_H_
+#define _IXGBE_HV_VF_H_
+
+#include "ixgbe_type.h"
+
+s32 ixgbevf_hv_init_ops_vf(struct ixgbe_hw *hw);
+
+#endif /* _IXGBE_HV_VF_H_ */
diff --git a/sys/dev/ixgbe/ixgbe_osdep.c b/sys/dev/ixgbe/ixgbe_osdep.c
index d96e15f4f87f..00b7f27faead 100644
--- a/sys/dev/ixgbe/ixgbe_osdep.c
+++ b/sys/dev/ixgbe/ixgbe_osdep.c
@@ -39,10 +39,16 @@ ixgbe_dev_from_hw(struct ixgbe_hw *hw)
return ((struct ixgbe_softc *)hw->back)->dev;
}
+inline u8
+ixgbe_read_pci_cfg_byte(struct ixgbe_hw *hw, u32 reg)
+{
+ return (pci_read_config(ixgbe_dev_from_hw(hw), reg, 1));
+}
+
inline u16
ixgbe_read_pci_cfg(struct ixgbe_hw *hw, u32 reg)
{
- return pci_read_config(((struct ixgbe_softc *)hw->back)->dev, reg, 2);
+ return (pci_read_config(ixgbe_dev_from_hw(hw), reg, 2));
}
inline void
diff --git a/sys/dev/ixgbe/ixgbe_osdep.h b/sys/dev/ixgbe/ixgbe_osdep.h
index ec2b3274ec31..2066033ea174 100644
--- a/sys/dev/ixgbe/ixgbe_osdep.h
+++ b/sys/dev/ixgbe/ixgbe_osdep.h
@@ -126,6 +126,7 @@ enum {
#define UNREFERENCED_2PARAMETER(_p, _q)
#define UNREFERENCED_3PARAMETER(_p, _q, _r)
#define UNREFERENCED_4PARAMETER(_p, _q, _r, _s)
+#define UNREFERENCED_5PARAMETER(_p, _q, _r, _s, _t)
#define IXGBE_NTOHL(_i) ntohl(_i)
#define IXGBE_NTOHS(_i) ntohs(_i)
@@ -208,6 +209,9 @@ struct ixgbe_hw;
device_t ixgbe_dev_from_hw(struct ixgbe_hw *hw);
/* These routines are needed by the shared code */
+extern u8 ixgbe_read_pci_cfg_byte(struct ixgbe_hw *, u32);
+#define IXGBE_READ_PCIE_BYTE ixgbe_read_pci_cfg_byte
+
extern u16 ixgbe_read_pci_cfg(struct ixgbe_hw *, u32);
#define IXGBE_READ_PCIE_WORD ixgbe_read_pci_cfg
diff --git a/sys/modules/ixv/Makefile b/sys/modules/ixv/Makefile
index 743b2b407a5e..c2b27a689f76 100644
--- a/sys/modules/ixv/Makefile
+++ b/sys/modules/ixv/Makefile
@@ -6,6 +6,7 @@ SRCS += opt_inet.h opt_inet6.h opt_rss.h
SRCS += if_ixv.c if_fdir.c ix_txrx.c ixgbe_osdep.c
# Shared source
SRCS += ixgbe_common.c ixgbe_api.c ixgbe_phy.c ixgbe_mbx.c ixgbe_vf.c
+SRCS += ixgbe_hv_vf.c
SRCS += ixgbe_dcb.c ixgbe_dcb_82598.c ixgbe_dcb_82599.c
SRCS += ixgbe_82598.c ixgbe_82599.c ixgbe_x540.c ixgbe_x550.c ixgbe_e610.c
SRCS += ixgbe_fw_logging.c