From nobody Fri Oct 09 10:12:57 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4j1N3G1yJHz6vRd4 for ; Fri, 09 Oct 2026 10:12:58 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR2" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4j1N3F73Xxz4YMT for ; Fri, 09 Oct 2026 10:12:57 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1791540778; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Kqwe6V3q6qQ8emGJXpgpUuJy9dTQVuYc/BqYzmHoMAQ=; b=e1gY71dhPLyv0oUrk4IOsoish1KDEK4UGiuhe/tBbq4PPbbr5qSNIEl2OiqWo+eAJVc4fA qlLiihjpvd92qvvl7GroH7wKIARa49gYzswYBd8k342KZTz7A67/cO6wh3J93A1oMd5shg krGqH9lJp+5lODDr5VT7+MSg/d2yvhBQKkE0Ydu1BnePInLqQvU927gIuIXqCQBRcsD4Nm kq+12bFVhcpO03P5RDiRFpvDRJG/e22Q8xKLisE7J2E2/iPP1IaTJl7S3AfDMnh2x1I4tE vzIB12GZ7BpqzE8t1JJCbfqXPAfG7oFePidHQ+ScsJZbQzn7p2fekmQoJqg/Eg== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1791540778; b=DTWNv4B1qN12tNj66Qa38LJjGvDlm1YGUwrjsxAdHa+w8JLBeccJHYt8VLFVBv+N2iS548 ma9EM3quRGSPHnsXriTSxgvcdxm43sIG3GQXjeysUdwCb5ZSt89EeD9CmloWFwlPtJu8vD IT7rmXKn+5Yl4lLLRbYdjek9sTLlJMgiIwIvE/CzV1IRXB09r1dDWZxS8H3+krXnz6U/vm OA6pVLox7MTEwQ10lw2uRZ2uv71M/8d68JEX1Wbn2nIFtwRD6MUczoX91a/X/YeWC5j4do ILB5m+yAn71S0lgA4S3pMdvvj0fRTC2GPpi+kfC9NgxEsJWF4X3V/4xZP9bEqA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1791540778; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Kqwe6V3q6qQ8emGJXpgpUuJy9dTQVuYc/BqYzmHoMAQ=; b=PI55b3ezcSHQNzLQWeV+FK0fDP3qCqn2QJbHLkLJyHKLiiWJ8TghZCqzTYdgoBsoeHIDJb RRion9isgtzAJCw8GhRuUiP7EB9fdazNEtUBxcg2/sU/kuZzzwp7X1qI54ZDRq1BtFIDWn PKojtC+pgNGTlSC/Y1t9MrKwveggJosDXH22T3ip1kAW2k38W9wNUNrZyCRBi+Im8QiMV/ VjGWHbg+fP4NQS9SKjJ4fNdfv1b0yVKr5QrY6aaSibqFXHR8nsyE5hMnJLkBEyJHyPv9Ib D9rIJB8mSzzo5i+lXqEj08ZZg05NN8HpuqKqLZOjTcudAHeM0umjob0DgdQ/7w== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4j1N3F66q7z1LJ1 for ; Fri, 09 Oct 2026 10:12:57 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 4245d by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Fri, 09 Oct 2026 10:12:57 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: Sumit Saxena From: Sumit Saxena Subject: git: 22f37c46b484 - main - if_bnxt: rework interrupt coalescing onto the AGGINT_QCAPS scheme List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: ssaxena X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 22f37c46b4841fec22612fd4bc485f0515f27a28 Auto-Submitted: auto-generated Date: Fri, 09 Oct 2026 10:12:57 +0000 Message-Id: <6ac8be29.4245d.4855e418@gitrepo.freebsd.org> The branch main has been updated by ssaxena: URL: https://cgit.FreeBSD.org/src/commit/?id=22f37c46b4841fec22612fd4bc485f0515f27a28 commit 22f37c46b4841fec22612fd4bc485f0515f27a28 Author: Sumit Saxena AuthorDate: 2026-08-03 08:52:00 +0000 Commit: Sumit Saxena CommitDate: 2026-10-09 08:24:45 +0000 if_bnxt: rework interrupt coalescing onto the AGGINT_QCAPS scheme Query firmware-advertised coalescing capabilities and program per-direction rx/tx coalescing settings against them, replacing the old hardcoded scheme. Add sysctls for the coalescing mode, budget, and stats-timer knobs the new scheme exposes. Reviewed by: gallatin MFC after: 2 weeks Sponsored by: Broadcom Inc. Differential Revision: https://reviews.freebsd.org/D58621 --- sys/dev/bnxt/bnxt_en/bnxt.h | 64 ++++++++-- sys/dev/bnxt/bnxt_en/bnxt_hwrm.c | 250 +++++++++++++++++++++++++++--------- sys/dev/bnxt/bnxt_en/bnxt_hwrm.h | 1 + sys/dev/bnxt/bnxt_en/bnxt_sysctl.c | 253 ++++++++++++++++++++++++++++++++++--- sys/dev/bnxt/bnxt_en/if_bnxt.c | 50 ++++++++ 5 files changed, 534 insertions(+), 84 deletions(-) diff --git a/sys/dev/bnxt/bnxt_en/bnxt.h b/sys/dev/bnxt/bnxt_en/bnxt.h index e8ffc9fdb057..f93f0d4fe794 100644 --- a/sys/dev/bnxt/bnxt_en/bnxt.h +++ b/sys/dev/bnxt/bnxt_en/bnxt.h @@ -813,6 +813,56 @@ struct bnxt_hw_lro { uint32_t min_agg_len; }; +#define BNXT_LEGACY_COAL_CMPL_PARAMS \ + (HWRM_RING_AGGINT_QCAPS_OUTPUT_CMPL_PARAMS_INT_LAT_TMR_MIN | \ + HWRM_RING_AGGINT_QCAPS_OUTPUT_CMPL_PARAMS_INT_LAT_TMR_MAX | \ + HWRM_RING_AGGINT_QCAPS_OUTPUT_CMPL_PARAMS_TIMER_RESET | \ + HWRM_RING_AGGINT_QCAPS_OUTPUT_CMPL_PARAMS_RING_IDLE | \ + HWRM_RING_AGGINT_QCAPS_OUTPUT_CMPL_PARAMS_NUM_CMPL_DMA_AGGR | \ + HWRM_RING_AGGINT_QCAPS_OUTPUT_CMPL_PARAMS_NUM_CMPL_DMA_AGGR_DURING_INT | \ + HWRM_RING_AGGINT_QCAPS_OUTPUT_CMPL_PARAMS_CMPL_AGGR_DMA_TMR | \ + HWRM_RING_AGGINT_QCAPS_OUTPUT_CMPL_PARAMS_CMPL_AGGR_DMA_TMR_DURING_INT | \ + HWRM_RING_AGGINT_QCAPS_OUTPUT_CMPL_PARAMS_NUM_CMPL_AGGR_INT) + +#define BNXT_COAL_CMPL_ENABLES \ + (HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS_INPUT_ENABLES_NUM_CMPL_DMA_AGGR | \ + HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS_INPUT_ENABLES_CMPL_AGGR_DMA_TMR | \ + HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS_INPUT_ENABLES_INT_LAT_TMR_MAX | \ + HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS_INPUT_ENABLES_NUM_CMPL_AGGR_INT) + +#define BNXT_COAL_CMPL_MIN_TMR_ENABLE \ + HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS_INPUT_ENABLES_INT_LAT_TMR_MIN + +/* Gates cmpl_aggr_dma_tmr_during_int, but reuses num_cmpl_dma_aggr_during_int's + * enable bit - there's no separate bit for the timer field. */ +#define BNXT_COAL_CMPL_AGGR_TMR_DURING_INT_ENABLE \ + HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS_INPUT_ENABLES_NUM_CMPL_DMA_AGGR_DURING_INT + +struct bnxt_coal_cap { + uint32_t cmpl_params; + uint32_t nq_params; + uint16_t num_cmpl_dma_aggr_max; + uint16_t num_cmpl_dma_aggr_during_int_max; + uint16_t cmpl_aggr_dma_tmr_max; + uint16_t cmpl_aggr_dma_tmr_during_int_max; + uint16_t int_lat_tmr_min_max; + uint16_t int_lat_tmr_max_max; + uint16_t num_cmpl_aggr_int_max; + uint16_t timer_units; +}; + +struct bnxt_coal { + uint16_t coal_ticks; + uint16_t coal_ticks_irq; + uint16_t coal_bufs; + uint16_t coal_bufs_irq; + uint16_t idle_thresh; /* RING_IDLE enabled when coal ticks < idle_thresh */ + uint8_t bufs_per_record; + uint16_t budget; + uint16_t flags; + uint8_t timer_reset_during_ring_alloc; +}; + /* The hardware supports certain page sizes. Use the supported page sizes * to allocate the rings. */ @@ -1367,15 +1417,12 @@ struct bnxt_softc { volatile int detached; struct bnxt_hw_lro hw_lro; uint8_t wol_filter_id; - uint16_t rx_coal_usecs; - uint16_t rx_coal_usecs_irq; - uint16_t rx_coal_frames; - uint16_t rx_coal_frames_irq; - uint16_t tx_coal_usecs; - uint16_t tx_coal_usecs_irq; - uint16_t tx_coal_frames; - uint16_t tx_coal_frames_irq; + struct bnxt_coal_cap coal_cap; + struct bnxt_coal rx_coal; + struct bnxt_coal tx_coal; + + uint32_t stats_coal_ticks; #define BNXT_USEC_TO_COAL_TIMER(x) ((x) * 25 / 2) #define BNXT_DEF_STATS_COAL_TICKS 1000000 #define BNXT_MIN_STATS_COAL_TICKS 250000 @@ -1476,6 +1523,7 @@ struct bnxt_softc { #define BNXT_STATE_FW_NON_FATAL_COND 13 #define BNXT_STATE_FW_ACTIVATE_RESET 14 #define BNXT_STATE_HALF_OPEN 15 +#define BNXT_STATE_UP 16 #define BNXT_NO_FW_ACCESS(bp) \ test_bit(BNXT_STATE_FW_FATAL_COND, &(bp)->state) struct pci_dev *pdev; diff --git a/sys/dev/bnxt/bnxt_en/bnxt_hwrm.c b/sys/dev/bnxt/bnxt_en/bnxt_hwrm.c index b9cd7174209c..77e43079fd96 100644 --- a/sys/dev/bnxt/bnxt_en/bnxt_hwrm.c +++ b/sys/dev/bnxt/bnxt_en/bnxt_hwrm.c @@ -2136,6 +2136,9 @@ bnxt_hwrm_ring_alloc(struct bnxt_softc *softc, uint8_t type, req.nq_ring_id = htole16(softc->nq_rings[idx].ring.phys_id); req.enables |= htole32( HWRM_RING_ALLOC_INPUT_ENABLES_NQ_RING_ID_VALID); + + if (softc->rx_coal.timer_reset_during_ring_alloc) + req.flags |= HWRM_RING_ALLOC_INPUT_FLAGS_TIMER_RESET; break; case HWRM_RING_ALLOC_INPUT_RING_TYPE_NQ: req.int_mode = HWRM_RING_ALLOC_INPUT_INT_MODE_MSIX; @@ -3475,81 +3478,208 @@ bnxt_hwrm_free_wol_fltr(struct bnxt_softc *softc) return hwrm_send_message(softc, &req, sizeof(req)); } -static void bnxt_hwrm_set_coal_params(struct bnxt_softc *softc, uint32_t max_frames, - uint32_t buf_tmrs, uint16_t flags, - struct hwrm_ring_cmpl_ring_cfg_aggint_params_input *req) +void +bnxt_hwrm_coal_params_qcaps(struct bnxt_softc *softc) { - req->flags = htole16(flags); - req->num_cmpl_dma_aggr = htole16((uint16_t)max_frames); - req->num_cmpl_dma_aggr_during_int = htole16(max_frames >> 16); - req->cmpl_aggr_dma_tmr = htole16((uint16_t)buf_tmrs); - req->cmpl_aggr_dma_tmr_during_int = htole16(buf_tmrs >> 16); - /* Minimum time between 2 interrupts set to buf_tmr x 2 */ - req->int_lat_tmr_min = htole16((uint16_t)buf_tmrs * 2); - req->int_lat_tmr_max = htole16((uint16_t)buf_tmrs * 4); - req->num_cmpl_aggr_int = htole16((uint16_t)max_frames * 4); + struct bnxt_coal_cap *coal_cap = &softc->coal_cap; + struct hwrm_ring_aggint_qcaps_output *resp = + (void *)softc->hwrm_cmd_resp.idi_vaddr; + struct hwrm_ring_aggint_qcaps_input req = {0}; + int rc; + + coal_cap->cmpl_params = BNXT_LEGACY_COAL_CMPL_PARAMS; + coal_cap->num_cmpl_dma_aggr_max = 63; + coal_cap->num_cmpl_dma_aggr_during_int_max = 63; + coal_cap->cmpl_aggr_dma_tmr_max = 65535; + coal_cap->cmpl_aggr_dma_tmr_during_int_max = 65535; + coal_cap->int_lat_tmr_min_max = 65535; + coal_cap->int_lat_tmr_max_max = 65535; + coal_cap->num_cmpl_aggr_int_max = 65535; + coal_cap->timer_units = 80; + + if (softc->hwrm_spec_code < 0x10902) + return; + + bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_RING_AGGINT_QCAPS); + + BNXT_HWRM_LOCK(softc); + rc = _hwrm_send_message(softc, &req, sizeof(req)); + if (rc) { + BNXT_HWRM_UNLOCK(softc); + return; + } + + coal_cap->cmpl_params = le32toh(resp->cmpl_params); + coal_cap->nq_params = le32toh(resp->nq_params); + coal_cap->num_cmpl_dma_aggr_max = le16toh(resp->num_cmpl_dma_aggr_max); + coal_cap->num_cmpl_dma_aggr_during_int_max = + le16toh(resp->num_cmpl_dma_aggr_during_int_max); + coal_cap->cmpl_aggr_dma_tmr_max = le16toh(resp->cmpl_aggr_dma_tmr_max); + coal_cap->cmpl_aggr_dma_tmr_during_int_max = + le16toh(resp->cmpl_aggr_dma_tmr_during_int_max); + coal_cap->int_lat_tmr_min_max = le16toh(resp->int_lat_tmr_min_max); + coal_cap->int_lat_tmr_max_max = le16toh(resp->int_lat_tmr_max_max); + coal_cap->num_cmpl_aggr_int_max = le16toh(resp->num_cmpl_aggr_int_max); + coal_cap->timer_units = le16toh(resp->timer_units); + BNXT_HWRM_UNLOCK(softc); } -int bnxt_hwrm_set_coal(struct bnxt_softc *softc) +static uint16_t +bnxt_usec_to_coal_tmr(struct bnxt_softc *softc, uint16_t usec) { - int i, rc = 0; - struct hwrm_ring_cmpl_ring_cfg_aggint_params_input req_rx = {0}, - req_tx = {0}, *req; - uint16_t max_buf, max_buf_irq; - uint16_t buf_tmr, buf_tmr_irq; - uint32_t flags; + struct bnxt_coal_cap *coal_cap = &softc->coal_cap; - bnxt_hwrm_cmd_hdr_init(softc, &req_rx, - HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS); - bnxt_hwrm_cmd_hdr_init(softc, &req_tx, - HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS); + return (usec * 1000 / coal_cap->timer_units); +} - /* Each rx completion (2 records) should be DMAed immediately. - * DMA 1/4 of the completion buffers at a time. - */ - max_buf = min_t(uint16_t, softc->rx_coal_frames / 4, 2); - /* max_buf must not be zero */ - max_buf = clamp_t(uint16_t, max_buf, 1, 63); - max_buf_irq = clamp_t(uint16_t, softc->rx_coal_frames_irq, 1, 63); - buf_tmr = BNXT_USEC_TO_COAL_TIMER(softc->rx_coal_usecs); - /* buf timer set to 1/4 of interrupt timer */ - buf_tmr = max_t(uint16_t, buf_tmr / 4, 1); - buf_tmr_irq = BNXT_USEC_TO_COAL_TIMER(softc->rx_coal_usecs_irq); - buf_tmr_irq = max_t(uint16_t, buf_tmr_irq, 1); - - flags = HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS_INPUT_FLAGS_TIMER_RESET; - - /* RING_IDLE generates more IRQs for lower latency. Enable it only - * if coal_usecs is less than 25 us. +static void +bnxt_hwrm_set_coal_params(struct bnxt_softc *softc, struct bnxt_coal *hw_coal, + struct hwrm_ring_cmpl_ring_cfg_aggint_params_input *req) +{ + struct bnxt_coal_cap *coal_cap = &softc->coal_cap; + uint16_t val, tmr, max, flags = hw_coal->flags; + uint32_t cmpl_params = coal_cap->cmpl_params; + + max = hw_coal->bufs_per_record * 128; + if (hw_coal->budget) + max = hw_coal->bufs_per_record * hw_coal->budget; + max = min_t(uint16_t, max, coal_cap->num_cmpl_aggr_int_max); + + val = clamp_t(uint16_t, hw_coal->coal_bufs, 1, max); + req->num_cmpl_aggr_int = htole16(val); + + val = min_t(uint16_t, val, coal_cap->num_cmpl_dma_aggr_max); + req->num_cmpl_dma_aggr = htole16(val); + + val = clamp_t(uint16_t, hw_coal->coal_bufs_irq, 1, + coal_cap->num_cmpl_dma_aggr_during_int_max); + req->num_cmpl_dma_aggr_during_int = htole16(val); + + tmr = bnxt_usec_to_coal_tmr(softc, hw_coal->coal_ticks); + tmr = clamp_t(uint16_t, tmr, 1, coal_cap->int_lat_tmr_max_max); + req->int_lat_tmr_max = htole16(tmr); + + /* Minimum timer set to 1/2 of the interrupt timer. */ + if (cmpl_params & + HWRM_RING_AGGINT_QCAPS_OUTPUT_CMPL_PARAMS_INT_LAT_TMR_MIN) { + val = tmr / 2; + val = clamp_t(uint16_t, val, 1, coal_cap->int_lat_tmr_min_max); + req->int_lat_tmr_min = htole16(val); + req->enables |= htole16(BNXT_COAL_CMPL_MIN_TMR_ENABLE); + } + + /* Buf timer set to 1/4 of the interrupt timer. */ + val = clamp_t(uint16_t, tmr / 4, 1, coal_cap->cmpl_aggr_dma_tmr_max); + req->cmpl_aggr_dma_tmr = htole16(val); + + /* + * Gate on CMPL_AGGR_DMA_TMR_DURING_INT, not the similarly-named + * NUM_CMPL_DMA_AGGR_DURING_INT bit which covers the unrelated count field. */ - if (softc->rx_coal_usecs < 25) + if (cmpl_params & + HWRM_RING_AGGINT_QCAPS_OUTPUT_CMPL_PARAMS_CMPL_AGGR_DMA_TMR_DURING_INT) { + tmr = bnxt_usec_to_coal_tmr(softc, hw_coal->coal_ticks_irq); + val = clamp_t(uint16_t, tmr, 1, + coal_cap->cmpl_aggr_dma_tmr_during_int_max); + req->cmpl_aggr_dma_tmr_during_int = htole16(val); + /* + * No dedicated enable bit exists for this field; reusing + * NUM_CMPL_DMA_AGGR_DURING_INT's enable bit matches existing behavior. + */ + req->enables |= + htole16(BNXT_COAL_CMPL_AGGR_TMR_DURING_INT_ENABLE); + } + + if ((cmpl_params & HWRM_RING_AGGINT_QCAPS_OUTPUT_CMPL_PARAMS_RING_IDLE) && + hw_coal->idle_thresh && hw_coal->coal_ticks < hw_coal->idle_thresh) flags |= HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS_INPUT_FLAGS_RING_IDLE; - bnxt_hwrm_set_coal_params(softc, max_buf_irq << 16 | max_buf, - buf_tmr_irq << 16 | buf_tmr, flags, &req_rx); - - /* max_buf must not be zero */ - max_buf = clamp_t(uint16_t, softc->tx_coal_frames, 1, 63); - max_buf_irq = clamp_t(uint16_t, softc->tx_coal_frames_irq, 1, 63); - buf_tmr = BNXT_USEC_TO_COAL_TIMER(softc->tx_coal_usecs); - /* buf timer set to 1/4 of interrupt timer */ - buf_tmr = max_t(uint16_t, buf_tmr / 4, 1); - buf_tmr_irq = BNXT_USEC_TO_COAL_TIMER(softc->tx_coal_usecs_irq); - buf_tmr_irq = max_t(uint16_t, buf_tmr_irq, 1); - flags = HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS_INPUT_FLAGS_TIMER_RESET; - bnxt_hwrm_set_coal_params(softc, max_buf_irq << 16 | max_buf, - buf_tmr_irq << 16 | buf_tmr, flags, &req_tx); + req->flags = htole16(flags); + req->enables |= htole16(BNXT_COAL_CMPL_ENABLES); +} - for (i = 0; i < softc->nrxqsets; i++) { +static int +bnxt_hwrm_set_coal_nq(struct bnxt_softc *softc, uint32_t ring_id, + struct bnxt_coal *hw_coal) +{ + struct hwrm_ring_cmpl_ring_cfg_aggint_params_input req = {0}; + struct bnxt_coal_cap *coal_cap = &softc->coal_cap; + uint16_t tmr; + + if (!(coal_cap->nq_params & + HWRM_RING_AGGINT_QCAPS_OUTPUT_NQ_PARAMS_INT_LAT_TMR_MIN)) + return (0); + + bnxt_hwrm_cmd_hdr_init(softc, &req, + HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS); + + req.ring_id = htole16(ring_id); + req.flags = + htole16(HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS_INPUT_FLAGS_IS_NQ); + + tmr = bnxt_usec_to_coal_tmr(softc, hw_coal->coal_ticks) / 2; + tmr = clamp_t(uint16_t, tmr, 1, coal_cap->int_lat_tmr_min_max); + req.int_lat_tmr_min = htole16(tmr); + req.enables |= htole16(BNXT_COAL_CMPL_MIN_TMR_ENABLE); + + return (hwrm_send_message(softc, &req, sizeof(req))); +} + +int bnxt_hwrm_set_coal(struct bnxt_softc *softc) +{ + struct hwrm_ring_cmpl_ring_cfg_aggint_params_input req = {0}; + int i, rc = 0; + + if (!test_bit(BNXT_STATE_UP, &softc->state)) + return (rc); + + bnxt_hwrm_cmd_hdr_init(softc, &req, + HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS); + bnxt_hwrm_set_coal_params(softc, &softc->rx_coal, &req); - req = &req_rx; - req->ring_id = htole16(softc->grp_info[i].cp_ring_id); + for (i = 0; i < softc->nrxqsets; i++) { + req.ring_id = htole16(softc->grp_info[i].cp_ring_id); - rc = hwrm_send_message(softc, req, sizeof(*req)); + rc = hwrm_send_message(softc, &req, sizeof(req)); if (rc) break; + + if (BNXT_CHIP_P5_PLUS(softc)) + rc = bnxt_hwrm_set_coal_nq(softc, + softc->nq_rings[i].ring.phys_id, &softc->rx_coal); + else + rc = bnxt_hwrm_set_coal_nq(softc, + softc->rx_cp_rings[i].ring.phys_id, &softc->rx_coal); + if (rc) { + device_printf(softc->dev, + "%s: Rx NQ coalesce setting failed for queue %d\n", + __func__, i); + break; + } } - return rc; + + if (softc->fw_cap & BNXT_FLAG_TX_COAL_CMPL) { + struct hwrm_ring_cmpl_ring_cfg_aggint_params_input req_tx = {0}; + + bnxt_hwrm_cmd_hdr_init(softc, &req_tx, + HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS); + bnxt_hwrm_set_coal_params(softc, &softc->tx_coal, &req_tx); + + for (i = 0; i < softc->ntxqsets; i++) { + req_tx.ring_id = + htole16(softc->tx_cp_rings[i].ring.phys_id); + + rc = hwrm_send_message(softc, &req_tx, sizeof(req_tx)); + if (rc) { + device_printf(softc->dev, + "%s: Tx coalesce setting failed for queue %d\n", + __func__, i); + break; + } + } + } + + return (rc); } void bnxt_hwrm_ring_info_get(struct bnxt_softc *softc, uint8_t ring_type, diff --git a/sys/dev/bnxt/bnxt_en/bnxt_hwrm.h b/sys/dev/bnxt/bnxt_en/bnxt_hwrm.h index e507b716303d..d3b25a243ec5 100644 --- a/sys/dev/bnxt/bnxt_en/bnxt_hwrm.h +++ b/sys/dev/bnxt/bnxt_en/bnxt_hwrm.h @@ -128,6 +128,7 @@ uint16_t bnxt_hwrm_get_wol_fltrs(struct bnxt_softc *softc, uint16_t handle); int bnxt_hwrm_alloc_wol_fltr(struct bnxt_softc *softc); int bnxt_hwrm_free_wol_fltr(struct bnxt_softc *softc); int bnxt_hwrm_set_coal(struct bnxt_softc *softc); +void bnxt_hwrm_coal_params_qcaps(struct bnxt_softc *softc); int bnxt_hwrm_func_rgtr_async_events(struct bnxt_softc *softc, unsigned long *bmap, int bmap_size); int bnxt_hwrm_func_backing_store_qcaps(struct bnxt_softc *softc); diff --git a/sys/dev/bnxt/bnxt_en/bnxt_sysctl.c b/sys/dev/bnxt/bnxt_en/bnxt_sysctl.c index 37a878c9d85f..cb906c38b906 100644 --- a/sys/dev/bnxt/bnxt_en/bnxt_sysctl.c +++ b/sys/dev/bnxt/bnxt_en/bnxt_sysctl.c @@ -1604,21 +1604,46 @@ bnxt_vlan_strip_sysctl(SYSCTL_HANDLER_ARGS) { return rc; } +/* + * sysctl_handle_int() allows any int-sized value; reject anything that + * would truncate/overflow when narrowed into the uint16_t coal field. + */ +static int +bnxt_sysctl_check_u16_range(struct bnxt_softc *softc, const char *what, + int val, uint16_t mult) +{ + int max = mult ? (UINT16_MAX / mult) : UINT16_MAX; + + if (val < 0 || val > max) { + device_printf(softc->dev, + "%s: value %d out of range [0, %d]\n", what, val, max); + return EINVAL; + } + return 0; +} + static int bnxt_set_coal_rx_usecs(SYSCTL_HANDLER_ARGS) { struct bnxt_softc *softc = arg1; + struct bnxt_coal *hw_coal; int rc; int val; if (softc == NULL) return EBUSY; - val = softc->rx_coal_usecs; + hw_coal = &softc->rx_coal; + val = hw_coal->coal_ticks; + rc = sysctl_handle_int(oidp, &val, 0, req); if (rc || !req->newptr) return rc; - softc->rx_coal_usecs = val; + rc = bnxt_sysctl_check_u16_range(softc, __func__, val, 0); + if (rc) + return rc; + + hw_coal->coal_ticks = val; rc = bnxt_hwrm_set_coal(softc); return rc; @@ -1627,18 +1652,33 @@ bnxt_set_coal_rx_usecs(SYSCTL_HANDLER_ARGS) { static int bnxt_set_coal_rx_frames(SYSCTL_HANDLER_ARGS) { struct bnxt_softc *softc = arg1; + struct bnxt_coal *hw_coal; + uint16_t mult; int rc; int val; if (softc == NULL) return EBUSY; - val = softc->rx_coal_frames; + hw_coal = &softc->rx_coal; + mult = hw_coal->bufs_per_record; + if (!mult) { + device_printf(softc->dev, + "%s: bufs_per_record is zero which is invalid\n", __func__); + return EINVAL; + } + + val = hw_coal->coal_bufs / mult; + rc = sysctl_handle_int(oidp, &val, 0, req); if (rc || !req->newptr) return rc; - softc->rx_coal_frames = val; + rc = bnxt_sysctl_check_u16_range(softc, __func__, val, mult); + if (rc) + return rc; + + hw_coal->coal_bufs = val * mult; rc = bnxt_hwrm_set_coal(softc); return rc; @@ -1647,18 +1687,25 @@ bnxt_set_coal_rx_frames(SYSCTL_HANDLER_ARGS) { static int bnxt_set_coal_rx_usecs_irq(SYSCTL_HANDLER_ARGS) { struct bnxt_softc *softc = arg1; + struct bnxt_coal *hw_coal; int rc; int val; if (softc == NULL) return EBUSY; - val = softc->rx_coal_usecs_irq; + hw_coal = &softc->rx_coal; + val = hw_coal->coal_ticks_irq; + rc = sysctl_handle_int(oidp, &val, 0, req); if (rc || !req->newptr) return rc; - softc->rx_coal_usecs_irq = val; + rc = bnxt_sysctl_check_u16_range(softc, __func__, val, 0); + if (rc) + return rc; + + hw_coal->coal_ticks_irq = val; rc = bnxt_hwrm_set_coal(softc); return rc; @@ -1667,38 +1714,111 @@ bnxt_set_coal_rx_usecs_irq(SYSCTL_HANDLER_ARGS) { static int bnxt_set_coal_rx_frames_irq(SYSCTL_HANDLER_ARGS) { struct bnxt_softc *softc = arg1; + struct bnxt_coal *hw_coal; + uint16_t mult; int rc; int val; if (softc == NULL) return EBUSY; - val = softc->rx_coal_frames_irq; + hw_coal = &softc->rx_coal; + mult = hw_coal->bufs_per_record; + if (!mult) { + device_printf(softc->dev, + "%s: bufs_per_record is zero which is invalid\n", __func__); + return EINVAL; + } + + val = hw_coal->coal_bufs_irq / mult; + rc = sysctl_handle_int(oidp, &val, 0, req); if (rc || !req->newptr) return rc; - softc->rx_coal_frames_irq = val; + rc = bnxt_sysctl_check_u16_range(softc, __func__, val, mult); + if (rc) + return rc; + + hw_coal->coal_bufs_irq = val * mult; rc = bnxt_hwrm_set_coal(softc); return rc; } +static int +bnxt_set_rx_coalesce_mode(SYSCTL_HANDLER_ARGS) { + struct bnxt_softc *softc = arg1; + struct bnxt_coal_cap *coal_cap; + struct bnxt_coal *hw_coal; + uint16_t flags; + int val; + int rc; + + if (softc == NULL) + return EBUSY; + + coal_cap = &softc->coal_cap; + + if (coal_cap->cmpl_params & + HWRM_RING_AGGINT_QCAPS_OUTPUT_CMPL_PARAMS_TIMER_RESET) { + hw_coal = &softc->rx_coal; + flags = hw_coal->flags; + + val = flags & HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS_INPUT_FLAGS_TIMER_RESET; + rc = sysctl_handle_int(oidp, &val, 0, req); + if (rc || !req->newptr) + return rc; + + if (val) + flags |= HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS_INPUT_FLAGS_TIMER_RESET; + else + flags &= ~HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS_INPUT_FLAGS_TIMER_RESET; + + hw_coal->flags = flags; + rc = bnxt_hwrm_set_coal(softc); + return rc; + } + + if (coal_cap->cmpl_params & + HWRM_RING_AGGINT_QCAPS_OUTPUT_CMPL_PARAMS_TMR_RESET_ON_ALLOC) { + hw_coal = &softc->rx_coal; + val = hw_coal->timer_reset_during_ring_alloc; + rc = sysctl_handle_int(oidp, &val, 0, req); + if (rc || !req->newptr) + return rc; + + /* Takes effect on next ring (re)alloc, so no bnxt_hwrm_set_coal() call needed here. */ + hw_coal->timer_reset_during_ring_alloc = val ? 1 : 0; + + return rc; + } + + return EOPNOTSUPP; +} + static int bnxt_set_coal_tx_usecs(SYSCTL_HANDLER_ARGS) { struct bnxt_softc *softc = arg1; + struct bnxt_coal *hw_coal; int rc; int val; if (softc == NULL) return EBUSY; - val = softc->tx_coal_usecs; + hw_coal = &softc->tx_coal; + val = hw_coal->coal_ticks; + rc = sysctl_handle_int(oidp, &val, 0, req); if (rc || !req->newptr) return rc; - softc->tx_coal_usecs = val; + rc = bnxt_sysctl_check_u16_range(softc, __func__, val, 0); + if (rc) + return rc; + + hw_coal->coal_ticks = val; rc = bnxt_hwrm_set_coal(softc); return rc; @@ -1707,18 +1827,33 @@ bnxt_set_coal_tx_usecs(SYSCTL_HANDLER_ARGS) { static int bnxt_set_coal_tx_frames(SYSCTL_HANDLER_ARGS) { struct bnxt_softc *softc = arg1; + struct bnxt_coal *hw_coal; + uint16_t mult; int rc; int val; if (softc == NULL) return EBUSY; - val = softc->tx_coal_frames; + hw_coal = &softc->tx_coal; + mult = hw_coal->bufs_per_record; + if (!mult) { + device_printf(softc->dev, + "%s: bufs_per_record is zero which is invalid\n", __func__); + return EINVAL; + } + + val = hw_coal->coal_bufs / mult; + rc = sysctl_handle_int(oidp, &val, 0, req); if (rc || !req->newptr) return rc; - softc->tx_coal_frames = val; + rc = bnxt_sysctl_check_u16_range(softc, __func__, val, mult); + if (rc) + return rc; + + hw_coal->coal_bufs = val * mult; rc = bnxt_hwrm_set_coal(softc); return rc; @@ -1727,18 +1862,25 @@ bnxt_set_coal_tx_frames(SYSCTL_HANDLER_ARGS) { static int bnxt_set_coal_tx_usecs_irq(SYSCTL_HANDLER_ARGS) { struct bnxt_softc *softc = arg1; + struct bnxt_coal *hw_coal; int rc; int val; if (softc == NULL) return EBUSY; - val = softc->tx_coal_usecs_irq; + hw_coal = &softc->tx_coal; + val = hw_coal->coal_ticks_irq; + rc = sysctl_handle_int(oidp, &val, 0, req); if (rc || !req->newptr) return rc; - softc->tx_coal_usecs_irq = val; + rc = bnxt_sysctl_check_u16_range(softc, __func__, val, 0); + if (rc) + return rc; + + hw_coal->coal_ticks_irq = val; rc = bnxt_hwrm_set_coal(softc); return rc; @@ -1747,23 +1889,62 @@ bnxt_set_coal_tx_usecs_irq(SYSCTL_HANDLER_ARGS) { static int bnxt_set_coal_tx_frames_irq(SYSCTL_HANDLER_ARGS) { struct bnxt_softc *softc = arg1; + struct bnxt_coal *hw_coal; + uint16_t mult; int rc; int val; if (softc == NULL) return EBUSY; - val = softc->tx_coal_frames_irq; + hw_coal = &softc->tx_coal; + mult = hw_coal->bufs_per_record; + if (!mult) { + device_printf(softc->dev, + "%s: bufs_per_record is zero which is invalid\n", __func__); + return EINVAL; + } + + val = hw_coal->coal_bufs_irq / mult; + rc = sysctl_handle_int(oidp, &val, 0, req); if (rc || !req->newptr) return rc; - softc->tx_coal_frames_irq = val; + rc = bnxt_sysctl_check_u16_range(softc, __func__, val, mult); + if (rc) + return rc; + + hw_coal->coal_bufs_irq = val * mult; rc = bnxt_hwrm_set_coal(softc); return rc; } +static int +bnxt_set_stats_coal_ticks(SYSCTL_HANDLER_ARGS) { + struct bnxt_softc *softc = arg1; + int rc; + int val; + + if (softc == NULL) + return EBUSY; + + val = softc->stats_coal_ticks; + + rc = sysctl_handle_int(oidp, &val, 0, req); + if (rc || !req->newptr) + return rc; + + softc->stats_coal_ticks = val; + /* + * Stats DMA period is set once at HWRM_STAT_CTX_ALLOC time; there's no + * HWRM_STAT_CTX_CFG to reprogram it, so nothing to apply this to yet. + */ + + return 0; +} + static int bnxt_set_cagr_tick_res(SYSCTL_HANDLER_ARGS) { struct bnxt_softc *softc = arg1; @@ -1788,6 +1969,34 @@ bnxt_set_cagr_tick_res(SYSCTL_HANDLER_ARGS) { return rc; } +static int +bnxt_set_rx_coal_budget(SYSCTL_HANDLER_ARGS) { + struct bnxt_softc *softc = arg1; + struct bnxt_coal *hw_coal; + int rc; + int val; + + if (softc == NULL) + return EBUSY; + + hw_coal = &softc->rx_coal; + + val = hw_coal->budget; + + rc = sysctl_handle_int(oidp, &val, 0, req); + if (rc || !req->newptr) + return rc; + + rc = bnxt_sysctl_check_u16_range(softc, __func__, val, 0); + if (rc) + return rc; + + hw_coal->budget = val; + rc = bnxt_hwrm_set_coal(softc); + + return rc; +} + static int bnxt_set_tx_host_coal_bds(SYSCTL_HANDLER_ARGS) { @@ -1914,6 +2123,10 @@ bnxt_create_config_sysctls_pre(struct bnxt_softc *softc) CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, softc, 0, bnxt_set_coal_rx_frames_irq, "I", "interrupt coalescing Rx Frames IRQ"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_coalesce_mode", + CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, softc, 0, + bnxt_set_rx_coalesce_mode, "I", + "set rx_coalesce_mode 0/1"); SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "intr_coal_tx_usecs", CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, softc, 0, bnxt_set_coal_tx_usecs, "I", "interrupt coalescing Tx Usces"); @@ -1928,9 +2141,17 @@ bnxt_create_config_sysctls_pre(struct bnxt_softc *softc) CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, softc, 0, bnxt_set_coal_tx_frames_irq, "I", "interrupt coalescing Tx Frames IRQ"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "intr_stats_coal_ticks", + CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, softc, 0, + bnxt_set_stats_coal_ticks, "I", + "interrupt coalescing stats coal ticks"); SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cagr_tick_res", CTLTYPE_INT | CTLFLAG_RDTUN | CTLFLAG_MPSAFE, softc, 0, bnxt_set_cagr_tick_res, "I", "CAGR tick resolution"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "intr_rx_coal_budget", + CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, softc, 0, + bnxt_set_rx_coal_budget, "I", + "Rx interrupt coalescing budget"); /* * Default coal_bds to half the Tx ring depth, clamped between diff --git a/sys/dev/bnxt/bnxt_en/if_bnxt.c b/sys/dev/bnxt/bnxt_en/if_bnxt.c index 0757985fa49f..e9c034065a6c 100644 --- a/sys/dev/bnxt/bnxt_en/if_bnxt.c +++ b/sys/dev/bnxt/bnxt_en/if_bnxt.c @@ -221,6 +221,7 @@ static int bnxt_detach(if_ctx_t ctx); /* Device configuration */ static void bnxt_init(if_ctx_t ctx); static int bnxt_init_hw(if_ctx_t ctx); +static void bnxt_init_dflt_coal(struct bnxt_softc *softc); static void bnxt_stop(if_ctx_t ctx); static void bnxt_if_led_func(if_ctx_t ctx, int onoff); static bool bnxt_if_led_supported(if_ctx_t ctx); @@ -2989,6 +2990,9 @@ bnxt_attach_pre(if_ctx_t ctx) scctx->isc_min_frame_size = BNXT_MIN_FRAME_SIZE; scctx->isc_txrx = &bnxt_txrx; + bnxt_hwrm_coal_params_qcaps(softc); + bnxt_init_dflt_coal(softc); + if (scctx->isc_nrxd[0] < ((scctx->isc_nrxd[1] * 4) + scctx->isc_nrxd[2])) device_printf(softc->dev, @@ -3627,6 +3631,49 @@ skip_aux_init: return; } +static void +bnxt_init_dflt_coal(struct bnxt_softc *softc) +{ + struct bnxt_coal_cap *coal_cap = &softc->coal_cap; + struct bnxt_coal *coal; + uint16_t flags = 0; + + if (coal_cap->cmpl_params & + HWRM_RING_AGGINT_QCAPS_OUTPUT_CMPL_PARAMS_TIMER_RESET) + flags |= HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS_INPUT_FLAGS_TIMER_RESET; + + coal = &softc->rx_coal; + if (coal_cap->cmpl_params & + HWRM_RING_AGGINT_QCAPS_OUTPUT_CMPL_PARAMS_TMR_RESET_ON_ALLOC) + coal->timer_reset_during_ring_alloc = 1; + + /* + * Tick values in microseconds. + * 1 coal_buf x bufs_per_record = 1 completion record. + */ + coal->coal_ticks = 6; + coal->coal_bufs = 12; + coal->coal_ticks_irq = 1; + if (BNXT_CHIP_P7(softc)) + coal->coal_bufs_irq = 4; + else + coal->coal_bufs_irq = 2; + coal->idle_thresh = 50; + coal->bufs_per_record = 2; + coal->budget = 64; + coal->flags = flags; + + coal = &softc->tx_coal; + coal->coal_ticks = 28; + coal->coal_bufs = 30; + coal->coal_ticks_irq = 2; + coal->coal_bufs_irq = 2; + coal->bufs_per_record = 1; + coal->flags = flags; + + softc->stats_coal_ticks = BNXT_MIN_STATS_COAL_TICKS; +} + /* Device configuration */ static void bnxt_init(if_ctx_t ctx) @@ -3850,6 +3897,8 @@ skip_def_cp_ring: bnxt_get_port_module_status(softc); bnxt_media_status(softc->ctx, &ifmr); bnxt_hwrm_cfa_l2_set_rx_mask(softc, &softc->vnic_info); + set_bit(BNXT_STATE_UP, &softc->state); + bnxt_hwrm_set_coal(softc); return (0); fail: @@ -3869,6 +3918,7 @@ bnxt_stop(if_ctx_t ctx) bnxt_ptp_stop_calibration(softc->ptp_cfg); softc->rx_ts_enabled = false; } + clear_bit(BNXT_STATE_UP, &softc->state); softc->is_dev_init = false; bnxt_do_disable_intr(&softc->def_cp_ring); bnxt_func_reset(softc);