Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 24 Feb 2020 09:50:20 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org
Subject:   svn commit: r358272 - stable/11/sys/net
Message-ID:  <202002240950.01O9oK19079674@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hselasky
Date: Mon Feb 24 09:50:19 2020
New Revision: 358272
URL: https://svnweb.freebsd.org/changeset/base/358272

Log:
  MFC r357799:
  Make sure the so-called end of receive interrupts don't starve in iflib.
  
  When the receive ring cannot be filled with mbufs, due to lack of memory,
  no more interrupts may be generated to fill the receive ring later on.
  Make sure to have a watchdog, to try refilling the receive ring from time
  to time, hopefully when more mbufs are available.
  
  Differential Revision:	https://reviews.freebsd.org/D23315
  Reviewed by:	gallatin@
  Sponsored by:	Mellanox Technologies

Modified:
  stable/11/sys/net/iflib.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/net/iflib.c
==============================================================================
--- stable/11/sys/net/iflib.c	Mon Feb 24 09:38:47 2020	(r358271)
+++ stable/11/sys/net/iflib.c	Mon Feb 24 09:50:19 2020	(r358272)
@@ -137,6 +137,9 @@ __FBSDID("$FreeBSD$");
  */
 static MALLOC_DEFINE(M_IFLIB, "iflib", "ifnet library");
 
+#define	IFLIB_RXEOF_MORE (1U << 0)
+#define	IFLIB_RXEOF_EMPTY (2U << 0)
+
 struct iflib_txq;
 typedef struct iflib_txq *iflib_txq_t;
 struct iflib_rxq;
@@ -460,6 +463,7 @@ struct iflib_rxq {
 	uint8_t		ifr_txqid[IFLIB_MAX_TX_SHARED_INTR];
 	struct lro_ctrl			ifr_lc;
 	struct grouptask        ifr_task;
+	struct callout		ifr_watchdog;
 	struct iflib_filter_info ifr_filter_info;
 	iflib_dma_info_t		ifr_ifdi;
 
@@ -1806,7 +1810,7 @@ _rxq_refill_cb(void *arg, bus_dma_segment_t *segs, int
  *	(Re)populate an rxq free-buffer list with up to @n new packet buffers.
  *	The caller must assure that @n does not exceed the queue's capacity.
  */
-static void
+static uint8_t
 _iflib_fl_refill(if_ctx_t ctx, iflib_fl_t fl, int count)
 {
 	struct mbuf *m;
@@ -1945,9 +1949,11 @@ done:
 				BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 	ctx->isc_rxd_flush(ctx->ifc_softc, fl->ifl_rxq->ifr_id, fl->ifl_id, pidx);
 	fl->ifl_fragidx = frag_idx;
+
+	return (n == -1 ? 0 : IFLIB_RXEOF_EMPTY);
 }
 
-static __inline void
+static __inline uint8_t
 __iflib_fl_refill_lt(if_ctx_t ctx, iflib_fl_t fl, int max)
 {
 	/* we avoid allowing pidx to catch up with cidx as it confuses ixl */
@@ -1960,7 +1966,8 @@ __iflib_fl_refill_lt(if_ctx_t ctx, iflib_fl_t fl, int 
 	MPASS(reclaimable == delta);
 
 	if (reclaimable > 0)
-		_iflib_fl_refill(ctx, fl, min(max, reclaimable));
+		return (_iflib_fl_refill(ctx, fl, min(max, reclaimable)));
+	return (0);
 }
 
 uint8_t
@@ -2052,7 +2059,7 @@ iflib_fl_setup(iflib_fl_t fl)
 	/* avoid pre-allocating zillions of clusters to an idle card
 	 * potentially speeding up attach
 	 */
-	_iflib_fl_refill(ctx, fl, min(128, fl->ifl_size));
+	(void) _iflib_fl_refill(ctx, fl, min(128, fl->ifl_size));
 	MPASS(min(128, fl->ifl_size) == fl->ifl_credits);
 	if (min(128, fl->ifl_size) != fl->ifl_credits)
 		return (ENOBUFS);
@@ -2536,7 +2543,15 @@ iflib_get_ip_forwarding(struct lro_ctrl *lc __unused, 
 }
 #endif
 
-static bool
+static void
+_task_fn_rx_watchdog(void *context)
+{
+	iflib_rxq_t rxq = context;
+
+	GROUPTASK_ENQUEUE(&rxq->ifr_task);
+}
+
+static uint8_t
 iflib_rxeof(iflib_rxq_t rxq, qidx_t budget)
 {
 	if_ctx_t ctx = rxq->ifr_ctx;
@@ -2551,6 +2566,7 @@ iflib_rxeof(iflib_rxq_t rxq, qidx_t budget)
 	int lro_enabled;
 	bool lro_possible = false;
 	bool v4_forwarding, v6_forwarding;
+	uint8_t retval = 0;
 
 	/*
 	 * XXX early demux data packets so that if_input processing only handles
@@ -2568,9 +2584,9 @@ iflib_rxeof(iflib_rxq_t rxq, qidx_t budget)
 		cidxp = &rxq->ifr_fl[0].ifl_cidx;
 	if ((avail = iflib_rxd_avail(ctx, rxq, *cidxp, budget)) == 0) {
 		for (i = 0, fl = &rxq->ifr_fl[0]; i < sctx->isc_nfl; i++, fl++)
-			__iflib_fl_refill_lt(ctx, fl, budget + 8);
+			retval |= __iflib_fl_refill_lt(ctx, fl, budget + 8);
 		DBG_COUNTER_INC(rx_unavail);
-		return (false);
+		return (retval);
 	}
 
 	for (budget_left = budget; (budget_left > 0) && (avail > 0); budget_left--, avail--) {
@@ -2624,7 +2640,7 @@ iflib_rxeof(iflib_rxq_t rxq, qidx_t budget)
 	}
 	/* make sure that we can refill faster than drain */
 	for (i = 0, fl = &rxq->ifr_fl[0]; i < sctx->isc_nfl; i++, fl++)
-		__iflib_fl_refill_lt(ctx, fl, budget + 8);
+		retval |= __iflib_fl_refill_lt(ctx, fl, budget + 8);
 
 	lro_enabled = (if_getcapenable(ifp) & IFCAP_LRO);
 	if (lro_enabled)
@@ -2683,15 +2699,15 @@ iflib_rxeof(iflib_rxq_t rxq, qidx_t budget)
 #if defined(INET6) || defined(INET)
 	tcp_lro_flush_all(&rxq->ifr_lc);
 #endif
-	if (avail)
-		return true;
-	return (iflib_rxd_avail(ctx, rxq, *cidxp, 1));
+	if (avail != 0 || iflib_rxd_avail(ctx, rxq, *cidxp, 1) != 0)
+		retval |= IFLIB_RXEOF_MORE;
+	return (retval);
 err:
 	STATE_LOCK(ctx);
 	ctx->ifc_flags |= IFC_DO_RESET;
 	iflib_admin_intr_deferred(ctx);
 	STATE_UNLOCK(ctx);
-	return (false);
+	return (0);
 }
 
 #define TXD_NOTIFY_COUNT(txq) (((txq)->ift_size / (txq)->ift_update_freq)-1)
@@ -3701,7 +3717,7 @@ _task_fn_rx(void *context)
 {
 	iflib_rxq_t rxq = context;
 	if_ctx_t ctx = rxq->ifr_ctx;
-	bool more;
+	uint8_t more;
 	int rc;
 	uint16_t budget;
 
@@ -3711,19 +3727,23 @@ _task_fn_rx(void *context)
 	DBG_COUNTER_INC(task_fn_rxs);
 	if (__predict_false(!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)))
 		return;
-	more = true;
 #ifdef DEV_NETMAP
 	if (if_getcapenable(ctx->ifc_ifp) & IFCAP_NETMAP) {
 		u_int work = 0;
 		if (netmap_rx_irq(ctx->ifc_ifp, rxq->ifr_id, &work)) {
-			more = false;
+			more = 0;
+			goto skip_rxeof;
 		}
 	}
 #endif
 	budget = ctx->ifc_sysctl_rx_budget;
 	if (budget == 0)
 		budget = 16;	/* XXX */
-	if (more == false || (more = iflib_rxeof(rxq, budget)) == false) {
+	more = iflib_rxeof(rxq, budget);
+#ifdef DEV_NETMAP
+skip_rxeof:
+#endif
+	if ((more & IFLIB_RXEOF_MORE) == 0) {
 		if (ctx->ifc_flags & IFC_LEGACY)
 			IFDI_INTR_ENABLE(ctx);
 		else {
@@ -3734,8 +3754,11 @@ _task_fn_rx(void *context)
 	}
 	if (__predict_false(!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)))
 		return;
-	if (more)
+
+	if (more & IFLIB_RXEOF_MORE)
 		GROUPTASK_ENQUEUE(&rxq->ifr_task);
+	else if (more & IFLIB_RXEOF_EMPTY)
+		callout_reset_curcpu(&rxq->ifr_watchdog, 1, &_task_fn_rx_watchdog, rxq);
 }
 
 static void
@@ -4539,6 +4562,7 @@ iflib_device_deregister(if_ctx_t ctx)
 			taskqgroup_detach(tqg, &txq->ift_task);
 	}
 	for (i = 0, rxq = ctx->ifc_rxqs; i < NRXQSETS(ctx); i++, rxq++) {
+		callout_drain(&rxq->ifr_watchdog);
 		if (rxq->ifr_task.gt_uniq != NULL)
 			taskqgroup_detach(tqg, &rxq->ifr_task);
 
@@ -4898,6 +4922,7 @@ iflib_queues_alloc(if_ctx_t ctx)
 
 	for (rxconf = i = 0; i < nrxqsets; i++, rxconf++, rxq++) {
 		/* Set up some basics */
+		callout_init(&rxq->ifr_watchdog, 1);
 
 		if ((ifdip = malloc(sizeof(struct iflib_dma_info) * nrxqs, M_IFLIB, M_WAITOK|M_ZERO)) == NULL) {
 			device_printf(dev, "failed to allocate iflib_dma_info\n");



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202002240950.01O9oK19079674>