aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/ixgbe/if_ixv.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ixgbe/if_ixv.c')
-rw-r--r--sys/dev/ixgbe/if_ixv.c522
1 files changed, 404 insertions, 118 deletions
diff --git a/sys/dev/ixgbe/if_ixv.c b/sys/dev/ixgbe/if_ixv.c
index 8a1c1aae041d..e8c3606721e2 100644
--- a/sys/dev/ixgbe/if_ixv.c
+++ b/sys/dev/ixgbe/if_ixv.c
@@ -99,20 +99,27 @@ static void ixv_if_update_admin_status(if_ctx_t);
static int ixv_if_msix_intr_assign(if_ctx_t, int);
static int ixv_if_mtu_set(if_ctx_t, uint32_t);
+static void ixv_reconcile_mac(struct ixgbe_softc *, if_t);
static void ixv_if_init(if_ctx_t);
static void ixv_if_local_timer(if_ctx_t, uint16_t);
static void ixv_if_stop(if_ctx_t);
static int ixv_negotiate_api(struct ixgbe_softc *);
+static int ixv_queue_limit(struct ixgbe_softc *, bool);
static void ixv_initialize_transmit_units(if_ctx_t);
static void ixv_initialize_receive_units(if_ctx_t);
static void ixv_initialize_rss_mapping(struct ixgbe_softc *);
static void ixv_setup_vlan_support(if_ctx_t);
+static void ixv_vlan_retry_add(struct ixgbe_softc *, u16);
+static void ixv_vlan_retry_clear(struct ixgbe_softc *, u16);
+static bool ixv_vlan_retry_pending(const struct ixgbe_softc *);
+static void ixv_vlan_retry_tick(struct ixgbe_softc *);
static void ixv_configure_ivars(struct ixgbe_softc *);
static void ixv_if_enable_intr(if_ctx_t);
static void ixv_if_disable_intr(if_ctx_t);
static void ixv_if_multi_set(if_ctx_t);
+static int ixv_if_promisc_set(if_ctx_t, int);
static void ixv_if_register_vlan(if_ctx_t, u16);
static void ixv_if_unregister_vlan(if_ctx_t, u16);
@@ -173,6 +180,7 @@ static device_method_t ixv_if_methods[] = {
DEVMETHOD(ifdi_queues_free, ixv_if_queues_free),
DEVMETHOD(ifdi_update_admin_status, ixv_if_update_admin_status),
DEVMETHOD(ifdi_multi_set, ixv_if_multi_set),
+ DEVMETHOD(ifdi_promisc_set, ixv_if_promisc_set),
DEVMETHOD(ifdi_mtu_set, ixv_if_mtu_set),
DEVMETHOD(ifdi_media_status, ixv_if_media_status),
DEVMETHOD(ifdi_media_change, ixv_if_media_change),
@@ -188,22 +196,8 @@ static driver_t ixv_if_driver = {
"ixv_if", ixv_if_methods, sizeof(struct ixgbe_softc)
};
-/*
- * TUNEABLE PARAMETERS:
- */
-
-/* Flow control setting, default to full */
-static int ixv_flow_control = ixgbe_fc_full;
-TUNABLE_INT("hw.ixv.flow_control", &ixv_flow_control);
-
-/*
- * Header split: this causes the hardware to DMA
- * the header into a separate mbuf from the payload,
- * it can be a performance win in some workloads, but
- * in others it actually hurts, its off by default.
- */
-static int ixv_header_split = false;
-TUNABLE_INT("hw.ixv.hdr_split", &ixv_header_split);
+#define IXV_VLAN_RETRY_BATCH 4
+#define IXV_VLAN_RETRY_WINDOW (8 * SBT_1S)
extern struct if_txrx ixgbe_txrx;
@@ -396,6 +390,7 @@ ixv_if_attach_pre(if_ctx_t ctx)
device_t dev;
if_softc_ctx_t scctx;
struct ixgbe_hw *hw;
+ bool mailbox_ready;
int error = 0;
INIT_DEBUGOUT("ixv_attach: begin");
@@ -438,36 +433,40 @@ ixv_if_attach_pre(if_ctx_t ctx)
/* Setup the mailbox */
ixgbe_init_mbx_params_vf(hw);
+ mailbox_ready = false;
error = hw->mac.ops.reset_hw(hw);
- if (error == IXGBE_ERR_RESET_FAILED)
- device_printf(dev, "...reset_hw() failure: Reset Failed!\n");
- else if (error)
- device_printf(dev, "...reset_hw() failed with error %d\n",
- error);
- if (error) {
- error = EIO;
- goto err_out;
- }
-
- error = hw->mac.ops.init_hw(hw);
- if (error) {
- device_printf(dev, "...init_hw() failed with error %d\n",
- error);
- error = EIO;
- goto err_out;
- }
-
- /* Negotiate mailbox API version */
- error = ixv_negotiate_api(sc);
- if (error) {
+ if (error != IXGBE_SUCCESS) {
+ /*
+ * A PF may be resetting or servicing a slow link event while its
+ * VFs are enumerated. Keep the VF attached so a later if_init can
+ * retry the mailbox handshake.
+ */
device_printf(dev,
- "Mailbox API negotiation failed during attach!\n");
- goto err_out;
+ "PF did not respond to the reset handshake: %d; "
+ "continuing attach\n", error);
+ } else {
+ error = hw->mac.ops.init_hw(hw);
+ if (error != IXGBE_SUCCESS) {
+ device_printf(dev, "...init_hw() failed with error %d\n",
+ error);
+ error = EIO;
+ goto err_out;
+ }
+
+ /* Negotiate mailbox API version. */
+ error = ixv_negotiate_api(sc);
+ if (error != 0) {
+ device_printf(dev,
+ "Mailbox API negotiation failed during attach; "
+ "continuing attach\n");
+ hw->mac.ops.stop_adapter(hw);
+ } else
+ mailbox_ready = true;
}
- /* Check if VF was disabled by PF */
- error = hw->mac.ops.get_link_state(hw, &sc->link_enabled);
- if (error) {
+ /* Check if VF was disabled by PF. */
+ if (!mailbox_ready ||
+ hw->mac.ops.get_link_state(hw, &sc->link_enabled) != 0) {
/* PF is not capable of controlling VF state. Enable link. */
sc->link_enabled = true;
}
@@ -483,15 +482,8 @@ ixv_if_attach_pre(if_ctx_t ctx)
/* Most of the iflib initialization... */
iflib_set_mac(ctx, hw->mac.addr);
- switch (sc->hw.mac.type) {
- case ixgbe_mac_X550_vf:
- case ixgbe_mac_X550EM_x_vf:
- case ixgbe_mac_X550EM_a_vf:
- scctx->isc_ntxqsets_max = scctx->isc_nrxqsets_max = 2;
- break;
- default:
- scctx->isc_ntxqsets_max = scctx->isc_nrxqsets_max = 1;
- }
+ scctx->isc_ntxqsets_max = scctx->isc_nrxqsets_max =
+ ixv_queue_limit(sc, mailbox_ready);
scctx->isc_txqsizes[0] =
roundup2(scctx->isc_ntxd[0] * sizeof(union ixgbe_adv_tx_desc) +
sizeof(u32), DBA_ALIGN);
@@ -500,7 +492,8 @@ ixv_if_attach_pre(if_ctx_t ctx)
DBA_ALIGN);
/* XXX */
scctx->isc_tx_csum_flags = CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_TSO |
- CSUM_IP6_TCP | CSUM_IP6_UDP | CSUM_IP6_TSO;
+ CSUM_IP6_TCP | CSUM_IP6_UDP | CSUM_IP6_TSO | CSUM_SCTP |
+ CSUM_IP6_SCTP;
scctx->isc_tx_nsegments = IXGBE_82599_SCATTER;
scctx->isc_msix_bar = pci_msix_table_bar(dev);
scctx->isc_tx_tso_segments_max = scctx->isc_tx_nsegments;
@@ -591,6 +584,29 @@ ixv_if_mtu_set(if_ctx_t ctx, uint32_t mtu)
return error;
} /* ixv_if_mtu_set */
+static void
+ixv_reconcile_mac(struct ixgbe_softc *sc, if_t ifp)
+{
+ uint8_t *lladdr;
+
+ if (ixgbe_validate_mac_addr(sc->hw.mac.addr) != IXGBE_SUCCESS)
+ return;
+ lladdr = (uint8_t *)if_getlladdr(ifp);
+ if (bcmp(lladdr, sc->hw.mac.addr, ETHER_ADDR_LEN) == 0)
+ return;
+
+ device_printf(sc->dev,
+ "PF rejected or replaced the requested MAC; using %6D\n",
+ sc->hw.mac.addr, ":");
+ /*
+ * Initialization holds the context lock; avoid re-entering the driver.
+ */
+ bcopy(sc->hw.mac.addr, lladdr, ETHER_ADDR_LEN);
+ CURVNET_SET_QUIET(if_getvnet(ifp));
+ EVENTHANDLER_INVOKE(iflladdr_event, ifp);
+ CURVNET_RESTORE();
+} /* ixv_reconcile_mac */
+
/************************************************************************
* ixv_if_init - Init entry point
*
@@ -621,13 +637,28 @@ ixv_if_init(if_ctx_t ctx)
bcopy(if_getlladdr(ifp), hw->mac.addr, IXGBE_ETH_LENGTH_OF_ADDRESS);
hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, 1);
- /* Reset VF and renegotiate mailbox API version */
- hw->mac.ops.reset_hw(hw);
+ /* Reset VF and renegotiate mailbox API version. */
+ error = hw->mac.ops.reset_hw(hw);
+ if (error != IXGBE_SUCCESS) {
+ device_printf(dev,
+ "PF did not respond to the reset handshake: %d\n", error);
+ return;
+ }
hw->mac.ops.start_hw(hw);
+ hw->mac.ops.get_mac_addr(hw, hw->mac.addr);
+ ixv_reconcile_mac(sc, ifp);
error = ixv_negotiate_api(sc);
if (error) {
device_printf(dev,
"Mailbox API negotiation failed in if_init!\n");
+ /*
+ * Leave the adapter stopped until an explicit or deferred retry.
+ * Otherwise the admin-status callback immediately requests another
+ * reset and can keep its taskqueue in a tight loop while the PF is
+ * deliberately withholding mailbox CTS (for example, when the VF is
+ * quarantined).
+ */
+ hw->mac.ops.stop_adapter(hw);
return;
}
@@ -734,9 +765,8 @@ ixv_msix_mbx(void *arg)
/* Clear interrupt with write */
IXGBE_WRITE_REG(hw, IXGBE_VTEICR, reg);
- /* Link status change */
- if (reg & IXGBE_EICR_LSC)
- iflib_admin_intr_deferred(sc->ctx);
+ /* The admin vector also carries PF mailbox notifications. */
+ iflib_admin_intr_deferred(sc->ctx);
IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, IXGBE_EIMS_OTHER);
@@ -822,6 +852,7 @@ ixv_negotiate_api(struct ixgbe_softc *sc)
{
struct ixgbe_hw *hw = &sc->hw;
int mbx_api[] = {
+ ixgbe_mbox_api_13,
ixgbe_mbox_api_12,
ixgbe_mbox_api_11,
ixgbe_mbox_api_10,
@@ -838,15 +869,110 @@ ixv_negotiate_api(struct ixgbe_softc *sc)
return (EINVAL);
} /* ixv_negotiate_api */
+/************************************************************************
+ * ixv_queue_limit
+ *
+ * Discover the number of symmetric RSS queue sets available to iflib.
+ ************************************************************************/
+static int
+ixv_queue_limit(struct ixgbe_softc *sc, bool mailbox_ready)
+{
+ struct ixgbe_hw *hw;
+ unsigned int default_tc, num_tcs;
+ int admin_vectors, limit, msix_vectors;
+
+ hw = &sc->hw;
+ /* Preserve the current family limit as the mailbox fallback. */
+ switch (hw->mac.type) {
+ case ixgbe_mac_82599_vf:
+ case ixgbe_mac_X540_vf:
+ limit = 1;
+ break;
+ case ixgbe_mac_X550_vf:
+ case ixgbe_mac_X550EM_x_vf:
+ case ixgbe_mac_X550EM_a_vf:
+ limit = 2;
+ break;
+ default:
+ return (1);
+ }
+
+ /* Replace the fallback with the queue grant reported by the PF. */
+ if (mailbox_ready) {
+ switch (hw->api_version) {
+ case ixgbe_mbox_api_11:
+ case ixgbe_mbox_api_12:
+ case ixgbe_mbox_api_13:
+ num_tcs = default_tc = 0;
+ if (ixgbevf_get_queues(hw, &num_tcs, &default_tc) == 0) {
+ limit = imin(hw->mac.max_tx_queues,
+ hw->mac.max_rx_queues);
+ limit = imin(limit, 2);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ /*
+ * iflib assigns one data vector to each queue set. A VF has at most
+ * three MSI-X vectors; reserve one of them for the mailbox interrupt.
+ */
+ admin_vectors = iflib_get_sctx(sc->ctx)->isc_admin_intrcnt;
+ msix_vectors = pci_msix_count(sc->dev);
+ if (msix_vectors <= admin_vectors)
+ return (1);
+
+ return (imax(1, imin(limit, msix_vectors - admin_vectors)));
+} /* ixv_queue_limit */
+
+static int
+ixv_update_xcast_mode(struct ixgbe_softc *sc, int flags)
+{
+ if_t ifp;
+ int mode;
+
+ ifp = iflib_get_ifp(sc->ctx);
+ if (flags & IFF_PROMISC)
+ mode = IXGBEVF_XCAST_MODE_PROMISC;
+ else if ((flags & IFF_ALLMULTI) != 0 ||
+ if_llmaddr_count(ifp) > IXGBE_MAX_VF_MC)
+ mode = IXGBEVF_XCAST_MODE_ALLMULTI;
+ else if (if_llmaddr_count(ifp) != 0)
+ mode = IXGBEVF_XCAST_MODE_MULTI;
+ else
+ mode = IXGBEVF_XCAST_MODE_NONE;
+ return (ixgbevf_update_xcast_mode(&sc->hw, mode));
+}
+
+static int
+ixv_if_promisc_set(if_ctx_t ctx, int flags)
+{
+ struct ixgbe_softc *sc;
+ if_t ifp;
+
+ sc = iflib_get_softc(ctx);
+ ifp = iflib_get_ifp(ctx);
+ if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0)
+ return (0);
+ if (ixv_update_xcast_mode(sc, flags) != IXGBE_SUCCESS)
+ return (EOPNOTSUPP);
+ return (0);
+} /* ixv_if_promisc_set */
+
static u_int
ixv_if_multi_set_cb(void *cb_arg, struct sockaddr_dl *addr, u_int cnt)
{
+ if (cnt >= MAX_NUM_MULTICAST_ADDRESSES)
+ return (0);
+
bcopy(LLADDR(addr),
&((u8 *)cb_arg)[cnt * IXGBE_ETH_LENGTH_OF_ADDRESS],
IXGBE_ETH_LENGTH_OF_ADDRESS);
- return (++cnt);
+ return (1);
}
/************************************************************************
@@ -861,7 +987,7 @@ ixv_if_multi_set(if_ctx_t ctx)
struct ixgbe_softc *sc = iflib_get_softc(ctx);
u8 *update_ptr;
if_t ifp = iflib_get_ifp(ctx);
- int mcnt = 0;
+ int error, mcnt = 0;
IOCTL_DEBUGOUT("ixv_if_multi_set: begin");
@@ -871,6 +997,16 @@ ixv_if_multi_set(if_ctx_t ctx)
sc->hw.mac.ops.update_mc_addr_list(&sc->hw, update_ptr, mcnt,
ixv_mc_array_itr, true);
+ error = ixv_update_xcast_mode(sc, if_getflags(ifp));
+ if (mcnt > IXGBE_MAX_VF_MC && error != IXGBE_SUCCESS) {
+ if (!sc->vf_mcast_overflow_warned)
+ device_printf(sc->dev,
+ "PF rejected all-multicast fallback; only %d "
+ "multicast addresses are active\n",
+ IXGBE_MAX_VF_MC);
+ sc->vf_mcast_overflow_warned = true;
+ } else if (mcnt <= IXGBE_MAX_VF_MC)
+ sc->vf_mcast_overflow_warned = false;
} /* ixv_if_multi_set */
/************************************************************************
@@ -903,9 +1039,14 @@ ixv_mc_array_itr(struct ixgbe_hw *hw, u8 **update_ptr, u32 *vmdq)
static void
ixv_if_local_timer(if_ctx_t ctx, uint16_t qid)
{
+ struct ixgbe_softc *sc;
+
if (qid != 0)
return;
+ sc = iflib_get_softc(ctx);
+ atomic_set_32(&sc->vf_vlan_retry_tick, 1);
+
/* Fire off the adminq task */
iflib_admin_intr_deferred(ctx);
} /* ixv_if_local_timer */
@@ -922,6 +1063,7 @@ ixv_if_update_admin_status(if_ctx_t ctx)
{
struct ixgbe_softc *sc = iflib_get_softc(ctx);
device_t dev = iflib_get_dev(ctx);
+ if_t ifp = iflib_get_ifp(ctx);
s32 status;
sc->hw.mac.get_link_status = true;
@@ -932,7 +1074,8 @@ ixv_if_update_admin_status(if_ctx_t ctx)
if (status != IXGBE_SUCCESS && sc->hw.adapter_stopped == false) {
/* Mailbox's Clear To Send status is lost or timeout occurred.
* We need reinitialization. */
- if_init(iflib_get_ifp(ctx), ctx);
+ iflib_request_reset(ctx);
+ iflib_admin_intr_deferred(ctx);
}
if (sc->link_up && sc->link_enabled) {
@@ -954,6 +1097,11 @@ ixv_if_update_admin_status(if_ctx_t ctx)
}
}
+ /* iflib clears RUNNING before stop; do not replay after VF reset. */
+ if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0 &&
+ atomic_readandclear_32(&sc->vf_vlan_retry_tick) != 0)
+ ixv_vlan_retry_tick(sc);
+
/* Stats Update */
ixv_update_stats(sc);
} /* ixv_if_update_admin_status */
@@ -1228,7 +1376,8 @@ ixv_if_needs_restart(if_ctx_t ctx __unused, enum iflib_restart_event event)
{
switch (event) {
case IFLIB_RESTART_VLAN_CONFIG:
- /* XXX: This may not need to return true */
+ /* The callbacks update the PF directly and queue failed work. */
+ return (false);
default:
return (true);
}
@@ -1252,9 +1401,9 @@ ixv_initialize_transmit_units(if_ctx_t ctx)
u32 txctrl, txdctl;
int j = txr->me;
- /* Set WTHRESH to 8, burst writeback */
txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(j));
- txdctl |= (8 << 16);
+ txdctl &= ~IXGBE_TXDCTL_THRESH_MASK;
+ txdctl |= IXGBE_TXDCTL_THRESH_DEFAULT;
IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(j), txdctl);
/* Set the HW Tx Head and Tail indices */
@@ -1517,91 +1666,211 @@ ixv_initialize_receive_units(if_ctx_t ctx)
} /* ixv_initialize_receive_units */
/************************************************************************
- * ixv_setup_vlan_support
+ * VF VLAN mailbox retry helpers
************************************************************************/
static void
-ixv_setup_vlan_support(if_ctx_t ctx)
+ixv_vlan_retry_add(struct ixgbe_softc *sc, u16 vid)
{
- if_t ifp = iflib_get_ifp(ctx);
- struct ixgbe_softc *sc = iflib_get_softc(ctx);
- struct ixgbe_hw *hw = &sc->hw;
- u32 ctrl, vid, vfta, retry;
+ bool pending;
+ pending = ixv_vlan_retry_pending(sc);
+ sc->vf_vfta_retry[vid >> 5] |= 1U << (vid & 0x1f);
+ /* Start a bounded no-progress window when work becomes pending. */
+ if (!pending || sc->vf_vlan_retry_deadline == 0)
+ sc->vf_vlan_retry_deadline =
+ getsbinuptime() + IXV_VLAN_RETRY_WINDOW;
+}
+
+static void
+ixv_vlan_retry_clear(struct ixgbe_softc *sc, u16 vid)
+{
+ u32 bit;
+ bool pending;
+
+ bit = 1U << (vid & 0x1f);
+ pending = (sc->vf_vfta_retry[vid >> 5] & bit) != 0;
+ sc->vf_vfta_retry[vid >> 5] &= ~bit;
+ if (!pending) {
+ /* A successful mailbox operation proves the PF is responsive. */
+ if (sc->vf_vlan_retry_deadline == 0 &&
+ ixv_vlan_retry_pending(sc))
+ sc->vf_vlan_retry_deadline =
+ getsbinuptime() + IXV_VLAN_RETRY_WINDOW;
+ return;
+ }
+ if (ixv_vlan_retry_pending(sc))
+ sc->vf_vlan_retry_deadline =
+ getsbinuptime() + IXV_VLAN_RETRY_WINDOW;
+ else
+ sc->vf_vlan_retry_deadline = 0;
+}
+
+static bool
+ixv_vlan_retry_pending(const struct ixgbe_softc *sc)
+{
+ int i;
+
+ for (i = 0; i < IXGBE_VFTA_SIZE; i++)
+ if (sc->vf_vfta_retry[i] != 0)
+ return (true);
+ return (false);
+}
+
+static void
+ixv_vlan_retry_tick(struct ixgbe_softc *sc)
+{
+ struct ixgbe_hw *hw;
+ bool enable;
+ s32 error;
+ u32 bit;
+ u16 vid;
+ int attempts, i, remaining;
+
+ if (!ixv_vlan_retry_pending(sc)) {
+ sc->vf_vlan_retry_deadline = 0;
+ return;
+ }
/*
- * We get here thru if_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.
+ * Exhausted entries remain dormant until reset, a VLAN callback, or
+ * another successful VLAN mailbox request.
*/
- if (sc->num_vlans == 0)
+ if (sc->vf_vlan_retry_deadline == 0)
+ return;
+ if (getsbinuptime() >= sc->vf_vlan_retry_deadline) {
+ remaining = 0;
+ for (i = 0; i < IXGBE_VFTA_SIZE; i++)
+ remaining += bitcount32(sc->vf_vfta_retry[i]);
+ sc->vf_vlan_retry_deadline = 0;
+ device_printf(sc->dev,
+ "VF VLAN retries exhausted for %d VIDs\n", remaining);
return;
+ }
+
+ /*
+ * A mailbox NACK does not distinguish transient PF unavailability
+ * from a permanent policy rejection or VLVF exhaustion. Reconcile a
+ * bounded batch per timer tick so none of those cases creates a busy
+ * mailbox poller. Stop after the first failure so a silent PF can
+ * consume at most one mailbox timeout per pass, while a responsive PF
+ * can drain several successful requests.
+ */
+ hw = &sc->hw;
+ for (attempts = 0, i = 0;
+ attempts < IXV_VLAN_RETRY_BATCH && i < 4096; i++) {
+ vid = sc->vf_vlan_retry_cursor;
+ sc->vf_vlan_retry_cursor = (vid + 1) & 0xfff;
+ bit = 1U << (vid & 0x1f);
+ if ((sc->vf_vfta_retry[vid >> 5] & bit) == 0)
+ continue;
+ attempts++;
+ enable = (sc->shadow_vfta[vid >> 5] & bit) != 0;
+ error = hw->mac.ops.set_vfta(hw, vid, 0, enable, false);
+ if (error != IXGBE_SUCCESS)
+ break;
+ ixv_vlan_retry_clear(sc, vid);
+ }
+}
+
+/************************************************************************
+ * ixv_setup_vlan_support - Configure and restore VLAN support
+ ************************************************************************/
+static void
+ixv_setup_vlan_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;
+ s32 error;
+ u32 ctrl, vfta;
+ u16 vid;
+ int restore_failures;
- if (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) {
- /* Enable the queues */
- for (int i = 0; i < sc->num_rx_queues; i++) {
- ctrl = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i));
+ for (int i = 0; i < sc->num_rx_queues; i++) {
+ ctrl = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i));
+ if (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) {
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.
- */
sc->rx_queues[i].rxr.vtag_strip = true;
+ } else {
+ ctrl &= ~IXGBE_RXDCTL_VME;
+ sc->rx_queues[i].rxr.vtag_strip = false;
}
+ IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(i), ctrl);
}
/*
- * If filtering VLAN tags is disabled,
- * there is no need to fill VLAN Filter Table Array (VFTA).
- */
- if ((if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) == 0)
- return;
-
- /*
- * A soft reset zero's out the VFTA, so
- * we need to repopulate it now.
+ * The PF controls the pool membership independently of the VF's local
+ * HWFILTER capability. A reset removes those memberships, so replay
+ * every registered VLAN through the mailbox.
+ *
+ * Keep failed removal requests pending as well. They are harmless and
+ * idempotent after a successful reset, and still needed if the reset
+ * handshake did not reach the PF.
*/
+ sc->vf_vlan_retry_deadline = 0;
+ sc->vf_vlan_retry_cursor = 0;
+ restore_failures = 0;
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)
+ if ((vfta & (1U << 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;
- }
+ /* One timeout is enough to declare this replay deferred. */
+ if (restore_failures == 0)
+ error = hw->mac.ops.set_vfta(hw, vid, 0, true,
+ false);
+ else
+ error = IXGBE_ERR_MBX;
+ if (error != IXGBE_SUCCESS) {
+ ixv_vlan_retry_add(sc, vid);
+ restore_failures++;
+ } else
+ ixv_vlan_retry_clear(sc, vid);
}
}
+ if (ixv_vlan_retry_pending(sc))
+ sc->vf_vlan_retry_deadline =
+ getsbinuptime() + IXV_VLAN_RETRY_WINDOW;
+ if (restore_failures != 0)
+ device_printf(sc->dev,
+ "VF VLAN restore failed for %d VIDs; retrying\n",
+ restore_failures);
} /* ixv_setup_vlan_support */
/************************************************************************
* ixv_if_register_vlan
*
* Run via a vlan config EVENT, it enables us to use the
- * HW Filter table since we can get the vlan id. This just
- * creates the entry in the soft version of the VFTA, init
- * will repopulate the real table.
+ * HW Filter table since we can get the vlan id.
************************************************************************/
static void
ixv_if_register_vlan(if_ctx_t ctx, u16 vtag)
{
struct ixgbe_softc *sc = iflib_get_softc(ctx);
- u16 index, bit;
+ bool pending, present;
+ u32 index, mask;
+ s32 error;
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;
+ pending = (sc->vf_vfta_retry[index] & mask) != 0;
+ sc->shadow_vfta[index] |= mask;
+ if (!present)
+ ++sc->num_vlans;
+ if (present && !pending)
+ return;
+
+ error = sc->hw.mac.ops.set_vfta(&sc->hw, vtag, 0, true, false);
+ if (error != IXGBE_SUCCESS) {
+ ixv_vlan_retry_add(sc, vtag);
+ if (!pending)
+ device_printf(sc->dev,
+ "VF VLAN %u add request failed; retrying\n", vtag);
+ } else
+ ixv_vlan_retry_clear(sc, vtag);
} /* ixv_if_register_vlan */
/************************************************************************
@@ -1614,12 +1883,29 @@ static void
ixv_if_unregister_vlan(if_ctx_t ctx, u16 vtag)
{
struct ixgbe_softc *sc = iflib_get_softc(ctx);
- u16 index, bit;
+ bool pending, present;
+ u32 index, mask;
+ s32 error;
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;
+ pending = (sc->vf_vfta_retry[index] & mask) != 0;
+ sc->shadow_vfta[index] &= ~mask;
+ if (present)
+ --sc->num_vlans;
+ if (!present && !pending)
+ return;
+
+ error = sc->hw.mac.ops.set_vfta(&sc->hw, vtag, 0, false, false);
+ if (error != IXGBE_SUCCESS) {
+ ixv_vlan_retry_add(sc, vtag);
+ if (!pending)
+ device_printf(sc->dev,
+ "VF VLAN %u remove request failed; "
+ "retrying\n", vtag);
+ } else
+ ixv_vlan_retry_clear(sc, vtag);
} /* ixv_if_unregister_vlan */
/************************************************************************
@@ -1633,6 +1919,9 @@ ixv_if_enable_intr(if_ctx_t ctx)
struct ix_rx_queue *que = sc->rx_queues;
u32 mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE);
+ if (hw->adapter_stopped)
+ return;
+
IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask);
mask = IXGBE_EIMS_ENABLE_MASK;
@@ -1847,8 +2136,6 @@ ixv_add_stats_sysctls(struct ixgbe_softc *sc)
char namebuf[QUEUE_NAME_LEN];
/* Driver Statistics */
- SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events",
- CTLFLAG_RD, &sc->watchdog_events, "Watchdog timeouts");
SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "link_irq",
CTLFLAG_RD, &sc->link_irq, "Link MSI-X IRQ Handled");
@@ -1982,4 +2269,3 @@ ixv_init_device_features(struct ixgbe_softc *sc)
if (sc->feat_cap & IXGBE_FEATURE_NEEDS_CTXD)
sc->feat_en |= IXGBE_FEATURE_NEEDS_CTXD;
} /* ixv_init_device_features */
-