diff options
Diffstat (limited to 'sys/dev/ixgbe/if_ixv.c')
| -rw-r--r-- | sys/dev/ixgbe/if_ixv.c | 522 |
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 */ - |
