aboutsummaryrefslogtreecommitdiff
path: root/sys/net/iflib.c
diff options
context:
space:
mode:
authorMatt Macy <mmacy@FreeBSD.org>2020-12-19 01:08:33 +0000
committerMatt Macy <mmacy@FreeBSD.org>2021-01-07 22:07:35 +0000
commit81be655266fac2b333e25f386f32c9bcd17f523d (patch)
tree187ff1643f400c37da4c007193297d3d22c0c9a3 /sys/net/iflib.c
parent11403bdeb4158531af36bc7c51cbbba27deb69b1 (diff)
downloadsrc-81be655266fac2b333e25f386f32c9bcd17f523d.tar.gz
src-81be655266fac2b333e25f386f32c9bcd17f523d.zip
Diffstat (limited to 'sys/net/iflib.c')
-rw-r--r--sys/net/iflib.c94
1 files changed, 62 insertions, 32 deletions
diff --git a/sys/net/iflib.c b/sys/net/iflib.c
index 5db925fef05f..cc401a5db24d 100644
--- a/sys/net/iflib.c
+++ b/sys/net/iflib.c
@@ -585,6 +585,10 @@ SYSCTL_INT(_net_iflib, OID_AUTO, min_tx_latency, CTLFLAG_RW,
static int iflib_no_tx_batch = 0;
SYSCTL_INT(_net_iflib, OID_AUTO, no_tx_batch, CTLFLAG_RW,
&iflib_no_tx_batch, 0, "minimize transmit latency at the possible expense of throughput");
+static int iflib_timer_default = 1000;
+SYSCTL_INT(_net_iflib, OID_AUTO, timer_default, CTLFLAG_RW,
+ &iflib_timer_default, 0, "number of ticks between iflib_timer calls");
+
#if IFLIB_DEBUG_COUNTERS
@@ -2293,7 +2297,7 @@ iflib_timer(void *arg)
** can be done without the lock because its RO
** and the HUNG state will be static if set.
*/
- if (this_tick - txq->ift_last_timer_tick >= hz / 2) {
+ if (this_tick - txq->ift_last_timer_tick >= iflib_timer_default) {
txq->ift_last_timer_tick = this_tick;
IFDI_TIMER(ctx, txq->ift_id);
if ((txq->ift_qstatus == IFLIB_QUEUE_HUNG) &&
@@ -2303,7 +2307,8 @@ iflib_timer(void *arg)
if (txq->ift_qstatus != IFLIB_QUEUE_IDLE &&
ifmp_ring_is_stalled(txq->ift_br)) {
- KASSERT(ctx->ifc_link_state == LINK_STATE_UP, ("queue can't be marked as hung if interface is down"));
+ KASSERT(ctx->ifc_link_state == LINK_STATE_UP,
+ ("queue can't be marked as hung if interface is down"));
txq->ift_qstatus = IFLIB_QUEUE_HUNG;
}
txq->ift_cleaned_prev = txq->ift_cleaned;
@@ -2314,7 +2319,8 @@ iflib_timer(void *arg)
sctx->isc_pause_frames = 0;
if (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)
- callout_reset_on(&txq->ift_timer, hz / 2, iflib_timer, txq, txq->ift_timer.c_cpu);
+ callout_reset_on(&txq->ift_timer, iflib_timer_default, iflib_timer,
+ txq, txq->ift_timer.c_cpu);
return;
hung:
@@ -2426,7 +2432,7 @@ done:
IFDI_INTR_ENABLE(ctx);
txq = ctx->ifc_txqs;
for (i = 0; i < sctx->isc_ntxqsets; i++, txq++)
- callout_reset_on(&txq->ift_timer, hz/2, iflib_timer, txq,
+ callout_reset_on(&txq->ift_timer, iflib_timer_default, iflib_timer, txq,
txq->ift_timer.c_cpu);
}
@@ -3001,26 +3007,37 @@ txq_max_rs_deferred(iflib_txq_t txq)
/* XXX we should be setting this to something other than zero */
#define RECLAIM_THRESH(ctx) ((ctx)->ifc_sctx->isc_tx_reclaim_thresh)
-#define MAX_TX_DESC(ctx) max((ctx)->ifc_softc_ctx.isc_tx_tso_segments_max, \
+#define MAX_TX_DESC(ctx) MAX((ctx)->ifc_softc_ctx.isc_tx_tso_segments_max, \
(ctx)->ifc_softc_ctx.isc_tx_nsegments)
static inline bool
-iflib_txd_db_check(if_ctx_t ctx, iflib_txq_t txq, int ring, qidx_t in_use)
+iflib_txd_db_check(iflib_txq_t txq, int ring)
{
+ if_ctx_t ctx = txq->ift_ctx;
qidx_t dbval, max;
- bool rang;
- rang = false;
- max = TXQ_MAX_DB_DEFERRED(txq, in_use);
- if (ring || txq->ift_db_pending >= max) {
+ max = TXQ_MAX_DB_DEFERRED(txq, txq->ift_in_use);
+
+ /* force || threshold exceeded || at the edge of the ring */
+ if (ring || (txq->ift_db_pending >= max) || (TXQ_AVAIL(txq) <= MAX_TX_DESC(ctx) + 2)) {
+
+ /*
+ * 'npending' is used if the card's doorbell is in terms of the number of descriptors
+ * pending flush (BRCM). 'pidx' is used in cases where the card's doorbeel uses the
+ * producer index explicitly (INTC).
+ */
dbval = txq->ift_npending ? txq->ift_npending : txq->ift_pidx;
bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
ctx->isc_txd_flush(ctx->ifc_softc, txq->ift_id, dbval);
+
+ /*
+ * Absent bugs there are zero packets pending so reset pending counts to zero.
+ */
txq->ift_db_pending = txq->ift_npending = 0;
- rang = true;
+ return (true);
}
- return (rang);
+ return (false);
}
#ifdef PKT_DEBUG
@@ -3481,6 +3498,7 @@ defrag:
MPASS(pi.ipi_new_pidx != pidx);
MPASS(ndesc > 0);
txq->ift_in_use += ndesc;
+ txq->ift_db_pending += ndesc;
/*
* We update the last software descriptor again here because there may
@@ -3647,8 +3665,8 @@ iflib_txq_drain(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx)
if_ctx_t ctx = txq->ift_ctx;
if_t ifp = ctx->ifc_ifp;
struct mbuf *m, **mp;
- int avail, bytes_sent, consumed, count, err, i, in_use_prev;
- int mcast_sent, pkt_sent, reclaimed, txq_avail;
+ int avail, bytes_sent, skipped, count, err, i;
+ int mcast_sent, pkt_sent, reclaimed;
bool do_prefetch, rang, ring;
if (__predict_false(!(if_getdrvflags(ifp) & IFF_DRV_RUNNING) ||
@@ -3657,9 +3675,13 @@ iflib_txq_drain(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx)
return (0);
}
reclaimed = iflib_completed_tx_reclaim(txq, RECLAIM_THRESH(ctx));
- rang = iflib_txd_db_check(ctx, txq, reclaimed, txq->ift_in_use);
+ rang = iflib_txd_db_check(txq, reclaimed && txq->ift_db_pending);
avail = IDXDIFF(pidx, cidx, r->size);
+
if (__predict_false(ctx->ifc_flags & IFC_QFLUSH)) {
+ /*
+ * The driver is unloading so we need to free all pending packets.
+ */
DBG_COUNTER_INC(txq_drain_flushing);
for (i = 0; i < avail; i++) {
if (__predict_true(r->items[(cidx + i) & (r->size-1)] != (void *)txq))
@@ -3677,9 +3699,13 @@ iflib_txq_drain(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx)
DBG_COUNTER_INC(txq_drain_oactive);
return (0);
}
+
+ /*
+ * If we've reclaimed any packets this queue cannot be hung.
+ */
if (reclaimed)
txq->ift_qstatus = IFLIB_QUEUE_IDLE;
- consumed = mcast_sent = bytes_sent = pkt_sent = 0;
+ skipped = mcast_sent = bytes_sent = pkt_sent = 0;
count = MIN(avail, TX_BATCH_SIZE);
#ifdef INVARIANTS
if (iflib_verbose_debug)
@@ -3687,54 +3713,57 @@ iflib_txq_drain(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx)
avail, ctx->ifc_flags, TXQ_AVAIL(txq));
#endif
do_prefetch = (ctx->ifc_flags & IFC_PREFETCH);
- txq_avail = TXQ_AVAIL(txq);
err = 0;
- for (i = 0; i < count && txq_avail > MAX_TX_DESC(ctx) + 2; i++) {
+ for (i = 0; i < count && TXQ_AVAIL(txq) >= MAX_TX_DESC(ctx) + 2; i++) {
int rem = do_prefetch ? count - i : 0;
mp = _ring_peek_one(r, cidx, i, rem);
MPASS(mp != NULL && *mp != NULL);
+
+ /*
+ * Completion interrupts will use the address of the txq
+ * as a sentinel to enqueue _something_ in order to acquire
+ * the lock on the mp_ring (there's no direct lock call).
+ * We obviously whave to check for these sentinel cases
+ * and skip them.
+ */
if (__predict_false(*mp == (struct mbuf *)txq)) {
- consumed++;
+ skipped++;
continue;
}
- in_use_prev = txq->ift_in_use;
err = iflib_encap(txq, mp);
if (__predict_false(err)) {
/* no room - bail out */
if (err == ENOBUFS)
break;
- consumed++;
+ skipped++;
/* we can't send this packet - skip it */
continue;
}
- consumed++;
pkt_sent++;
m = *mp;
DBG_COUNTER_INC(tx_sent);
bytes_sent += m->m_pkthdr.len;
mcast_sent += !!(m->m_flags & M_MCAST);
- txq_avail = TXQ_AVAIL(txq);
- txq->ift_db_pending += (txq->ift_in_use - in_use_prev);
- ETHER_BPF_MTAP(ifp, m);
if (__predict_false(!(ifp->if_drv_flags & IFF_DRV_RUNNING)))
break;
- rang = iflib_txd_db_check(ctx, txq, false, in_use_prev);
+ ETHER_BPF_MTAP(ifp, m);
+ rang = iflib_txd_db_check(txq, false);
}
/* deliberate use of bitwise or to avoid gratuitous short-circuit */
- ring = rang ? false : (iflib_min_tx_latency | err) || (TXQ_AVAIL(txq) < MAX_TX_DESC(ctx));
- iflib_txd_db_check(ctx, txq, ring, txq->ift_in_use);
+ ring = rang ? false : (iflib_min_tx_latency | err);
+ iflib_txd_db_check(txq, ring);
if_inc_counter(ifp, IFCOUNTER_OBYTES, bytes_sent);
if_inc_counter(ifp, IFCOUNTER_OPACKETS, pkt_sent);
if (mcast_sent)
if_inc_counter(ifp, IFCOUNTER_OMCASTS, mcast_sent);
#ifdef INVARIANTS
if (iflib_verbose_debug)
- printf("consumed=%d\n", consumed);
+ printf("consumed=%d\n", skipped + pkt_sent);
#endif
- return (consumed);
+ return (skipped + pkt_sent);
}
static uint32_t
@@ -3907,7 +3936,7 @@ _task_fn_admin(void *context)
}
IFDI_UPDATE_ADMIN_STATUS(ctx);
for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) {
- callout_reset_on(&txq->ift_timer, hz / 2, iflib_timer, txq,
+ callout_reset_on(&txq->ift_timer, iflib_timer_default, iflib_timer, txq,
txq->ift_timer.c_cpu);
}
IFDI_LINK_INTR_ENABLE(ctx);
@@ -5301,6 +5330,7 @@ iflib_device_iov_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params)
static int
iflib_module_init(void)
{
+ iflib_timer_default = hz / 2;
return (0);
}
@@ -6861,7 +6891,7 @@ iflib_debugnet_transmit(if_t ifp, struct mbuf *m)
txq = &ctx->ifc_txqs[0];
error = iflib_encap(txq, &m);
if (error == 0)
- (void)iflib_txd_db_check(ctx, txq, true, txq->ift_in_use);
+ (void)iflib_txd_db_check(txq, true);
return (error);
}