Page MenuHomeFreeBSD

D58266.id182220.diff
No OneTemporary

D58266.id182220.diff

diff --git a/sys/net/iflib.c b/sys/net/iflib.c
--- a/sys/net/iflib.c
+++ b/sys/net/iflib.c
@@ -312,6 +312,19 @@
/* The minimum descriptors per second before we start coalescing */
#define IFLIB_MIN_DESC_SEC 16384
#define IFLIB_DEFAULT_TX_UPDATE_FREQ 16
+/*
+ * Consecutive armed timer periods before a suspect TX queue is
+ * declared hung. A healthy queue on writeback-coalescing hardware
+ * (e.g. 8254x, TXDCTL.WTHRESH) shows armed runs of at most two
+ * periods (measured on 82541PI); a wedged queue stays armed until
+ * reset.
+ */
+#define IFLIB_WDOG_ARMED_PERIODS 4
+/*
+ * The queue states below, ift_qstatus, and ift_cleaned_prev no longer
+ * participate in the TX watchdog decision and are scheduled for
+ * removal.
+ */
#define IFLIB_QUEUE_IDLE 0
#define IFLIB_QUEUE_HUNG 1
#define IFLIB_QUEUE_WORKING 2
@@ -368,11 +381,14 @@
uint16_t ift_npending;
uint16_t ift_db_pending;
uint16_t ift_rs_pending;
+ qidx_t ift_outstanding_prev;
+ uint8_t ift_wdog_armed;
uint32_t ift_last_reclaim;
uint16_t ift_reclaim_thresh;
uint16_t ift_reclaim_ticks;
uint8_t ift_txd_size[8];
uint64_t ift_processed;
+ uint64_t ift_processed_prev;
uint64_t ift_cleaned;
uint64_t ift_cleaned_prev;
#if MEMORY_LOGGING
@@ -2403,25 +2419,80 @@
return;
/*
- ** Check on the state of the TX queue(s), this
- ** can be done without the lock because its RO
- ** and the HUNG state will be static if set.
- */
+ * Check on the state of the TX queue(s); this can be done
+ * without the lock: the counters the check reads are only
+ * advanced by the queue's tx task and a stale read just
+ * delays the verdict by one timer period.
+ */
if (this_tick - txq->ift_last_timer_tick >= iflib_timer_default) {
+ qidx_t outstanding;
+ bool frozen;
+
txq->ift_last_timer_tick = this_tick;
IFDI_TIMER(ctx, txq->ift_id);
- if ((txq->ift_qstatus == IFLIB_QUEUE_HUNG) &&
- ((txq->ift_cleaned_prev == txq->ift_cleaned) ||
- (sctx->isc_pause_frames == 0)))
- goto hung;
- 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"));
- txq->ift_qstatus = IFLIB_QUEUE_HUNG;
+ /*
+ * Descriptors handed to the hardware for which a
+ * completion writeback is still owed: those neither
+ * harvested as credits (ift_processed) nor reclaimed
+ * (ift_cleaned accounts the difference to ift_in_use).
+ * The tail whose report-status request is still
+ * deferred (ift_rs_pending over-counts it by one per
+ * packet) never writes back and must not count as
+ * owed.
+ */
+ outstanding = txq->ift_in_use -
+ (qidx_t)(txq->ift_processed - txq->ift_cleaned);
+
+ /*
+ * A period is frozen if writeback-owed work exists
+ * and no completions were harvested since the last
+ * period, with the link up, no pause frames seen,
+ * and no doorbell pending (the laggard check below
+ * rings it).
+ *
+ * Frozen alone is a normal state: hardware with
+ * descriptor-writeback coalescing (e.g. 8254x,
+ * TXDCTL.WTHRESH) legitimately withholds the final
+ * report-status writeback of a quiet queue
+ * indefinitely, so a constant owed tail must never
+ * trigger the watchdog. Only a queue that received
+ * new work across a frozen period (the owed count
+ * grew) arms, and the verdict waits until it has
+ * stayed frozen for IFLIB_WDOG_ARMED_PERIODS
+ * consecutive periods.
+ */
+ frozen = outstanding > txq->ift_rs_pending &&
+ txq->ift_processed == txq->ift_processed_prev &&
+ txq->ift_db_pending == 0 &&
+ sctx->isc_pause_frames == 0 &&
+ ctx->ifc_link_state == LINK_STATE_UP;
+ if (!frozen)
+ txq->ift_wdog_armed = 0;
+ else if (txq->ift_wdog_armed > 0 ||
+ outstanding > txq->ift_outstanding_prev) {
+ if (txq->ift_wdog_armed < UINT8_MAX)
+ txq->ift_wdog_armed++;
}
- txq->ift_cleaned_prev = txq->ift_cleaned;
+
+ /*
+ * Armed long enough - ask the hardware: if
+ * completions are ready but nobody harvested them
+ * for this long, the completion interrupt went
+ * missing - kick the queue's task instead of
+ * resetting; if it reported nothing although the
+ * owed count grew, the queue is hung.
+ */
+ if (txq->ift_wdog_armed >= IFLIB_WDOG_ARMED_PERIODS) {
+ bus_dmamap_sync(txq->ift_ifdi->idi_tag,
+ txq->ift_ifdi->idi_map, BUS_DMASYNC_POSTREAD);
+ if (ctx->isc_txd_credits_update(ctx->ifc_softc,
+ txq->ift_id, false) == 0)
+ goto hung;
+ GROUPTASK_ENQUEUE(&txq->ift_task);
+ }
+ txq->ift_outstanding_prev = outstanding;
+ txq->ift_processed_prev = txq->ift_processed;
}
/* handle any laggards */
if (txq->ift_db_pending)
@@ -2625,6 +2696,9 @@
iflib_txsd_free(ctx, txq, j);
}
txq->ift_processed = txq->ift_cleaned = txq->ift_cidx_processed = 0;
+ txq->ift_processed_prev = 0;
+ txq->ift_outstanding_prev = 0;
+ txq->ift_wdog_armed = 0;
txq->ift_in_use = txq->ift_gen = txq->ift_no_desc_avail = 0;
if (sctx->isc_flags & IFLIB_PRESERVE_TX_INDICES)
txq->ift_cidx = txq->ift_pidx;

File Metadata

Mime Type
text/plain
Expires
Fri, Aug 14, 1:20 PM (10 h, 22 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35275397
Default Alt Text
D58266.id182220.diff (5 KB)

Event Timeline