diff options
| -rw-r--r-- | share/man/man4/ix.4 | 24 | ||||
| -rw-r--r-- | sys/dev/ixgbe/if_ix.c | 216 | ||||
| -rw-r--r-- | sys/dev/ixgbe/if_sriov.c | 222 | ||||
| -rw-r--r-- | sys/dev/ixgbe/ix_txrx.c | 18 | ||||
| -rw-r--r-- | sys/dev/ixgbe/ixgbe.h | 6 |
5 files changed, 392 insertions, 94 deletions
diff --git a/share/man/man4/ix.4 b/share/man/man4/ix.4 index 39ed49aa8dfc..fb1d1032c0f1 100644 --- a/share/man/man4/ix.4 +++ b/share/man/man4/ix.4 @@ -29,7 +29,7 @@ .\" .\" * Other names and brands may be claimed as the property of others. .\" -.Dd November 10, 2025 +.Dd August 6, 2026 .Dt IX 4 .Os .Sh NAME @@ -70,6 +70,27 @@ The maximum MTU size for Jumbo Frames is 9710. This driver version supports VLANs. For information on enabling VLANs, see .Xr ifconfig 8 . +.Sh SR-IOV +The driver-specific +.Va vlan +parameter in +.Xr iovctl.conf 5 +accepts a VLAN identifier from 1 through 4095 or the keyword +.Dq trunk , +which is the default. +A numeric VLAN configures an access VF: the PF inserts the VLAN tag on +transmit and strips it on receive. +The stripped administrative tag is not presented to the VF network stack as +.Dv M_VLANTAG , +so received packets are delivered directly through the VF interface. +With +.Dq trunk , +the VF may add and remove individual VLAN memberships; tags for VLANs +registered by the VF are presented normally to its network stack. +.Pp +VLAN filtering remains enabled in the hardware while SR-IOV is active so that +the PF can enforce VLAN ownership for each VF pool, including when hardware +VLAN filtering has been disabled on the PF interface. .Sh HARDWARE The .Nm @@ -220,6 +241,7 @@ issue to .Xr ng_ether 4 , .Xr polling 4 , .Xr vlan 4 , +.Xr iovctl.conf 5 , .Xr ifconfig 8 , .Xr sysctl 8 .Sh HISTORY diff --git a/sys/dev/ixgbe/if_ix.c b/sys/dev/ixgbe/if_ix.c index 6f8c453c0690..6a9bf6089a97 100644 --- a/sys/dev/ixgbe/if_ix.c +++ b/sys/dev/ixgbe/if_ix.c @@ -237,7 +237,6 @@ static void ixgbe_add_hw_stats(struct ixgbe_softc *); static int ixgbe_set_flowcntl(struct ixgbe_softc *, int); static int ixgbe_set_advertise(struct ixgbe_softc *, int); static int ixgbe_get_default_advertise(struct ixgbe_softc *); -static void ixgbe_setup_vlan_hw_support(if_ctx_t); static void ixgbe_config_gpie(struct ixgbe_softc *); static void ixgbe_config_delay_values(struct ixgbe_softc *); @@ -2310,12 +2309,21 @@ static void ixgbe_if_vlan_register(if_ctx_t ctx, u16 vtag) { struct ixgbe_softc *sc = iflib_get_softc(ctx); - u16 index, bit; + bool present; + u16 index; + u32 mask; index = (vtag >> 5) & 0x7F; - bit = vtag & 0x1F; - sc->shadow_vfta[index] |= (1 << bit); - ++sc->num_vlans; + mask = 1U << (vtag & 0x1F); + present = (sc->shadow_vfta[index] & mask) != 0; + sc->shadow_vfta[index] |= mask; + if (!present) + ++sc->num_vlans; +#ifdef PCI_IOV + if ((sc->feat_en & IXGBE_FEATURE_SRIOV) != 0 && + sc->iov_vfta_valid && !sc->iov_vlan_promisc) + (void)ixgbe_set_vfta(&sc->hw, vtag, sc->pool, true, true); +#endif ixgbe_setup_vlan_hw_support(ctx); } /* ixgbe_if_vlan_register */ @@ -2328,96 +2336,167 @@ static void ixgbe_if_vlan_unregister(if_ctx_t ctx, u16 vtag) { struct ixgbe_softc *sc = iflib_get_softc(ctx); - u16 index, bit; + bool present; + u16 index; + u32 mask; index = (vtag >> 5) & 0x7F; - bit = vtag & 0x1F; - sc->shadow_vfta[index] &= ~(1 << bit); - --sc->num_vlans; - /* Re-init to load the changes */ + mask = 1U << (vtag & 0x1F); + present = (sc->shadow_vfta[index] & mask) != 0; + sc->shadow_vfta[index] &= ~mask; + if (present) + --sc->num_vlans; +#ifdef PCI_IOV + if ((sc->feat_en & IXGBE_FEATURE_SRIOV) != 0 && + sc->iov_vfta_valid && !sc->iov_vlan_promisc) + (void)ixgbe_set_vfta(&sc->hw, vtag, sc->pool, false, true); +#endif ixgbe_setup_vlan_hw_support(ctx); } /* ixgbe_if_vlan_unregister */ +#ifdef PCI_IOV +static bool +ixgbe_iov_pf_owns_vlan(const struct ixgbe_softc *sc, u16 vlan) +{ + + return ((sc->shadow_vfta[vlan >> 5] & + (1U << (vlan & 0x1f))) != 0); +} + +/* + * start_hw clears both VFTA and VLVF. Reconstruct the shared tables from + * PF and VF desired state after every reset or filtering-mode transition. + * Allocate VF entries first so PF-only VLANs cannot exhaust VLVF. + */ +static void +ixgbe_iov_vlan_rebuild(struct ixgbe_softc *sc, bool promisc) +{ + struct ixgbe_hw *hw; + struct ixgbe_vf *vf; + u32 vfta[IXGBE_VFTA_SIZE]; + u32 bits, vlan, vlvf; + int bit, failures, i, word; + + hw = &sc->hw; + bcopy(sc->shadow_vfta, vfta, sizeof(vfta)); + (void)ixgbe_clear_vfta(hw); + failures = 0; + for (i = 0; i < sc->num_vfs; i++) { + vf = &sc->vfs[i]; + if ((vf->flags & IXGBE_VF_ACTIVE) == 0) + continue; + for (word = 0; word < IXGBE_VFTA_SIZE; word++) { + bits = vf->vlans[word]; + while (bits != 0) { + bit = ffs(bits) - 1; + vlan = word * 32 + bit; + if (ixgbe_set_vfta(hw, vlan, vf->pool, true, + false) == IXGBE_SUCCESS) + vfta[word] |= 1U << bit; + else + failures++; + bits &= ~(1U << bit); + } + } + } + + /* Add the PF to shared entries, or every entry in promiscuous mode. */ + for (i = 1; i < IXGBE_VLVF_ENTRIES; i++) { + vlvf = IXGBE_READ_REG(hw, IXGBE_VLVF(i)); + if ((vlvf & IXGBE_VLVF_VIEN) == 0) + continue; + vlan = vlvf & IXGBE_VLVF_VLANID_MASK; + if (promisc || ixgbe_iov_pf_owns_vlan(sc, vlan)) + (void)ixgbe_set_vfta(hw, vlan, sc->pool, true, true); + vfta[vlan >> 5] |= 1U << (vlan & 0x1f); + } + if (promisc) + for (i = 0; i < IXGBE_VFTA_SIZE; i++) + vfta[i] = UINT32_MAX; + for (i = 0; i < IXGBE_VFTA_SIZE; i++) + IXGBE_WRITE_REG(hw, IXGBE_VFTA(i), vfta[i]); + if (failures != 0) + device_printf(sc->dev, + "VF VLAN restore failed for %d memberships\n", failures); +} + +static void +ixgbe_iov_vlan_sync(struct ixgbe_softc *sc, bool promisc) +{ + + if (sc->iov_vfta_valid && sc->iov_vlan_promisc == promisc) + return; + ixgbe_iov_vlan_rebuild(sc, promisc); + sc->iov_vlan_promisc = promisc; + sc->iov_vfta_valid = true; +} +#endif + /************************************************************************ * ixgbe_setup_vlan_hw_support ************************************************************************/ -static void +void ixgbe_setup_vlan_hw_support(if_ctx_t ctx) { if_t ifp = iflib_get_ifp(ctx); struct ixgbe_softc *sc = iflib_get_softc(ctx); struct ixgbe_hw *hw = &sc->hw; struct rx_ring *rxr; + bool strip; int i; u32 ctrl; - - /* - * We get here thru init_locked, 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 || - (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) == 0) { - /* Clear the vlan hw flag */ - for (i = 0; i < sc->num_rx_queues; i++) { - rxr = &sc->rx_queues[i].rxr; - /* On 82599 the VLAN enable is per/queue in RXDCTL */ - if (hw->mac.type != ixgbe_mac_82598EB) { - ctrl = IXGBE_READ_REG(hw, - IXGBE_RXDCTL(rxr->me)); + strip = sc->num_vlans != 0 && + (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) != 0; + for (i = 0; i < sc->num_rx_queues; i++) { + rxr = &sc->rx_queues[i].rxr; + /* On 82599 and newer VLAN stripping is per receive queue. */ + if (hw->mac.type != ixgbe_mac_82598EB) { + ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)); + if (strip) + ctrl |= IXGBE_RXDCTL_VME; + else ctrl &= ~IXGBE_RXDCTL_VME; - IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), - ctrl); - } - rxr->vtag_strip = false; + IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), ctrl); } - ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); - /* Enable the Filter Table if enabled */ - ctrl |= IXGBE_VLNCTRL_CFIEN; - ctrl &= ~IXGBE_VLNCTRL_VFE; - if (hw->mac.type == ixgbe_mac_82598EB) + rxr->vtag_strip = strip; + } + + ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); + if (hw->mac.type == ixgbe_mac_82598EB) { + if (strip) + ctrl |= IXGBE_VLNCTRL_VME; + else ctrl &= ~IXGBE_VLNCTRL_VME; + } + +#ifdef PCI_IOV + if ((sc->feat_en & IXGBE_FEATURE_SRIOV) != 0) { + /* + * VFE must remain enabled to enforce per-pool VLAN ownership. + */ + ctrl &= ~IXGBE_VLNCTRL_CFIEN; + ctrl |= IXGBE_VLNCTRL_VFE; IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl); + ixgbe_iov_vlan_sync(sc, + (if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) == 0); return; } +#endif - /* Setup the queues for vlans */ - if (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) { - for (i = 0; i < sc->num_rx_queues; i++) { - rxr = &sc->rx_queues[i].rxr; - /* On 82599 the VLAN enable is per/queue in RXDCTL */ - if (hw->mac.type != ixgbe_mac_82598EB) { - ctrl = IXGBE_READ_REG(hw, - IXGBE_RXDCTL(rxr->me)); - ctrl |= IXGBE_RXDCTL_VME; - IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), - ctrl); - } - rxr->vtag_strip = true; - } + if (!strip || + (if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) == 0) { + ctrl |= IXGBE_VLNCTRL_CFIEN; + ctrl &= ~IXGBE_VLNCTRL_VFE; + IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl); + return; } - if ((if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) == 0) - return; - /* - * A soft reset zero's out the VFTA, so - * we need to repopulate it now. - */ + /* A soft reset clears VFTA, so restore the PF's desired bitmap. */ for (i = 0; i < IXGBE_VFTA_SIZE; i++) - if (sc->shadow_vfta[i] != 0) - IXGBE_WRITE_REG(hw, IXGBE_VFTA(i), - sc->shadow_vfta[i]); - - ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); - /* Enable the Filter Table if enabled */ - if (if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) { - ctrl &= ~IXGBE_VLNCTRL_CFIEN; - ctrl |= IXGBE_VLNCTRL_VFE; - } - if (hw->mac.type == ixgbe_mac_82598EB) - ctrl |= IXGBE_VLNCTRL_VME; + IXGBE_WRITE_REG(hw, IXGBE_VFTA(i), sc->shadow_vfta[i]); + ctrl &= ~IXGBE_VLNCTRL_CFIEN; + ctrl |= IXGBE_VLNCTRL_VFE; IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl); } /* ixgbe_setup_vlan_hw_support */ @@ -3828,6 +3907,7 @@ ixgbe_if_init(if_ctx_t ctx) ixgbe_init_hw(hw); sc->iov_mta_valid = false; + sc->iov_vfta_valid = false; ixgbe_initialize_iov(sc); diff --git a/sys/dev/ixgbe/if_sriov.c b/sys/dev/ixgbe/if_sriov.c index 963f4392b2fd..318e0fe70759 100644 --- a/sys/dev/ixgbe/if_sriov.c +++ b/sys/dev/ixgbe/if_sriov.c @@ -36,6 +36,7 @@ #ifdef PCI_IOV +#include <sys/iov.h> #include <sys/ktr.h> MALLOC_DEFINE(M_IXGBE_SRIOV, "ix_sriov", "ix SR-IOV allocations"); @@ -66,6 +67,8 @@ ixgbe_define_iov_schemas(device_t dev, int *error) IOV_SCHEMA_HASDEFAULT, false); pci_iov_schema_add_bool(vf_schema, "allow-promisc", IOV_SCHEMA_HASDEFAULT, false); + pci_iov_schema_add_vlan(vf_schema, "vlan", IOV_SCHEMA_HASDEFAULT, + VF_VLAN_TRUNK); *error = pci_iov_attach(dev, pf_schema, vf_schema); if (*error != 0) { device_printf(dev, @@ -249,16 +252,105 @@ ixgbe_ping_all_vfs(struct ixgbe_softc *sc) } /* ixgbe_ping_all_vfs */ +static bool +ixgbe_pf_owns_vlan(struct ixgbe_softc *sc, uint16_t tag) +{ + if_t ifp; + + ifp = iflib_get_ifp(sc->ctx); + if ((if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) == 0) + return (true); + return ((sc->shadow_vfta[tag >> 5] & + (1U << (tag & 0x1f))) != 0); +} + +static bool +ixgbe_vf_owns_vlan(const struct ixgbe_vf *vf, uint16_t tag) +{ + + return ((vf->vlans[tag >> 5] & (1U << (tag & 0x1f))) != 0); +} + static void -ixgbe_vf_set_default_vlan(struct ixgbe_softc *sc, struct ixgbe_vf *vf, - uint16_t tag) +ixgbe_vf_vlan_release_pf_only(struct ixgbe_softc *sc, uint16_t tag) { struct ixgbe_hw *hw; - uint32_t vmolr, vmvir; + uint32_t bits[2]; + s32 slot; + + hw = &sc->hw; + slot = ixgbe_find_vlvf_slot(hw, tag, true); + if (slot <= 0) + return; + bits[0] = IXGBE_READ_REG(hw, IXGBE_VLVFB(slot * 2)); + bits[1] = IXGBE_READ_REG(hw, IXGBE_VLVFB(slot * 2 + 1)); + bits[sc->pool / 32] &= ~(1U << (sc->pool % 32)); + if (bits[0] != 0 || bits[1] != 0) + return; + + /* The VFTA bit still admits this VLAN to the PF's default pool. */ + IXGBE_WRITE_REG(hw, IXGBE_VLVF(slot), 0); + IXGBE_WRITE_REG(hw, IXGBE_VLVFB(slot * 2), 0); + IXGBE_WRITE_REG(hw, IXGBE_VLVFB(slot * 2 + 1), 0); +} + +static s32 +ixgbe_vf_vlan_hw_update(struct ixgbe_softc *sc, struct ixgbe_vf *vf, + uint16_t tag, bool enable) +{ + struct ixgbe_hw *hw; + s32 error; hw = &sc->hw; + if (!enable && + ixgbe_find_vlvf_slot(hw, tag, true) < IXGBE_SUCCESS) + return (IXGBE_SUCCESS); + /* + * Allocate the VLVF entry with the PF first when it also owns this + * VLAN. This guarantees that adding the VF cannot hide the VLAN from + * the PF when the shared VFTA bit becomes pool-selective. + */ + if (enable && ixgbe_pf_owns_vlan(sc, tag)) { + error = ixgbe_set_vfta(hw, tag, sc->pool, true, false); + if (error != IXGBE_SUCCESS) + return (error); + } - vf->vlan_tag = tag; + error = ixgbe_set_vfta(hw, tag, vf->pool, enable, false); + if (error != IXGBE_SUCCESS) + return (error); + + /* Free a PF-only VLVF slot without removing the PF's VFTA bit. */ + if (!enable && ixgbe_pf_owns_vlan(sc, tag)) + ixgbe_vf_vlan_release_pf_only(sc, tag); + return (IXGBE_SUCCESS); +} + +static void +ixgbe_vf_vlan_record(struct ixgbe_vf *vf, uint16_t tag, bool enable) +{ + u32 mask; + + mask = 1U << (tag & 0x1f); + if (enable) { + vf->vlans[tag >> 5] |= mask; + vf->num_vlans++; + } else { + vf->vlans[tag >> 5] &= ~mask; + vf->num_vlans--; + } +} + +static void +ixgbe_vf_configure_default_vlan(struct ixgbe_softc *sc, + struct ixgbe_vf *vf) +{ + struct ixgbe_hw *hw; + uint32_t vmolr, vmvir; + uint16_t tag; + + hw = &sc->hw; + tag = vf->default_vlan; vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(vf->pool)); @@ -286,7 +378,45 @@ ixgbe_vf_set_default_vlan(struct ixgbe_softc *sc, struct ixgbe_vf *vf, } IXGBE_WRITE_REG(hw, IXGBE_VMOLR(vf->pool), vmolr); IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf->pool), vmvir); -} /* ixgbe_vf_set_default_vlan */ +} /* ixgbe_vf_configure_default_vlan */ + +static void +ixgbe_vf_clear_vlans(struct ixgbe_softc *sc, struct ixgbe_vf *vf, + bool clear_hw) +{ + uint32_t bits; + int bit, index; + + for (index = 0; index < IXGBE_VFTA_SIZE; index++) { + bits = vf->vlans[index]; + while (bits != 0) { + bit = ffs(bits) - 1; + if (clear_hw) + (void)ixgbe_vf_vlan_hw_update(sc, vf, + index * 32 + bit, false); + bits &= ~(1U << bit); + } + } + bzero(vf->vlans, sizeof(vf->vlans)); + vf->num_vlans = 0; +} + +static s32 +ixgbe_vf_reset_vlan(struct ixgbe_softc *sc, struct ixgbe_vf *vf, + bool clear_hw) +{ + s32 error; + + ixgbe_vf_clear_vlans(sc, vf, clear_hw); + error = IXGBE_SUCCESS; + if (vf->default_vlan != 0) { + error = ixgbe_vf_vlan_hw_update(sc, vf, vf->default_vlan, true); + if (error == IXGBE_SUCCESS) + ixgbe_vf_vlan_record(vf, vf->default_vlan, true); + } + ixgbe_vf_configure_default_vlan(sc, vf); + return (error); +} static boolean_t ixgbe_vf_frame_size_compatible(struct ixgbe_softc *sc, struct ixgbe_vf *vf) @@ -338,8 +468,13 @@ static void ixgbe_process_vf_reset(struct ixgbe_softc *sc, struct ixgbe_vf *vf) { bool rebuild_mta; + s32 error; - ixgbe_vf_set_default_vlan(sc, vf, vf->default_vlan); + error = ixgbe_vf_reset_vlan(sc, vf, true); + if (error != IXGBE_SUCCESS) + device_printf(sc->dev, + "VF %u default VLAN restore failed: %d\n", + vf->pool, error); rebuild_mta = vf->num_mc_hashes != 0; vf->num_mc_hashes = 0; @@ -497,26 +632,37 @@ ixgbe_vf_set_mc_addr(struct ixgbe_softc *sc, struct ixgbe_vf *vf, u32 *msg) static void ixgbe_vf_set_vlan(struct ixgbe_softc *sc, struct ixgbe_vf *vf, uint32_t *msg) { - struct ixgbe_hw *hw; - int enable; + bool enable, present; + s32 error; uint16_t tag; - hw = &sc->hw; - enable = IXGBE_VT_MSGINFO(msg[0]); + enable = IXGBE_VT_MSGINFO(msg[0]) != 0; tag = msg[1] & IXGBE_VLVF_VLANID_MASK; - if (!(vf->flags & IXGBE_VF_CAP_VLAN)) { + if (!(vf->flags & IXGBE_VF_CAP_VLAN) || vf->default_vlan != 0 || + (msg[1] & ~IXGBE_VLVF_VLANID_MASK) != 0) { ixgbe_send_vf_failure(sc, vf, msg[0]); return; } /* It is illegal to enable vlan tag 0. */ - if (tag == 0 && enable != 0) { + if (tag == 0 && enable) { ixgbe_send_vf_failure(sc, vf, msg[0]); return; } - ixgbe_set_vfta(hw, tag, vf->pool, enable, false); + present = ixgbe_vf_owns_vlan(vf, tag); + if (enable == present) { + ixgbe_send_vf_success(sc, vf, msg[0]); + return; + } + + error = ixgbe_vf_vlan_hw_update(sc, vf, tag, enable); + if (error != IXGBE_SUCCESS) { + ixgbe_send_vf_failure(sc, vf, msg[0]); + return; + } + ixgbe_vf_vlan_record(vf, tag, enable); ixgbe_send_vf_success(sc, vf, msg[0]); } /* ixgbe_vf_set_vlan */ @@ -811,25 +957,32 @@ ixgbe_if_iov_uninit(if_ctx_t ctx) free(sc->vfs, M_IXGBE_SRIOV); sc->vfs = NULL; sc->feat_en &= ~IXGBE_FEATURE_SRIOV; + sc->iov_vfta_valid = false; + sc->iov_vlan_promisc = false; + (void)ixgbe_clear_vfta(hw); + ixgbe_setup_vlan_hw_support(ctx); } /* ixgbe_if_iov_uninit */ -static void +static s32 ixgbe_init_vf(struct ixgbe_softc *sc, struct ixgbe_vf *vf) { struct ixgbe_hw *hw; uint32_t vf_index, pfmbimr; + s32 error; hw = &sc->hw; if (!(vf->flags & IXGBE_VF_ACTIVE)) - return; + return (IXGBE_SUCCESS); vf_index = IXGBE_VF_INDEX(vf->pool); pfmbimr = IXGBE_READ_REG(hw, IXGBE_PFMBIMR(vf_index)); pfmbimr |= IXGBE_VF_BIT(vf->pool); IXGBE_WRITE_REG(hw, IXGBE_PFMBIMR(vf_index), pfmbimr); - ixgbe_vf_set_default_vlan(sc, vf, vf->vlan_tag); + error = ixgbe_vf_reset_vlan(sc, vf, false); + if (error != IXGBE_SUCCESS) + return (error); vf->num_mc_hashes = 0; bzero(vf->mc_hash, sizeof(vf->mc_hash)); @@ -843,6 +996,7 @@ ixgbe_init_vf(struct ixgbe_softc *sc, struct ixgbe_vf *vf) ixgbe_vf_enable_receive(sc, vf); ixgbe_send_vf_msg(&sc->hw, vf, IXGBE_PF_CONTROL_MSG); + return (IXGBE_SUCCESS); } /* ixgbe_init_vf */ void @@ -900,8 +1054,11 @@ ixgbe_initialize_iov(struct ixgbe_softc *sc) vt_ctl |= (sc->pool << IXGBE_VT_CTL_POOL_SHIFT); IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vt_ctl); - for (i = 0; i < sc->num_vfs; i++) - ixgbe_init_vf(sc, &sc->vfs[i]); + for (i = 0; i < sc->num_vfs; i++) { + if (ixgbe_init_vf(sc, &sc->vfs[i]) != IXGBE_SUCCESS) + device_printf(sc->dev, + "VF %d default VLAN restore failed\n", i); + } } /* ixgbe_initialize_iov */ @@ -924,6 +1081,9 @@ ixgbe_if_iov_vf_add(if_ctx_t ctx, u16 vfnum, const nvlist_t *config) struct ixgbe_softc *sc; struct ixgbe_vf *vf; const void *mac; + uint64_t configured_vlan; + uint16_t vlan; + s32 error; sc = iflib_get_softc(ctx); @@ -931,11 +1091,23 @@ ixgbe_if_iov_vf_add(if_ctx_t ctx, u16 vfnum, const nvlist_t *config) vfnum, sc->num_vfs)); vf = &sc->vfs[vfnum]; - vf->pool= vfnum; + if (vf->flags & IXGBE_VF_ACTIVE) + return (EBUSY); + + configured_vlan = nvlist_get_number(config, "vlan"); + if (configured_vlan > VF_VLAN_TRUNK) + return (EINVAL); + vlan = configured_vlan; + if (vlan == 0) + return (ENOTSUP); + if (vlan == VF_VLAN_TRUNK) + vlan = 0; + + vf->pool = vfnum; /* RAR[0] is used by the PF so use vfnum + 1 for VF RAR. */ vf->rar_index = vfnum + 1; - vf->default_vlan = 0; + vf->default_vlan = vlan; vf->maximum_frame_size = ETHER_MAX_LEN; ixgbe_update_max_frame(sc, vf->maximum_frame_size); if (nvlist_get_bool(config, "mac-anti-spoof")) @@ -952,10 +1124,18 @@ ixgbe_if_iov_vf_add(if_ctx_t ctx, u16 vfnum, const nvlist_t *config) * we must allow the VF to choose one. */ vf->flags |= IXGBE_VF_CAP_MAC; + if (vf->default_vlan == 0) + vf->flags |= IXGBE_VF_CAP_VLAN; vf->flags |= IXGBE_VF_ACTIVE; - ixgbe_init_vf(sc, vf); + error = ixgbe_init_vf(sc, vf); + if (error != IXGBE_SUCCESS) { + vf->flags &= ~IXGBE_VF_ACTIVE; + vf->default_vlan = 0; + ixgbe_vf_clear_vlans(sc, vf, true); + return (ENOSPC); + } return (0); } /* ixgbe_if_iov_vf_add */ diff --git a/sys/dev/ixgbe/ix_txrx.c b/sys/dev/ixgbe/ix_txrx.c index 3dda3270a2de..c95c3fc903ef 100644 --- a/sys/dev/ixgbe/ix_txrx.c +++ b/sys/dev/ixgbe/ix_txrx.c @@ -403,7 +403,7 @@ ixgbe_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri) struct rx_ring *rxr = &que->rxr; union ixgbe_adv_rx_desc *rxd; - uint16_t pkt_info, len, cidx, i; + uint16_t pkt_info, len, cidx, i, vid, vtag; uint32_t ptype; uint32_t staterr = 0; bool eop; @@ -463,8 +463,20 @@ ixgbe_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri) ri->iri_rsstype = M_HASHTYPE_OPAQUE_HASH; } if ((rxr->vtag_strip) && (staterr & IXGBE_RXD_STAT_VP)) { - ri->iri_vtag = le16toh(rxd->wb.upper.vlan); - ri->iri_flags |= M_VLANTAG; + vtag = le16toh(rxd->wb.upper.vlan); + vid = EVL_VLANOFTAG(vtag); + /* + * A PF-assigned port VLAN is stripped before a VF receives the + * frame, but it is not one of the VLANs registered by the VF. + * Do not expose that administrative tag to the VF's network + * stack. Locally registered trunk VLANs retain M_VLANTAG. + */ + if ((sc->feat_en & IXGBE_FEATURE_VF) == 0 || + (sc->shadow_vfta[vid >> 5] & + (1U << (vid & 0x1f))) != 0) { + ri->iri_vtag = vtag; + ri->iri_flags |= M_VLANTAG; + } } ri->iri_nfrags = i; diff --git a/sys/dev/ixgbe/ixgbe.h b/sys/dev/ixgbe/ixgbe.h index ae246433348e..26513a0ba965 100644 --- a/sys/dev/ixgbe/ixgbe.h +++ b/sys/dev/ixgbe/ixgbe.h @@ -352,9 +352,10 @@ struct ixgbe_vf { uint32_t flags; uint8_t ether_addr[ETHER_ADDR_LEN]; uint16_t mc_hash[IXGBE_MAX_VF_MC]; + uint32_t vlans[IXGBE_VFTA_SIZE]; uint16_t num_mc_hashes; + uint16_t num_vlans; uint16_t default_vlan; - uint16_t vlan_tag; uint16_t api_ver; }; @@ -442,6 +443,8 @@ struct ixgbe_softc { int pool; struct ixgbe_vf *vfs; bool iov_mta_valid; + bool iov_vfta_valid; + bool iov_vlan_promisc; /* Bypass */ struct ixgbe_bp_data bypass; @@ -607,6 +610,7 @@ void ixgbe_free_transmit_structures(struct ixgbe_softc *); int ixgbe_setup_receive_structures(struct ixgbe_softc *); void ixgbe_free_receive_structures(struct ixgbe_softc *); int ixgbe_get_regs(SYSCTL_HANDLER_ARGS); +void ixgbe_setup_vlan_hw_support(if_ctx_t); void ixgbe_add_fw_logging_tunables(struct ixgbe_softc *sc, struct sysctl_oid *parent); |
