igb: Add SR-IOV PF support for 82576 and I350

Add the PCI IOV schema and PF control plane for up to seven VFs with
one hardware queue per pool. Implement VF mailbox handling, MAC and
VLAN assignment, multicast filtering, promiscuity policy,
anti-spoofing, malicious-driver recovery, reset replay, and queue
lifecycle management.

The basic SR-IOV and VMDq PF implementation follows DPDK Intel e1000
code, including PF pool selection, one queue per pool, mailbox
dispatch, and VF enablement. Intel FreeBSD igb-2.5.31 supplies the
older driver baseline. Linux igb and the Intel SDMs clear up lifecycle,
isolation, reset, and family-specific details absent from DPDK.

Enabling IOV requires the PF to attach with one TX and RX queue.
Systems whose defaults select RSS queues must set the documented iflib
queue override tunables before attach.

Only 82576 and I350 support SR-IOV in silicon.  The series has been
extensively tested on I350, including thowing boundaries at the PCI BAR
that shipping drivers will never.  Still, think carefully before
reaching for this in critical environments.

Relnotes:	yes
Sponsored by:	BBOX.io
This commit is contained in:
Kevin Bowling committed 2026-07-29 20:06:46 -07:00
1 parent 930f2e4da9
commit a2ed165f00
7 files changed
+2261 -51

No files matched your search

+2
View File
@@ -1638,6 +1638,8 @@ dev/efidev/efirt.c optional efirt
dev/efidev/efirtc.c optional efirt efirtc
dev/e1000/if_em.c optional em \
compile-with "${NORMAL_C} -I$S/dev/e1000"
dev/e1000/if_igb_iov.c optional em \
compile-with "${NORMAL_C} -I$S/dev/e1000"
dev/e1000/em_txrx.c optional em \
compile-with "${NORMAL_C} -I$S/dev/e1000"
dev/e1000/igb_txrx.c optional em \
+330 -48
View File
@@ -28,6 +28,7 @@
*/
#include "if_em.h"
#include "if_igb_iov.h"
#include <sys/sbuf.h>
#include <machine/_inttypes.h>
@@ -404,6 +405,11 @@ static const pci_vendor_info_t igbv_vendor_info_array[] = {
static void *em_register(device_t);
static void *igb_register(device_t);
static void *igbv_register(device_t);
static int igb_device_attach(device_t);
#ifdef PCI_IOV
static int igb_device_iov_init(device_t, uint16_t, const nvlist_t *);
static void igb_device_iov_uninit(device_t);
#endif
static int em_if_attach_pre(if_ctx_t);
static int em_if_attach_post(if_ctx_t);
static int em_if_detach(if_ctx_t);
@@ -455,6 +461,8 @@ static void em_update_vf_stats_counters(struct e1000_softc *);
static void em_update_stats_counters(struct e1000_softc *);
static void em_add_hw_stats(struct e1000_softc *);
static int em_if_set_promisc(if_ctx_t, int);
static int em_if_set_promisc_impl(if_ctx_t, int);
static bool em_if_defer_promisc(struct e1000_softc *);
static bool em_if_vlan_filter_capable(if_ctx_t);
static bool em_if_vlan_filter_used(if_ctx_t);
static void em_if_vlan_filter_enable(struct e1000_softc *);
@@ -529,11 +537,16 @@ static device_method_t igb_methods[] = {
/* Device interface */
DEVMETHOD(device_register, igb_register),
DEVMETHOD(device_probe, iflib_device_probe),
DEVMETHOD(device_attach, iflib_device_attach),
DEVMETHOD(device_attach, igb_device_attach),
DEVMETHOD(device_detach, iflib_device_detach),
DEVMETHOD(device_shutdown, iflib_device_shutdown),
DEVMETHOD(device_suspend, iflib_device_suspend),
DEVMETHOD(device_resume, iflib_device_resume),
#ifdef PCI_IOV
DEVMETHOD(pci_iov_init, igb_device_iov_init),
DEVMETHOD(pci_iov_uninit, igb_device_iov_uninit),
DEVMETHOD(pci_iov_add_vf, iflib_device_iov_add_vf),
#endif
DEVMETHOD_END
};
@@ -655,6 +668,11 @@ static device_method_t igb_if_methods[] = {
DEVMETHOD(ifdi_tx_queue_intr_enable, igb_if_tx_queue_intr_enable),
DEVMETHOD(ifdi_debug, em_if_debug),
DEVMETHOD(ifdi_needs_restart, em_if_needs_restart),
#ifdef PCI_IOV
DEVMETHOD(ifdi_iov_init, igb_if_iov_init),
DEVMETHOD(ifdi_iov_uninit, igb_if_iov_uninit),
DEVMETHOD(ifdi_iov_vf_add, igb_if_iov_vf_add),
#endif
DEVMETHOD_END
};
@@ -982,6 +1000,59 @@ igbv_register(device_t dev)
return (&igbv_sctx_init);
}
static int
igb_device_attach(device_t dev)
{
struct e1000_softc *sc;
if_ctx_t ctx;
int error;
error = iflib_device_attach(dev);
if (error != 0)
return (error);
ctx = device_get_softc(dev);
sc = iflib_get_softc(ctx);
(void)igb_iov_attach(sc);
return (0);
}
#ifdef PCI_IOV
static int
igb_device_iov_init(device_t dev, uint16_t num_vfs,
const nvlist_t *params)
{
struct e1000_softc *sc;
if_ctx_t ctx;
int error;
ctx = device_get_softc(dev);
sc = iflib_get_softc(ctx);
error = igb_iov_validate(sc, num_vfs);
if (error != 0)
return (error);
return (iflib_device_iov_init_restart(dev, num_vfs, params));
}
static void
igb_device_iov_uninit(device_t dev)
{
struct e1000_softc *sc;
if_ctx_t ctx;
ctx = device_get_softc(dev);
sc = iflib_get_softc(ctx);
/*
* pci_iov(4) has already detached the VF devices. Tell the stop
* half of iflib's restart transaction not to wait for acknowledgements
* from VFs which can no longer service their mailbox vectors.
*/
atomic_store_rel_32(&sc->iov_teardown, 1);
iflib_device_iov_uninit_restart(dev);
}
#endif
static int
em_set_num_queues(if_ctx_t ctx)
{
@@ -1513,6 +1584,7 @@ em_if_detach(if_ctx_t ctx)
INIT_DEBUGOUT("em_if_detach: begin");
igb_iov_detach(sc);
e1000_phy_hw_reset(&sc->hw);
em_release_manageability(sc);
@@ -1601,7 +1673,7 @@ em_if_mtu_set(if_ctx_t ctx, uint32_t mtu)
break;
default:
if (sc->hw.mac.type >= igb_mac_min)
max_frame_size = 9234;
max_frame_size = IGB_MAX_FRAME_SIZE;
else /* lem */
max_frame_size = MAX_JUMBO_FRAME_SIZE;
}
@@ -1633,6 +1705,8 @@ em_if_init(if_ctx_t ctx)
int i;
INIT_DEBUGOUT("em_if_init: begin");
if (sc->vf_ifp)
sc->vf_reset_pending = true;
/* Get the latest mac address, User can use a LAA */
bcopy(if_getlladdr(ifp), sc->hw.mac.addr, ETHER_ADDR_LEN);
@@ -1653,6 +1727,7 @@ em_if_init(if_ctx_t ctx)
}
/* Initialize the hardware */
igb_iov_reset_prepare(sc);
em_reset(ctx);
/* Re-arm a link-up transition deferred for this reset. */
if (sc->link_state == EM_LINK_STATE_DOWN_RESET_PENDING ||
@@ -1697,7 +1772,11 @@ em_if_init(if_ctx_t ctx)
em_setup_vlan_hw_support(ctx);
/* Don't lose promiscuous settings */
em_if_set_promisc(ctx, if_getflags(ifp));
em_if_set_promisc_impl(ctx, if_getflags(ifp));
atomic_readandclear_32(&sc->promisc_pending);
/* Restore PF/VF pool configuration after the global reset. */
igb_iov_initialize(sc);
if (sc->hw.mac.ops.clear_hw_cntrs != NULL)
sc->hw.mac.ops.clear_hw_cntrs(&sc->hw);
@@ -1733,6 +1812,8 @@ em_if_init(if_ctx_t ctx)
else
e1000_set_eee_i350(&sc->hw, true, true);
}
if (sc->vf_ifp)
sc->vf_reset_pending = false;
}
/*
@@ -2039,17 +2120,43 @@ em_msix_link(void *arg)
++sc->link_irq;
MPASS(sc->hw.back != NULL);
/*
* The VF's admin vector represents mailbox and link activity. It has
* no PF ICR at E1000_ICR, so process every admin-vector interrupt,
* matching the igbvf misc-vector model.
*/
if (sc->vf_ifp) {
sc->hw.mac.get_link_status = true;
iflib_admin_intr_deferred(sc->ctx);
E1000_WRITE_REG(&sc->hw, E1000_EIMS, sc->link_mask);
return (FILTER_HANDLED);
}
reg_icr = E1000_READ_REG(&sc->hw, E1000_ICR);
/*
* Enabling or disabling SR-IOV can briefly make PF MMIO reads return
* all ones. This is not an interrupt cause; in particular, do not
* turn it into a malicious-driver event.
*/
if (__predict_false(reg_icr == 0xffffffff))
goto rearm;
if (reg_icr & E1000_ICR_RXO)
sc->rx_overruns++;
if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC))
em_handle_link(sc->ctx);
if (reg_icr & E1000_ICR_MDDET)
igb_iov_mdd_event(sc);
if (reg_icr & E1000_ICR_VMMB)
iflib_admin_intr_deferred(sc->ctx);
rearm:
/* Re-arm unconditionally */
if (sc->hw.mac.type >= igb_mac_min) {
E1000_WRITE_REG(&sc->hw, E1000_IMS, E1000_IMS_LSC);
E1000_WRITE_REG(&sc->hw, E1000_IMS,
E1000_IMS_LSC | igb_iov_intr_mask(sc));
E1000_WRITE_REG(&sc->hw, E1000_EIMS, sc->link_mask);
} else if (sc->hw.mac.type == e1000_82574) {
E1000_WRITE_REG(&sc->hw, E1000_IMS,
@@ -2186,12 +2293,63 @@ em_if_media_change(if_ctx_t ctx)
static int
em_if_set_promisc(if_ctx_t ctx, int flags)
{
struct e1000_softc *sc;
sc = iflib_get_softc(ctx);
if (em_if_defer_promisc(sc))
return (0);
return (em_if_set_promisc_impl(ctx, flags));
}
static bool
em_if_defer_promisc(struct e1000_softc *sc)
{
switch (sc->hw.mac.type) {
case e1000_82576:
case e1000_i350:
case e1000_vfadapt:
case e1000_vfadapt_i350:
break;
default:
return (false);
}
/*
* iflib drops its context lock around IFDI_PROMISC_SET. Run mailbox
* and IOV register operations later from the locked admin task.
* A deferred VF mailbox rejection cannot be returned to ifconfig; the
* admin task logs it instead.
*/
atomic_set_32(&sc->promisc_pending, 1);
iflib_admin_intr_deferred(sc->ctx);
return (true);
}
static int
em_if_set_promisc_impl(if_ctx_t ctx, int flags)
{
struct e1000_softc *sc = iflib_get_softc(ctx);
if_t ifp = iflib_get_ifp(ctx);
enum e1000_promisc_type type;
u32 reg_rctl;
int mcnt = 0;
if (sc->vf_ifp) {
if (flags & IFF_PROMISC)
type = e1000_promisc_enabled;
else if (flags & IFF_ALLMULTI)
type = e1000_promisc_multicast;
else
type = e1000_promisc_disabled;
if (e1000_promisc_set_vf(&sc->hw, type) != E1000_SUCCESS) {
device_printf(sc->dev,
"VF promiscuous-mode request failed\n");
return (EPERM);
}
return (0);
}
reg_rctl = E1000_READ_REG(&sc->hw, E1000_RCTL);
reg_rctl &= ~(E1000_RCTL_SBP | E1000_RCTL_UPE);
if (flags & IFF_ALLMULTI)
@@ -2210,16 +2368,21 @@ em_if_set_promisc(if_ctx_t ctx, int flags)
if (em_debug_sbp)
reg_rctl |= E1000_RCTL_SBP;
E1000_WRITE_REG(&sc->hw, E1000_RCTL, reg_rctl);
em_if_vlan_filter_disable(sc);
if (igb_iov_enabled(sc))
em_if_vlan_filter_enable(sc);
else
em_if_vlan_filter_disable(sc);
} else {
if (flags & IFF_ALLMULTI) {
reg_rctl |= E1000_RCTL_MPE;
reg_rctl &= ~E1000_RCTL_UPE;
E1000_WRITE_REG(&sc->hw, E1000_RCTL, reg_rctl);
}
if (em_if_vlan_filter_used(ctx))
if (igb_iov_enabled(sc) || em_if_vlan_filter_used(ctx))
em_if_vlan_filter_enable(sc);
}
igb_iov_update_pf_vmolr(sc);
igb_iov_rebuild_vlan(sc);
return (0);
}
@@ -2268,6 +2431,11 @@ em_if_multi_set(if_ctx_t ctx)
mcnt = if_foreach_llmaddr(ifp, em_copy_maddr, mta);
if (sc->vf_ifp) {
e1000_update_mc_addr_list(&sc->hw, mta, mcnt);
return;
}
if (mcnt < MAX_NUM_MULTICAST_ADDRESSES)
e1000_update_mc_addr_list(&sc->hw, mta, mcnt);
@@ -2293,6 +2461,8 @@ em_if_multi_set(if_ctx_t ctx)
if (sc->hw.bus.pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
e1000_pci_set_mwi(&sc->hw);
}
igb_iov_rebuild_mta(sc);
igb_iov_update_pf_vmolr(sc);
}
/*********************************************************************
@@ -2321,6 +2491,12 @@ em_if_update_admin_status(if_ctx_t ctx)
u32 link_check, thstat, ctrl;
bool reset_requested = false;
if (atomic_readandclear_32(&sc->promisc_pending) != 0)
(void)em_if_set_promisc_impl(ctx,
if_getflags(iflib_get_ifp(ctx)));
igb_iov_handle_mdd(sc);
igb_iov_handle_mbx(sc);
link_check = thstat = ctrl = 0;
/* Get the cached link value or read phy for real */
switch (hw->phy.media_type) {
@@ -2348,7 +2524,12 @@ em_if_update_admin_status(if_ctx_t ctx)
break;
/* VF device is type_unknown */
case e1000_media_type_unknown:
e1000_check_for_link(hw);
if (e1000_check_for_link(hw) != E1000_SUCCESS &&
sc->vf_ifp && !sc->vf_reset_pending) {
sc->vf_reset_pending = true;
iflib_request_reset(ctx);
iflib_admin_intr_deferred(ctx);
}
link_check = !hw->mac.get_link_status;
/* FALLTHROUGH */
default:
@@ -2401,7 +2582,12 @@ em_if_update_admin_status(if_ctx_t ctx)
hw->mac.type >= igb_mac_min) {
hw->dev_spec._82575.media_changed = false;
sc->flags |= IGB_MEDIA_RESET;
em_reset(ctx);
if (igb_iov_enabled(sc)) {
iflib_request_reset(ctx);
iflib_admin_intr_deferred(ctx);
reset_requested = true;
} else
em_reset(ctx);
}
/* Only do TSO on gigabit for older chips due to errata */
if (hw->mac.type < igb_mac_min)
@@ -2417,6 +2603,7 @@ em_if_update_admin_status(if_ctx_t ctx)
iflib_link_state_change(ctx, LINK_STATE_UP,
IF_Mbps(sc->link_speed));
}
igb_iov_ping_all_vfs(sc);
} else if (!link_check &&
(sc->link_state == EM_LINK_STATE_UP ||
sc->link_state == EM_LINK_STATE_UP_RESET_PENDING)) {
@@ -2432,6 +2619,7 @@ em_if_update_admin_status(if_ctx_t ctx)
EM_LINK_STATE_DOWN_RESET_PENDING : EM_LINK_STATE_DOWN;
if (link_was_published)
iflib_link_state_change(ctx, LINK_STATE_DOWN, 0);
igb_iov_ping_all_vfs(sc);
}
em_update_stats_counters(sc);
@@ -2472,6 +2660,7 @@ em_if_stop(if_ctx_t ctx)
if (sc->hw.mac.type >= e1000_pch_spt && sc->hw.mac.type < igb_mac_min)
em_flush_desc_rings(sc);
igb_iov_reset_prepare(sc);
e1000_reset_hw(&sc->hw);
if (sc->hw.mac.type >= e1000_82544 && !sc->vf_ifp)
E1000_WRITE_REG(&sc->hw, E1000_WUFC, 0);
@@ -2682,6 +2871,14 @@ igb_configure_queues(struct e1000_softc *sc)
struct em_tx_queue *tx_que;
u32 tmp, ivar = 0;
/*
* Queue ownership can change when SR-IOV is enabled or disabled.
* Rebuild the interrupt mask for the current layout instead of
* retaining vectors from a previous initialization.
*/
sc->que_mask = 0;
sc->link_mask = 0;
/* First turn on RSS capability */
if (hw->mac.type != e1000_82575)
E1000_WRITE_REG(hw, E1000_GPIE,
@@ -2714,6 +2911,7 @@ igb_configure_queues(struct e1000_softc *sc)
ivar |= rx_que->msix | E1000_IVAR_VALID;
}
E1000_WRITE_REG_ARRAY(hw, E1000_IVAR0, index, ivar);
sc->que_mask |= rx_que->eims;
}
/* TX entries */
for (int i = 0; i < sc->tx_num_queues; i++) {
@@ -2845,6 +3043,8 @@ igb_initialize_interrupt_rate(struct e1000_softc *sc)
E1000_WRITE_REG(hw, E1000_EITR(rx_que->msix),
rx_que->itr_setting);
}
if (sc->intr_type == IFLIB_INTR_MSIX)
E1000_WRITE_REG(hw, E1000_EITR(sc->linkvec), newitr);
}
static void
@@ -2974,6 +3174,16 @@ igb_init_dmac(struct e1000_softc *sc, u32 pba)
if (hw->mac.type == e1000_i211)
return;
/*
* I350 DMA coalescing and SR-IOV are mutually exclusive. Preserve
* the configured value so it can be restored after IOV is disabled.
*/
if (igb_iov_enabled(sc)) {
if (hw->mac.type > e1000_82580)
E1000_WRITE_REG(hw, E1000_DMACR, 0);
return;
}
max_frame_size = sc->shared->isc_max_frame_size;
if (hw->mac.type > e1000_82580) {
@@ -3945,7 +4155,7 @@ em_initialize_receive_unit(if_ctx_t ctx)
rctl &= ~E1000_RCTL_SBP;
/* Enable Long Packet receive */
if (if_getmtu(ifp) > ETHERMTU)
if (igb_iov_enabled(sc) || if_getmtu(ifp) > ETHERMTU)
rctl |= E1000_RCTL_LPE;
else
rctl &= ~E1000_RCTL_LPE;
@@ -4086,16 +4296,16 @@ em_initialize_receive_unit(if_ctx_t ctx)
} else if (hw->mac.type >= igb_mac_min) {
u32 psize, srrctl = 0;
if (if_getmtu(ifp) > ETHERMTU) {
if (igb_iov_enabled(sc)) {
E1000_WRITE_REG(hw, E1000_RLPML,
IGB_IOV_MAX_FRAME_SIZE);
} else if (!sc->vf_ifp && if_getmtu(ifp) > ETHERMTU) {
psize = scctx->isc_max_frame_size;
/* are we on a vlan? */
if (if_vlantrunkinuse(ifp))
psize += VLAN_TAG_SIZE;
if (sc->vf_ifp)
e1000_rlpml_set_vf(hw, psize);
else
E1000_WRITE_REG(hw, E1000_RLPML, psize);
E1000_WRITE_REG(hw, E1000_RLPML, psize);
}
/* Set maximum packet buffer len */
@@ -4109,11 +4319,11 @@ em_initialize_receive_unit(if_ctx_t ctx)
* This drops frames rather than hanging the RX MAC for all
* queues.
*/
if ((sc->rx_num_queues > 1) &&
if (igb_iov_enabled(sc) ||
((sc->rx_num_queues > 1) &&
(sc->fc == e1000_fc_none ||
sc->fc == e1000_fc_rx_pause)) {
sc->fc == e1000_fc_rx_pause)))
srrctl |= E1000_SRRCTL_DROP_EN;
}
/* Setup the Base and Length of the Rx Descriptor Rings */
for (i = 0, que = sc->rx_queues; i < sc->rx_num_queues;
i++, que++) {
@@ -4190,37 +4400,62 @@ static void
em_if_vlan_register(if_ctx_t ctx, u16 vtag)
{
struct e1000_softc *sc = iflib_get_softc(ctx);
u32 index, bit;
bool present;
u32 index, mask;
index = (vtag >> 5) & 0x7F;
bit = vtag & 0x1F;
sc->shadow_vfta[index] |= (1 << bit);
++sc->num_vlans;
if (!sc->vf_ifp)
em_if_vlan_filter_write(sc);
else
/*
* Physical funtion may reject registering VLAN
* but we have no way to inform the stack
* about that.
*/
e1000_vfta_set_vf(&sc->hw, vtag, true);
mask = 1U << (vtag & 0x1F);
present = (sc->shadow_vfta[index] & mask) != 0;
/*
* On a VF, record registration intent for replay even if the PF is not
* ready to accept it yet.
*/
sc->shadow_vfta[index] |= mask;
if (!present)
++sc->num_vlans;
if (sc->vf_ifp &&
e1000_vfta_set_vf(&sc->hw, vtag, true) != E1000_SUCCESS) {
device_printf(sc->dev,
"VF VLAN %u add request failed\n", vtag);
}
if (!sc->vf_ifp) {
if (igb_iov_enabled(sc))
igb_iov_rebuild_vlan(sc);
else
em_if_vlan_filter_write(sc);
}
}
static void
em_if_vlan_unregister(if_ctx_t ctx, u16 vtag)
{
struct e1000_softc *sc = iflib_get_softc(ctx);
u32 index, bit;
bool present;
u32 index, mask;
index = (vtag >> 5) & 0x7F;
bit = vtag & 0x1F;
sc->shadow_vfta[index] &= ~(1 << bit);
--sc->num_vlans;
if (!sc->vf_ifp)
em_if_vlan_filter_write(sc);
else
e1000_vfta_set_vf(&sc->hw, vtag, false);
mask = 1U << (vtag & 0x1F);
present = (sc->shadow_vfta[index] & mask) != 0;
if (sc->vf_ifp &&
e1000_vfta_set_vf(&sc->hw, vtag, false) != E1000_SUCCESS) {
device_printf(sc->dev,
"VF VLAN %u remove request failed\n", vtag);
/*
* The PF can still admit this VID. Retain the bit so its
* stripped frames remain tagged and are dropped by vlan(4)
* after the child disappears, rather than reaching the parent.
*/
return;
}
sc->shadow_vfta[index] &= ~mask;
if (present)
--sc->num_vlans;
if (!sc->vf_ifp) {
if (igb_iov_enabled(sc))
igb_iov_rebuild_vlan(sc);
else
em_if_vlan_filter_write(sc);
}
}
static bool
@@ -4299,15 +4534,29 @@ em_setup_vlan_hw_support(if_ctx_t ctx)
struct e1000_softc *sc = iflib_get_softc(ctx);
struct e1000_hw *hw = &sc->hw;
if_t ifp = iflib_get_ifp(ctx);
u32 reg;
u32 max_frame_size, reg;
u16 vid;
/*
* Only PFs have control over VLAN HW filtering
* configuration. VFs have to act as if it's always
* enabled.
*/
if (sc->vf_ifp)
if (sc->vf_ifp) {
max_frame_size = min(sc->shared->isc_max_frame_size +
VLAN_TAG_SIZE, IGB_IOV_MAX_FRAME_SIZE);
e1000_rlpml_set_vf(hw, max_frame_size);
for (vid = 0; vid < 4096; vid++) {
if ((sc->shadow_vfta[vid >> 5] &
(1U << (vid & 0x1f))) == 0)
continue;
if (e1000_vfta_set_vf(hw, vid, true) != E1000_SUCCESS)
device_printf(sc->dev,
"VF VLAN %u restore request failed\n",
vid);
}
return;
}
if (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING &&
!em_disable_crc_stripping) {
@@ -4320,11 +4569,25 @@ em_setup_vlan_hw_support(if_ctx_t ctx)
E1000_WRITE_REG(hw, E1000_CTRL, reg);
}
/* If we aren't doing HW filtering, we're done */
/*
* SR-IOV always needs VFE for VF isolation. When PF hardware VLAN
* filtering is disabled, the IOV VLAN rebuild instead makes the PF
* VLAN-promiscuous without disabling the global filter.
*/
if (!em_if_vlan_filter_capable(ctx)) {
em_if_vlan_filter_disable(sc);
if (igb_iov_enabled(sc)) {
#ifdef PCI_IOV
sc->iov_pf_vlan_promisc = true;
#endif
em_if_vlan_filter_enable(sc);
} else
em_if_vlan_filter_disable(sc);
return;
}
#ifdef PCI_IOV
if (igb_iov_enabled(sc))
sc->iov_pf_vlan_promisc = false;
#endif
/*
* A soft reset zero's out the VFTA, so
@@ -4371,14 +4634,21 @@ igb_if_intr_enable(if_ctx_t ctx)
{
struct e1000_softc *sc = iflib_get_softc(ctx);
struct e1000_hw *hw = &sc->hw;
u32 mask;
u32 mask, reg;
if (__predict_true(sc->intr_type == IFLIB_INTR_MSIX)) {
mask = (sc->que_mask | sc->link_mask);
E1000_WRITE_REG(hw, E1000_EIAC, mask);
E1000_WRITE_REG(hw, E1000_EIAM, mask);
/*
* VF interrupt controls are also mapped into these registers.
* Preserve them and change only the PF vectors we own.
*/
reg = E1000_READ_REG(hw, E1000_EIAC);
E1000_WRITE_REG(hw, E1000_EIAC, reg | mask);
reg = E1000_READ_REG(hw, E1000_EIAM);
E1000_WRITE_REG(hw, E1000_EIAM, reg | mask);
E1000_WRITE_REG(hw, E1000_EIMS, mask);
E1000_WRITE_REG(hw, E1000_IMS, E1000_IMS_LSC);
E1000_WRITE_REG(hw, E1000_IMS,
E1000_IMS_LSC | igb_iov_intr_mask(sc));
} else
E1000_WRITE_REG(hw, E1000_IMS, IMS_ENABLE_MASK);
E1000_WRITE_FLUSH(hw);
@@ -4389,10 +4659,22 @@ igb_if_intr_disable(if_ctx_t ctx)
{
struct e1000_softc *sc = iflib_get_softc(ctx);
struct e1000_hw *hw = &sc->hw;
u32 mask, reg;
if (__predict_true(sc->intr_type == IFLIB_INTR_MSIX)) {
E1000_WRITE_REG(hw, E1000_EIMC, 0xffffffff);
E1000_WRITE_REG(hw, E1000_EIAC, 0);
/*
* Do not use a blanket EIMC write here. VF interrupt controls
* are mapped into the same PF register space, so clearing bits
* we do not own can leave running VFs with interrupts masked.
* Before initial queue configuration the owned mask is zero
* because this driver has not enabled a vector yet.
*/
mask = (sc->que_mask | sc->link_mask);
reg = E1000_READ_REG(hw, E1000_EIAM);
E1000_WRITE_REG(hw, E1000_EIAM, reg & ~mask);
E1000_WRITE_REG(hw, E1000_EIMC, mask);
reg = E1000_READ_REG(hw, E1000_EIAC);
E1000_WRITE_REG(hw, E1000_EIAC, reg & ~mask);
}
E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
E1000_WRITE_FLUSH(hw);
+27
View File
@@ -48,6 +48,7 @@
#endif
#include <sys/buf_ring.h>
#include <sys/bus.h>
#include <sys/callout.h>
#include <sys/endian.h>
#include <sys/kernel.h>
#include <sys/kthread.h>
@@ -95,6 +96,9 @@
#include "e1000_82571.h"
#include "ifdi_if.h"
struct igb_vf;
struct igb_vf_mac_filter;
/* Tunables */
/*
@@ -133,6 +137,7 @@
#define EM_DEFAULT_RXD 1024
#define EM_DEFAULT_MULTI_RXD 4096
#define IGB_MAX_RXD 4096
#define IGB_MAX_FRAME_SIZE 9234
/*
* EM_TIDV - Transmit Interrupt Delay Value
@@ -592,6 +597,27 @@ struct e1000_softc {
u32 pba;
int link_mask;
int tso_automasked;
u32 promisc_pending;
#ifdef PCI_IOV
struct igb_vf *vfs;
struct igb_vf_mac_filter *vf_mac_filters;
struct callout iov_mbx_retry;
u32 iov_vfta[EM_VFTA_SIZE];
u32 iov_mdd_cause;
u32 iov_pending;
u32 iov_spoof_pending;
u32 iov_teardown;
struct timeval iov_last_mdd_log;
u16 num_vfs;
u16 num_vf_mac_filters;
u16 pool;
bool iov_hw_active;
bool iov_mbx_retry_initialized;
bool iov_pf_mdd_blocked;
bool iov_pf_vlan_promisc;
bool iov_vfta_valid;
#endif
u64 que_mask;
@@ -616,6 +642,7 @@ struct e1000_softc {
} ustats;
u16 vf_ifp;
bool vf_reset_pending;
};
/********************************************************************************
File diff suppressed because it is too large. Load diff
+57
View File
@@ -0,0 +1,57 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2010-2016, Intel Corporation
* Copyright (c) 2026 Kevin Bowling <kbowling@FreeBSD.org>
*/
#ifndef _IF_IGB_IOV_H_
#define _IF_IGB_IOV_H_
#define IGB_IOV_MAX_FRAME_SIZE 0x2600
#ifdef PCI_IOV
#include <sys/nv.h>
#include <sys/iov_schema.h>
#include <dev/pci/pci_iov.h>
int igb_iov_attach(struct e1000_softc *);
void igb_iov_detach(struct e1000_softc *);
bool igb_iov_supported(const struct e1000_softc *);
bool igb_iov_enabled(const struct e1000_softc *);
int igb_iov_validate(struct e1000_softc *, u16);
int igb_if_iov_init(if_ctx_t, u16, const nvlist_t *);
void igb_if_iov_uninit(if_ctx_t);
int igb_if_iov_vf_add(if_ctx_t, u16, const nvlist_t *);
void igb_iov_initialize(struct e1000_softc *);
void igb_iov_handle_mbx(struct e1000_softc *);
void igb_iov_handle_mdd(struct e1000_softc *);
void igb_iov_mdd_event(struct e1000_softc *);
void igb_iov_ping_all_vfs(struct e1000_softc *);
void igb_iov_reset_prepare(struct e1000_softc *);
u32 igb_iov_intr_mask(const struct e1000_softc *);
void igb_iov_rebuild_mta(struct e1000_softc *);
void igb_iov_rebuild_vlan(struct e1000_softc *);
void igb_iov_update_pf_vmolr(struct e1000_softc *);
#else
#define igb_iov_attach(_sc) ((void)(_sc), 0)
#define igb_iov_detach(_sc) ((void)(_sc))
#define igb_iov_supported(_sc) (false)
#define igb_iov_enabled(_sc) (false)
#define igb_iov_initialize(_sc)
#define igb_iov_handle_mbx(_sc)
#define igb_iov_handle_mdd(_sc)
#define igb_iov_mdd_event(_sc)
#define igb_iov_ping_all_vfs(_sc)
#define igb_iov_reset_prepare(_sc)
#define igb_iov_intr_mask(_sc) (0)
#define igb_iov_rebuild_mta(_sc)
#define igb_iov_rebuild_vlan(_sc)
#define igb_iov_update_pf_vmolr(_sc)
#endif
#endif /* _IF_IGB_IOV_H_ */
+24 -1
View File
@@ -73,6 +73,28 @@ struct if_txrx igb_txrx = {
.ift_legacy_intr = em_intr
};
static bool
igb_vf_vlan_registered(const struct e1000_softc *sc, u16 vtag)
{
u16 vid;
/*
* 82576 strips an administrative access VLAN but still reports it in
* the descriptor. Like Linux igbvf, expose tags only when the VF
* requested that VID from the PF.
*/
if (sc->hw.mac.type != e1000_vfadapt &&
sc->hw.mac.type != e1000_vfadapt_i350)
return (true);
vid = EVL_VLANOFTAG(vtag);
/*
* A trunk VF is an implicit member of VID 0, so retain priority-tag
* metadata without requiring vlan(4) to register a VID-0 interface.
*/
return (vid == 0 ||
(sc->shadow_vfta[vid >> 5] & (1U << (vid & 0x1f))) != 0);
}
/**********************************************************************
*
* Setup work for hardware segmentation offload (TSO) on
@@ -519,7 +541,8 @@ igb_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
ri->iri_vtag = be16toh(rxd->wb.upper.vlan);
else
ri->iri_vtag = le16toh(rxd->wb.upper.vlan);
ri->iri_flags |= M_VLANTAG;
if (igb_vf_vlan_registered(sc, ri->iri_vtag))
ri->iri_flags |= M_VLANTAG;
}
ri->iri_flowid =
+2 -2
View File
@@ -1,10 +1,10 @@
.PATH: ${SRCTOP}/sys/dev/e1000
KMOD = if_em
SRCS = device_if.h bus_if.h pci_if.h opt_ddb.h opt_inet.h \
SRCS = device_if.h bus_if.h pci_if.h pci_iov_if.h opt_ddb.h opt_inet.h \
opt_inet6.h opt_rss.h ifdi_if.h
SRCS += $(CORE_SRC) $(LEGACY_SRC)
SRCS += $(COMMON_SHARED) $(LEGACY_SHARED) $(PCIE_SHARED)
CORE_SRC = if_em.c em_txrx.c e1000_osdep.c
CORE_SRC = if_em.c if_igb_iov.c em_txrx.c e1000_osdep.c
CORE_SRC += igb_txrx.c
COMMON_SHARED = e1000_api.c e1000_base.c e1000_phy.c e1000_nvm.c e1000_mac.c \
e1000_manage.c e1000_vf.c e1000_mbx.c e1000_i210.c