git: b64408358d7f - main - aq(4): enable jumbo frames, software LRO, and suspend/resume

From: Adrian Chadd <adrian_at_FreeBSD.org>
Date: Sat, 20 Jun 2026 19:10:38 UTC
The branch main has been updated by adrian:

URL: https://cgit.FreeBSD.org/src/commit/?id=b64408358d7f27a69b84d9fd1e23e239e8bd00fc

commit b64408358d7f27a69b84d9fd1e23e239e8bd00fc
Author:     Nick Price <nick@spun.io>
AuthorDate: 2026-06-20 19:03:00 +0000
Commit:     Adrian Chadd <adrian@FreeBSD.org>
CommitDate: 2026-06-20 19:10:15 +0000

    aq(4): enable jumbo frames, software LRO, and suspend/resume
    
    - Configure the RX buffer size from the interface MTU and enable jumbo
      frames up to 9000 bytes, replacing the fixed standard-frame setup.
    
    - Advertise IFCAP_LRO so iflib coalesces received TCP segments with its
      software tcp_lro(9), like every other in-tree iflib driver
      (ix/igc/em/vmxnet3); aq does no hardware LRO.  iflib builds the
      per-RX-queue LRO context unconditionally, so the capability bit is all
      that is required; enabled by default via isc_capenable, toggle at
      runtime with ifconfig.
    
    - Add suspend/shutdown/resume handlers, replacing the unimplemented-
      function placeholders.  aq_if_shutdown/aq_if_suspend stop the interface
      and deinitialize the hardware; aq_if_resume re-resets the F/W, re-reads
      the mailbox address and re-selects fw_ops via aq_hw_mpi_create() before
      iflib re-inits, because the runtime init path (aq_hw_init) reuses the
      cached mailbox/fw_ops and a D3 power cycle can clear them.  iflib calls
      IFDI_RESUME unconditionally, so this also covers resuming while the
      interface was administratively down.
    
    Reviewed by:    adrian
    Differential Revision:  https://reviews.freebsd.org/D57437
---
 sys/dev/aq/aq_main.c | 49 ++++++++++++++++++++++++++++++-------------------
 sys/dev/aq/aq_ring.c |  2 +-
 2 files changed, 31 insertions(+), 20 deletions(-)

diff --git a/sys/dev/aq/aq_main.c b/sys/dev/aq/aq_main.c
index c7701cc4f6d8..e159ce7e72ff 100644
--- a/sys/dev/aq/aq_main.c
+++ b/sys/dev/aq/aq_main.c
@@ -392,8 +392,8 @@ aq_if_attach_pre(if_ctx_t ctx)
 	scctx->isc_tx_csum_flags = CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_TSO;
 #if __FreeBSD__ >= 12
 	scctx->isc_capabilities = IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_HWCSUM |
-	    IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_VLAN_HWFILTER | IFCAP_VLAN_MTU |
-	    IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWCSUM;
+	    IFCAP_TSO | IFCAP_LRO | IFCAP_JUMBO_MTU | IFCAP_VLAN_HWFILTER |
+	    IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWCSUM;
 	scctx->isc_capenable = scctx->isc_capabilities;
 #else
 	if_t ifp;
@@ -408,6 +408,8 @@ aq_if_attach_pre(if_ctx_t ctx)
 	    HW_ATL_B0_TSO_SIZE - sizeof(struct ether_vlan_header);
 	scctx->isc_tx_tso_segsize_max = HW_ATL_B0_MTU_JUMBO;
 	scctx->isc_min_frame_size = 52;
+	scctx->isc_max_frame_size = ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN +
+	    ETHER_VLAN_ENCAP_LEN;
 	scctx->isc_txrx = &aq_txrx;
 
 	scctx->isc_txqsizes[0] = sizeof(aq_tx_desc_t) * scctx->isc_ntxd[0];
@@ -512,21 +514,18 @@ aq_if_detach(if_ctx_t ctx)
 static int
 aq_if_shutdown(if_ctx_t ctx)
 {
-
-	AQ_DBG_ENTER();
-
-	AQ_XXX_UNIMPLEMENTED_FUNCTION;
-
-	AQ_DBG_EXIT(0);
-	return (0);
+	return (aq_if_suspend(ctx));
 }
 
 static int
 aq_if_suspend(if_ctx_t ctx)
 {
+	struct aq_dev *softc = iflib_get_softc(ctx);
+
 	AQ_DBG_ENTER();
 
-	AQ_XXX_UNIMPLEMENTED_FUNCTION;
+	aq_if_stop(ctx);
+	aq_hw_deinit(&softc->hw);
 
 	AQ_DBG_EXIT(0);
 	return (0);
@@ -535,12 +534,13 @@ aq_if_suspend(if_ctx_t ctx)
 static int
 aq_if_resume(if_ctx_t ctx)
 {
-	AQ_DBG_ENTER();
-
-	AQ_XXX_UNIMPLEMENTED_FUNCTION;
+	struct aq_dev *softc = iflib_get_softc(ctx);
+	int err;
 
-	AQ_DBG_EXIT(0);
-	return (0);
+	AQ_DBG_ENTER();
+	err = aq_hw_mpi_create(&softc->hw);
+	AQ_DBG_EXIT(err);
+	return (err);
 }
 
 _Static_assert(sizeof(struct aq_ring_stats) % sizeof(counter_u64_t) == 0,
@@ -755,6 +755,7 @@ aq_if_init(if_ctx_t ctx)
 	}
 	for (i = 0; i < softc->rx_rings_count; i++) {
 		struct aq_ring *ring = softc->rx_rings[i];
+		ring->rx_max_frame_size = iflib_get_rx_mbuf_sz(ctx);
 		err = aq_ring_rx_init(&softc->hw, ring);
 		if (err) {
 			device_printf(softc->dev,
@@ -901,11 +902,21 @@ aq_if_multi_set(if_ctx_t ctx)
 static int
 aq_if_mtu_set(if_ctx_t ctx, uint32_t mtu)
 {
-	int err = 0;
-	AQ_DBG_ENTER();
+	if_softc_ctx_t scctx = iflib_get_softc_ctx(ctx);
+	uint32_t max_frame;
 
-	AQ_DBG_EXIT(err);
-	return (err);
+	AQ_DBG_ENTERA("mtu %u", mtu);
+
+	max_frame = mtu + ETHER_HDR_LEN + ETHER_CRC_LEN + ETHER_VLAN_ENCAP_LEN;
+	if (max_frame > HW_ATL_B0_MTU_JUMBO) {
+		AQ_DBG_EXIT(EINVAL);
+		return (EINVAL);
+	}
+
+	scctx->isc_max_frame_size = max_frame;
+
+	AQ_DBG_EXIT(0);
+	return (0);
 }
 
 static void
diff --git a/sys/dev/aq/aq_ring.c b/sys/dev/aq/aq_ring.c
index 900061437ddb..9b7f6ae2bf0e 100644
--- a/sys/dev/aq/aq_ring.c
+++ b/sys/dev/aq/aq_ring.c
@@ -371,7 +371,7 @@ aq_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
 			len = ring->rx_max_frame_size;
 		} else {
 			total_len = le32toh(rx_desc->wb.pkt_len);
-			len = total_len & (ring->rx_max_frame_size - 1);
+			len = total_len - (size_t)i * ring->rx_max_frame_size;
 		}
 		ri->iri_frags[i].irf_flid = 0;
 		ri->iri_frags[i].irf_idx = cidx;