I updated my patch to remove AIM code. I can't see any performance improvement
with AIM enabled. I ran packet forwarding test with Cisco TRex traffic
Generator (*1). AIM doesn't improves performance in this test.

*1: https://trex-tgn.cisco.com/

With my latest patch, I've got following maximum packet forwarding rate in
stateless benchmark (stl/bench.py) without packet loss. It starts to drop
packets over these rate.

Stateless benchmark (stl/bench.py)

| N cpu cores | mbps |
|-------------|------|
|      2      | 3390 |
|      4      | 4250 |
|      6      | 4340 |

Without PF (Packet Filter) improves performance as follows.

| N cpu cores | mbps |
|-------------|------|
|      2      | 4740 |
|      4      | 7190 |
|      6      | 8410 |

All tests run in MTU 1500. Host hardware spec is shown as below.

Vendor: FUJITSU PRIMERGY RX2530 M2
CPU: 24 CPUs x Intel(R) Xeon(R) CPU E5-2650 v4 @ 2.20GHz
Memory: 192 GB
NIC: Intel X540-AT2
ESXi version: 7.0U3

OK?

diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC
index 3563126b2a1..e421c38e95f 100644
--- a/sys/arch/amd64/conf/GENERIC
+++ b/sys/arch/amd64/conf/GENERIC
@@ -522,6 +522,7 @@ msk*        at mskc?                        #  each port of 
above
 em*    at pci?                         # Intel Pro/1000 ethernet
 ixgb*  at pci?                         # Intel Pro/10Gb ethernet
 ix*    at pci?                         # Intel 82598EB 10Gb ethernet
+ixv*   at pci?                         # Virtual Function of Intel 82598EB
 myx*   at pci?                         # Myricom Myri-10G 10Gb ethernet
 oce*   at pci?                         # Emulex OneConnect 10Gb ethernet
 txp*   at pci?                         # 3com 3CR990
diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci
index a803dc9b659..7d6402e524e 100644
--- a/sys/dev/pci/files.pci
+++ b/sys/dev/pci/files.pci
@@ -350,13 +350,19 @@ file      dev/pci/ixgb_hw.c               ixgb
 # Intel 82598 10GbE
 device ix: ether, ifnet, ifmedia, intrmap, stoeplitz
 attach ix at pci
-file   dev/pci/if_ix.c                 ix
-file   dev/pci/ixgbe.c                 ix
-file   dev/pci/ixgbe_82598.c           ix
-file   dev/pci/ixgbe_82599.c           ix
-file   dev/pci/ixgbe_x540.c            ix
-file   dev/pci/ixgbe_x550.c            ix
-file   dev/pci/ixgbe_phy.c             ix
+file   dev/pci/if_ix.c                 ix | ixv
+file   dev/pci/ixgbe.c                 ix | ixv
+file   dev/pci/ixgbe_82598.c           ix | ixv
+file   dev/pci/ixgbe_82599.c           ix | ixv
+file   dev/pci/ixgbe_x540.c            ix | ixv
+file   dev/pci/ixgbe_x550.c            ix | ixv
+file   dev/pci/ixgbe_phy.c             ix | ixv
+
+# Virtual Function of i82599.
+device ixv: ether, ifnet, ifmedia, intrmap, stoeplitz
+attach ixv at pci
+file   dev/pci/if_ixv.c                ixv
+file   dev/pci/ixgbe_vf.c              ixv

 # Intel Ethernet 700 Series
 device ixl: ether, ifnet, ifmedia, intrmap, stoeplitz
diff --git a/sys/dev/pci/if_ix.c b/sys/dev/pci/if_ix.c
index b59ec28d9f1..4fb01d85778 100644
--- a/sys/dev/pci/if_ix.c
+++ b/sys/dev/pci/if_ix.c
@@ -507,7 +507,7 @@ ixgbe_start(struct ifqueue *ifq)
         * hardware that this frame is available to transmit.
         */
        if (post)
-               IXGBE_WRITE_REG(&sc->hw, IXGBE_TDT(txr->me),
+               IXGBE_WRITE_REG(&sc->hw, txr->tail,
                    txr->next_avail_desc);
 }

@@ -706,7 +706,7 @@ ixgbe_watchdog(struct ifnet * ifp)
        for (i = 0; i < sc->num_queues; i++, txr++) {
                printf("%s: Queue(%d) tdh = %d, hw tdt = %d\n", ifp->if_xname, 
i,
                    IXGBE_READ_REG(hw, IXGBE_TDH(i)),
-                   IXGBE_READ_REG(hw, IXGBE_TDT(i)));
+                   IXGBE_READ_REG(hw, sc->tx_rings[i].tail));
                printf("%s: TX(%d) Next TX to Clean = %d\n", ifp->if_xname,
                    i, txr->next_to_clean);
        }
@@ -826,7 +826,7 @@ ixgbe_init(void *arg)
                                msec_delay(1);
                }
                IXGBE_WRITE_FLUSH(&sc->hw);
-               IXGBE_WRITE_REG(&sc->hw, IXGBE_RDT(i), rxr->last_desc_filled);
+               IXGBE_WRITE_REG(&sc->hw, rxr[i].tail, rxr->last_desc_filled);
        }

        /* Set up VLAN support and filter */
@@ -2359,9 +2359,12 @@ ixgbe_initialize_transmit_units(struct ix_softc *sc)
                IXGBE_WRITE_REG(hw, IXGBE_TDLEN(i),
                    sc->num_tx_desc * sizeof(struct ixgbe_legacy_tx_desc));

+               /* Set Tx Tail register */
+               txr->tail = IXGBE_TDT(i);
+
                /* Setup the HW Tx Head and Tail descriptor pointers */
                IXGBE_WRITE_REG(hw, IXGBE_TDH(i), 0);
-               IXGBE_WRITE_REG(hw, IXGBE_TDT(i), 0);
+               IXGBE_WRITE_REG(hw, txr->tail, 0);

                /* Setup Transmit Descriptor Cmd Settings */
                txr->txd_cmd = IXGBE_TXD_CMD_IFCS;
@@ -2834,7 +2837,7 @@ ixgbe_rxrefill(void *xrxr)

        if (ixgbe_rxfill(rxr)) {
                /* Advance the Rx Queue "Tail Pointer" */
-               IXGBE_WRITE_REG(&sc->hw, IXGBE_RDT(rxr->me),
+               IXGBE_WRITE_REG(&sc->hw, rxr->tail,
                    rxr->last_desc_filled);
        } else if (if_rxr_inuse(&rxr->rx_ring) == 0)
                timeout_add(&rxr->rx_refill, 1);
@@ -2928,6 +2931,9 @@ ixgbe_initialize_receive_units(struct ix_softc *sc)
                srrctl = bufsz | IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
                IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(i), srrctl);

+               /* Capture Rx Tail index */
+               rxr->tail = IXGBE_RDT(i);
+
                if (ISSET(ifp->if_xflags, IFXF_TSO)) {
                        rdrxctl = IXGBE_READ_REG(&sc->hw, IXGBE_RSCCTL(i));

@@ -2940,7 +2946,7 @@ ixgbe_initialize_receive_units(struct ix_softc *sc)

                /* Setup the HW Rx Head and Tail Descriptor Pointers */
                IXGBE_WRITE_REG(hw, IXGBE_RDH(i), 0);
-               IXGBE_WRITE_REG(hw, IXGBE_RDT(i), 0);
+               IXGBE_WRITE_REG(hw, rxr->tail, 0);
        }

        if (sc->hw.mac.type != ixgbe_mac_82598EB) {
diff --git a/sys/dev/pci/if_ix.h b/sys/dev/pci/if_ix.h
index 41d756110c7..5426cf9bc8a 100644
--- a/sys/dev/pci/if_ix.h
+++ b/sys/dev/pci/if_ix.h
@@ -82,7 +82,14 @@
  */
 #define IXGBE_TX_OP_THRESHOLD  (sc->num_segs + 2)

+/* These defines are used in MTU calculations */
 #define IXGBE_MAX_FRAME_SIZE   9216
+#define IXGBE_MTU_HDR         (ETHER_HDR_LEN + ETHER_CRC_LEN)
+#define IXGBE_MTU_HDR_VLAN    (ETHER_HDR_LEN + ETHER_CRC_LEN + \
+                              ETHER_VLAN_ENCAP_LEN)
+#define IXGBE_MAX_MTU         (IXGBE_MAX_FRAME_SIZE - IXGBE_MTU_HDR)
+#define IXGBE_MAX_MTU_VLAN    (IXGBE_MAX_FRAME_SIZE - IXGBE_MTU_HDR_VLAN)
+

 /* Flow control constants */
 #define IXGBE_FC_PAUSE         0xFFFF
@@ -116,6 +123,8 @@
 #define IXGBE_BR_SIZE                  4096
 #define IXGBE_QUEUE_MIN_FREE           32

+#define IXGBE_EITR_DEFAULT              128
+
 /*
  * Interrupt Moderation parameters
  */
@@ -169,6 +178,7 @@ struct tx_ring {
        struct ix_softc         *sc;
        struct ifqueue          *ifq;
        uint32_t                me;
+       uint32_t                tail;
        uint32_t                watchdog_timer;
        union ixgbe_adv_tx_desc *tx_base;
        struct ixgbe_tx_buf     *tx_buffers;
@@ -194,6 +204,7 @@ struct rx_ring {
        struct ix_softc         *sc;
        struct ifiqueue         *ifiq;
        uint32_t                me;
+       uint32_t                tail;
        union ixgbe_adv_rx_desc *rx_base;
        struct ixgbe_dma_alloc  rxdma;
 #if 0
@@ -245,6 +256,7 @@ struct ix_softc {
        uint16_t                num_segs;
        uint32_t                link_speed;
        bool                    link_up;
+       bool                    link_enabled;
        uint32_t                linkvec;
        struct rwlock           sfflock;

diff --git a/sys/dev/pci/if_ixv.c b/sys/dev/pci/if_ixv.c
new file mode 100644
index 00000000000..07fc8fd3976
--- /dev/null
+++ b/sys/dev/pci/if_ixv.c
@@ -0,0 +1,1652 @@
+/*     $OpenBSD$       */
+
+/******************************************************************************
+
+  Copyright (c) 2001-2017, Intel Corporation
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+   1. Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+   2. Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+   3. Neither the name of the Intel Corporation nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+
+#include <dev/pci/if_ix.h>
+#include <dev/pci/ixgbe_type.h>
+#include <dev/pci/ixgbe.h>
+
+/************************************************************************
+ * Driver version
+ ************************************************************************/
+char ixv_driver_version[] = "1.5.32";
+
+/************************************************************************
+ * PCI Device ID Table
+ *
+ *   Used by probe to select devices to load on
+ *   Last field stores an index into ixv_strings
+ *   Last entry must be all 0s
+ *
+ *   { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index }
+ ************************************************************************/
+const struct pci_matchid ixv_devices[] = {
+       {PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82599VF},
+       {PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X540_VF},
+       {PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X550_VF},
+       {PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X550EM_X_VF},
+       {PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X550EM_A_VF}
+};
+
+/************************************************************************
+ * Function prototypes
+ ************************************************************************/
+static int     ixv_probe(struct device *, void *, void *);
+static void    ixv_identify_hardware(struct ix_softc *sc);
+static void    ixv_attach(struct device *, struct device *, void *);
+static int     ixv_detach(struct device *, int);
+static int     ixv_ioctl(struct ifnet *, u_long, caddr_t);
+static void    ixv_watchdog(struct ifnet *);
+static void    ixv_init(struct ix_softc *);
+static void    ixv_stop(void *);
+static int     ixv_allocate_msix(struct ix_softc *);
+static void    ixv_setup_interface(struct device *, struct ix_softc *);
+static int     ixv_negotiate_api(struct ix_softc *);
+
+static void    ixv_initialize_transmit_units(struct ix_softc *);
+static void    ixv_initialize_receive_units(struct ix_softc *);
+static void    ixv_initialize_rss_mapping(struct ix_softc *);
+
+static void    ixv_enable_intr(struct ix_softc *);
+static void    ixv_disable_intr(struct ix_softc *);
+static void    ixv_set_multi(struct ix_softc *);
+static void    ixv_set_ivar(struct ix_softc *, uint8_t, uint8_t, int8_t);
+static void    ixv_configure_ivars(struct ix_softc *);
+static uint8_t *ixv_mc_array_itr(struct ixgbe_hw *, uint8_t **, uint32_t *);
+
+static void    ixv_setup_vlan_support(struct ix_softc *);
+static void    ixv_configure_vlan(struct ifnet *, uint16_t, uint16_t);
+
+/* The MSI-X Interrupt handlers */
+static int     ixv_msix_que(void *);
+static int     ixv_msix_mbx(void *);
+
+/* Deferred interrupt tasklets */
+static void     ixv_handle_link(void *, int);
+
+
+/* Share functions between ixv and ix. */
+void    ixgbe_start(struct ifqueue *ifq);
+int    ixgbe_activate(struct device *, int);
+int    ixgbe_allocate_queues(struct ix_softc *);
+int    ixgbe_setup_transmit_structures(struct ix_softc *);
+int    ixgbe_setup_receive_structures(struct ix_softc *);
+void   ixgbe_free_transmit_structures(struct ix_softc *);
+void   ixgbe_free_receive_structures(struct ix_softc *);
+int    ixgbe_txeof(struct tx_ring *);
+int    ixgbe_rxeof(struct rx_ring *);
+void   ixgbe_rxrefill(void *);
+void    ixgbe_update_link_status(struct ix_softc *);
+int     ixgbe_allocate_pci_resources(struct ix_softc *);
+void    ixgbe_free_pci_resources(struct ix_softc *);
+void   ixgbe_media_status(struct ifnet *, struct ifmediareq *);
+int    ixgbe_media_change(struct ifnet *);
+void   ixgbe_add_media_types(struct ix_softc *);
+int    ixgbe_get_sffpage(struct ix_softc *, struct if_sffpage *);
+int    ixgbe_rxrinfo(struct ix_softc *, struct if_rxrinfo *);
+
+#if NKSTAT > 0
+static void    ixv_kstats(struct ix_softc *);
+static void    ixv_rxq_kstats(struct ix_softc *, struct rx_ring *);
+static void    ixv_txq_kstats(struct ix_softc *, struct tx_ring *);
+static void    ixv_kstats_tick(void *);
+#endif
+
+/*********************************************************************
+ *  OpenBSD Device Interface Entry Points
+ *********************************************************************/
+
+struct cfdriver ixv_cd = {
+       NULL, "ixv", DV_IFNET
+};
+
+const struct cfattach ixv_ca = {
+       sizeof(struct ix_softc), ixv_probe, ixv_attach, ixv_detach,
+       ixgbe_activate
+};
+
+/*
+ * This checks for a zero mac addr, something that will be likely
+ * unless the Admin on the Host has created one.
+ */
+static inline bool
+ixv_check_ether_addr(uint8_t *addr)
+{
+       bool status = TRUE;
+
+       if ((addr[0] == 0 && addr[1]== 0 && addr[2] == 0 &&
+            addr[3] == 0 && addr[4]== 0 && addr[5] == 0))
+               status = FALSE;
+
+       return (status);
+}
+
+/************************************************************************
+ * ixv_probe - Device identification routine
+ *
+ *   Determines if the driver should be loaded on
+ *   adapter based on its PCI vendor/device ID.
+ *
+ *   return BUS_PROBE_DEFAULT on success, positive on failure
+ ************************************************************************/
+static int
+ixv_probe(struct device *parent, void *match, void *aux)
+{
+       INIT_DEBUGOUT("ixv_probe: begin");
+
+       return (pci_matchbyid((struct pci_attach_args *)aux, ixv_devices,
+           nitems(ixv_devices)));
+}
+
+/*********************************************************************
+ *
+ *  Determine hardware revision.
+ *
+ **********************************************************************/
+static void
+ixv_identify_hardware(struct ix_softc *sc)
+{
+       struct ixgbe_osdep      *os = &sc->osdep;
+       struct pci_attach_args  *pa = &os->os_pa;
+       uint32_t                 reg;
+
+       /* Save off the information about this board */
+       sc->hw.vendor_id = PCI_VENDOR(pa->pa_id);
+       sc->hw.device_id = PCI_PRODUCT(pa->pa_id);
+
+       reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CLASS_REG);
+       sc->hw.revision_id = PCI_REVISION(reg);
+
+       reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
+       sc->hw.subsystem_vendor_id = PCI_VENDOR(reg);
+       sc->hw.subsystem_device_id = PCI_PRODUCT(reg);
+
+       /* Pick up the 82599 and VF settings */
+       if (sc->hw.mac.type != ixgbe_mac_82598EB)
+               sc->hw.phy.smart_speed = ixgbe_smart_speed_on;
+       sc->num_segs = IXGBE_82599_SCATTER;
+}
+
+/************************************************************************
+ * ixv_attach - Device initialization routine
+ *
+ *   Called when the driver is being loaded.
+ *   Identifies the type of hardware, allocates all resources
+ *   and initializes the hardware.
+ *
+ *   return 0 on success, positive on failure
+ ************************************************************************/
+static void
+ixv_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct pci_attach_args  *pa = (struct pci_attach_args *)aux;
+       struct ix_softc         *sc = (struct ix_softc *)self;
+       struct ixgbe_hw *hw;
+       int     error;
+
+       INIT_DEBUGOUT("ixv_attach: begin");
+
+       sc->osdep.os_sc = sc;
+       sc->osdep.os_pa = *pa;
+
+       rw_init(&sc->sfflock, "ixvsff");
+
+       /* Allocate, clear, and link in our adapter structure */
+       sc->dev = *self;
+       sc->hw.back = sc;
+       hw = &sc->hw;
+
+       /* Indicate to RX setup to use Jumbo Clusters */
+       sc->num_tx_desc = DEFAULT_TXD;
+       sc->num_rx_desc = DEFAULT_RXD;
+
+       ixv_identify_hardware(sc);
+
+#if NKSTAT > 0
+       ixv_kstats(sc);
+#endif
+
+       /* Allocate multicast array memory */
+       sc->mta = mallocarray(IXGBE_ETH_LENGTH_OF_ADDRESS,
+           IXGBE_MAX_MULTICAST_ADDRESSES_VF, M_DEVBUF, M_NOWAIT);
+       if (sc->mta == NULL) {
+               printf("Can not allocate multicast setup array\n");
+               return;
+       }
+
+       /* Do base PCI setup - map BAR0 */
+       if (ixgbe_allocate_pci_resources(sc)) {
+               printf("ixgbe_allocate_pci_resources() failed!\n");
+               goto err_out;
+       }
+
+       /* A subset of set_mac_type */
+       switch (hw->device_id) {
+       case IXGBE_DEV_ID_82599_VF:
+               hw->mac.type = ixgbe_mac_82599_vf;
+               break;
+       case IXGBE_DEV_ID_X540_VF:
+               hw->mac.type = ixgbe_mac_X540_vf;
+               break;
+       case IXGBE_DEV_ID_X550_VF:
+               hw->mac.type = ixgbe_mac_X550_vf;
+               break;
+       case IXGBE_DEV_ID_X550EM_X_VF:
+               hw->mac.type = ixgbe_mac_X550EM_x_vf;
+               break;
+       case IXGBE_DEV_ID_X550EM_A_VF:
+               hw->mac.type = ixgbe_mac_X550EM_a_vf;
+               break;
+       default:
+               /* Shouldn't get here since probe succeeded */
+               printf("Unknown device ID!\n");
+               goto err_out;
+       }
+
+       /* Initialize the shared code */
+       if (ixgbe_init_ops_vf(hw)) {
+               printf("ixgbe_init_ops_vf() failed!\n");
+               goto err_out;
+       }
+
+       /* Setup the mailbox */
+       ixgbe_init_mbx_params_vf(hw);
+
+       hw->mac.max_tx_queues = 4;
+       hw->mac.max_rx_queues = 4;
+
+       /* Set the right number of segments */
+       sc->num_segs = IXGBE_82599_SCATTER;
+
+       error = hw->mac.ops.reset_hw(hw);
+       switch (error) {
+       case 0:
+               break;
+       case IXGBE_ERR_RESET_FAILED:
+               printf("...reset_hw() failure: Reset Failed!\n");
+               goto err_out;
+       default:
+               printf("...reset_hw() failed with error %d\n",
+                   error);
+               goto err_out;
+       }
+
+       error = hw->mac.ops.init_hw(hw);
+       if (error) {
+               printf("...init_hw() failed with error %d\n",
+                   error);
+               goto err_out;
+       }
+
+       /* Negotiate mailbox API version */
+       if (ixv_negotiate_api(sc)) {
+               printf("Mailbox API negotiation failed during attach!\n");
+               goto err_out;
+       }
+
+       /* If no mac address was assigned, make a random one */
+       if (!ixv_check_ether_addr(hw->mac.addr)) {
+               uint8_t addr[ETHER_ADDR_LEN];
+               arc4random_buf(&addr, sizeof(addr));
+               addr[0] &= 0xFE;
+               addr[0] |= 0x02;
+               bcopy(addr, hw->mac.addr, sizeof(addr));
+               bcopy(addr, hw->mac.perm_addr, sizeof(addr));
+       }
+
+       bcopy(hw->mac.addr, sc->arpcom.ac_enaddr,
+           IXGBE_ETH_LENGTH_OF_ADDRESS);
+
+
+       /* Allocate our TX/RX Queues */
+       if (ixgbe_allocate_queues(sc)) {
+               printf("ixgbe_allocate_queues() failed!\n");
+               goto err_out;
+       }
+
+       /* Setup OS specific network interface */
+       ixv_setup_interface(self, sc);
+
+       /* Setup MSI-X */
+       if (ixv_allocate_msix(sc)) {
+               printf("ixv_allocate_msix() failed!\n");
+               goto err_late;
+       }
+
+       /* Check if VF was disabled by PF */
+       if (hw->mac.ops.get_link_state(hw, &sc->link_enabled)) {
+               /* PF is not capable of controlling VF state. Enable the link. 
*/
+               sc->link_enabled = TRUE;
+       }
+
+       /* Set an initial default flow control value */
+       sc->fc = ixgbe_fc_full;
+
+       INIT_DEBUGOUT("ixv_attach: end");
+
+       return;
+
+err_late:
+       ixgbe_free_transmit_structures(sc);
+       ixgbe_free_receive_structures(sc);
+err_out:
+       ixgbe_free_pci_resources(sc);
+       free(sc->mta, M_DEVBUF, IXGBE_ETH_LENGTH_OF_ADDRESS *
+            IXGBE_MAX_MULTICAST_ADDRESSES_VF);
+} /* ixv_attach */
+
+/************************************************************************
+ * ixv_detach - Device removal routine
+ *
+ *   Called when the driver is being removed.
+ *   Stops the adapter and deallocates all the resources
+ *   that were allocated for driver operation.
+ *
+ *   return 0 on success, positive on failure
+ ************************************************************************/
+static int
+ixv_detach(struct device *self, int flags)
+{
+       struct ix_softc *sc = (struct ix_softc *)self;
+       struct ifnet *ifp = &sc->arpcom.ac_if;
+
+       INIT_DEBUGOUT("ixv_detach: begin");
+
+       ixv_stop(sc);
+       ether_ifdetach(ifp);
+       if_detach(ifp);
+
+       free(sc->mta, M_DEVBUF, IXGBE_ETH_LENGTH_OF_ADDRESS *
+            IXGBE_MAX_MULTICAST_ADDRESSES_VF);
+
+       ixgbe_free_pci_resources(sc);
+
+       ixgbe_free_transmit_structures(sc);
+       ixgbe_free_receive_structures(sc);
+
+       return (0);
+} /* ixv_detach */
+
+/*********************************************************************
+ *  Watchdog entry point
+ *
+ **********************************************************************/
+static void
+ixv_watchdog(struct ifnet * ifp)
+{
+       struct ix_softc *sc = (struct ix_softc *)ifp->if_softc;
+       struct tx_ring *txr = sc->tx_rings;
+       struct ixgbe_hw *hw = &sc->hw;
+       int             tx_hang = FALSE;
+       int             i;
+
+       /*
+        * The timer is set to 5 every time ixgbe_start() queues a packet.
+        * Anytime all descriptors are clean the timer is set to 0.
+        */
+       for (i = 0; i < sc->num_queues; i++, txr++) {
+               if (txr->watchdog_timer == 0 || --txr->watchdog_timer)
+                       continue;
+               else {
+                       tx_hang = TRUE;
+                       break;
+               }
+       }
+       if (tx_hang == FALSE)
+               return;
+
+
+       printf("%s: Watchdog timeout -- resetting\n", ifp->if_xname);
+       for (i = 0; i < sc->num_queues; i++, txr++) {
+               printf("%s: Queue(%d) tdh = %d, hw tdt = %d\n", ifp->if_xname, 
i,
+                   IXGBE_READ_REG(hw, IXGBE_VFTDH(i)),
+                   IXGBE_READ_REG(hw, txr->tail));
+               printf("%s: TX(%d) Next TX to Clean = %d\n", ifp->if_xname,
+                   i, txr->next_to_clean);
+       }
+       ifp->if_flags &= ~IFF_RUNNING;
+
+       ixv_init(sc);
+}
+
+/************************************************************************
+ * ixv_init - Init entry point
+ *
+ *   Used in two ways: It is used by the stack as an init entry
+ *   point in network interface structure. It is also used
+ *   by the driver as a hw/sw initialization routine to get
+ *   to a consistent state.
+ *
+ *   return 0 on success, positive on failure
+ ************************************************************************/
+void
+ixv_init(struct ix_softc *sc)
+{
+       struct ifnet    *ifp = &sc->arpcom.ac_if;
+       struct ixgbe_hw *hw = &sc->hw;
+       int             i, s, error = 0;
+
+       INIT_DEBUGOUT("ixv_init: begin");
+
+       s = splnet();
+
+       hw->adapter_stopped = FALSE;
+       hw->mac.ops.stop_adapter(hw);
+
+       /* reprogram the RAR[0] in case user changed it. */
+       hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV);
+
+       /* Get the latest mac address, User can use a LAA */
+       bcopy(sc->arpcom.ac_enaddr, sc->hw.mac.addr,
+           IXGBE_ETH_LENGTH_OF_ADDRESS);
+
+       hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, 1);
+
+       /* Prepare transmit descriptors and buffers */
+       if (ixgbe_setup_transmit_structures(sc)) {
+               printf("Could not setup transmit structures\n");
+               ixv_stop(sc);
+               splx(s);
+               return;
+       }
+
+       /* Reset VF and renegotiate mailbox API version */
+       hw->mac.ops.reset_hw(hw);
+       error = ixv_negotiate_api(sc);
+       if (error) {
+               printf("Mailbox API negotiation failed in init!\n");
+               splx(s);
+               return;
+       }
+
+       ixv_initialize_transmit_units(sc);
+
+       /* Setup Multicast table */
+       ixv_set_multi(sc);
+
+       /* Use 2k clusters, even for jumbo frames */
+       sc->rx_mbuf_sz = MCLBYTES + ETHER_ALIGN;
+
+       /* Prepare receive descriptors and buffers */
+       if (ixgbe_setup_receive_structures(sc)) {
+               printf("Could not setup receive structures\n");
+               ixv_stop(sc);
+               splx(s);
+               return;
+       }
+
+       /* Configure RX settings */
+       ixv_initialize_receive_units(sc);
+
+       /* Set up VLAN offload and filter */
+       ixv_setup_vlan_support(sc);
+
+       /* Set up MSI-X routing */
+       ixv_configure_ivars(sc);
+
+       /* Set up auto-mask */
+       IXGBE_WRITE_REG(hw, IXGBE_VTEIAM, IXGBE_EICS_RTX_QUEUE);
+
+       if (sc->sc_intrmap) {
+               /* Set moderation on the Link interrupt */
+               IXGBE_WRITE_REG(&sc->hw, IXGBE_VTEITR(sc->linkvec),
+                   IXGBE_LINK_ITR);
+       }
+
+       /* Config/Enable Link */
+       error = hw->mac.ops.get_link_state(hw, &sc->link_enabled);
+       if (error) {
+               /* PF is not capable of controlling VF state. Enable the link. 
*/
+               sc->link_enabled = TRUE;
+       } else if (sc->link_enabled == FALSE)
+               printf("VF is disabled by PF\n");
+
+       hw->mac.ops.check_link(hw, &sc->link_speed, &sc->link_up,
+           FALSE);
+
+       /* And now turn on interrupts */
+       ixv_enable_intr(sc);
+
+       /* Now inform the stack we're ready */
+       ifp->if_flags |= IFF_RUNNING;
+       for (i = 0; i < sc->num_queues; i++)
+               ifq_clr_oactive(ifp->if_ifqs[i]);
+
+       splx(s);
+} /* ixv_init */
+
+/*
+ * MSI-X Interrupt Handlers and Tasklets
+ */
+
+static inline void
+ixv_enable_queue(struct ix_softc *sc, uint32_t vector)
+{
+       struct ixgbe_hw *hw = &sc->hw;
+       uint32_t             queue = 1 << vector;
+       uint32_t             mask;
+
+       mask = (IXGBE_EIMS_RTX_QUEUE & queue);
+       IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask);
+} /* ixv_enable_queue */
+
+static inline void
+ixv_disable_queue(struct ix_softc *sc, uint32_t vector)
+{
+       struct ixgbe_hw *hw = &sc->hw;
+       uint64_t             queue = (1ULL << vector);
+       uint32_t             mask;
+
+       mask = (IXGBE_EIMS_RTX_QUEUE & queue);
+       IXGBE_WRITE_REG(hw, IXGBE_VTEIMC, mask);
+} /* ixv_disable_queue */
+
+/************************************************************************
+ * ixv_msix_que - MSI Queue Interrupt Service routine
+ ************************************************************************/
+int
+ixv_msix_que(void *arg)
+{
+       struct ix_queue *que = arg;
+       struct ix_softc *sc = que->sc;
+       struct ifnet    *ifp = &sc->arpcom.ac_if;
+       struct tx_ring  *txr = que->txr;
+       struct rx_ring  *rxr = que->rxr;
+
+       if ((ifp->if_flags & IFF_RUNNING) == 0)
+               return 1;
+
+       ixv_disable_queue(sc, que->msix);
+
+       ixgbe_rxeof(rxr);
+       ixgbe_txeof(txr);
+       ixgbe_rxrefill(rxr);
+
+       /* Reenable this interrupt */
+       ixv_enable_queue(sc, que->msix);
+
+       return 1;
+} /* ixv_msix_que */
+
+
+/************************************************************************
+ * ixv_msix_mbx
+ ************************************************************************/
+static int
+ixv_msix_mbx(void *arg)
+{
+       struct ix_softc  *sc = arg;
+       struct ixgbe_hw *hw = &sc->hw;
+       uint32_t             reg;
+
+       /* First get the cause */
+       reg = IXGBE_READ_REG(hw, IXGBE_VTEICS);
+       /* Clear interrupt with write */
+       IXGBE_WRITE_REG(hw, IXGBE_VTEICR, reg);
+
+       IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, IXGBE_EIMS_OTHER);
+
+       ixv_handle_link(sc, 0);
+
+       return 1;
+} /* ixv_msix_mbx */
+
+/************************************************************************
+ * ixv_negotiate_api
+ *
+ *   Negotiate the Mailbox API with the PF;
+ *   start with the most featured API first.
+ ************************************************************************/
+static int
+ixv_negotiate_api(struct ix_softc *sc)
+{
+       struct ixgbe_hw *hw = &sc->hw;
+       int             mbx_api[] = { ixgbe_mbox_api_12,
+                                     ixgbe_mbox_api_11,
+                                     ixgbe_mbox_api_10,
+                                     ixgbe_mbox_api_unknown };
+       int             i = 0;
+
+       while (mbx_api[i] != ixgbe_mbox_api_unknown) {
+               if (ixgbevf_negotiate_api_version(hw, mbx_api[i]) == 0)
+                       return (0);
+               i++;
+       }
+
+       return (EINVAL);
+} /* ixv_negotiate_api */
+
+
+/************************************************************************
+ * ixv_set_multi - Multicast Update
+ *
+ *   Called whenever multicast address list is updated.
+ ************************************************************************/
+static void
+ixv_set_multi(struct ix_softc *sc)
+{
+       struct ifnet       *ifp = &sc->arpcom.ac_if;
+       struct ixgbe_hw    *hw = &sc->hw;
+       struct arpcom      *ac = &sc->arpcom;
+       uint8_t            *mta, *update_ptr;
+       struct ether_multi *enm;
+       struct ether_multistep step;
+       int                xcast_mode, mcnt = 0;
+
+       IOCTL_DEBUGOUT("ixv_set_multi: begin");
+
+        mta = sc->mta;
+       bzero(mta, sizeof(uint8_t) * IXGBE_ETH_LENGTH_OF_ADDRESS *
+             IXGBE_MAX_MULTICAST_ADDRESSES_VF);
+
+       ifp->if_flags &= ~IFF_ALLMULTI;
+       if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0 ||
+           ac->ac_multicnt > IXGBE_MAX_MULTICAST_ADDRESSES_VF) {
+               ifp->if_flags |= IFF_ALLMULTI;
+       } else {
+               ETHER_FIRST_MULTI(step, &sc->arpcom, enm);
+               while (enm != NULL) {
+                       bcopy(enm->enm_addrlo,
+                             &mta[mcnt * IXGBE_ETH_LENGTH_OF_ADDRESS],
+                             IXGBE_ETH_LENGTH_OF_ADDRESS);
+                       mcnt++;
+
+                       ETHER_NEXT_MULTI(step, enm);
+               }
+
+               update_ptr = mta;
+               hw->mac.ops.update_mc_addr_list(hw, update_ptr, mcnt,
+                                               ixv_mc_array_itr, TRUE);
+       }
+
+        /* request the most inclusive mode we need */
+        if (ISSET(ifp->if_flags, IFF_PROMISC))
+                xcast_mode = IXGBEVF_XCAST_MODE_PROMISC;
+        else if (ISSET(ifp->if_flags, IFF_ALLMULTI))
+                xcast_mode = IXGBEVF_XCAST_MODE_ALLMULTI;
+        else if (ISSET(ifp->if_flags, (IFF_BROADCAST | IFF_MULTICAST)))
+                xcast_mode = IXGBEVF_XCAST_MODE_MULTI;
+        else
+                xcast_mode = IXGBEVF_XCAST_MODE_NONE;
+
+        hw->mac.ops.update_xcast_mode(hw, xcast_mode);
+
+
+} /* ixv_set_multi */
+
+/************************************************************************
+ * ixv_mc_array_itr
+ *
+ *   An iterator function needed by the multicast shared code.
+ *   It feeds the shared code routine the addresses in the
+ *   array of ixv_set_multi() one by one.
+ ************************************************************************/
+static uint8_t *
+ixv_mc_array_itr(struct ixgbe_hw *hw, uint8_t **update_ptr, uint32_t *vmdq)
+{
+       uint8_t *mta = *update_ptr;
+
+       *vmdq = 0;
+       *update_ptr = mta + IXGBE_ETH_LENGTH_OF_ADDRESS;
+
+       return (mta);
+} /* ixv_mc_array_itr */
+
+/************************************************************************
+ * ixv_stop - Stop the hardware
+ *
+ *   Disables all traffic on the adapter by issuing a
+ *   global reset on the MAC and deallocates TX/RX buffers.
+ ************************************************************************/
+static void
+ixv_stop(void *arg)
+{
+       struct ix_softc  *sc = arg;
+       struct ifnet *ifp = &sc->arpcom.ac_if;
+       struct ixgbe_hw *hw = &sc->hw;
+       int i;
+
+       INIT_DEBUGOUT("ixv_stop: begin\n");
+#if NKSTAT > 0
+       timeout_del(&sc->sc_kstat_tmo);
+#endif
+       ixv_disable_intr(sc);
+
+
+       /* Tell the stack that the interface is no longer active */
+       ifp->if_flags &= ~IFF_RUNNING;
+
+       hw->mac.ops.reset_hw(hw);
+       sc->hw.adapter_stopped = FALSE;
+       hw->mac.ops.stop_adapter(hw);
+
+       /* reprogram the RAR[0] in case user changed it. */
+       hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV);
+
+       intr_barrier(sc->tag);
+       for (i = 0; i < sc->num_queues; i++) {
+               struct ifqueue *ifq = ifp->if_ifqs[i];
+               ifq_barrier(ifq);
+               ifq_clr_oactive(ifq);
+
+               if (sc->queues[i].tag != NULL)
+                       intr_barrier(sc->queues[i].tag);
+               timeout_del(&sc->rx_rings[i].rx_refill);
+       }
+
+       KASSERT((ifp->if_flags & IFF_RUNNING) == 0);
+
+       /* Should we really clear all structures on stop? */
+       ixgbe_free_transmit_structures(sc);
+       ixgbe_free_receive_structures(sc);
+
+       ixgbe_update_link_status(sc);
+} /* ixv_stop */
+
+/************************************************************************
+ * ixv_setup_interface
+ *
+ *   Setup networking device structure and register an interface.
+ ************************************************************************/
+static void
+ixv_setup_interface(struct device *dev, struct ix_softc *sc)
+{
+       struct ifnet *ifp;
+       int i;
+
+       ifp = &sc->arpcom.ac_if;
+
+       strlcpy(ifp->if_xname, sc->dev.dv_xname, IFNAMSIZ);
+       ifp->if_softc = sc;
+       ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+       ifp->if_xflags = IFXF_MPSAFE;
+       ifp->if_ioctl = ixv_ioctl;
+       ifp->if_qstart = ixgbe_start;
+       ifp->if_timer = 0;
+       ifp->if_watchdog = ixv_watchdog;
+       ifp->if_hardmtu = IXGBE_MAX_FRAME_SIZE -
+           ETHER_HDR_LEN - ETHER_CRC_LEN;
+       ifp->if_configure_vlan = ixv_configure_vlan;
+       ifq_set_maxlen(&ifp->if_snd, sc->num_tx_desc - 1);
+
+       ifp->if_capabilities = IFCAP_VLAN_MTU;
+
+#if NVLAN > 0
+       ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
+#endif
+
+       ifp->if_capabilities |= IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4;
+       ifp->if_capabilities |= IFCAP_CSUM_TCPv6 | IFCAP_CSUM_UDPv6;
+       ifp->if_capabilities |= IFCAP_CSUM_IPv4;
+
+       if (sc->hw.mac.type != ixgbe_mac_82598EB)
+               ifp->if_capabilities |= IFCAP_TSO;
+
+       /*
+        * Specify the media types supported by this sc and register
+        * callbacks to update media and link information
+        */
+       ifmedia_init(&sc->media, IFM_IMASK, ixgbe_media_change,
+           ixgbe_media_status);
+       ixgbe_add_media_types(sc);
+       ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO);
+
+       if_attach(ifp);
+       ether_ifattach(ifp);
+
+       if_attach_queues(ifp, sc->num_queues);
+       if_attach_iqueues(ifp, sc->num_queues);
+       for (i = 0; i < sc->num_queues; i++) {
+               struct ifqueue *ifq = ifp->if_ifqs[i];
+               struct ifiqueue *ifiq = ifp->if_iqs[i];
+               struct tx_ring *txr = &sc->tx_rings[i];
+               struct rx_ring *rxr = &sc->rx_rings[i];
+
+               ifq->ifq_softc = txr;
+               txr->ifq = ifq;
+
+               ifiq->ifiq_softc = rxr;
+               rxr->ifiq = ifiq;
+
+#if NKSTAT > 0
+               ixv_txq_kstats(sc, txr);
+               ixv_rxq_kstats(sc, rxr);
+#endif
+       }
+
+       sc->max_frame_size = IXGBE_MAX_FRAME_SIZE;
+} /* ixv_setup_interface */
+
+/************************************************************************
+ * ixv_initialize_transmit_units - Enable transmit unit.
+ ************************************************************************/
+static void
+ixv_initialize_transmit_units(struct ix_softc *sc)
+{
+        struct ifnet    *ifp = &sc->arpcom.ac_if;
+       struct tx_ring  *txr;
+       struct ixgbe_hw *hw = &sc->hw;
+       uint64_t tdba;
+       uint32_t txctrl, txdctl;
+
+       for (int i = 0; i < sc->num_queues; i++, txr++) {
+               txr = &sc->tx_rings[i];
+               tdba = txr->txdma.dma_map->dm_segs[0].ds_addr;
+
+               /* Set WTHRESH to 8, burst writeback */
+               txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(i));
+               txdctl |= (8 << 16);
+               IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(i), txdctl);
+
+               /* Set Tx Tail register */
+               txr->tail = IXGBE_VFTDT(i);
+
+               /* Set the HW Tx Head and Tail indices */
+               IXGBE_WRITE_REG(&sc->hw, IXGBE_VFTDH(i), 0);
+               IXGBE_WRITE_REG(&sc->hw, txr->tail, 0);
+
+               /* Setup Transmit Descriptor Cmd Settings */
+               txr->txd_cmd = IXGBE_TXD_CMD_IFCS;
+               txr->queue_status = IXGBE_QUEUE_IDLE;
+               txr->watchdog_timer = 0;
+
+               /* Set Ring parameters */
+               IXGBE_WRITE_REG(hw, IXGBE_VFTDBAL(i),
+                   (tdba & 0x00000000ffffffffULL));
+               IXGBE_WRITE_REG(hw, IXGBE_VFTDBAH(i), (tdba >> 32));
+               IXGBE_WRITE_REG(hw, IXGBE_VFTDLEN(i),
+                   sc->num_tx_desc * sizeof(struct ixgbe_legacy_tx_desc));
+               txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(i));
+               txctrl &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN;
+               IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(i), txctrl);
+
+               /* Now enable */
+               txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(i));
+               txdctl |= IXGBE_TXDCTL_ENABLE;
+               IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(i), txdctl);
+       }
+        ifp->if_timer = 0;
+
+       return;
+} /* ixv_initialize_transmit_units */
+
+/************************************************************************
+ * ixv_initialize_rss_mapping
+ ************************************************************************/
+static void
+ixv_initialize_rss_mapping(struct ix_softc *sc)
+{
+       struct ixgbe_hw *hw = &sc->hw;
+       uint32_t             reta = 0, mrqc, rss_key[10];
+       int             queue_id;
+       int             i, j;
+
+        /* set up random bits */
+       stoeplitz_to_key(&rss_key, sizeof(rss_key));
+
+       /* Now fill out hash function seeds */
+       for (i = 0; i < 10; i++)
+               IXGBE_WRITE_REG(hw, IXGBE_VFRSSRK(i), rss_key[i]);
+
+       /* Set up the redirection table */
+       for (i = 0, j = 0; i < 64; i++, j++) {
+               if (j == sc->num_queues)
+                       j = 0;
+
+               /*
+                * Fetch the RSS bucket id for the given indirection
+                * entry. Cap it at the number of configured buckets
+                * (which is num_queues.)
+                */
+               queue_id = queue_id % sc->num_queues;
+
+               /*
+                * The low 8 bits are for hash value (n+0);
+                * The next 8 bits are for hash value (n+1), etc.
+                */
+               reta >>= 8;
+               reta |= ((uint32_t)queue_id) << 24;
+               if ((i & 3) == 3) {
+                       IXGBE_WRITE_REG(hw, IXGBE_VFRETA(i >> 2), reta);
+                       reta = 0;
+               }
+       }
+
+ /* * Disable UDP - IP fragments aren't currently being handled * and so we end up with a mix of 2-tuple and 4-tuple * traffic. */
+       mrqc = IXGBE_MRQC_RSSEN
+               | IXGBE_MRQC_RSS_FIELD_IPV4
+               | IXGBE_MRQC_RSS_FIELD_IPV4_TCP
+               | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP
+               | IXGBE_MRQC_RSS_FIELD_IPV6_EX
+               | IXGBE_MRQC_RSS_FIELD_IPV6
+               | IXGBE_MRQC_RSS_FIELD_IPV6_TCP
+       ;
+       IXGBE_WRITE_REG(hw, IXGBE_VFMRQC, mrqc);
+} /* ixv_initialize_rss_mapping */
+
+
+/************************************************************************
+ * ixv_initialize_receive_units - Setup receive registers and features.
+ ************************************************************************/
+static void
+ixv_initialize_receive_units(struct ix_softc *sc)
+{
+       struct rx_ring  *rxr = sc->rx_rings;
+       struct ixgbe_hw *hw = &sc->hw;
+       uint32_t             bufsz, psrtype;
+
+       bufsz = (sc->rx_mbuf_sz - ETHER_ALIGN) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+
+       psrtype = IXGBE_PSRTYPE_TCPHDR
+               | IXGBE_PSRTYPE_UDPHDR
+               | IXGBE_PSRTYPE_IPV4HDR
+               | IXGBE_PSRTYPE_IPV6HDR
+               | IXGBE_PSRTYPE_L2HDR;
+
+       if (sc->num_queues > 1)
+               psrtype |= 1 << 29;
+
+       IXGBE_WRITE_REG(hw, IXGBE_VFPSRTYPE, psrtype);
+
+       /* Tell PF our max_frame size */
+       if (ixgbevf_rlpml_set_vf(hw, sc->max_frame_size) != 0) {
+               printf("There is a problem with the PF setup."
+                      "  It is likely the receive unit for this VF will not 
function correctly.\n");
+       }
+
+       for (int i = 0; i < sc->num_queues; i++, rxr++) {
+                uint64_t rdba = rxr->rxdma.dma_map->dm_segs[0].ds_addr;
+               uint32_t reg, rxdctl;
+
+               /* Disable the queue */
+               rxdctl = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i));
+               rxdctl &= ~IXGBE_RXDCTL_ENABLE;
+               IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(i), rxdctl);
+               for (int j = 0; j < 10; j++) {
+                       if (IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i)) &
+                           IXGBE_RXDCTL_ENABLE)
+                               msec_delay(1);
+                       else
+                               break;
+               }
+
+               /* Setup the Base and Length of the Rx Descriptor Ring */
+               IXGBE_WRITE_REG(hw, IXGBE_VFRDBAL(i),
+                   (rdba & 0x00000000ffffffffULL));
+               IXGBE_WRITE_REG(hw, IXGBE_VFRDBAH(i), (rdba >> 32));
+               IXGBE_WRITE_REG(hw, IXGBE_VFRDLEN(i),
+                   sc->num_rx_desc * sizeof(union ixgbe_adv_rx_desc));
+
+               /* Capture Rx Tail index */
+               rxr->tail = IXGBE_VFRDT(rxr->me);
+
+               /* Reset the ring indices */
+               IXGBE_WRITE_REG(hw, IXGBE_VFRDH(rxr->me), 0);
+               IXGBE_WRITE_REG(hw, rxr->tail, 0);
+
+               /* Set up the SRRCTL register */
+               reg = IXGBE_READ_REG(hw, IXGBE_VFSRRCTL(i));
+               reg &= ~IXGBE_SRRCTL_BSIZEHDR_MASK;
+               reg &= ~IXGBE_SRRCTL_BSIZEPKT_MASK;
+               reg |= bufsz;
+               reg |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
+               IXGBE_WRITE_REG(hw, IXGBE_VFSRRCTL(i), reg);
+
+               /* Do the queue enabling last */
+               rxdctl |= IXGBE_RXDCTL_ENABLE | IXGBE_RXDCTL_VME;
+               IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(i), rxdctl);
+               for (int k = 0; k < 10; k++) {
+                       if (IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i)) &
+                           IXGBE_RXDCTL_ENABLE)
+                               break;
+                       msec_delay(1);
+               }
+
+               /* Set the Tail Pointer */
+               IXGBE_WRITE_REG(hw, IXGBE_VFRDT(rxr->me),
+                               sc->num_rx_desc - 1);
+       }
+
+       /*
+        * Do not touch RSS and RETA settings for older hardware
+        * as those are shared among PF and all VF.
+        */
+       if (sc->hw.mac.type >= ixgbe_mac_X550_vf)
+               ixv_initialize_rss_mapping(sc);
+
+       return;
+} /* ixv_initialize_receive_units */
+
+/************************************************************************
+ * ixv_setup_vlan_support
+ ************************************************************************/
+static void
+ixv_setup_vlan_support(struct ix_softc *sc)
+{
+       struct ixgbe_hw *hw = &sc->hw;
+       uint32_t             ctrl, vid, vfta, retry;
+
+       /*
+        * We get here thru init, meaning
+        * a soft reset, this has already cleared
+        * the VFTA and other state, so if there
+        * have been no vlan's registered do nothing.
+        */
+       if (sc->num_vlans == 0) {
+               sc->vlan_stripping = 0;
+               return;
+       }
+       sc->vlan_stripping = 1;
+
+       /* Enable the queues */
+       for (int i = 0; i < sc->num_queues; i++) {
+               ctrl = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i));
+               ctrl |= IXGBE_RXDCTL_VME;
+               IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(i), ctrl);
+               /*
+                * Let Rx path know that it needs to store VLAN tag
+                * as part of extra mbuf info.
+                */
+       }
+
+       /*
+        * A soft reset zero's out the VFTA, so
+        * we need to repopulate it now.
+        */
+       for (int i = 0; i < IXGBE_VFTA_SIZE; i++) {
+               if (sc->shadow_vfta[i] == 0)
+                       continue;
+               vfta = sc->shadow_vfta[i];
+               /*
+                * Reconstruct the vlan id's
+                * based on the bits set in each
+                * of the array ints.
+                */
+               for (int j = 0; j < 32; j++) {
+                       retry = 0;
+                       if ((vfta & (1 << j)) == 0)
+                               continue;
+                       vid = (i * 32) + j;
+                       /* Call the shared code mailbox routine */
+                       while (hw->mac.ops.set_vfta(hw, vid, 0, TRUE, FALSE)) {
+                               if (++retry > 5)
+                                       break;
+                       }
+               }
+       }
+} /* ixv_setup_vlan_support */
+
+static void
+ixv_configure_vlan(struct ifnet *ifp, uint16_t vtag_add, uint16_t vtag_del)
+{
+       struct ix_softc *sc = ifp->if_softc;
+       uint16_t            index, bit;
+
+       if ((vtag_add > 0) && (vtag_add < 4096)) {
+               index = (vtag_add >> 5) & 0x7F;
+               bit = vtag_add & 0x1F;
+               sc->shadow_vfta[index] |= (1 << bit);
+               ++sc->num_vlans;
+       }
+
+       if ((vtag_del > 0) && (vtag_del < 4096) && (sc->num_vlans > 0)) {
+               index = (vtag_del >> 5) & 0x7F;
+               bit = vtag_del & 0x1F;
+               sc->shadow_vfta[index] &= ~(1 << bit);
+               --sc->num_vlans;
+       }
+
+       /* Re-init to load the changes */
+       ixv_init(sc);
+} /* ixv_configure_vlan */
+
+/************************************************************************
+ * ixv_enable_intr
+ ************************************************************************/
+static void
+ixv_enable_intr(struct ix_softc *sc)
+{
+       struct ixgbe_hw *hw = &sc->hw;
+       struct ix_queue *que = sc->queues;
+       uint32_t             mask = (IXGBE_EIMS_ENABLE_MASK & 
~IXGBE_EIMS_RTX_QUEUE);
+
+
+       IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask);
+
+       mask = IXGBE_EIMS_ENABLE_MASK;
+       mask &= ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC);
+       IXGBE_WRITE_REG(hw, IXGBE_VTEIAC, mask);
+
+       for (int i = 0; i < sc->num_queues; i++, que++)
+               ixv_enable_queue(sc, que->msix);
+
+       IXGBE_WRITE_FLUSH(hw);
+
+       return;
+} /* ixv_enable_intr */
+
+/************************************************************************
+ * ixv_disable_intr
+ ************************************************************************/
+static void
+ixv_disable_intr(struct ix_softc *sc)
+{
+       IXGBE_WRITE_REG(&sc->hw, IXGBE_VTEIAC, 0);
+       IXGBE_WRITE_REG(&sc->hw, IXGBE_VTEIMC, ~0);
+       IXGBE_WRITE_FLUSH(&sc->hw);
+
+       return;
+} /* ixv_disable_intr */
+
+/************************************************************************
+ * ixv_set_ivar
+ *
+ *   Setup the correct IVAR register for a particular MSI-X interrupt
+ *    - entry is the register array entry
+ *    - vector is the MSI-X vector for this queue
+ *    - type is RX/TX/MISC
+ ************************************************************************/
+static void
+ixv_set_ivar(struct ix_softc *sc, uint8_t entry, uint8_t vector, int8_t type)
+{
+       struct ixgbe_hw *hw = &sc->hw;
+       uint32_t             ivar, index;
+
+       vector |= IXGBE_IVAR_ALLOC_VAL;
+
+       if (type == -1) { /* MISC IVAR */
+               ivar = IXGBE_READ_REG(hw, IXGBE_VTIVAR_MISC);
+               ivar &= ~0xFF;
+               ivar |= vector;
+               IXGBE_WRITE_REG(hw, IXGBE_VTIVAR_MISC, ivar);
+       } else {          /* RX/TX IVARS */
+               index = (16 * (entry & 1)) + (8 * type);
+               ivar = IXGBE_READ_REG(hw, IXGBE_VTIVAR(entry >> 1));
+               ivar &= ~(0xFF << index);
+               ivar |= (vector << index);
+               IXGBE_WRITE_REG(hw, IXGBE_VTIVAR(entry >> 1), ivar);
+       }
+} /* ixv_set_ivar */
+
+/************************************************************************
+ * ixv_configure_ivars
+ ************************************************************************/
+static void
+ixv_configure_ivars(struct ix_softc *sc)
+{
+       struct ix_queue *que = sc->queues;
+
+       for (int i = 0; i < sc->num_queues; i++, que++) {
+               /* First the RX queue entry */
+               ixv_set_ivar(sc, i, que->msix, 0);
+               /* ... and the TX */
+               ixv_set_ivar(sc, i, que->msix, 1);
+               /* Set an initial value in EITR */
+               IXGBE_WRITE_REG(&sc->hw, IXGBE_VTEITR(que->msix),
+                   IXGBE_EITR_DEFAULT);
+       }
+
+       /* For the mailbox interrupt */
+       ixv_set_ivar(sc, 1, sc->linkvec, -1);
+} /* ixv_configure_ivars */
+
+/************************************************************************
+ * ixv_ioctl - Ioctl entry point
+ *
+ *   Called when the user wants to configure the interface.
+ *
+ *   return 0 on success, positive on failure
+ ************************************************************************/
+static int
+ixv_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+{
+       struct ix_softc *sc = ifp->if_softc;
+       struct ifreq   *ifr = (struct ifreq *)data;
+       int             s, error = 0;
+
+       s = splnet();
+
+       switch (command) {
+       case SIOCSIFADDR:
+               IOCTL_DEBUGOUT("ioctl: SIOCxIFADDR (Get/Set Interface Addr)");
+               ifp->if_flags |= IFF_UP;
+               if (!(ifp->if_flags & IFF_RUNNING))
+                       ixv_init(sc);
+               break;
+
+       case SIOCSIFFLAGS:
+               IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)");
+               if (ifp->if_flags & IFF_UP) {
+                       if (ifp->if_flags & IFF_RUNNING)
+                               error = ENETRESET;
+                       else
+                               ixv_init(sc);
+               } else {
+                       if (ifp->if_flags & IFF_RUNNING)
+                               ixv_stop(sc);
+               }
+               break;
+
+       case SIOCSIFMEDIA:
+       case SIOCGIFMEDIA:
+               IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)");
+               error = ifmedia_ioctl(ifp, ifr, &sc->media, command);
+               break;
+
+       case SIOCGIFRXR:
+               error = ixgbe_rxrinfo(sc, (struct if_rxrinfo *)ifr->ifr_data);
+               break;
+
+       case SIOCGIFSFFPAGE:
+               error = rw_enter(&sc->sfflock, RW_WRITE|RW_INTR);
+               if (error != 0)
+                       break;
+
+               error = ixgbe_get_sffpage(sc, (struct if_sffpage *)data);
+               rw_exit(&sc->sfflock);
+               break;
+
+       default:
+               error = ether_ioctl(ifp, &sc->arpcom, command, data);
+       }
+
+       if (error == ENETRESET) {
+               if (ifp->if_flags & IFF_RUNNING) {
+                       ixv_disable_intr(sc);
+                       ixv_set_multi(sc);
+                       ixv_enable_intr(sc);
+               }
+               error = 0;
+       }
+
+       splx(s);
+       return (error);
+} /* ixv_ioctl */
+
+/************************************************************************
+ * ixv_allocate_msix - Setup MSI-X Interrupt resources and handlers
+ ************************************************************************/
+static int
+ixv_allocate_msix(struct ix_softc *sc)
+{
+        struct ixgbe_osdep      *os = &sc->osdep;
+        struct pci_attach_args  *pa  = &os->os_pa;
+       int                      i = 0, error = 0;
+       struct ix_queue         *que;
+       pci_intr_handle_t       ih;
+       pcireg_t                reg, msix_ctrl;
+
+       for (i = 0, que = sc->queues; i < sc->num_queues; i++, que++) {
+               if (pci_intr_map_msix(pa, i, &ih)) {
+                       printf("ixv_allocate_msix: "
+                              "pci_intr_map_msix vec %d failed\n", i);
+                       error = ENOMEM;
+                       goto fail;
+               }
+
+               que->tag = pci_intr_establish_cpu(pa->pa_pc, ih,
+                       IPL_NET | IPL_MPSAFE, intrmap_cpu(sc->sc_intrmap, i),
+                       ixv_msix_que, que, que->name);
+               if (que->tag == NULL) {
+                       printf("ixv_allocate_msix: "
+                              "pci_intr_establish vec %d failed\n", i);
+                       error = ENOMEM;
+                       goto fail;
+               }
+
+               que->msix = i;
+       }
+
+       /* and Mailbox */
+       if (pci_intr_map_msix(pa, i, &ih)) {
+               printf("ixgbe_allocate_msix: "
+                      "pci_intr_map_msix mbox vector failed\n");
+               error = ENOMEM;
+               goto fail;
+       }
+
+       sc->tag = pci_intr_establish(pa->pa_pc, ih, IPL_NET | IPL_MPSAFE,
+                       ixv_msix_mbx, sc, sc->dev.dv_xname);
+       if (sc->tag == NULL) {
+               printf("ixv_allocate_msix: "
+                      "pci_intr_establish mbox vector failed\n");
+               error = ENOMEM;
+               goto fail;
+       }
+       sc->linkvec = i;
+
+       /*
+        * Due to a broken design QEMU will fail to properly
+        * enable the guest for MSI-X unless the vectors in
+        * the table are all set up, so we must rewrite the
+        * ENABLE in the MSI-X control register again at this
+        * point to cause it to successfully initialize us.
+        */
+       if (sc->hw.mac.type == ixgbe_mac_82599_vf &&
+           pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_MSIX, NULL, 
&reg)) {
+               reg += PCIR_MSIX_CTRL;
+               msix_ctrl = pci_conf_read(pa->pa_pc, pa->pa_tag, reg);
+               msix_ctrl |= PCI_MSIX_MC_MSIXE;
+               pci_conf_write(pa->pa_pc, pa->pa_tag, msix_ctrl, reg);
+       }
+
+       printf(", %s, %d queue%s\n", pci_intr_string(pa->pa_pc, ih),
+           i, (i > 1) ? "s" : "");
+
+       return (0);
+
+fail:
+       for (que = sc->queues; i > 0; i--, que++) {
+               if (que->tag == NULL)
+                       continue;
+               pci_intr_disestablish(pa->pa_pc, que->tag);
+               que->tag = NULL;
+       }
+       return (error);
+} /* ixv_allocate_msix */
+
+/************************************************************************
+ * ixv_handle_link - Tasklet handler for MSI-X MBX interrupts
+ *
+ *   Done outside of interrupt context since the driver might sleep
+ ************************************************************************/
+static void
+ixv_handle_link(void *context, int pending)
+{
+       struct ix_softc *sc = context;
+
+       sc->hw.mac.ops.check_link(&sc->hw, &sc->link_speed,
+           &sc->link_up, FALSE);
+       ixgbe_update_link_status(sc);
+} /* ixv_handle_link */
+
+#if NKSTAT > 0
+enum ixv_counter_idx {
+       ixv_good_packets_received_count,
+       ixv_good_packets_transmitted_count,
+       ixv_good_octets_received_count,
+       ixv_good_octets_transmitted_count,
+       ixv_multicast_packets_received_count,
+
+       ixv_counter_num,
+};
+
+CTASSERT(KSTAT_KV_U_PACKETS <= 0xff);
+CTASSERT(KSTAT_KV_U_BYTES <= 0xff);
+
+struct ixv_counter {
+       char                     name[KSTAT_KV_NAMELEN];
+       uint32_t                 reg;
+       uint8_t                  width;
+       uint8_t                  unit;
+};
+
+static const struct ixv_counter ixv_counters[ixv_counter_num] = {
+       [ixv_good_packets_received_count] = { "rx good",  IXGBE_VFGPRC, 32, 
KSTAT_KV_U_PACKETS },
+       [ixv_good_packets_transmitted_count] = { "tx good",  IXGBE_VFGPTC, 32, 
KSTAT_KV_U_PACKETS },
+       [ixv_good_octets_received_count] = { "rx total",  IXGBE_VFGORC_LSB, 36, 
KSTAT_KV_U_BYTES },
+       [ixv_good_octets_transmitted_count] = { "tx total",  IXGBE_VFGOTC_LSB, 
36, KSTAT_KV_U_BYTES },
+       [ixv_multicast_packets_received_count] = { "rx mcast",  IXGBE_VFMPRC, 
32, KSTAT_KV_U_PACKETS },
+};
+
+struct ixv_rxq_kstats {
+       struct kstat_kv qprc;
+       struct kstat_kv qbrc;
+       struct kstat_kv qprdc;
+};
+
+static const struct ixv_rxq_kstats ixv_rxq_kstats_tpl = {
+       KSTAT_KV_UNIT_INITIALIZER("packets",
+           KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS),
+       KSTAT_KV_UNIT_INITIALIZER("bytes",
+           KSTAT_KV_T_COUNTER64, KSTAT_KV_U_BYTES),
+       KSTAT_KV_UNIT_INITIALIZER("qdrops",
+           KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS),
+};
+
+struct ixv_txq_kstats {
+       struct kstat_kv qptc;
+       struct kstat_kv qbtc;
+};
+
+static const struct ixv_txq_kstats ixv_txq_kstats_tpl = {
+       KSTAT_KV_UNIT_INITIALIZER("packets",
+           KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS),
+       KSTAT_KV_UNIT_INITIALIZER("bytes",
+           KSTAT_KV_T_COUNTER64, KSTAT_KV_U_BYTES),
+};
+
+static int     ixv_kstats_read(struct kstat *ks);
+static int     ixv_rxq_kstats_read(struct kstat *ks);
+static int     ixv_txq_kstats_read(struct kstat *ks);
+
+static void
+ixv_kstats(struct ix_softc *sc)
+{
+       struct kstat *ks;
+       struct kstat_kv *kvs;
+       unsigned int i;
+
+       mtx_init(&sc->sc_kstat_mtx, IPL_SOFTCLOCK);
+       timeout_set(&sc->sc_kstat_tmo, ixv_kstats_tick, sc);
+
+       ks = kstat_create(sc->dev.dv_xname, 0, "ixv-stats", 0,
+           KSTAT_T_KV, 0);
+       if (ks == NULL)
+               return;
+
+       kvs = mallocarray(nitems(ixv_counters), sizeof(*kvs),
+           M_DEVBUF, M_WAITOK|M_ZERO);
+
+       for (i = 0; i < nitems(ixv_counters); i++) {
+               const struct ixv_counter *ixc = &ixv_counters[i];
+
+               kstat_kv_unit_init(&kvs[i], ixc->name,
+                   KSTAT_KV_T_COUNTER64, ixc->unit);
+       }
+
+       kstat_set_mutex(ks, &sc->sc_kstat_mtx);
+       ks->ks_softc = sc;
+       ks->ks_data = kvs;
+       ks->ks_datalen = nitems(ixv_counters) * sizeof(*kvs);
+       ks->ks_read = ixv_kstats_read;
+
+       sc->sc_kstat = ks;
+       kstat_install(ks);
+}
+
+static void
+ixv_rxq_kstats(struct ix_softc *sc, struct rx_ring *rxr)
+{
+       struct ixv_rxq_kstats *stats;
+       struct kstat *ks;
+
+       ks = kstat_create(sc->dev.dv_xname, 0, "ixv-rxq", rxr->me,
+           KSTAT_T_KV, 0);
+       if (ks == NULL)
+               return;
+
+       stats = malloc(sizeof(*stats), M_DEVBUF, M_WAITOK|M_ZERO);
+       *stats = ixv_rxq_kstats_tpl;
+
+       kstat_set_mutex(ks, &sc->sc_kstat_mtx);
+       ks->ks_softc = rxr;
+       ks->ks_data = stats;
+       ks->ks_datalen = sizeof(*stats);
+       ks->ks_read = ixv_rxq_kstats_read;
+
+       rxr->kstat = ks;
+       kstat_install(ks);
+}
+
+static void
+ixv_txq_kstats(struct ix_softc *sc, struct tx_ring *txr)
+{
+       struct ixv_txq_kstats *stats;
+       struct kstat *ks;
+
+       ks = kstat_create(sc->dev.dv_xname, 0, "ixv-txq", txr->me,
+           KSTAT_T_KV, 0);
+       if (ks == NULL)
+               return;
+
+       stats = malloc(sizeof(*stats), M_DEVBUF, M_WAITOK|M_ZERO);
+       *stats = ixv_txq_kstats_tpl;
+
+       kstat_set_mutex(ks, &sc->sc_kstat_mtx);
+       ks->ks_softc = txr;
+       ks->ks_data = stats;
+       ks->ks_datalen = sizeof(*stats);
+       ks->ks_read = ixv_txq_kstats_read;
+
+       txr->kstat = ks;
+       kstat_install(ks);
+}
+
+/**********************************************************************
+ *
+ *  Update the board statistics counters.
+ *
+ **********************************************************************/
+
+static void
+ixv_kstats_tick(void *arg)
+{
+       struct ix_softc *sc = arg;
+       int i;
+
+       timeout_add_sec(&sc->sc_kstat_tmo, 1);
+
+       mtx_enter(&sc->sc_kstat_mtx);
+       ixv_kstats_read(sc->sc_kstat);
+       for (i = 0; i < sc->num_queues; i++) {
+               ixv_rxq_kstats_read(sc->rx_rings[i].kstat);
+               ixv_txq_kstats_read(sc->tx_rings[i].kstat);
+       }
+       mtx_leave(&sc->sc_kstat_mtx);
+}
+
+static uint64_t
+ixv_read36(struct ixgbe_hw *hw, bus_size_t loreg, bus_size_t hireg)
+{
+       uint64_t lo, hi;
+
+       lo = IXGBE_READ_REG(hw, loreg);
+       hi = IXGBE_READ_REG(hw, hireg);
+
+       return (((hi & 0xf) << 32) | lo);
+}
+
+static int
+ixv_kstats_read(struct kstat *ks)
+{
+       struct ix_softc *sc = ks->ks_softc;
+       struct kstat_kv *kvs = ks->ks_data;
+       struct ixgbe_hw *hw = &sc->hw;
+       unsigned int i;
+
+       for (i = 0; i < nitems(ixv_counters); i++) {
+               const struct ixv_counter *ixc = &ixv_counters[i];
+               uint32_t reg = ixc->reg;
+               uint64_t v;
+
+               if (reg == 0)
+                       continue;
+
+               if (ixc->width > 32) {
+                       if (sc->hw.mac.type == ixgbe_mac_82598EB)
+                               v = IXGBE_READ_REG(hw, reg + 4);
+                       else
+                               v = ixv_read36(hw, reg, reg + 4);
+               } else
+                       v = IXGBE_READ_REG(hw, reg);
+
+               kstat_kv_u64(&kvs[i]) = v;
+       }
+
+       getnanouptime(&ks->ks_updated);
+
+       return (0);
+}
+
+int
+ixv_rxq_kstats_read(struct kstat *ks)
+{
+       struct ixv_rxq_kstats *stats = ks->ks_data;
+       struct rx_ring *rxr = ks->ks_softc;
+       struct ix_softc *sc = rxr->sc;
+       struct ixgbe_hw *hw = &sc->hw;
+       uint32_t i = rxr->me;
+
+       kstat_kv_u64(&stats->qprc) += IXGBE_READ_REG(hw, IXGBE_QPRC(i));
+       if (sc->hw.mac.type == ixgbe_mac_82598EB) {
+               kstat_kv_u64(&stats->qprdc) +=
+                   IXGBE_READ_REG(hw, IXGBE_RNBC(i));
+               kstat_kv_u64(&stats->qbrc) +=
+                   IXGBE_READ_REG(hw, IXGBE_QBRC(i));
+       } else {
+               kstat_kv_u64(&stats->qprdc) +=
+                   IXGBE_READ_REG(hw, IXGBE_QPRDC(i));
+               kstat_kv_u64(&stats->qbrc) +=
+                   ixv_read36(hw, IXGBE_QBRC_L(i), IXGBE_QBRC_H(i));
+       }
+
+       getnanouptime(&ks->ks_updated);
+
+       return (0);
+}
+
+int
+ixv_txq_kstats_read(struct kstat *ks)
+{
+       struct ixv_txq_kstats *stats = ks->ks_data;
+       struct tx_ring *txr = ks->ks_softc;
+       struct ix_softc *sc = txr->sc;
+       struct ixgbe_hw *hw = &sc->hw;
+       uint32_t i = txr->me;
+
+       kstat_kv_u64(&stats->qptc) += IXGBE_READ_REG(hw, IXGBE_QPTC(i));
+       if (sc->hw.mac.type == ixgbe_mac_82598EB) {
+               kstat_kv_u64(&stats->qbtc) +=
+                   IXGBE_READ_REG(hw, IXGBE_QBTC(i));
+       } else {
+               kstat_kv_u64(&stats->qbtc) +=
+                   ixv_read36(hw, IXGBE_QBTC_L(i), IXGBE_QBTC_H(i));
+       }
+
+       getnanouptime(&ks->ks_updated);
+
+       return (0);
+}
+#endif /* NKVSTAT > 0 */
diff --git a/sys/dev/pci/ixgbe.c b/sys/dev/pci/ixgbe.c
index 0fd3b9b8fbf..b395715ed27 100644
--- a/sys/dev/pci/ixgbe.c
+++ b/sys/dev/pci/ixgbe.c
@@ -70,7 +70,6 @@ int32_t prot_autoc_write_generic(struct ixgbe_hw *, uint32_t, 
bool);
 /* MBX */
 int32_t ixgbe_poll_for_msg(struct ixgbe_hw *hw, uint16_t mbx_id);
 int32_t ixgbe_poll_for_ack(struct ixgbe_hw *hw, uint16_t mbx_id);
-uint32_t ixgbe_read_v2p_mailbox(struct ixgbe_hw *hw);
 int32_t ixgbe_check_for_bit_pf(struct ixgbe_hw *hw, uint32_t mask,
                               int32_t index);
 int32_t ixgbe_check_for_msg_pf(struct ixgbe_hw *hw, uint16_t vf_number);
@@ -4473,7 +4472,6 @@ void ixgbe_enable_rx(struct ixgbe_hw *hw)
 int32_t ixgbe_read_mbx(struct ixgbe_hw *hw, uint32_t *msg, uint16_t size, 
uint16_t mbx_id)
 {
        struct ixgbe_mbx_info *mbx = &hw->mbx;
-       int32_t ret_val = IXGBE_ERR_MBX;

        DEBUGFUNC("ixgbe_read_mbx");

@@ -4482,7 +4480,40 @@ int32_t ixgbe_read_mbx(struct ixgbe_hw *hw, uint32_t 
*msg, uint16_t size, uint16
                size = mbx->size;

        if (mbx->ops.read)
-               ret_val = mbx->ops.read(hw, msg, size, mbx_id);
+           return mbx->ops.read(hw, msg, size, mbx_id);
+
+       return IXGBE_ERR_CONFIG;
+}
+
+/**
+ * ixgbe_poll_mbx - Wait for message and read it from the mailbox
+ * @hw: pointer to the HW structure
+ * @msg: The message buffer
+ * @size: Length of buffer
+ * @mbx_id: id of mailbox to read
+ *
+ * returns SUCCESS if it successfully read message from buffer
+ **/
+int32_t ixgbe_poll_mbx(struct ixgbe_hw *hw, uint32_t *msg, uint16_t size,
+                      uint16_t mbx_id)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+       int32_t ret_val;
+
+       DEBUGFUNC("ixgbe_poll_mbx");
+
+       if (!mbx->ops.read || !mbx->ops.check_for_msg ||
+           !mbx->timeout)
+               return IXGBE_ERR_CONFIG;
+
+       /* limit read to size of mailbox */
+       if (size > mbx->size)
+               size = mbx->size;
+
+       ret_val = ixgbe_poll_for_msg(hw, mbx_id);
+       /* if ack received read message, otherwise we timed out */
+       if (!ret_val)
+               return mbx->ops.read(hw, msg, size, mbx_id);

        return ret_val;
 }
@@ -4499,15 +4530,25 @@ int32_t ixgbe_read_mbx(struct ixgbe_hw *hw, uint32_t 
*msg, uint16_t size, uint16
 int32_t ixgbe_write_mbx(struct ixgbe_hw *hw, uint32_t *msg, uint16_t size, 
uint16_t mbx_id)
 {
        struct ixgbe_mbx_info *mbx = &hw->mbx;
-       int32_t ret_val = IXGBE_SUCCESS;
+       int32_t ret_val = IXGBE_ERR_MBX;

        DEBUGFUNC("ixgbe_write_mbx");

-       if (size > mbx->size)
-               ret_val = IXGBE_ERR_MBX;
+       /*
+        * exit if either we can't write, release
+        * or there is no timeout defined
+        */
+       if (!mbx->ops.write || !mbx->ops.check_for_ack ||
+           !mbx->ops.release || !mbx->timeout)
+               return IXGBE_ERR_CONFIG;

-       else if (mbx->ops.write)
+       if (size > mbx->size) {
+               ret_val = IXGBE_ERR_PARAM;
+               ERROR_REPORT2(IXGBE_ERROR_ARGUMENT,
+                            "Invalid mailbox message size %u", size);
+       } else {
                ret_val = mbx->ops.write(hw, msg, size, mbx_id);
+       }

        return ret_val;
 }
@@ -4587,7 +4628,7 @@ int32_t ixgbe_poll_for_msg(struct ixgbe_hw *hw, uint16_t 
mbx_id)
        DEBUGFUNC("ixgbe_poll_for_msg");

        if (!countdown || !mbx->ops.check_for_msg)
-               goto out;
+               return IXGBE_ERR_CONFIG;

        while (countdown && mbx->ops.check_for_msg(hw, mbx_id)) {
                countdown--;
@@ -4596,12 +4637,13 @@ int32_t ixgbe_poll_for_msg(struct ixgbe_hw *hw, 
uint16_t mbx_id)
                usec_delay(mbx->usec_delay);
        }

-       if (countdown == 0)
+       if (countdown == 0) {
                ERROR_REPORT2(IXGBE_ERROR_POLLING,
-                          "Polling for VF%d mailbox message timedout", mbx_id);
+                          "Polling for VF%u mailbox message timedout", mbx_id);
+               return IXGBE_ERR_TIMEOUT;
+       }

-out:
-       return countdown ? IXGBE_SUCCESS : IXGBE_ERR_MBX;
+       return IXGBE_SUCCESS;
 }

 /**
@@ -4619,7 +4661,7 @@ int32_t ixgbe_poll_for_ack(struct ixgbe_hw *hw, uint16_t 
mbx_id)
        DEBUGFUNC("ixgbe_poll_for_ack");

        if (!countdown || !mbx->ops.check_for_ack)
-               goto out;
+               return IXGBE_ERR_CONFIG;

        while (countdown && mbx->ops.check_for_ack(hw, mbx_id)) {
                countdown--;
@@ -4628,12 +4670,180 @@ int32_t ixgbe_poll_for_ack(struct ixgbe_hw *hw, 
uint16_t mbx_id)
                usec_delay(mbx->usec_delay);
        }

-       if (countdown == 0)
+       if (countdown == 0) {
                ERROR_REPORT2(IXGBE_ERROR_POLLING,
-                            "Polling for VF%d mailbox ack timedout", mbx_id);
+                            "Polling for VF%u mailbox ack timedout", mbx_id);
+               return IXGBE_ERR_TIMEOUT;
+       }

-out:
-       return countdown ? IXGBE_SUCCESS : IXGBE_ERR_MBX;
+       return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_read_mailbox_vf - read VF's mailbox register
+ * @hw: pointer to the HW structure
+ *
+ * This function is used to read the mailbox register dedicated for VF without
+ * losing the read to clear status bits.
+ **/
+static uint32_t ixgbe_read_mailbox_vf(struct ixgbe_hw *hw)
+{
+       uint32_t vf_mailbox = IXGBE_READ_REG(hw, IXGBE_VFMAILBOX);
+
+       vf_mailbox |= hw->mbx.vf_mailbox;
+       hw->mbx.vf_mailbox |= vf_mailbox & IXGBE_VFMAILBOX_R2C_BITS;
+
+       return vf_mailbox;
+}
+
+static void ixgbe_clear_msg_vf(struct ixgbe_hw *hw)
+{
+       uint32_t vf_mailbox = ixgbe_read_mailbox_vf(hw);
+
+       if (vf_mailbox & IXGBE_VFMAILBOX_PFSTS) {
+               hw->mbx.stats.reqs++;
+               hw->mbx.vf_mailbox &= ~IXGBE_VFMAILBOX_PFSTS;
+       }
+}
+
+static void ixgbe_clear_ack_vf(struct ixgbe_hw *hw)
+{
+       uint32_t vf_mailbox = ixgbe_read_mailbox_vf(hw);
+
+       if (vf_mailbox & IXGBE_VFMAILBOX_PFACK) {
+               hw->mbx.stats.acks++;
+               hw->mbx.vf_mailbox &= ~IXGBE_VFMAILBOX_PFACK;
+       }
+}
+
+static void ixgbe_clear_rst_vf(struct ixgbe_hw *hw)
+{
+       uint32_t vf_mailbox = ixgbe_read_mailbox_vf(hw);
+
+       if (vf_mailbox & (IXGBE_VFMAILBOX_RSTI | IXGBE_VFMAILBOX_RSTD)) {
+               hw->mbx.stats.rsts++;
+               hw->mbx.vf_mailbox &= ~(IXGBE_VFMAILBOX_RSTI |
+                                       IXGBE_VFMAILBOX_RSTD);
+       }
+}
+
+/**
+ * ixgbe_check_for_bit_vf - Determine if a status bit was set
+ * @hw: pointer to the HW structure
+ * @mask: bitmask for bits to be tested and cleared
+ *
+ * This function is used to check for the read to clear bits within
+ * the V2P mailbox.
+ **/
+static int32_t ixgbe_check_for_bit_vf(struct ixgbe_hw *hw, uint32_t mask)
+{
+       uint32_t vf_mailbox = ixgbe_read_mailbox_vf(hw);
+
+       if (vf_mailbox & mask)
+               return IXGBE_SUCCESS;
+
+       return IXGBE_ERR_MBX;
+}
+
+/**
+ * ixgbe_check_for_msg_vf - checks to see if the PF has sent mail
+ * @hw: pointer to the HW structure
+ * @mbx_id: id of mailbox to check
+ *
+ * returns SUCCESS if the PF has set the Status bit or else ERR_MBX
+ **/
+static int32_t ixgbe_check_for_msg_vf(struct ixgbe_hw *hw, uint16_t mbx_id)
+{
+       DEBUGFUNC("ixgbe_check_for_msg_vf");
+
+       if (!ixgbe_check_for_bit_vf(hw, IXGBE_VFMAILBOX_PFSTS))
+               return IXGBE_SUCCESS;
+
+       return IXGBE_ERR_MBX;
+}
+
+/**
+ * ixgbe_check_for_ack_vf - checks to see if the PF has ACK'd
+ * @hw: pointer to the HW structure
+ * @mbx_id: id of mailbox to check
+ *
+ * returns SUCCESS if the PF has set the ACK bit or else ERR_MBX
+ **/
+static int32_t ixgbe_check_for_ack_vf(struct ixgbe_hw *hw, uint16_t mbx_id)
+{
+       DEBUGFUNC("ixgbe_check_for_ack_vf");
+
+       if (!ixgbe_check_for_bit_vf(hw, IXGBE_VFMAILBOX_PFACK)) {
+               /* TODO: should this be autocleared? */
+               ixgbe_clear_ack_vf(hw);
+               return IXGBE_SUCCESS;
+       }
+
+       return IXGBE_ERR_MBX;
+}
+
+/**
+ * ixgbe_check_for_rst_vf - checks to see if the PF has reset
+ * @hw: pointer to the HW structure
+ * @mbx_id: id of mailbox to check
+ *
+ * returns TRUE if the PF has set the reset done bit or else FALSE
+ **/
+static int32_t ixgbe_check_for_rst_vf(struct ixgbe_hw *hw, uint16_t mbx_id)
+{
+       DEBUGFUNC("ixgbe_check_for_rst_vf");
+
+       if (!ixgbe_check_for_bit_vf(hw, IXGBE_VFMAILBOX_RSTI |
+                                         IXGBE_VFMAILBOX_RSTD)) {
+               /* TODO: should this be autocleared? */
+               ixgbe_clear_rst_vf(hw);
+               return IXGBE_SUCCESS;
+       }
+
+       return IXGBE_ERR_MBX;
+}
+
+/**
+ * ixgbe_obtain_mbx_lock_vf - obtain mailbox lock
+ * @hw: pointer to the HW structure
+ *
+ * return SUCCESS if we obtained the mailbox lock
+ **/
+static int32_t ixgbe_obtain_mbx_lock_vf(struct ixgbe_hw *hw)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+       int countdown = mbx->timeout;
+       int32_t ret_val = IXGBE_ERR_MBX;
+       uint32_t vf_mailbox;
+
+       DEBUGFUNC("ixgbe_obtain_mbx_lock_vf");
+
+       if (!mbx->timeout)
+               return IXGBE_ERR_CONFIG;
+
+       while (countdown--) {
+               /* Reserve mailbox for VF use */
+               vf_mailbox = ixgbe_read_mailbox_vf(hw);
+               vf_mailbox |= IXGBE_VFMAILBOX_VFU;
+               IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, vf_mailbox);
+
+               /* Verify that VF is the owner of the lock */
+               if (ixgbe_read_mailbox_vf(hw) & IXGBE_VFMAILBOX_VFU) {
+                       ret_val = IXGBE_SUCCESS;
+                       break;
+               }
+
+               /* Wait a bit before trying again */
+               usec_delay(mbx->usec_delay);
+       }
+
+       if (ret_val != IXGBE_SUCCESS) {
+               ERROR_REPORT1(IXGBE_ERROR_INVALID_STATE,
+                               "Failed to obtain mailbox lock");
+               ret_val = IXGBE_ERR_TIMEOUT;
+       }
+
+       return ret_val;
 }

 /**
@@ -4711,34 +4921,14 @@ void ixgbe_init_mbx_ops_generic(struct ixgbe_hw *hw)
        mbx->ops.write_posted = ixgbe_write_posted_mbx;
 }

-/**
- *  ixgbe_read_v2p_mailbox - read v2p mailbox
- *  @hw: pointer to the HW structure
- *
- *  This function is used to read the v2p mailbox without losing the read to
- *  clear status bits.
- **/
-uint32_t ixgbe_read_v2p_mailbox(struct ixgbe_hw *hw)
-{
-       uint32_t v2p_mailbox = IXGBE_READ_REG(hw, IXGBE_VFMAILBOX);
-
-       v2p_mailbox |= hw->mbx.v2p_mailbox;
-       hw->mbx.v2p_mailbox |= v2p_mailbox & IXGBE_VFMAILBOX_R2C_BITS;
-
-       return v2p_mailbox;
-}
-
 int32_t ixgbe_check_for_bit_pf(struct ixgbe_hw *hw, uint32_t mask, int32_t 
index)
 {
-       uint32_t mbvficr = IXGBE_READ_REG(hw, IXGBE_MBVFICR(index));
-       int32_t ret_val = IXGBE_ERR_MBX;
+       uint32_t pfmbicr = IXGBE_READ_REG(hw, IXGBE_PFMBICR(index));

-       if (mbvficr & mask) {
-               ret_val = IXGBE_SUCCESS;
-               IXGBE_WRITE_REG(hw, IXGBE_MBVFICR(index), mask);
-       }
+       if (pfmbicr & mask)
+               return IXGBE_SUCCESS;

-       return ret_val;
+       return IXGBE_ERR_MBX;
 }

 /**
@@ -4748,21 +4938,47 @@ int32_t ixgbe_check_for_bit_pf(struct ixgbe_hw *hw, 
uint32_t mask, int32_t index
  *
  *  returns SUCCESS if the VF has set the Status bit or else ERR_MBX
  **/
-int32_t ixgbe_check_for_msg_pf(struct ixgbe_hw *hw, uint16_t vf_number)
+int32_t ixgbe_check_for_msg_pf(struct ixgbe_hw *hw, uint16_t vf_id)
 {
-       int32_t ret_val = IXGBE_ERR_MBX;
-       int32_t index = IXGBE_MBVFICR_INDEX(vf_number);
-       uint32_t vf_bit = vf_number % 16;
-
+       uint32_t vf_shift = IXGBE_PFMBICR_SHIFT(vf_id);
+       int32_t index = IXGBE_PFMBICR_INDEX(vf_id);
        DEBUGFUNC("ixgbe_check_for_msg_pf");

-       if (!ixgbe_check_for_bit_pf(hw, IXGBE_MBVFICR_VFREQ_VF1 << vf_bit,
-                                   index)) {
-               ret_val = IXGBE_SUCCESS;
+       if (!ixgbe_check_for_bit_pf(hw, IXGBE_PFMBICR_VFREQ_VF1 << vf_shift,
+                                   index))
+               return IXGBE_SUCCESS;
+
+       return IXGBE_ERR_MBX;
+}
+
+static void ixgbe_clear_msg_pf(struct ixgbe_hw *hw, uint16_t vf_id)
+{
+       uint32_t vf_shift = IXGBE_PFMBICR_SHIFT(vf_id);
+       int32_t index = IXGBE_PFMBICR_INDEX(vf_id);
+       uint32_t pfmbicr;
+
+       pfmbicr = IXGBE_READ_REG(hw, IXGBE_PFMBICR(index));
+
+       if (pfmbicr & (IXGBE_PFMBICR_VFREQ_VF1 << vf_shift))
                hw->mbx.stats.reqs++;
-       }

-       return ret_val;
+       IXGBE_WRITE_REG(hw, IXGBE_PFMBICR(index),
+                       IXGBE_PFMBICR_VFREQ_VF1 << vf_shift);
+}
+
+static void ixgbe_clear_ack_pf(struct ixgbe_hw *hw, uint16_t vf_id)
+{
+       uint32_t vf_shift = IXGBE_PFMBICR_SHIFT(vf_id);
+       int32_t index = IXGBE_PFMBICR_INDEX(vf_id);
+       uint32_t pfmbicr;
+
+       pfmbicr = IXGBE_READ_REG(hw, IXGBE_PFMBICR(index));
+
+       if (pfmbicr & (IXGBE_PFMBICR_VFACK_VF1 << vf_shift))
+               hw->mbx.stats.acks++;
+
+       IXGBE_WRITE_REG(hw, IXGBE_PFMBICR(index),
+                       IXGBE_PFMBICR_VFACK_VF1 << vf_shift);
 }

 /**
@@ -4772,18 +4988,19 @@ int32_t ixgbe_check_for_msg_pf(struct ixgbe_hw *hw, 
uint16_t vf_number)
  *
  *  returns SUCCESS if the VF has set the Status bit or else ERR_MBX
  **/
-int32_t ixgbe_check_for_ack_pf(struct ixgbe_hw *hw, uint16_t vf_number)
+int32_t ixgbe_check_for_ack_pf(struct ixgbe_hw *hw, uint16_t vf_id)
 {
+       uint32_t vf_shift = IXGBE_PFMBICR_SHIFT(vf_id);
+       int32_t index = IXGBE_PFMBICR_INDEX(vf_id);
        int32_t ret_val = IXGBE_ERR_MBX;
-       int32_t index = IXGBE_MBVFICR_INDEX(vf_number);
-       uint32_t vf_bit = vf_number % 16;

        DEBUGFUNC("ixgbe_check_for_ack_pf");

-       if (!ixgbe_check_for_bit_pf(hw, IXGBE_MBVFICR_VFACK_VF1 << vf_bit,
+       if (!ixgbe_check_for_bit_pf(hw, IXGBE_PFMBICR_VFACK_VF1 << vf_shift,
                                    index)) {
                ret_val = IXGBE_SUCCESS;
-               hw->mbx.stats.acks++;
+               /* TODO: should this be autocleared? */
+               ixgbe_clear_ack_pf(hw, vf_id);
        }

        return ret_val;
@@ -4796,24 +5013,24 @@ int32_t ixgbe_check_for_ack_pf(struct ixgbe_hw *hw, 
uint16_t vf_number)
  *
  *  returns SUCCESS if the VF has set the Status bit or else ERR_MBX
  **/
-int32_t ixgbe_check_for_rst_pf(struct ixgbe_hw *hw, uint16_t vf_number)
+int32_t ixgbe_check_for_rst_pf(struct ixgbe_hw *hw, uint16_t vf_id)
 {
-       uint32_t reg_offset = (vf_number < 32) ? 0 : 1;
-       uint32_t vf_shift = vf_number % 32;
-       uint32_t vflre = 0;
+       uint32_t vf_shift = IXGBE_PFVFLRE_SHIFT(vf_id);
+       uint32_t index = IXGBE_PFVFLRE_INDEX(vf_id);
        int32_t ret_val = IXGBE_ERR_MBX;
+       uint32_t vflre = 0;

        DEBUGFUNC("ixgbe_check_for_rst_pf");

        switch (hw->mac.type) {
        case ixgbe_mac_82599EB:
-               vflre = IXGBE_READ_REG(hw, IXGBE_VFLRE(reg_offset));
+               vflre = IXGBE_READ_REG(hw, IXGBE_PFVFLRE(index));
                break;
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
        case ixgbe_mac_X550EM_a:
        case ixgbe_mac_X540:
-               vflre = IXGBE_READ_REG(hw, IXGBE_VFLREC(reg_offset));
+               vflre = IXGBE_READ_REG(hw, IXGBE_PFVFLREC(index));
                break;
        default:
                break;
@@ -4821,7 +5038,7 @@ int32_t ixgbe_check_for_rst_pf(struct ixgbe_hw *hw, 
uint16_t vf_number)

        if (vflre & (1 << vf_shift)) {
                ret_val = IXGBE_SUCCESS;
-               IXGBE_WRITE_REG(hw, IXGBE_VFLREC(reg_offset), (1 << vf_shift));
+               IXGBE_WRITE_REG(hw, IXGBE_PFVFLREC(index), (1 << vf_shift));
                hw->mbx.stats.rsts++;
        }

@@ -4835,28 +5052,61 @@ int32_t ixgbe_check_for_rst_pf(struct ixgbe_hw *hw, 
uint16_t vf_number)
  *
  *  return SUCCESS if we obtained the mailbox lock
  **/
-int32_t ixgbe_obtain_mbx_lock_pf(struct ixgbe_hw *hw, uint16_t vf_number)
+int32_t ixgbe_obtain_mbx_lock_pf(struct ixgbe_hw *hw, uint16_t vf_id)
 {
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+       int countdown = mbx->timeout;
        int32_t ret_val = IXGBE_ERR_MBX;
-       uint32_t p2v_mailbox;
+       uint32_t pf_mailbox;

        DEBUGFUNC("ixgbe_obtain_mbx_lock_pf");

-       /* Take ownership of the buffer */
-       IXGBE_WRITE_REG(hw, IXGBE_PFMAILBOX(vf_number), IXGBE_PFMAILBOX_PFU);
+       if (!mbx->timeout)
+               return IXGBE_ERR_CONFIG;

-       /* reserve mailbox for vf use */
-       p2v_mailbox = IXGBE_READ_REG(hw, IXGBE_PFMAILBOX(vf_number));
-       if (p2v_mailbox & IXGBE_PFMAILBOX_PFU)
-               ret_val = IXGBE_SUCCESS;
-       else
-               ERROR_REPORT2(IXGBE_ERROR_POLLING,
-                          "Failed to obtain mailbox lock for VF%d", vf_number);
+       while (countdown--) {
+               /* Reserve mailbox for PF use */
+               pf_mailbox = IXGBE_READ_REG(hw, IXGBE_PFMAILBOX(vf_id));
+               pf_mailbox |= IXGBE_PFMAILBOX_PFU;
+               IXGBE_WRITE_REG(hw, IXGBE_PFMAILBOX(vf_id), pf_mailbox);
+
+               /* Verify that PF is the owner of the lock */
+               pf_mailbox = IXGBE_READ_REG(hw, IXGBE_PFMAILBOX(vf_id));
+               if (pf_mailbox & IXGBE_PFMAILBOX_PFU) {
+                       ret_val = IXGBE_SUCCESS;
+                       break;
+               }

+               /* Wait a bit before trying again */
+               usec_delay(mbx->usec_delay);
+       }
+
+       if (ret_val != IXGBE_SUCCESS) {
+               ERROR_REPORT1(IXGBE_ERROR_INVALID_STATE,
+                             "Failed to obtain mailbox lock");
+               ret_val = IXGBE_ERR_TIMEOUT;
+       }

        return ret_val;
 }

+/**
+ * ixgbe_release_mbx_lock_pf - release mailbox lock
+ * @hw: pointer to the HW structure
+ * @vf_id: the VF index
+ **/
+static void ixgbe_release_mbx_lock_pf(struct ixgbe_hw *hw, uint16_t vf_id)
+{
+       uint32_t pf_mailbox;
+
+       DEBUGFUNC("ixgbe_release_mbx_lock_pf");
+
+       /* Return ownership of the buffer */
+       pf_mailbox = IXGBE_READ_REG(hw, IXGBE_PFMAILBOX(vf_id));
+       pf_mailbox &= ~IXGBE_PFMAILBOX_PFU;
+       IXGBE_WRITE_REG(hw, IXGBE_PFMAILBOX(vf_id), pf_mailbox);
+}
+
 /**
  *  ixgbe_write_mbx_pf - Places a message in the mailbox
  *  @hw: pointer to the HW structure
@@ -4867,35 +5117,79 @@ int32_t ixgbe_obtain_mbx_lock_pf(struct ixgbe_hw *hw, 
uint16_t vf_number)
  *  returns SUCCESS if it successfully copied message into the buffer
  **/
 int32_t ixgbe_write_mbx_pf(struct ixgbe_hw *hw, uint32_t *msg, uint16_t size,
-                          uint16_t vf_number)
+                          uint16_t vf_id)
 {
+       uint32_t pf_mailbox;
        int32_t ret_val;
        uint16_t i;

        DEBUGFUNC("ixgbe_write_mbx_pf");

        /* lock the mailbox to prevent pf/vf race condition */
-       ret_val = ixgbe_obtain_mbx_lock_pf(hw, vf_number);
+       ret_val = ixgbe_obtain_mbx_lock_pf(hw, vf_id);
        if (ret_val)
-               goto out_no_write;
+               goto out;

        /* flush msg and acks as we are overwriting the message buffer */
-       ixgbe_check_for_msg_pf(hw, vf_number);
-       ixgbe_check_for_ack_pf(hw, vf_number);
+       ixgbe_clear_msg_pf(hw, vf_id);
+       ixgbe_clear_ack_pf(hw, vf_id);

        /* copy the caller specified message to the mailbox memory buffer */
        for (i = 0; i < size; i++)
-               IXGBE_WRITE_REG_ARRAY(hw, IXGBE_PFMBMEM(vf_number), i, msg[i]);
+               IXGBE_WRITE_REG_ARRAY(hw, IXGBE_PFMBMEM(vf_id), i, msg[i]);

-       /* Interrupt VF to tell it a message has been sent and release buffer*/
-       IXGBE_WRITE_REG(hw, IXGBE_PFMAILBOX(vf_number), IXGBE_PFMAILBOX_STS);
+       /* Interrupt VF to tell it a message has been sent */
+       pf_mailbox = IXGBE_READ_REG(hw, IXGBE_PFMAILBOX(vf_id));
+       pf_mailbox |= IXGBE_PFMAILBOX_STS;
+       IXGBE_WRITE_REG(hw, IXGBE_PFMAILBOX(vf_id), pf_mailbox);
+
+       /* if msg sent wait until we receive an ack */
+       ixgbe_poll_for_ack(hw, vf_id);

        /* update stats */
        hw->mbx.stats.msgs_tx++;

-out_no_write:
+out:
+       hw->mbx.ops.release(hw, vf_id);
+
        return ret_val;
+}
+
+/**
+ * ixgbe_read_mbx_pf_legacy - Read a message from the mailbox
+ * @hw: pointer to the HW structure
+ * @msg: The message buffer
+ * @size: Length of buffer
+ * @vf_id: the VF index
+ *
+ * This function copies a message from the mailbox buffer to the caller's
+ * memory buffer.  The presumption is that the caller knows that there was
+ * a message due to a VF request so no polling for message is needed.
+ **/
+static int32_t ixgbe_read_mbx_pf_legacy(struct ixgbe_hw *hw, uint32_t *msg,
+                                       uint16_t size, uint16_t vf_id)
+{
+       int32_t ret_val;
+       uint16_t i;
+
+       DEBUGFUNC("ixgbe_read_mbx_pf_legacy");
+
+       /* lock the mailbox to prevent pf/vf race condition */
+       ret_val = ixgbe_obtain_mbx_lock_pf(hw, vf_id);
+       if (ret_val != IXGBE_SUCCESS)
+               return ret_val;
+
+       /* copy the message to the mailbox memory buffer */
+       for (i = 0; i < size; i++)
+               msg[i] = IXGBE_READ_REG_ARRAY(hw, IXGBE_PFMBMEM(vf_id), i);
+
+       /* Acknowledge the message and release buffer */
+       IXGBE_WRITE_REG(hw, IXGBE_PFMAILBOX(vf_id), IXGBE_PFMAILBOX_ACK);
+
+       /* update stats */
+       hw->mbx.stats.msgs_rx++;

+       return IXGBE_SUCCESS;
 }

 /**
@@ -4910,32 +5204,350 @@ out_no_write:
  *  a message due to a VF request so no polling for message is needed.
  **/
 int32_t ixgbe_read_mbx_pf(struct ixgbe_hw *hw, uint32_t *msg, uint16_t size,
-                         uint16_t vf_number)
+                         uint16_t vf_id)
 {
+       uint32_t pf_mailbox;
        int32_t ret_val;
        uint16_t i;

        DEBUGFUNC("ixgbe_read_mbx_pf");

-       /* lock the mailbox to prevent pf/vf race condition */
-       ret_val = ixgbe_obtain_mbx_lock_pf(hw, vf_number);
-       if (ret_val)
-               goto out_no_read;
+       /* check if there is a message from VF */
+       ret_val = ixgbe_check_for_msg_pf(hw, vf_id);
+       if (ret_val != IXGBE_SUCCESS)
+               return IXGBE_ERR_MBX_NOMSG;
+
+       ixgbe_clear_msg_pf(hw, vf_id);

        /* copy the message to the mailbox memory buffer */
        for (i = 0; i < size; i++)
-               msg[i] = IXGBE_READ_REG_ARRAY(hw, IXGBE_PFMBMEM(vf_number), i);
+               msg[i] = IXGBE_READ_REG_ARRAY(hw, IXGBE_PFMBMEM(vf_id), i);

        /* Acknowledge the message and release buffer */
-       IXGBE_WRITE_REG(hw, IXGBE_PFMAILBOX(vf_number), IXGBE_PFMAILBOX_ACK);
+       pf_mailbox = IXGBE_READ_REG(hw, IXGBE_PFMAILBOX(vf_id));
+       pf_mailbox |= IXGBE_PFMAILBOX_ACK;
+       IXGBE_WRITE_REG(hw, IXGBE_PFMAILBOX(vf_id), pf_mailbox);

        /* update stats */
        hw->mbx.stats.msgs_rx++;

-out_no_read:
+       return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_release_mbx_lock_dummy - release mailbox lock
+ * @hw: pointer to the HW structure
+ * @mbx_id: id of mailbox to read
+ **/
+static void ixgbe_release_mbx_lock_dummy(struct ixgbe_hw *hw, uint16_t mbx_id)
+{
+       DEBUGFUNC("ixgbe_release_mbx_lock_dummy");
+}
+
+/**
+ * ixgbe_release_mbx_lock_vf - release mailbox lock
+ * @hw: pointer to the HW structure
+ * @mbx_id: id of mailbox to read
+ **/
+static void ixgbe_release_mbx_lock_vf(struct ixgbe_hw *hw, uint16_t mbx_id)
+{
+       uint32_t vf_mailbox;
+
+       DEBUGFUNC("ixgbe_release_mbx_lock_vf");
+
+       /* Return ownership of the buffer */
+       vf_mailbox = ixgbe_read_mailbox_vf(hw);
+       vf_mailbox &= ~IXGBE_VFMAILBOX_VFU;
+       IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, vf_mailbox);
+}
+
+/**
+ * ixgbe_write_mbx_vf_legacy - Write a message to the mailbox
+ * @hw: pointer to the HW structure
+ * @msg: The message buffer
+ * @size: Length of buffer
+ * @mbx_id: id of mailbox to write
+ *
+ * returns SUCCESS if it successfully copied message into the buffer
+ **/
+static int32_t ixgbe_write_mbx_vf_legacy(struct ixgbe_hw *hw, uint32_t *msg,
+                                        uint16_t size, uint16_t mbx_id)
+{
+       int32_t ret_val;
+       uint16_t i;
+
+       DEBUGFUNC("ixgbe_write_mbx_vf_legacy");
+
+       /* lock the mailbox to prevent pf/vf race condition */
+       ret_val = ixgbe_obtain_mbx_lock_vf(hw);
+       if (ret_val)
+               return ret_val;
+
+       /* flush msg and acks as we are overwriting the message buffer */
+       ixgbe_check_for_msg_vf(hw, 0);
+       ixgbe_clear_msg_vf(hw);
+       ixgbe_check_for_ack_vf(hw, 0);
+       ixgbe_clear_ack_vf(hw);
+
+       /* copy the caller specified message to the mailbox memory buffer */
+       for (i = 0; i < size; i++)
+               IXGBE_WRITE_REG_ARRAY(hw, IXGBE_VFMBMEM, i, msg[i]);
+
+       /* update stats */
+       hw->mbx.stats.msgs_tx++;
+
+       /* interrupt the PF to tell it a message has been sent */
+       IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, IXGBE_VFMAILBOX_REQ);
+
+       return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_write_mbx_vf - Write a message to the mailbox
+ * @hw: pointer to the HW structure
+ * @msg: The message buffer
+ * @size: Length of buffer
+ * @mbx_id: id of mailbox to write
+ *
+ * returns SUCCESS if it successfully copied message into the buffer
+ **/
+static int32_t ixgbe_write_mbx_vf(struct ixgbe_hw *hw, uint32_t *msg,
+                                 uint16_t size, uint16_t mbx_id)
+{
+       uint32_t vf_mailbox;
+       int32_t ret_val;
+       uint16_t i;
+
+       DEBUGFUNC("ixgbe_write_mbx_vf");
+
+       /* lock the mailbox to prevent pf/vf race condition */
+       ret_val = ixgbe_obtain_mbx_lock_vf(hw);
+       if (ret_val)
+               goto out;
+
+       /* flush msg and acks as we are overwriting the message buffer */
+       ixgbe_clear_msg_vf(hw);
+       ixgbe_clear_ack_vf(hw);
+
+       /* copy the caller specified message to the mailbox memory buffer */
+       for (i = 0; i < size; i++)
+               IXGBE_WRITE_REG_ARRAY(hw, IXGBE_VFMBMEM, i, msg[i]);
+
+       /* update stats */
+       hw->mbx.stats.msgs_tx++;
+
+       /* interrupt the PF to tell it a message has been sent */
+       vf_mailbox = ixgbe_read_mailbox_vf(hw);
+       vf_mailbox |= IXGBE_VFMAILBOX_REQ;
+       IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, vf_mailbox);
+
+       /* if msg sent wait until we receive an ack */
+       ixgbe_poll_for_ack(hw, mbx_id);
+
+out:
+       hw->mbx.ops.release(hw, mbx_id);
+
        return ret_val;
 }

+/**
+ * ixgbe_read_mbx_vf_legacy - Reads a message from the inbox intended for vf
+ * @hw: pointer to the HW structure
+ * @msg: The message buffer
+ * @size: Length of buffer
+ * @mbx_id: id of mailbox to read
+ *
+ * returns SUCCESS if it successfully read message from buffer
+ **/
+static int32_t ixgbe_read_mbx_vf_legacy(struct ixgbe_hw *hw, uint32_t *msg,
+                                       uint16_t size, uint16_t mbx_id)
+{
+       int32_t ret_val;
+       uint16_t i;
+
+       DEBUGFUNC("ixgbe_read_mbx_vf_legacy");
+
+       /* lock the mailbox to prevent pf/vf race condition */
+       ret_val = ixgbe_obtain_mbx_lock_vf(hw);
+       if (ret_val)
+               return ret_val;
+
+       /* copy the message from the mailbox memory buffer */
+       for (i = 0; i < size; i++)
+               msg[i] = IXGBE_READ_REG_ARRAY(hw, IXGBE_VFMBMEM, i);
+
+       /* Acknowledge receipt and release mailbox, then we're done */
+       IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, IXGBE_VFMAILBOX_ACK);
+
+       /* update stats */
+       hw->mbx.stats.msgs_rx++;
+
+       return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_read_mbx_vf - Reads a message from the inbox intended for vf
+ * @hw: pointer to the HW structure
+ * @msg: The message buffer
+ * @size: Length of buffer
+ * @mbx_id: id of mailbox to read
+ *
+ * returns SUCCESS if it successfully read message from buffer
+ **/
+static int32_t ixgbe_read_mbx_vf(struct ixgbe_hw *hw, uint32_t *msg, uint16_t 
size,
+                                uint16_t mbx_id)
+{
+       uint32_t vf_mailbox;
+       int32_t ret_val;
+       uint16_t i;
+
+       DEBUGFUNC("ixgbe_read_mbx_vf");
+
+       /* check if there is a message from PF */
+       ret_val = ixgbe_check_for_msg_vf(hw, 0);
+       if (ret_val != IXGBE_SUCCESS)
+               return IXGBE_ERR_MBX_NOMSG;
+
+       ixgbe_clear_msg_vf(hw);
+
+       /* copy the message from the mailbox memory buffer */
+       for (i = 0; i < size; i++)
+               msg[i] = IXGBE_READ_REG_ARRAY(hw, IXGBE_VFMBMEM, i);
+
+       /* Acknowledge receipt */
+       vf_mailbox = ixgbe_read_mailbox_vf(hw);
+       vf_mailbox |= IXGBE_VFMAILBOX_ACK;
+       IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, vf_mailbox);
+
+       /* update stats */
+       hw->mbx.stats.msgs_rx++;
+
+       return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_init_mbx_params_vf - set initial values for vf mailbox
+ * @hw: pointer to the HW structure
+ *
+ * Initializes single set the hw->mbx struct to correct values for vf mailbox
+ * Set of legacy functions is being used here
+ */
+void ixgbe_init_mbx_params_vf(struct ixgbe_hw *hw)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+
+       mbx->timeout = IXGBE_VF_MBX_INIT_TIMEOUT;
+       mbx->usec_delay = IXGBE_VF_MBX_INIT_DELAY;
+
+       mbx->size = IXGBE_VFMAILBOX_SIZE;
+
+       mbx->ops.release = ixgbe_release_mbx_lock_dummy;
+       mbx->ops.read = ixgbe_read_mbx_vf_legacy;
+       mbx->ops.write = ixgbe_write_mbx_vf_legacy;
+       mbx->ops.check_for_msg = ixgbe_check_for_msg_vf;
+       mbx->ops.check_for_ack = ixgbe_check_for_ack_vf;
+       mbx->ops.check_for_rst = ixgbe_check_for_rst_vf;
+       mbx->ops.clear = NULL;
+
+       mbx->stats.msgs_tx = 0;
+       mbx->stats.msgs_rx = 0;
+       mbx->stats.reqs = 0;
+       mbx->stats.acks = 0;
+       mbx->stats.rsts = 0;
+}
+
+/**
+ * ixgbe_upgrade_mbx_params_vf - set initial values for vf mailbox
+ * @hw: pointer to the HW structure
+ *
+ * Initializes the hw->mbx struct to correct values for vf mailbox
+ */
+void ixgbe_upgrade_mbx_params_vf(struct ixgbe_hw *hw)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+
+       mbx->timeout = IXGBE_VF_MBX_INIT_TIMEOUT;
+       mbx->usec_delay = IXGBE_VF_MBX_INIT_DELAY;
+
+       mbx->size = IXGBE_VFMAILBOX_SIZE;
+
+       mbx->ops.release = ixgbe_release_mbx_lock_vf;
+       mbx->ops.read = ixgbe_read_mbx_vf;
+       mbx->ops.write = ixgbe_write_mbx_vf;
+       mbx->ops.check_for_msg = ixgbe_check_for_msg_vf;
+       mbx->ops.check_for_ack = ixgbe_check_for_ack_vf;
+       mbx->ops.check_for_rst = ixgbe_check_for_rst_vf;
+       mbx->ops.clear = NULL;
+
+       mbx->stats.msgs_tx = 0;
+       mbx->stats.msgs_rx = 0;
+       mbx->stats.reqs = 0;
+       mbx->stats.acks = 0;
+       mbx->stats.rsts = 0;
+}
+
+/**
+ * ixgbe_write_mbx_pf_legacy - Places a message in the mailbox
+ * @hw: pointer to the HW structure
+ * @msg: The message buffer
+ * @size: Length of buffer
+ * @vf_id: the VF index
+ *
+ * returns SUCCESS if it successfully copied message into the buffer
+ **/
+static int32_t ixgbe_write_mbx_pf_legacy(struct ixgbe_hw *hw, uint32_t *msg,
+                                        uint16_t size, uint16_t vf_id)
+{
+       int32_t ret_val;
+       uint16_t i;
+
+       DEBUGFUNC("ixgbe_write_mbx_pf_legacy");
+
+       /* lock the mailbox to prevent pf/vf race condition */
+       ret_val = ixgbe_obtain_mbx_lock_pf(hw, vf_id);
+       if (ret_val)
+               return ret_val;
+
+       /* flush msg and acks as we are overwriting the message buffer */
+       ixgbe_check_for_msg_pf(hw, vf_id);
+       ixgbe_clear_msg_pf(hw, vf_id);
+       ixgbe_check_for_ack_pf(hw, vf_id);
+       ixgbe_clear_ack_pf(hw, vf_id);
+
+       /* copy the caller specified message to the mailbox memory buffer */
+       for (i = 0; i < size; i++)
+               IXGBE_WRITE_REG_ARRAY(hw, IXGBE_PFMBMEM(vf_id), i, msg[i]);
+
+       /* Interrupt VF to tell it a message has been sent and release buffer*/
+       IXGBE_WRITE_REG(hw, IXGBE_PFMAILBOX(vf_id), IXGBE_PFMAILBOX_STS);
+
+       /* update stats */
+       hw->mbx.stats.msgs_tx++;
+
+       return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_clear_mbx_pf - Clear Mailbox Memory
+ * @hw: pointer to the HW structure
+ * @vf_id: the VF index
+ *
+ * Set VFMBMEM of given VF to 0x0.
+ **/
+static int32_t ixgbe_clear_mbx_pf(struct ixgbe_hw *hw, uint16_t vf_id)
+{
+       uint16_t mbx_size = hw->mbx.size;
+       uint16_t i;
+
+       if (vf_id > 63)
+               return IXGBE_ERR_PARAM;
+
+       for (i = 0; i < mbx_size; ++i)
+               IXGBE_WRITE_REG_ARRAY(hw, IXGBE_PFMBMEM(vf_id), i, 0x0);
+
+       return IXGBE_SUCCESS;
+}
+
 /**
  *  ixgbe_init_mbx_params_pf - set initial values for pf mailbox
  *  @hw: pointer to the HW structure
@@ -4953,18 +5565,59 @@ void ixgbe_init_mbx_params_pf(struct ixgbe_hw *hw)
            hw->mac.type != ixgbe_mac_X540)
                return;

-       mbx->timeout = 0;
-       mbx->usec_delay = 0;
+       /* Initialize common mailbox settings */
+       mbx->timeout = IXGBE_VF_MBX_INIT_TIMEOUT;
+       mbx->usec_delay = IXGBE_VF_MBX_INIT_DELAY;
+       mbx->size = IXGBE_VFMAILBOX_SIZE;
+
+       /* Initialize counters with zeroes */
+       mbx->stats.msgs_tx = 0;
+       mbx->stats.msgs_rx = 0;
+       mbx->stats.reqs = 0;
+       mbx->stats.acks = 0;
+       mbx->stats.rsts = 0;
+
+       /* Initialize mailbox operations */
+       mbx->ops.release = ixgbe_release_mbx_lock_dummy;
+       mbx->ops.read = ixgbe_read_mbx_pf_legacy;
+       mbx->ops.write = ixgbe_write_mbx_pf_legacy;
+       mbx->ops.check_for_msg = ixgbe_check_for_msg_pf;
+       mbx->ops.check_for_ack = ixgbe_check_for_ack_pf;
+       mbx->ops.check_for_rst = ixgbe_check_for_rst_pf;
+       mbx->ops.clear = ixgbe_clear_mbx_pf;
+}
+
+/**
+ * ixgbe_upgrade_mbx_params_pf - Upgrade initial values for pf mailbox
+ * @hw: pointer to the HW structure
+ * @vf_id: the VF index
+ *
+ * Initializes the hw->mbx struct to new function set for improved
+ * stability and handling of messages.
+ */
+void ixgbe_upgrade_mbx_params_pf(struct ixgbe_hw *hw, uint16_t vf_id)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+
+   /* Ensure we are not calling this function from VF */
+       if (hw->mac.type != ixgbe_mac_82599EB &&
+           hw->mac.type != ixgbe_mac_X550 &&
+           hw->mac.type != ixgbe_mac_X550EM_x &&
+           hw->mac.type != ixgbe_mac_X550EM_a &&
+           hw->mac.type != ixgbe_mac_X540)
+               return;

+       mbx->timeout = IXGBE_VF_MBX_INIT_TIMEOUT;
+       mbx->usec_delay = IXGBE_VF_MBX_INIT_DELAY;
        mbx->size = IXGBE_VFMAILBOX_SIZE;

+       mbx->ops.release = ixgbe_release_mbx_lock_pf;
        mbx->ops.read = ixgbe_read_mbx_pf;
        mbx->ops.write = ixgbe_write_mbx_pf;
-       mbx->ops.read_posted = ixgbe_read_posted_mbx;
-       mbx->ops.write_posted = ixgbe_write_posted_mbx;
        mbx->ops.check_for_msg = ixgbe_check_for_msg_pf;
        mbx->ops.check_for_ack = ixgbe_check_for_ack_pf;
        mbx->ops.check_for_rst = ixgbe_check_for_rst_pf;
+       mbx->ops.clear = ixgbe_clear_mbx_pf;

        mbx->stats.msgs_tx = 0;
        mbx->stats.msgs_rx = 0;
diff --git a/sys/dev/pci/ixgbe.h b/sys/dev/pci/ixgbe.h
index af6ebde1f9f..2abef50ba89 100644
--- a/sys/dev/pci/ixgbe.h
+++ b/sys/dev/pci/ixgbe.h
@@ -280,6 +280,7 @@ int32_t ixgbe_clear_vmdq(struct ixgbe_hw *hw, uint32_t rar, 
uint32_t vmdq);
 int32_t ixgbe_init_uta_tables(struct ixgbe_hw *hw);

 void ixgbe_add_uc_addr(struct ixgbe_hw *hw, uint8_t *addr, uint32_t vmdq);
+int32_t ixgbe_mta_vector(struct ixgbe_hw *hw, uint8_t *mc_addr);
 void ixgbe_set_mta(struct ixgbe_hw *hw, uint8_t *mc_addr);

 void ixgbe_disable_rx(struct ixgbe_hw *hw);
@@ -356,8 +357,37 @@ int32_t ixgbe_write_i2c_combined_generic(struct ixgbe_hw 
*, uint8_t addr, uint16
 int32_t ixgbe_write_i2c_combined_generic_unlocked(struct ixgbe_hw *, uint8_t 
addr,
                                                  uint16_t reg, uint16_t val);

+/* Virtual Functions */
+int32_t ixgbe_init_ops_vf(struct ixgbe_hw *hw);
+int32_t ixgbe_init_hw_vf(struct ixgbe_hw *hw);
+int32_t ixgbe_start_hw_vf(struct ixgbe_hw *hw);
+int32_t ixgbe_reset_hw_vf(struct ixgbe_hw *hw);
+int32_t ixgbe_stop_adapter_vf(struct ixgbe_hw *hw);
+uint32_t ixgbe_get_num_of_tx_queues_vf(struct ixgbe_hw *hw);
+uint32_t ixgbe_get_num_of_rx_queues_vf(struct ixgbe_hw *hw);
+int32_t ixgbe_get_mac_addr_vf(struct ixgbe_hw *hw, uint8_t *mac_addr);
+int32_t ixgbe_setup_mac_link_vf(struct ixgbe_hw *hw, ixgbe_link_speed speed,
+                           bool autoneg_wait_to_complete);
+int32_t ixgbe_check_mac_link_vf(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
+                           bool *link_up, bool autoneg_wait_to_complete);
+int32_t ixgbe_set_rar_vf(struct ixgbe_hw *hw, uint32_t index, uint8_t *addr, 
uint32_t vmdq,
+                    uint32_t enable_addr);
+int32_t ixgbevf_set_uc_addr_vf(struct ixgbe_hw *hw, uint32_t index, uint8_t 
*addr);
+int32_t ixgbe_update_mc_addr_list_vf(struct ixgbe_hw *hw, uint8_t 
*mc_addr_list,
+                                uint32_t mc_addr_count, ixgbe_mc_addr_itr,
+                                bool clear);
+int32_t ixgbevf_update_xcast_mode(struct ixgbe_hw *hw, int xcast_mode);
+int32_t ixgbe_get_link_state_vf(struct ixgbe_hw *hw, bool *link_state);
+int32_t ixgbe_set_vfta_vf(struct ixgbe_hw *hw, uint32_t vlan, uint32_t vind,
+                     bool vlan_on, bool vlvf_bypass);
+int32_t ixgbevf_rlpml_set_vf(struct ixgbe_hw *hw, uint16_t max_size);
+int ixgbevf_negotiate_api_version(struct ixgbe_hw *hw, int api);
+int ixgbevf_get_queues(struct ixgbe_hw *hw, unsigned int *num_tcs,
+                      unsigned int *default_tc);
+
 /* MBX */
 int32_t ixgbe_read_mbx(struct ixgbe_hw *, uint32_t *, uint16_t, uint16_t);
+int32_t ixgbe_poll_mbx(struct ixgbe_hw *, uint32_t *, uint16_t, uint16_t);
 int32_t ixgbe_write_mbx(struct ixgbe_hw *, uint32_t *, uint16_t, uint16_t);
 int32_t ixgbe_read_posted_mbx(struct ixgbe_hw *, uint32_t *, uint16_t, 
uint16_t);
 int32_t ixgbe_write_posted_mbx(struct ixgbe_hw *, uint32_t *, uint16_t, 
uint16_t);
@@ -365,6 +395,10 @@ int32_t ixgbe_check_for_msg(struct ixgbe_hw *, uint16_t);
 int32_t ixgbe_check_for_ack(struct ixgbe_hw *, uint16_t);
 int32_t ixgbe_check_for_rst(struct ixgbe_hw *, uint16_t);
 void ixgbe_init_mbx_ops_generic(struct ixgbe_hw *hw);
+void ixgbe_init_mbx_params_vf(struct ixgbe_hw *);
+void ixgbe_upgrade_mbx_params_vf(struct ixgbe_hw *);
 void ixgbe_init_mbx_params_pf(struct ixgbe_hw *);
+void ixgbe_init_mbx_params_pf_id(struct ixgbe_hw *, uint16_t);
+void ixgbe_upgrade_mbx_params_pf(struct ixgbe_hw *, uint16_t);

 #endif /* _IXGBE_H_ */
diff --git a/sys/dev/pci/ixgbe_type.h b/sys/dev/pci/ixgbe_type.h
index 78ae1e3158b..5665f276a0f 100644
--- a/sys/dev/pci/ixgbe_type.h
+++ b/sys/dev/pci/ixgbe_type.h
@@ -463,8 +463,14 @@ struct ixgbe_nvm_version {
 #define IXGBE_PFMAILBOX(_i)    (0x04B00 + (4 * (_i))) /* 64 total */
 /* 64 Mailboxes, 16 DW each */
 #define IXGBE_PFMBMEM(_i)      (0x13000 + (64 * (_i)))
+#define IXGBE_PFMBICR_INDEX(_i)        ((_i) >> 4)
+#define IXGBE_PFMBICR_SHIFT(_i)        ((_i) % 16)
 #define IXGBE_PFMBICR(_i)      (0x00710 + (4 * (_i))) /* 4 total */
 #define IXGBE_PFMBIMR(_i)      (0x00720 + (4 * (_i))) /* 4 total */
+#define IXGBE_PFVFLRE(_i)      ((((_i) & 1) ? 0x001C0 : 0x00600))
+#define IXGBE_PFVFLREC(_i)     (0x00700 + ((_i) * 4))
+#define IXGBE_PFVFLRE_INDEX(_i)        ((_i) >> 5)
+#define IXGBE_PFVFLRE_SHIFT(_i)        ((_i) % 32)
 #define IXGBE_VFRE(_i)         (0x051E0 + ((_i) * 4))
 #define IXGBE_VFTE(_i)         (0x08110 + ((_i) * 4))
 #define IXGBE_VMECM(_i)                (0x08790 + ((_i) * 4))
@@ -3948,6 +3954,7 @@ struct ixgbe_mac_operations {
        int32_t (*update_mc_addr_list)(struct ixgbe_hw *, uint8_t *, uint32_t,
                                   ixgbe_mc_addr_itr, bool clear);
        int32_t (*update_xcast_mode)(struct ixgbe_hw *, int);
+       int32_t (*get_link_state)(struct ixgbe_hw *hw, bool *link_state);
        int32_t (*enable_mc)(struct ixgbe_hw *);
        int32_t (*disable_mc)(struct ixgbe_hw *);
        int32_t (*clear_vfta)(struct ixgbe_hw *);
@@ -3967,7 +3974,7 @@ struct ixgbe_mac_operations {
        /* Manageability interface */
        void (*disable_rx)(struct ixgbe_hw *hw);
        void (*enable_rx)(struct ixgbe_hw *hw);
-  void (*stop_mac_link_on_d3)(struct ixgbe_hw *);
+       void (*stop_mac_link_on_d3)(struct ixgbe_hw *);
        void (*set_source_address_pruning)(struct ixgbe_hw *, bool,
                                           unsigned int);
        int32_t (*dmac_update_tcs)(struct ixgbe_hw *hw);
@@ -4092,7 +4099,7 @@ struct ixgbe_phy_info {
 };

 #define IXGBE_VFMAILBOX_SIZE   16 /* 16 32 bit words - 64 bytes */
-#define IXGBE_ERR_MBX          -100
+#define IXGBE_MAX_MULTICAST_ADDRESSES_VF  30

 #define IXGBE_VFMAILBOX                0x002FC
 #define IXGBE_VFMBMEM          0x00200
@@ -4114,22 +4121,25 @@ struct ixgbe_phy_info {
 #define IXGBE_PFMAILBOX_PFU    0x00000008 /* PF owns the mailbox buffer */
 #define IXGBE_PFMAILBOX_RVFU   0x00000010 /* Reset VFU - used when VF stuck */

-#define IXGBE_MBVFICR_VFREQ_MASK       0x0000FFFF /* bits for VF messages */
-#define IXGBE_MBVFICR_VFREQ_VF1                0x00000001 /* bit for VF 1 
message */
-#define IXGBE_MBVFICR_VFACK_MASK       0xFFFF0000 /* bits for VF acks */
-#define IXGBE_MBVFICR_VFACK_VF1                0x00010000 /* bit for VF 1 ack 
*/
+#define IXGBE_PFMBICR_VFREQ_MASK       0x0000FFFF /* bits for VF messages */
+#define IXGBE_PFMBICR_VFREQ_VF1                0x00000001 /* bit for VF 1 
message */
+#define IXGBE_PFMBICR_VFACK_MASK       0xFFFF0000 /* bits for VF acks */
+#define IXGBE_PFMBICR_VFACK_VF1                0x00010000 /* bit for VF 1 ack 
*/


 /* If it's a IXGBE_VF_* msg then it originates in the VF and is sent to the
  * PF.  The reverse is TRUE if it is IXGBE_PF_*.
- * Message ACK's are the value or'd with 0xF0000000
+ * Message results are the value or'd with 0xF0000000
  */
-#define IXGBE_VT_MSGTYPE_ACK   0x80000000 /* Messages below or'd with
-                                           * this are the ACK */
-#define IXGBE_VT_MSGTYPE_NACK  0x40000000 /* Messages below or'd with
-                                           * this are the NACK */
-#define IXGBE_VT_MSGTYPE_CTS   0x20000000 /* Indicates that VF is still
-                                           * clear to send requests */
+#define IXGBE_VT_MSGTYPE_SUCCESS       0x80000000 /* Messages or'd with this
+                                                   * have succeeded
+                                                   */
+#define IXGBE_VT_MSGTYPE_FAILURE       0x40000000 /* Messages or'd with this
+                                                   * have failed
+                                                   */
+#define IXGBE_VT_MSGTYPE_CTS           0x20000000 /* Indicates that VF is still
+                                                   * clear to send requests
+                                                   */
 #define IXGBE_VT_MSGINFO_SHIFT 16
 /* bits 23:16 are used for extra info for certain messages */
 #define IXGBE_VT_MSGINFO_MASK  (0xFF << IXGBE_VT_MSGINFO_SHIFT)
@@ -4146,6 +4156,9 @@ enum ixgbe_pfvf_api_rev {
        ixgbe_mbox_api_11,      /* API version 1.1, linux/freebsd VF driver */
        ixgbe_mbox_api_12,      /* API version 1.2, linux/freebsd VF driver */
        ixgbe_mbox_api_13,      /* API version 1.3, linux/freebsd VF driver */
+       /* API 1.4 is being used in the upstream for IPsec */
+       ixgbe_mbox_api_14,      /* API version 1.4, linux/freebsd VF driver */
+       ixgbe_mbox_api_15,      /* API version 1.5, linux/freebsd VF driver */
        /* This value should always be last */
        ixgbe_mbox_api_unknown, /* indicates that API version is not known */
 };
@@ -4168,6 +4181,7 @@ enum ixgbe_pfvf_api_rev {
 #define IXGBE_VF_GET_RETA      0x0a    /* VF request for RETA */
 #define IXGBE_VF_GET_RSS_KEY   0x0b    /* get RSS key */
 #define IXGBE_VF_UPDATE_XCAST_MODE     0x0c
+#define IXGBE_VF_GET_LINK_STATE 0x10 /* get vf link state */

 /* mode choices for IXGBE_VF_UPDATE_XCAST_MODE */
 enum ixgbevf_xcast_modes {
@@ -4206,9 +4220,61 @@ enum ixgbevf_xcast_modes {
 #define IXGBE_VF_MBX_INIT_TIMEOUT      2000 /* number of retries on mailbox */
 #define IXGBE_VF_MBX_INIT_DELAY                500  /* microseconds between 
retries */

+#define IXGBE_VF_IRQ_CLEAR_MASK        7
+#define IXGBE_VF_MAX_TX_QUEUES 8
+#define IXGBE_VF_MAX_RX_QUEUES 8
+/* DCB define */
+#define IXGBE_VF_MAX_TRAFFIC_CLASS     8
+
+#define IXGBE_VFCTRL           0x00000
+#define IXGBE_VFSTATUS         0x00008
+#define IXGBE_VFLINKS          0x00010
+#define IXGBE_VFFRTIMER                0x00048
+#define IXGBE_VFRXMEMWRAP      0x03190
+#define IXGBE_VTEICR           0x00100
+#define IXGBE_VTEICS           0x00104
+#define IXGBE_VTEIMS           0x00108
+#define IXGBE_VTEIMC           0x0010C
+#define IXGBE_VTEIAC           0x00110
+#define IXGBE_VTEIAM           0x00114
+#define IXGBE_VTEITR(x)                (0x00820 + (4 * (x)))
+#define IXGBE_VTIVAR(x)                (0x00120 + (4 * (x)))
+#define IXGBE_VTIVAR_MISC      0x00140
+#define IXGBE_VTRSCINT(x)      (0x00180 + (4 * (x)))
+/* define IXGBE_VFPBACL  still says TBD in EAS */
+#define IXGBE_VFRDBAL(x)       (0x01000 + (0x40 * (x)))
+#define IXGBE_VFRDBAH(x)       (0x01004 + (0x40 * (x)))
+#define IXGBE_VFRDLEN(x)       (0x01008 + (0x40 * (x)))
+#define IXGBE_VFRDH(x)         (0x01010 + (0x40 * (x)))
+#define IXGBE_VFRDT(x)         (0x01018 + (0x40 * (x)))
+#define IXGBE_VFRXDCTL(x)      (0x01028 + (0x40 * (x)))
+#define IXGBE_VFSRRCTL(x)      (0x01014 + (0x40 * (x)))
+#define IXGBE_VFRSCCTL(x)      (0x0102C + (0x40 * (x)))
+#define IXGBE_VFPSRTYPE                0x00300
+#define IXGBE_VFTDBAL(x)       (0x02000 + (0x40 * (x)))
+#define IXGBE_VFTDBAH(x)       (0x02004 + (0x40 * (x)))
+#define IXGBE_VFTDLEN(x)       (0x02008 + (0x40 * (x)))
+#define IXGBE_VFTDH(x)         (0x02010 + (0x40 * (x)))
+#define IXGBE_VFTDT(x)         (0x02018 + (0x40 * (x)))
+#define IXGBE_VFTXDCTL(x)      (0x02028 + (0x40 * (x)))
+#define IXGBE_VFTDWBAL(x)      (0x02038 + (0x40 * (x)))
+#define IXGBE_VFTDWBAH(x)      (0x0203C + (0x40 * (x)))
+#define IXGBE_VFDCA_RXCTRL(x)  (0x0100C + (0x40 * (x)))
+#define IXGBE_VFDCA_TXCTRL(x)  (0x0200c + (0x40 * (x)))
+#define IXGBE_VFGPRC           0x0101C
+#define IXGBE_VFGPTC           0x0201C
+#define IXGBE_VFGORC_LSB       0x01020
+#define IXGBE_VFGORC_MSB       0x01024
+#define IXGBE_VFGOTC_LSB       0x02020
+#define IXGBE_VFGOTC_MSB       0x02024
+#define IXGBE_VFMPRC           0x01034
+#define IXGBE_VFMRQC           0x3000
+#define IXGBE_VFRSSRK(x)       (0x3100 + ((x) * 4))
+#define IXGBE_VFRETA(x)                (0x3200 + ((x) * 4))

 struct ixgbe_mbx_operations {
        void (*init_params)(struct ixgbe_hw *hw);
+       void (*release)(struct ixgbe_hw *, uint16_t);
        int32_t  (*read)(struct ixgbe_hw *, uint32_t *, uint16_t,  uint16_t);
        int32_t  (*write)(struct ixgbe_hw *, uint32_t *, uint16_t, uint16_t);
        int32_t  (*read_posted)(struct ixgbe_hw *, uint32_t *, uint16_t,  
uint16_t);
@@ -4216,6 +4282,7 @@ struct ixgbe_mbx_operations {
        int32_t  (*check_for_msg)(struct ixgbe_hw *, uint16_t);
        int32_t  (*check_for_ack)(struct ixgbe_hw *, uint16_t);
        int32_t  (*check_for_rst)(struct ixgbe_hw *, uint16_t);
+       int32_t  (*clear)(struct ixgbe_hw *, uint16_t);
 };

 struct ixgbe_mbx_stats {
@@ -4232,7 +4299,7 @@ struct ixgbe_mbx_info {
        struct ixgbe_mbx_stats stats;
        uint32_t timeout;
        uint32_t usec_delay;
-       uint32_t v2p_mailbox;
+       uint32_t vf_mailbox;
        uint16_t size;
 };

@@ -4306,6 +4373,9 @@ struct ixgbe_hw {
 #define IXGBE_ERR_FDIR_CMD_INCOMPLETE          -38
 #define IXGBE_ERR_FW_RESP_INVALID              -39
 #define IXGBE_ERR_TOKEN_RETRY                  -40
+#define IXGBE_ERR_MBX                          -41
+#define IXGBE_ERR_MBX_NOMSG                    -42
+#define IXGBE_ERR_TIMEOUT                      -43

 #define IXGBE_NOT_IMPLEMENTED                  0x7FFFFFFF

diff --git a/sys/dev/pci/ixgbe_vf.c b/sys/dev/pci/ixgbe_vf.c
new file mode 100644
index 00000000000..f3cffdfcca6
--- /dev/null
+++ b/sys/dev/pci/ixgbe_vf.c
@@ -0,0 +1,799 @@
+/*     $OpenBSD$       */
+
+/******************************************************************************
+
+  Copyright (c) 2001-2017, Intel Corporation
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+   1. Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+   2. Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+   3. Neither the name of the Intel Corporation nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+
+#include <dev/pci/ixgbe.h>
+#include <dev/pci/ixgbe_type.h>
+
+#ifndef IXGBE_VFWRITE_REG
+#define IXGBE_VFWRITE_REG IXGBE_WRITE_REG
+#endif
+#ifndef IXGBE_VFREAD_REG
+#define IXGBE_VFREAD_REG IXGBE_READ_REG
+#endif
+
+/**
+   Dummy handlers.
+   They are called from ix driver code,
+   and there is nothing to do for VF.
+ */
+static uint64_t
+ixgbe_dummy_uint64_handler_vf(struct ixgbe_hw *hw)
+{
+       return 0;
+}
+
+static int32_t
+ixgbe_dummy_handler_vf(struct ixgbe_hw *hw)
+{
+       return 0;
+}
+
+static void
+ixgbe_dummy_void_handler_vf(struct ixgbe_hw *hw)
+{
+       return;
+}
+
+/**
+ * ixgbe_init_ops_vf - Initialize the pointers for vf
+ * @hw: pointer to hardware structure
+ *
+ * This will assign function pointers, adapter-specific functions can
+ * override the assignment of generic function pointers by assigning
+ * their own adapter-specific function pointers.
+ * Does not touch the hardware.
+ **/
+int32_t ixgbe_init_ops_vf(struct ixgbe_hw *hw)
+{
+       /* MAC */
+       hw->mac.ops.init_hw = ixgbe_init_hw_vf;
+       hw->mac.ops.reset_hw = ixgbe_reset_hw_vf;
+       hw->mac.ops.start_hw = ixgbe_start_hw_vf;
+       /* Cannot clear stats on VF */
+       hw->mac.ops.clear_hw_cntrs = NULL;
+       hw->mac.ops.get_media_type = NULL;
+       hw->mac.ops.get_supported_physical_layer =
+               ixgbe_dummy_uint64_handler_vf;
+       hw->mac.ops.get_mac_addr = ixgbe_get_mac_addr_vf;
+       hw->mac.ops.stop_adapter = ixgbe_stop_adapter_vf;
+       hw->mac.ops.get_bus_info = NULL;
+       hw->mac.ops.negotiate_api_version = ixgbevf_negotiate_api_version;
+
+       /* Link */
+       hw->mac.ops.setup_link = ixgbe_setup_mac_link_vf;
+       hw->mac.ops.check_link = ixgbe_check_mac_link_vf;
+       hw->mac.ops.get_link_capabilities = NULL;
+
+       /* RAR, Multicast, VLAN */
+       hw->mac.ops.set_rar = ixgbe_set_rar_vf;
+       hw->mac.ops.set_uc_addr = ixgbevf_set_uc_addr_vf;
+       hw->mac.ops.init_rx_addrs = NULL;
+       hw->mac.ops.update_mc_addr_list = ixgbe_update_mc_addr_list_vf;
+       hw->mac.ops.update_xcast_mode = ixgbevf_update_xcast_mode;
+       hw->mac.ops.get_link_state = ixgbe_get_link_state_vf;
+       hw->mac.ops.enable_mc = NULL;
+       hw->mac.ops.disable_mc = NULL;
+       hw->mac.ops.clear_vfta = NULL;
+       hw->mac.ops.set_vfta = ixgbe_set_vfta_vf;
+       hw->mac.ops.set_rlpml = ixgbevf_rlpml_set_vf;
+
+       /* Flow Control */
+       hw->mac.ops.fc_enable = ixgbe_dummy_handler_vf;
+       hw->mac.ops.setup_fc = ixgbe_dummy_handler_vf;
+       hw->mac.ops.fc_autoneg = ixgbe_dummy_void_handler_vf;
+
+       hw->mac.max_tx_queues = 1;
+       hw->mac.max_rx_queues = 1;
+
+       hw->mbx.ops.init_params = ixgbe_init_mbx_params_vf;
+
+       return IXGBE_SUCCESS;
+}
+
+/* ixgbe_virt_clr_reg - Set register to default (power on) state.
+ * @hw: pointer to hardware structure
+ */
+static void ixgbe_virt_clr_reg(struct ixgbe_hw *hw)
+{
+       int i;
+       uint32_t vfsrrctl;
+       uint32_t vfdca_rxctrl;
+       uint32_t vfdca_txctrl;
+
+       /* VRSRRCTL default values (BSIZEPACKET = 2048, BSIZEHEADER = 256) */
+       vfsrrctl = 0x100 << IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT;
+       vfsrrctl |= 0x800 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+
+       /* DCA_RXCTRL default value */
+       vfdca_rxctrl = IXGBE_DCA_RXCTRL_DESC_RRO_EN |
+                      IXGBE_DCA_RXCTRL_DATA_WRO_EN |
+                      IXGBE_DCA_RXCTRL_HEAD_WRO_EN;
+
+       /* DCA_TXCTRL default value */
+       vfdca_txctrl = IXGBE_DCA_TXCTRL_DESC_RRO_EN |
+                      IXGBE_DCA_TXCTRL_DESC_WRO_EN |
+                      IXGBE_DCA_TXCTRL_DATA_RRO_EN;
+
+       IXGBE_WRITE_REG(hw, IXGBE_VFPSRTYPE, 0);
+
+       for (i = 0; i < 7; i++) {
+               IXGBE_WRITE_REG(hw, IXGBE_VFRDH(i), 0);
+               IXGBE_WRITE_REG(hw, IXGBE_VFRDT(i), 0);
+               IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(i), 0);
+               IXGBE_WRITE_REG(hw, IXGBE_VFSRRCTL(i), vfsrrctl);
+               IXGBE_WRITE_REG(hw, IXGBE_VFTDH(i), 0);
+               IXGBE_WRITE_REG(hw, IXGBE_VFTDT(i), 0);
+               IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(i), 0);
+               IXGBE_WRITE_REG(hw, IXGBE_VFTDWBAH(i), 0);
+               IXGBE_WRITE_REG(hw, IXGBE_VFTDWBAL(i), 0);
+               IXGBE_WRITE_REG(hw, IXGBE_VFDCA_RXCTRL(i), vfdca_rxctrl);
+               IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(i), vfdca_txctrl);
+       }
+
+       IXGBE_WRITE_FLUSH(hw);
+}
+
+/**
+ * ixgbe_start_hw_vf - Prepare hardware for Tx/Rx
+ * @hw: pointer to hardware structure
+ *
+ * Starts the hardware by filling the bus info structure and media type, clears
+ * all on chip counters, initializes receive address registers, multicast
+ * table, VLAN filter table, calls routine to set up link and flow control
+ * settings, and leaves transmit and receive units disabled and uninitialized
+ **/
+int32_t ixgbe_start_hw_vf(struct ixgbe_hw *hw)
+{
+       /* Clear adapter stopped flag */
+       hw->adapter_stopped = FALSE;
+
+       return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_init_hw_vf - virtual function hardware initialization
+ * @hw: pointer to hardware structure
+ *
+ * Initialize the hardware by resetting the hardware and then starting
+ * the hardware
+ **/
+int32_t ixgbe_init_hw_vf(struct ixgbe_hw *hw)
+{
+       int32_t status = hw->mac.ops.start_hw(hw);
+
+       hw->mac.ops.get_mac_addr(hw, hw->mac.addr);
+
+       return status;
+}
+
+/**
+ * ixgbe_reset_hw_vf - Performs hardware reset
+ * @hw: pointer to hardware structure
+ *
+ * Resets the hardware by resetting the transmit and receive units, masks and
+ * clears all interrupts.
+ **/
+int32_t ixgbe_reset_hw_vf(struct ixgbe_hw *hw)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+       uint32_t timeout = IXGBE_VF_INIT_TIMEOUT;
+       int32_t ret_val = IXGBE_ERR_INVALID_MAC_ADDR;
+       uint32_t msgbuf[IXGBE_VF_PERMADDR_MSG_LEN];
+       uint8_t *addr = (uint8_t *)(&msgbuf[1]);
+
+       DEBUGFUNC("ixgbevf_reset_hw_vf");
+
+       /* Call adapter stop to disable tx/rx and clear interrupts */
+       hw->mac.ops.stop_adapter(hw);
+
+       /* reset the api version */
+       hw->api_version = ixgbe_mbox_api_10;
+       ixgbe_init_mbx_params_vf(hw);
+
+       DEBUGOUT("Issuing a function level reset to MAC\n");
+
+       IXGBE_VFWRITE_REG(hw, IXGBE_VFCTRL, IXGBE_CTRL_RST);
+       IXGBE_WRITE_FLUSH(hw);
+
+       msec_delay(50);
+
+       /* we cannot reset while the RSTI / RSTD bits are asserted */
+       while (!mbx->ops.check_for_rst(hw, 0) && timeout) {
+               timeout--;
+               usec_delay(5);
+       }
+
+       if (!timeout)
+               return IXGBE_ERR_RESET_FAILED;
+
+       /* Reset VF registers to initial values */
+       ixgbe_virt_clr_reg(hw);
+
+       /* mailbox timeout can now become active */
+       mbx->timeout = IXGBE_VF_MBX_INIT_TIMEOUT;
+
+       msgbuf[0] = IXGBE_VF_RESET;
+       ixgbe_write_mbx(hw, msgbuf, 1, 0);
+
+       msec_delay(10);
+
+       /*
+        * set our "perm_addr" based on info provided by PF
+        * also set up the mc_filter_type which is piggy backed
+        * on the mac address in word 3
+        */
+       ret_val = ixgbe_poll_mbx(hw, msgbuf,
+                                IXGBE_VF_PERMADDR_MSG_LEN, 0);
+       if (ret_val)
+               return ret_val;
+
+       if (msgbuf[0] != (IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_SUCCESS) &&
+           msgbuf[0] != (IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_FAILURE))
+               return IXGBE_ERR_INVALID_MAC_ADDR;
+
+       if (msgbuf[0] == (IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_SUCCESS))
+               memcpy(hw->mac.perm_addr, addr, IXGBE_ETH_LENGTH_OF_ADDRESS);
+
+       hw->mac.mc_filter_type = msgbuf[IXGBE_VF_MC_TYPE_WORD];
+
+       return ret_val;
+}
+
+/**
+ * ixgbe_stop_adapter_vf - Generic stop Tx/Rx units
+ * @hw: pointer to hardware structure
+ *
+ * Sets the adapter_stopped flag within ixgbe_hw struct. Clears interrupts,
+ * disables transmit and receive units. The adapter_stopped flag is used by
+ * the shared code and drivers to determine if the adapter is in a stopped
+ * state and should not touch the hardware.
+ **/
+int32_t ixgbe_stop_adapter_vf(struct ixgbe_hw *hw)
+{
+       uint32_t reg_val;
+       uint16_t i;
+
+       /*
+        * Set the adapter_stopped flag so other driver functions stop touching
+        * the hardware
+        */
+       hw->adapter_stopped = TRUE;
+
+       /* Clear interrupt mask to stop from interrupts being generated */
+       IXGBE_VFWRITE_REG(hw, IXGBE_VTEIMC, IXGBE_VF_IRQ_CLEAR_MASK);
+
+       /* Clear any pending interrupts, flush previous writes */
+       IXGBE_VFREAD_REG(hw, IXGBE_VTEICR);
+
+       /* Disable the transmit unit.  Each queue must be disabled. */
+       for (i = 0; i < hw->mac.max_tx_queues; i++)
+               IXGBE_VFWRITE_REG(hw, IXGBE_VFTXDCTL(i), IXGBE_TXDCTL_SWFLSH);
+
+       /* Disable the receive unit by stopping each queue */
+       for (i = 0; i < hw->mac.max_rx_queues; i++) {
+               reg_val = IXGBE_VFREAD_REG(hw, IXGBE_VFRXDCTL(i));
+               reg_val &= ~IXGBE_RXDCTL_ENABLE;
+               IXGBE_VFWRITE_REG(hw, IXGBE_VFRXDCTL(i), reg_val);
+       }
+       /* Clear packet split and pool config */
+       IXGBE_WRITE_REG(hw, IXGBE_VFPSRTYPE, 0);
+
+       /* flush all queues disables */
+       IXGBE_WRITE_FLUSH(hw);
+       msec_delay(2);
+
+       return IXGBE_SUCCESS;
+}
+
+static int32_t ixgbevf_write_msg_read_ack(struct ixgbe_hw *hw, uint32_t *msg,
+                                     uint32_t *retmsg, uint16_t size)
+{
+       int32_t retval = ixgbe_write_mbx(hw, msg, size, 0);
+
+       if (retval)
+               return retval;
+
+       return ixgbe_poll_mbx(hw, retmsg, size, 0);
+}
+
+/**
+ * ixgbe_set_rar_vf - set device MAC address
+ * @hw: pointer to hardware structure
+ * @index: Receive address register to write
+ * @addr: Address to put into receive address register
+ * @vmdq: VMDq "set" or "pool" index
+ * @enable_addr: set flag that address is active
+ **/
+int32_t ixgbe_set_rar_vf(struct ixgbe_hw *hw, uint32_t index, uint8_t *addr,
+                        uint32_t vmdq, uint32_t enable_addr)
+{
+       uint32_t msgbuf[3];
+       uint8_t *msg_addr = (uint8_t *)(&msgbuf[1]);
+       int32_t ret_val;
+
+       memset(msgbuf, 0, 12);
+       msgbuf[0] = IXGBE_VF_SET_MAC_ADDR;
+       memcpy(msg_addr, addr, 6);
+       ret_val = ixgbevf_write_msg_read_ack(hw, msgbuf, msgbuf, 3);
+
+       msgbuf[0] &= ~IXGBE_VT_MSGTYPE_CTS;
+
+       /* if nacked the address was rejected, use "perm_addr" */
+       if (!ret_val &&
+           (msgbuf[0] == (IXGBE_VF_SET_MAC_ADDR | IXGBE_VT_MSGTYPE_FAILURE))) {
+               ixgbe_get_mac_addr_vf(hw, hw->mac.addr);
+               return IXGBE_ERR_MBX;
+       }
+
+       return ret_val;
+}
+
+/**
+ * ixgbe_update_mc_addr_list_vf - Update Multicast addresses
+ * @hw: pointer to the HW structure
+ * @mc_addr_list: array of multicast addresses to program
+ * @mc_addr_count: number of multicast addresses to program
+ * @next: caller supplied function to return next address in list
+ * @clear: unused
+ *
+ * Updates the Multicast Table Array.
+ **/
+int32_t ixgbe_update_mc_addr_list_vf(struct ixgbe_hw *hw, uint8_t 
*mc_addr_list,
+                                    uint32_t mc_addr_count, ixgbe_mc_addr_itr 
next,
+                                    bool clear)
+{
+       uint32_t msgbuf[IXGBE_VFMAILBOX_SIZE];
+       uint16_t *vector_list = (uint16_t *)&msgbuf[1];
+       uint32_t vector;
+       uint32_t cnt, i;
+       uint32_t vmdq;
+
+       DEBUGFUNC("ixgbe_update_mc_addr_list_vf");
+
+       /* Each entry in the list uses 1 16 bit word.  We have 30
+        * 16 bit words available in our HW msg buffer (minus 1 for the
+        * msg type).  That's 30 hash values if we pack 'em right.  If
+        * there are more than 30 MC addresses to add then punt the
+        * extras for now and then add code to handle more than 30 later.
+        * It would be unusual for a server to request that many multi-cast
+        * addresses except for in large enterprise network environments.
+        */
+
+       DEBUGOUT1("MC Addr Count = %d\n", mc_addr_count);
+
+       cnt = (mc_addr_count > IXGBE_MAX_MULTICAST_ADDRESSES_VF) ? 
IXGBE_MAX_MULTICAST_ADDRESSES_VF : mc_addr_count;
+       msgbuf[0] = IXGBE_VF_SET_MULTICAST;
+       msgbuf[0] |= cnt << IXGBE_VT_MSGINFO_SHIFT;
+
+       for (i = 0; i < cnt; i++) {
+               vector = ixgbe_mta_vector(hw, next(hw, &mc_addr_list, &vmdq));
+               DEBUGOUT1("Hash value = 0x%03X\n", vector);
+               vector_list[i] = (uint16_t)vector;
+       }
+
+       return ixgbevf_write_msg_read_ack(hw, msgbuf, msgbuf, 
IXGBE_VFMAILBOX_SIZE);
+}
+
+/**
+ * ixgbevf_update_xcast_mode - Update Multicast mode
+ * @hw: pointer to the HW structure
+ * @xcast_mode: new multicast mode
+ *
+ * Updates the Multicast Mode of VF.
+ **/
+int32_t ixgbevf_update_xcast_mode(struct ixgbe_hw *hw, int xcast_mode)
+{
+       uint32_t msgbuf[2];
+       int32_t err;
+
+       switch (hw->api_version) {
+       case ixgbe_mbox_api_12:
+               /* New modes were introduced in 1.3 version */
+               if (xcast_mode > IXGBEVF_XCAST_MODE_ALLMULTI)
+                       return IXGBE_ERR_FEATURE_NOT_SUPPORTED;
+               /* Fall through */
+       case ixgbe_mbox_api_13:
+       case ixgbe_mbox_api_15:
+               break;
+       default:
+               return IXGBE_ERR_FEATURE_NOT_SUPPORTED;
+       }
+
+       msgbuf[0] = IXGBE_VF_UPDATE_XCAST_MODE;
+       msgbuf[1] = xcast_mode;
+
+       err = ixgbevf_write_msg_read_ack(hw, msgbuf, msgbuf, 2);
+       if (err)
+               return err;
+
+       msgbuf[0] &= ~IXGBE_VT_MSGTYPE_CTS;
+       if (msgbuf[0] == (IXGBE_VF_UPDATE_XCAST_MODE | 
IXGBE_VT_MSGTYPE_FAILURE))
+               return IXGBE_ERR_FEATURE_NOT_SUPPORTED;
+       return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_get_link_state_vf - Get VF link state from PF
+ * @hw: pointer to the HW structure
+ * @link_state: link state storage
+ *
+ * Returns state of the operation error or success.
+ **/
+int32_t ixgbe_get_link_state_vf(struct ixgbe_hw *hw, bool *link_state)
+{
+       uint32_t msgbuf[2];
+       int32_t err;
+       int32_t ret_val;
+
+       msgbuf[0] = IXGBE_VF_GET_LINK_STATE;
+       msgbuf[1] = 0x0;
+
+       err = ixgbevf_write_msg_read_ack(hw, msgbuf, msgbuf, 2);
+
+       if (err || (msgbuf[0] & IXGBE_VT_MSGTYPE_FAILURE)) {
+               ret_val = IXGBE_ERR_MBX;
+       } else {
+               ret_val = IXGBE_SUCCESS;
+               *link_state = msgbuf[1];
+       }
+
+       return ret_val;
+}
+
+/**
+ * ixgbe_set_vfta_vf - Set/Unset vlan filter table address
+ * @hw: pointer to the HW structure
+ * @vlan: 12 bit VLAN ID
+ * @vind: unused by VF drivers
+ * @vlan_on: if TRUE then set bit, else clear bit
+ * @vlvf_bypass: boolean flag indicating updating default pool is okay
+ *
+ * Turn on/off specified VLAN in the VLAN filter table.
+ **/
+int32_t ixgbe_set_vfta_vf(struct ixgbe_hw *hw, uint32_t vlan, uint32_t vind,
+                     bool vlan_on, bool vlvf_bypass)
+{
+       uint32_t msgbuf[2];
+       int32_t ret_val;
+
+       msgbuf[0] = IXGBE_VF_SET_VLAN;
+       msgbuf[1] = vlan;
+       /* Setting the 8 bit field MSG INFO to TRUE indicates "add" */
+       msgbuf[0] |= vlan_on << IXGBE_VT_MSGINFO_SHIFT;
+
+       ret_val = ixgbevf_write_msg_read_ack(hw, msgbuf, msgbuf, 2);
+       if (!ret_val && (msgbuf[0] & IXGBE_VT_MSGTYPE_SUCCESS))
+               return IXGBE_SUCCESS;
+
+       return ret_val | (msgbuf[0] & IXGBE_VT_MSGTYPE_FAILURE);
+}
+
+/**
+ * ixgbe_get_num_of_tx_queues_vf - Get number of TX queues
+ * @hw: pointer to hardware structure
+ *
+ * Returns the number of transmit queues for the given adapter.
+ **/
+uint32_t ixgbe_get_num_of_tx_queues_vf(struct ixgbe_hw *hw)
+{
+       return IXGBE_VF_MAX_TX_QUEUES;
+}
+
+/**
+ * ixgbe_get_num_of_rx_queues_vf - Get number of RX queues
+ * @hw: pointer to hardware structure
+ *
+ * Returns the number of receive queues for the given adapter.
+ **/
+uint32_t ixgbe_get_num_of_rx_queues_vf(struct ixgbe_hw *hw)
+{
+       return IXGBE_VF_MAX_RX_QUEUES;
+}
+
+/**
+ * ixgbe_get_mac_addr_vf - Read device MAC address
+ * @hw: pointer to the HW structure
+ * @mac_addr: the MAC address
+ **/
+int32_t ixgbe_get_mac_addr_vf(struct ixgbe_hw *hw, uint8_t *mac_addr)
+{
+       int i;
+
+       for (i = 0; i < IXGBE_ETH_LENGTH_OF_ADDRESS; i++)
+               mac_addr[i] = hw->mac.perm_addr[i];
+
+       return IXGBE_SUCCESS;
+}
+
+int32_t ixgbevf_set_uc_addr_vf(struct ixgbe_hw *hw, uint32_t index, uint8_t 
*addr)
+{
+       uint32_t msgbuf[3], msgbuf_chk;
+       uint8_t *msg_addr = (uint8_t *)(&msgbuf[1]);
+       int32_t ret_val;
+
+       memset(msgbuf, 0, sizeof(msgbuf));
+       /*
+        * If index is one then this is the start of a new list and needs
+        * indication to the PF so it can do it's own list management.
+        * If it is zero then that tells the PF to just clear all of
+        * this VF's macvlans and there is no new list.
+        */
+       msgbuf[0] |= index << IXGBE_VT_MSGINFO_SHIFT;
+       msgbuf[0] |= IXGBE_VF_SET_MACVLAN;
+       msgbuf_chk = msgbuf[0];
+       if (addr)
+               memcpy(msg_addr, addr, 6);
+
+       ret_val = ixgbevf_write_msg_read_ack(hw, msgbuf, msgbuf, 3);
+       if (!ret_val) {
+               msgbuf[0] &= ~IXGBE_VT_MSGTYPE_CTS;
+
+               if (msgbuf[0] == (msgbuf_chk | IXGBE_VT_MSGTYPE_FAILURE))
+                       return IXGBE_ERR_OUT_OF_MEM;
+       }
+
+       return ret_val;
+}
+
+/**
+ * ixgbe_setup_mac_link_vf - Setup MAC link settings
+ * @hw: pointer to hardware structure
+ * @speed: new link speed
+ * @autoneg_wait_to_complete: TRUE when waiting for completion is needed
+ *
+ * Set the link speed in the AUTOC register and restarts link.
+ **/
+int32_t ixgbe_setup_mac_link_vf(struct ixgbe_hw *hw, ixgbe_link_speed speed,
+                           bool autoneg_wait_to_complete)
+{
+       return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_check_mac_link_vf - Get link/speed status
+ * @hw: pointer to hardware structure
+ * @speed: pointer to link speed
+ * @link_up: TRUE is link is up, FALSE otherwise
+ * @autoneg_wait_to_complete: TRUE when waiting for completion is needed
+ *
+ * Reads the links register to determine if link is up and the current speed
+ **/
+int32_t ixgbe_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;
+       int32_t ret_val = IXGBE_SUCCESS;
+       uint32_t in_msg = 0;
+       uint32_t links_reg;
+
+       /* If we were hit with a reset drop the link */
+       if (!mbx->ops.check_for_rst(hw, 0) || !mbx->timeout)
+               mac->get_link_status = TRUE;
+
+       if (!mac->get_link_status)
+               goto out;
+
+       /* if link status is down no point in checking to see if pf is up */
+       links_reg = IXGBE_READ_REG(hw, IXGBE_VFLINKS);
+       if (!(links_reg & IXGBE_LINKS_UP))
+               goto out;
+
+       /* for SFP+ modules and DA cables on 82599 it can take up to 500usecs
+        * before the link status is correct
+        */
+       if (mac->type == ixgbe_mac_82599_vf) {
+               int i;
+
+               for (i = 0; i < 5; i++) {
+                       usec_delay(100);
+                       links_reg = IXGBE_READ_REG(hw, IXGBE_VFLINKS);
+
+                       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) {
+                       if (links_reg & IXGBE_LINKS_SPEED_NON_STD)
+                               *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) {
+                       if (links_reg & IXGBE_LINKS_SPEED_NON_STD)
+                               *speed = IXGBE_LINK_SPEED_5GB_FULL;
+               }
+               break;
+       case IXGBE_LINKS_SPEED_10_X550EM_A:
+               *speed = IXGBE_LINK_SPEED_UNKNOWN;
+               /* Since Reserved in older MAC's */
+               if (hw->mac.type >= ixgbe_mac_X550_vf)
+                       *speed = IXGBE_LINK_SPEED_10_FULL;
+               break;
+       default:
+               *speed = IXGBE_LINK_SPEED_UNKNOWN;
+       }
+
+       /* if the read failed it could just be a mailbox collision, best wait
+        * until we are called again and don't report an error
+        */
+       if (ixgbe_read_mbx(hw, &in_msg, 1, 0)) {
+               if (hw->api_version >= ixgbe_mbox_api_15)
+                       mac->get_link_status = FALSE;
+               goto out;
+       }
+
+       if (!(in_msg & IXGBE_VT_MSGTYPE_CTS)) {
+               /* msg is not CTS and is NACK we must have lost CTS status */
+               if (in_msg & IXGBE_VT_MSGTYPE_FAILURE)
+                       ret_val = IXGBE_ERR_MBX;
+               goto out;
+       }
+
+       /* the pf is talking, if we timed out in the past we reinit */
+       if (!mbx->timeout) {
+               ret_val = IXGBE_ERR_TIMEOUT;
+               goto out;
+       }
+
+       /* if we passed all the tests above then the link is up and we no
+        * longer need to check for link
+        */
+       mac->get_link_status = FALSE;
+
+out:
+       *link_up = !mac->get_link_status;
+       return ret_val;
+}
+
+/**
+ * ixgbevf_rlpml_set_vf - Set the maximum receive packet length
+ * @hw: pointer to the HW structure
+ * @max_size: value to assign to max frame size
+ **/
+int32_t ixgbevf_rlpml_set_vf(struct ixgbe_hw *hw, uint16_t max_size)
+{
+       uint32_t msgbuf[2];
+       int32_t retval;
+
+       msgbuf[0] = IXGBE_VF_SET_LPE;
+       msgbuf[1] = max_size;
+
+       retval = ixgbevf_write_msg_read_ack(hw, msgbuf, msgbuf, 2);
+       if (retval)
+               return retval;
+       if ((msgbuf[0] & IXGBE_VF_SET_LPE) &&
+           (msgbuf[0] & IXGBE_VT_MSGTYPE_FAILURE))
+               return IXGBE_ERR_MBX;
+
+       return 0;
+}
+
+/**
+ * ixgbevf_negotiate_api_version - Negotiate supported API version
+ * @hw: pointer to the HW structure
+ * @api: integer containing requested API version
+ **/
+int ixgbevf_negotiate_api_version(struct ixgbe_hw *hw, int api)
+{
+       int err;
+       uint32_t msg[3];
+
+       /* Negotiate the mailbox API version */
+       msg[0] = IXGBE_VF_API_NEGOTIATE;
+       msg[1] = api;
+       msg[2] = 0;
+
+       err = ixgbevf_write_msg_read_ack(hw, msg, msg, 3);
+       if (!err) {
+               msg[0] &= ~IXGBE_VT_MSGTYPE_CTS;
+
+               /* Store value and return 0 on success */
+               if (msg[0] == (IXGBE_VF_API_NEGOTIATE | 
IXGBE_VT_MSGTYPE_SUCCESS)) {
+                       hw->api_version = api;
+                       return 0;
+               }
+
+               err = IXGBE_ERR_INVALID_ARGUMENT;
+       }
+
+       return err;
+}
+
+int ixgbevf_get_queues(struct ixgbe_hw *hw, unsigned int *num_tcs,
+                      unsigned int *default_tc)
+{
+       int err;
+       uint32_t msg[5];
+
+       /* do nothing if API doesn't support ixgbevf_get_queues */
+       switch (hw->api_version) {
+       case ixgbe_mbox_api_11:
+       case ixgbe_mbox_api_12:
+       case ixgbe_mbox_api_13:
+       case ixgbe_mbox_api_15:
+               break;
+       default:
+               return 0;
+       }
+
+       /* Fetch queue configuration from the PF */
+       msg[0] = IXGBE_VF_GET_QUEUES;
+       msg[1] = msg[2] = msg[3] = msg[4] = 0;
+
+       err = ixgbevf_write_msg_read_ack(hw, msg, msg, 5);
+       if (!err) {
+               msg[0] &= ~IXGBE_VT_MSGTYPE_CTS;
+
+               /*
+                * if we didn't get a SUCCESS there must have been
+                * some sort of mailbox error so we should treat it
+                * as such
+                */
+               if (msg[0] != (IXGBE_VF_GET_QUEUES | IXGBE_VT_MSGTYPE_SUCCESS))
+                       return IXGBE_ERR_MBX;
+
+               /* record and validate values from message */
+               hw->mac.max_tx_queues = msg[IXGBE_VF_TX_QUEUES];
+               if (hw->mac.max_tx_queues == 0 ||
+                   hw->mac.max_tx_queues > IXGBE_VF_MAX_TX_QUEUES)
+                       hw->mac.max_tx_queues = IXGBE_VF_MAX_TX_QUEUES;
+
+               hw->mac.max_rx_queues = msg[IXGBE_VF_RX_QUEUES];
+               if (hw->mac.max_rx_queues == 0 ||
+                   hw->mac.max_rx_queues > IXGBE_VF_MAX_RX_QUEUES)
+                       hw->mac.max_rx_queues = IXGBE_VF_MAX_RX_QUEUES;
+
+               *num_tcs = msg[IXGBE_VF_TRANS_VLAN];
+               /* in case of unknown state assume we cannot tag frames */
+               if (*num_tcs > hw->mac.max_rx_queues)
+                       *num_tcs = 1;
+
+               *default_tc = msg[IXGBE_VF_DEF_QUEUE];
+               /* default to queue 0 on out-of-bounds queue number */
+               if (*default_tc >= hw->mac.max_tx_queues)
+                       *default_tc = 0;
+       }
+
+       return err;
+}
diff --git a/sys/dev/pci/pcidevs b/sys/dev/pci/pcidevs
index 5108df0145f..55a1fe812ab 100644
--- a/sys/dev/pci/pcidevs
+++ b/sys/dev/pci/pcidevs
@@ -3994,6 +3994,7 @@ product INTEL 82580_SERDES        0x1510  82580
 product INTEL 82580_SGMII      0x1511  82580
 product INTEL 82524EF          0x1513  82524EF Thunderbolt
 product INTEL 82599_KX4_MEZZ   0x1514  82599
+product INTEL X540_VF          0x1515  X540 VF
 product INTEL 82580_COPPER_DUAL        0x1516  82580
 product INTEL 82599_KR         0x1517  82599
 product INTEL 82576_NS_SERDES  0x1518  82576NS
@@ -4008,6 +4009,8 @@ product INTEL 82580_QUAD_FIBER    0x1527  82580 QF
 product INTEL X540T            0x1528  X540T
 product INTEL 82599_SFP_FCOE   0x1529  82599
 product INTEL 82599_BPLANE_FCOE        0x152a  82599
+product INTEL 82599_VF_HV      0x152e  82599 VF HV
+product INTEL X540_VF_HV       0x1530  X540 VF HV
 product INTEL I210_COPPER      0x1533  I210
 product INTEL I210_COPPER_OEM1 0x1534  I210
 product INTEL I210_COPPER_IT   0x1535  I210
@@ -4028,6 +4031,8 @@ product INTEL I218_V              0x1559  I218-V
 product INTEL I218_LM          0x155a  I218-LM
 product INTEL X540T1           0x1560  X540T
 product INTEL X550T            0x1563  X550T
+product INTEL X550_VF_HV       0x1564  X550 VF HV
+product INTEL X550_VF          0x1565  X550 VF
 product INTEL DSL5520          0x156c  DSL5520 Thunderbolt
 product INTEL DSL5520_PCIE     0x156d  DSL5520 Thunderbolt
 product INTEL I219_LM          0x156f  I219-LM
@@ -4051,11 +4056,14 @@ product INTEL I218_LM_2         0x15a0  I218-LM
 product INTEL I218_V_2         0x15a1  I218-V
 product INTEL I218_LM_3                0x15a2  I218-LM
 product INTEL I218_V_3         0x15a3  I218-V
+product INTEL X550EM_X_VF      0x15a8  X552 VF
+product INTEL X550EM_X_VF_HV   0x15a9  X552 VF HV
 product INTEL X550EM_X_KX4     0x15aa  X552 Backplane
 product INTEL X550EM_X_KR      0x15ab  X552 Backplane
 product INTEL X550EM_X_SFP     0x15ac  X552 SFP+
 product INTEL X550EM_X_10G_T   0x15ad  X552/X557-AT
 product INTEL X550EM_X_1G_T    0x15ae  X552 1GbaseT
+product INTEL X550EM_A_VF_HV   0x15b4  X553 VF HV
 product INTEL I219_LM2         0x15b7  I219-LM
 product INTEL I219_V2          0x15b8  I219-V
 product INTEL I219_LM3         0x15b9  I219-LM
@@ -4069,6 +4077,7 @@ product INTEL JHL6240_XHCI        0x15c1  JHL6240 
Thunderbolt 3
 product INTEL X550EM_A_KR      0x15c2  X553 Backplane
 product INTEL X550EM_A_KR_L    0x15c3  X553 Backplane
 product INTEL X550EM_A_SFP_N   0x15c4  X553 SFP+
+product INTEL X550EM_A_VF      0x15c5  X553 VF
 product INTEL X550EM_A_SGMII   0x15c6  X553 SGMII
 product INTEL X550EM_A_SGMII_L 0x15c7  X553 SGMII
 product INTEL X550EM_A_10G_T   0x15c8  X553 10GBaseT
diff --git a/sys/dev/pci/pcireg.h b/sys/dev/pci/pcireg.h
index 53124eccecb..49e2fd1fc0d 100644
--- a/sys/dev/pci/pcireg.h
+++ b/sys/dev/pci/pcireg.h
@@ -655,6 +655,8 @@ typedef u_int8_t pci_revision_t;
 #define PCI_MSIX_VC(i)         ((i) * 16 + 12)
 #define  PCI_MSIX_VC_MASK      0x00000001

+#define PCIR_MSIX_CTRL         0x2
+
 /*
  * Interrupt Configuration Register; contains interrupt pin and line.
  */
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
index fc7512c0974..7f9de7028ff 100644
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -172,6 +172,7 @@ struct ifnet {                              /* and the 
entries */
        int     (*if_ioctl)(struct ifnet *, u_long, caddr_t); /* ioctl hook */
        void    (*if_watchdog)(struct ifnet *); /* timer routine */
        int     (*if_wol)(struct ifnet *, int); /* WoL routine **/
+       void    (*if_configure_vlan)(struct ifnet *, uint16_t, uint16_t);       
/* configure vlan id **/

        /* queues */
        struct  ifqueue if_snd;         /* transmit queue */
diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c
index 42e09814397..413a2121aa9 100644
--- a/sys/net/if_vlan.c
+++ b/sys/net/if_vlan.c
@@ -867,10 +867,11 @@ vlan_setlladdr(struct vlan_softc *sc, struct ifreq *ifr)
 int
 vlan_set_vnetid(struct vlan_softc *sc, uint16_t tag)
 {
-       struct ifnet *ifp = &sc->sc_if;
+       struct ifnet *ifp0, *ifp = &sc->sc_if;
        struct vlan_list *tagh, *list;
        u_char link = ifp->if_link_state;
        uint64_t baud = ifp->if_baudrate;
+       uint16_t otag;
        int error;

        tagh = sc->sc_type == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh;
@@ -886,6 +887,7 @@ vlan_set_vnetid(struct vlan_softc *sc, uint16_t tag)
        if (error != 0)
                goto unlock;

+       otag = sc->sc_tag;
        if (ISSET(ifp->if_flags, IFF_RUNNING)) {
                list = &tagh[TAG_HASH(sc->sc_tag)];
                SMR_SLIST_REMOVE_LOCKED(list, sc, vlan_softc, sc_list);
@@ -897,6 +899,10 @@ vlan_set_vnetid(struct vlan_softc *sc, uint16_t tag)
        } else
                sc->sc_tag = tag;

+       ifp0 = if_get(sc->sc_ifidx0);
+       if (ifp0 != NULL && ifp0->if_configure_vlan != NULL)
+               (*ifp0->if_configure_vlan)(ifp0, tag, otag);
+
 unlock:
        rw_exit(&vlan_tagh_lk);

@@ -910,7 +916,7 @@ int
 vlan_set_parent(struct vlan_softc *sc, const char *parent)
 {
        struct ifnet *ifp = &sc->sc_if;
-       struct ifnet *ifp0;
+       struct ifnet *ifp0, *p;
        int error = 0;

        ifp0 = if_unit(parent);
@@ -937,6 +943,15 @@ vlan_set_parent(struct vlan_softc *sc, const char *parent)
                goto put;

        /* commit */
+       if (sc->sc_tag > 0) {
+               p = if_get(sc->sc_ifidx0);
+               if (p != NULL && p->if_configure_vlan != NULL)
+                       (*p->if_configure_vlan)(p, 0, sc->sc_tag);
+
+               if (ifp0->if_configure_vlan != NULL)
+                       (*ifp0->if_configure_vlan)(ifp0, sc->sc_tag, 0);
+       }
+
        sc->sc_ifidx0 = ifp0->if_index;
        if (!ISSET(sc->sc_flags, IFVF_LLADDR))
                if_setlladdr(ifp, LLADDR(ifp0->if_sadl));
@@ -949,12 +964,17 @@ put:
 int
 vlan_del_parent(struct vlan_softc *sc)
 {
-       struct ifnet *ifp = &sc->sc_if;
+       struct ifnet *ifp0, *ifp = &sc->sc_if;

        if (ISSET(ifp->if_flags, IFF_RUNNING))
                return (EBUSY);

        /* commit */
+       if (sc->sc_tag > 0) {
+               ifp0 = if_get(sc->sc_ifidx0);
+               if (ifp0 != NULL && ifp0->if_configure_vlan != NULL)
+                       (*ifp0->if_configure_vlan)(ifp0, 0, sc->sc_tag);
+       }
        sc->sc_ifidx0 = 0;
        if (!ISSET(sc->sc_flags, IFVF_LLADDR))
                if_setlladdr(ifp, etheranyaddr);


--
Yuichiro NAITO (naito.yuich...@gmail.com)

Reply via email to