From c05878045fbed4c47507038f295666d142ebbb59 Mon Sep 17 00:00:00 2001
From: Ryan Zezeski <ryan@zinascii.com>
Date: Fri, 30 Jan 2026 23:43:46 -0500
Subject: [PATCH] 17853 the last vnic will not go gentle into that good night

Change-Id: I6a6a636cda5d6b49c8b0f46e5fae6826582fff0d
---
 .../uts/common/io/mac/mac_datapath_setup.c    | 101 +++++-------------
 usr/src/uts/common/io/mac/mac_soft_ring.c     |  58 ++++++++++
 usr/src/uts/common/sys/mac_soft_ring.h        |   4 +
 3 files changed, 86 insertions(+), 77 deletions(-)

diff --git a/usr/src/uts/common/io/mac/mac_datapath_setup.c b/usr/src/uts/common/io/mac/mac_datapath_setup.c
index 22b70b65fe..89a10655ce 100644
--- a/usr/src/uts/common/io/mac/mac_datapath_setup.c
+++ b/usr/src/uts/common/io/mac/mac_datapath_setup.c
@@ -383,31 +383,8 @@ mac_srs_client_poll_enable_i(mac_soft_ring_set_t *srs, uint_t sr_cnt,
 	}
 
 	for (uint_t i = 0; i < sr_cnt; i++) {
-		mac_soft_ring_t *tcp_sr = tcp_rings[i];
-		mac_rx_fifo_t mrf;
-
-		/*
-		 * Polling should be configured only once on a given
-		 * softring.
-		 */
-		VERIFY3P(tcp_sr->s_ring_rx_arg2, ==, NULL);
-
-		mac_soft_ring_dls_bypass_enable(tcp_sr, drx, drx_arg);
-
-		bzero(&mrf, sizeof (mrf));
-		mrf.mrf_type = MAC_RX_FIFO;
-		mrf.mrf_receive = (mac_receive_t)mac_soft_ring_poll;
-		mrf.mrf_intr_enable =
-		    (mac_intr_enable_t)mac_soft_ring_intr_enable;
-		mrf.mrf_intr_disable =
-		    (mac_intr_disable_t)mac_soft_ring_intr_disable;
-		mrf.mrf_rx_arg = tcp_sr;
-		mrf.mrf_intr_handle = (mac_intr_handle_t)tcp_sr;
-		mrf.mrf_cpu_id = tcp_sr->s_ring_cpuid;
-		mrf.mrf_flow_priority = srs->srs_pri;
-
-		tcp_sr->s_ring_rx_arg2 = rcb->mrc_add(rcb->mrc_arg,
-		    (mac_resource_t *)&mrf);
+		mac_soft_ring_poll_enable(tcp_rings[i], drx, drx_arg, rcb,
+		    srs->srs_pri);
 	}
 }
 
@@ -434,7 +411,16 @@ mac_srs_client_poll_enable(mac_client_impl_t *mcip, mac_soft_ring_set_t *srs,
 	if (srs->srs_type & SRST_NO_SOFT_RINGS)
 		return;
 
-	if (is_v6) {
+	/*
+	 * Once mci_direct_rx is set for a given protocol (IPv4/IPv6) it is not
+	 * cleared. We probably should clear it when there is no longer a
+	 * client, but we don't. The resource callbacks in mci_rcb4/6, however,
+	 * are cleared when polling is disabled. So, even though DLS and polling
+	 * currently come as a pair, we make sure to check both mci_direct_rx
+	 * and mci_rcb4/6 before attemping to enable polling.
+	 */
+	if (is_v6 && mcip->mci_direct_rx.mdrx_v6 != NULL &&
+	    mcip->mci_rcb6.mrc_arg != NULL) {
 		mac_srs_client_poll_enable_i(srs, srs->srs_tcp_ring_count,
 		    srs->srs_udp6_soft_rings, srs->srs_tcp6_soft_rings,
 		    mcip->mci_direct_rx.mdrx_v6,
@@ -443,7 +429,8 @@ mac_srs_client_poll_enable(mac_client_impl_t *mcip, mac_soft_ring_set_t *srs,
 		mutex_enter(&srs->srs_lock);
 		srs->srs_type |= (SRST_CLIENT_POLL_V6 | SRST_DLS_BYPASS_V6);
 		mutex_exit(&srs->srs_lock);
-	} else {
+	} else if (!is_v6 && mcip->mci_direct_rx.mdrx_v4 != NULL &&
+	    mcip->mci_rcb4.mrc_arg != NULL) {
 		mac_srs_client_poll_enable_i(srs, srs->srs_tcp_ring_count,
 		    srs->srs_udp_soft_rings, srs->srs_tcp_soft_rings,
 		    mcip->mci_direct_rx.mdrx_v4,
@@ -461,21 +448,7 @@ mac_srs_client_poll_disable_i(mac_client_impl_t *mcip, uint_t sr_cnt,
     mac_resource_cb_t *rcb)
 {
 	for (uint_t i = 0; i < sr_cnt; i++) {
-		mac_soft_ring_t *tcp_sr = tcp_rings[i];
-
-		/*
-		 * Remove the IP ring if there is one associated with this
-		 * softring. Note that IP rings are a limited resource; and
-		 * SRST_CLIENT_POLL_V4/V6 being set on the SRS is no
-		 * guarantee that all TCP softrings have an associated IP
-		 * ring. This is by design. See ip_squeue_add_ring().
-		 */
-		if (tcp_sr->s_ring_rx_arg2 != NULL) {
-			VERIFY3P(rcb->mrc_arg, !=, NULL);
-			rcb->mrc_remove(rcb->mrc_arg, tcp_sr->s_ring_rx_arg2);
-			tcp_sr->s_ring_rx_arg2 = NULL;
-		}
-		mac_soft_ring_dls_bypass_disable(tcp_sr, mcip);
+		mac_soft_ring_poll_disable(tcp_rings[i], rcb, mcip);
 	}
 
 	for (uint_t i = 0; i < sr_cnt; i++) {
@@ -1774,18 +1747,9 @@ mac_srs_create_proto_softrings(int id, pri_t pri, mac_client_impl_t *mcip,
     void *x_arg1, mac_resource_handle_t x_arg2, boolean_t set_bypass)
 {
 	mac_soft_ring_t	*softring;
-	mac_rx_fifo_t	mrf;
-
-	bzero(&mrf, sizeof (mac_rx_fifo_t));
-	mrf.mrf_type = MAC_RX_FIFO;
-	mrf.mrf_receive = (mac_receive_t)mac_soft_ring_poll;
-	mrf.mrf_intr_enable = (mac_intr_enable_t)mac_soft_ring_intr_enable;
-	mrf.mrf_intr_disable = (mac_intr_disable_t)mac_soft_ring_intr_disable;
-	mrf.mrf_flow_priority = pri;
 
 	softring = mac_soft_ring_create(id, mac_soft_ring_worker_wait,
-	    ST_RING_TCP, pri, mcip, mac_srs,
-	    cpuid, rx_func, x_arg1, x_arg2);
+	    ST_RING_TCP, pri, mcip, mac_srs, cpuid, rx_func, x_arg1, x_arg2);
 	softring->s_ring_rx_arg2 = NULL;
 
 	/*
@@ -1794,13 +1758,6 @@ mac_srs_create_proto_softrings(int id, pri_t pri, mac_client_impl_t *mcip,
 	 */
 	if (set_bypass && mcip->mci_direct_rx.mdrx_v4 != NULL &&
 	    (mcip->mci_rcb4.mrc_arg != NULL)) {
-		mac_soft_ring_dls_bypass_enable(softring,
-		    mcip->mci_direct_rx.mdrx_v4,
-		    mcip->mci_direct_rx.mdrx_arg_v4);
-
-		mrf.mrf_rx_arg = softring;
-		mrf.mrf_intr_handle = (mac_intr_handle_t)softring;
-
 		/*
 		 * Make a call in IP to get a TCP squeue assigned to
 		 * this softring to maintain full CPU locality through
@@ -1808,8 +1765,8 @@ mac_srs_create_proto_softrings(int id, pri_t pri, mac_client_impl_t *mcip,
 		 * the softring so the flow control can be pushed
 		 * all the way to H/W.
 		 */
-		softring->s_ring_rx_arg2 = mcip->mci_rcb4.mrc_add(
-		    mcip->mci_rcb4.mrc_arg, (mac_resource_t *)&mrf);
+		mac_soft_ring_poll_enable(softring, mcip->mci_direct_rx.mdrx_v4,
+		    mcip->mci_direct_rx.mdrx_arg_v4, &mcip->mci_rcb4, pri);
 	}
 
 	/*
@@ -1819,8 +1776,7 @@ mac_srs_create_proto_softrings(int id, pri_t pri, mac_client_impl_t *mcip,
 	 * bypass the DLS layer.
 	 */
 	softring = mac_soft_ring_create(id, mac_soft_ring_worker_wait,
-	    ST_RING_UDP, pri, mcip, mac_srs,
-	    cpuid, rx_func, x_arg1, x_arg2);
+	    ST_RING_UDP, pri, mcip, mac_srs, cpuid, rx_func, x_arg1, x_arg2);
 	softring->s_ring_rx_arg2 = NULL;
 
 	if (set_bypass && mcip->mci_direct_rx.mdrx_v4 != NULL) {
@@ -1831,26 +1787,18 @@ mac_srs_create_proto_softrings(int id, pri_t pri, mac_client_impl_t *mcip,
 
 	/* TCP for IPv6. */
 	softring = mac_soft_ring_create(id, mac_soft_ring_worker_wait,
-	    ST_RING_TCP6, pri, mcip, mac_srs,
-	    cpuid, rx_func, x_arg1, x_arg2);
+	    ST_RING_TCP6, pri, mcip, mac_srs, cpuid, rx_func, x_arg1, x_arg2);
 	softring->s_ring_rx_arg2 = NULL;
 
 	if (set_bypass && mcip->mci_direct_rx.mdrx_v6 != NULL &&
 	    (mcip->mci_rcb6.mrc_arg != NULL)) {
-		mac_soft_ring_dls_bypass_enable(softring,
-		    mcip->mci_direct_rx.mdrx_v6,
-		    mcip->mci_direct_rx.mdrx_arg_v6);
-
-		mrf.mrf_rx_arg = softring;
-		mrf.mrf_intr_handle = (mac_intr_handle_t)softring;
-		softring->s_ring_rx_arg2 = mcip->mci_rcb6.mrc_add(
-		    mcip->mci_rcb6.mrc_arg, (mac_resource_t *)&mrf);
+		mac_soft_ring_poll_enable(softring, mcip->mci_direct_rx.mdrx_v6,
+		    mcip->mci_direct_rx.mdrx_arg_v6, &mcip->mci_rcb6, pri);
 	}
 
 	/* UDP for IPv6. */
 	softring = mac_soft_ring_create(id, mac_soft_ring_worker_wait,
-	    ST_RING_UDP6, pri, mcip, mac_srs,
-	    cpuid, rx_func, x_arg1, x_arg2);
+	    ST_RING_UDP6, pri, mcip, mac_srs, cpuid, rx_func, x_arg1, x_arg2);
 	softring->s_ring_rx_arg2 = NULL;
 
 	if (set_bypass && mcip->mci_direct_rx.mdrx_v6 != NULL) {
@@ -1861,8 +1809,7 @@ mac_srs_create_proto_softrings(int id, pri_t pri, mac_client_impl_t *mcip,
 
 	/* Create the Oth softrings which has to go through the DLS. */
 	softring = mac_soft_ring_create(id, mac_soft_ring_worker_wait,
-	    ST_RING_OTH, pri, mcip, mac_srs,
-	    cpuid, rx_func, x_arg1, x_arg2);
+	    ST_RING_OTH, pri, mcip, mac_srs, cpuid, rx_func, x_arg1, x_arg2);
 	softring->s_ring_rx_arg2 = NULL;
 }
 
diff --git a/usr/src/uts/common/io/mac/mac_soft_ring.c b/usr/src/uts/common/io/mac/mac_soft_ring.c
index d82abff249..e14d35a51c 100644
--- a/usr/src/uts/common/io/mac/mac_soft_ring.c
+++ b/usr/src/uts/common/io/mac/mac_soft_ring.c
@@ -633,6 +633,64 @@ mac_soft_ring_dls_bypass_disable(mac_soft_ring_t *softring,
 	mutex_exit(&softring->s_ring_lock);
 }
 
+void
+mac_soft_ring_poll_enable(mac_soft_ring_t *sr, mac_direct_rx_t drx,
+    void *drx_arg, mac_resource_cb_t *rcb, uint32_t pri)
+{
+	mac_rx_fifo_t mrf;
+
+	/* Only TCP/IP clients are poll capable at the moment. */
+	VERIFY((sr->s_ring_type & (ST_RING_TCP | ST_RING_TCP6)) != 0);
+	/* The client resourse callback structure better be set. */
+	VERIFY3P(rcb->mrc_arg, !=, NULL);
+	/* Polling should be configured only once on a given softring. */
+	VERIFY3P(sr->s_ring_rx_arg2, ==, NULL);
+
+	/*
+	 * As polling elides DLS processing we must make sure that
+	 * softring processing (i.e. non-polling) also bypasses DLS
+	 * processing.
+	 */
+	mac_soft_ring_dls_bypass_enable(sr, drx, drx_arg);
+
+	bzero(&mrf, sizeof (mrf));
+	mrf.mrf_type = MAC_RX_FIFO;
+	mrf.mrf_receive = (mac_receive_t)mac_soft_ring_poll;
+	mrf.mrf_intr_enable =
+	    (mac_intr_enable_t)mac_soft_ring_intr_enable;
+	mrf.mrf_intr_disable =
+	    (mac_intr_disable_t)mac_soft_ring_intr_disable;
+	mrf.mrf_rx_arg = sr;
+	mrf.mrf_intr_handle = (mac_intr_handle_t)sr;
+	mrf.mrf_cpu_id = sr->s_ring_cpuid;
+	mrf.mrf_flow_priority = pri;
+
+	sr->s_ring_rx_arg2 = rcb->mrc_add(rcb->mrc_arg,
+	    (mac_resource_t *)&mrf);
+}
+
+void
+mac_soft_ring_poll_disable(mac_soft_ring_t *sr, mac_resource_cb_t *rcb,
+    mac_client_impl_t *mcip)
+{
+	/* Only TCP/IP clients are poll capable at the moment. */
+	VERIFY((sr->s_ring_type & (ST_RING_TCP | ST_RING_TCP6)) != 0);
+
+	/*
+	 * Remove the IP ring if there is one associated with this
+	 * softring. Note that IP rings are a limited resource; and
+	 * SRST_CLIENT_POLL_V4/V6 being set on the SRS is no guarantee
+	 * that all TCP softrings have an associated IP ring. This is by
+	 * design. See ip_squeue_add_ring().
+	 */
+	if (sr->s_ring_rx_arg2 != NULL) {
+		VERIFY3P(rcb->mrc_arg, !=, NULL);
+		rcb->mrc_remove(rcb->mrc_arg, sr->s_ring_rx_arg2);
+		sr->s_ring_rx_arg2 = NULL;
+	}
+
+	mac_soft_ring_dls_bypass_disable(sr, mcip);
+}
 
 /*
  * mac_soft_ring_signal
diff --git a/usr/src/uts/common/sys/mac_soft_ring.h b/usr/src/uts/common/sys/mac_soft_ring.h
index d93dedfffc..bf9ce07412 100644
--- a/usr/src/uts/common/sys/mac_soft_ring.h
+++ b/usr/src/uts/common/sys/mac_soft_ring.h
@@ -653,6 +653,10 @@ extern void mac_soft_ring_dls_bypass_enable(mac_soft_ring_t *, mac_direct_rx_t,
     void *);
 extern void mac_soft_ring_dls_bypass_disable(mac_soft_ring_t *,
     mac_client_impl_t *);
+extern void mac_soft_ring_poll_enable(mac_soft_ring_t *, mac_direct_rx_t,
+    void *, mac_resource_cb_t *, uint32_t);
+extern void mac_soft_ring_poll_disable(mac_soft_ring_t *, mac_resource_cb_t *,
+    mac_client_impl_t *);
 
 /* Rx SRS */
 extern mac_soft_ring_set_t *mac_srs_create(struct mac_client_impl_s *,
-- 
2.51.2

