Index: sys/dev/bnxt/bnxt.h =================================================================== --- sys/dev/bnxt/bnxt.h +++ sys/dev/bnxt/bnxt.h @@ -214,6 +214,18 @@ /* Chip info */ #define BNXT_TSO_SIZE UINT16_MAX +#define min_t(type, x, y) ({ \ + type __min1 = (x); \ + type __min2 = (y); \ + __min1 < __min2 ? __min1 : __min2; }) + +#define max_t(type, x, y) ({ \ + type __max1 = (x); \ + type __max2 = (y); \ + __max1 > __max2 ? __max1 : __max2; }) + +#define clamp_t(type, _x, min, max) min_t(type, max_t(type, _x, min), max) + /* NVRAM access */ enum bnxt_nvm_directory_type { BNX_DIR_TYPE_UNUSED = 0, @@ -569,6 +581,20 @@ struct bnxt_nvram_info *nvm_info; bool wol; 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; + +#define BNXT_USEC_TO_COAL_TIMER(x) ((x) * 25 / 2) +#define BNXT_DEF_STATS_COAL_TICKS 1000000 +#define BNXT_MIN_STATS_COAL_TICKS 250000 +#define BNXT_MAX_STATS_COAL_TICKS 1000000 + }; struct bnxt_filter_info { Index: sys/dev/bnxt/bnxt_hwrm.h =================================================================== --- sys/dev/bnxt/bnxt_hwrm.h +++ sys/dev/bnxt/bnxt_hwrm.h @@ -101,5 +101,6 @@ 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); #endif Index: sys/dev/bnxt/bnxt_hwrm.c =================================================================== --- sys/dev/bnxt/bnxt_hwrm.c +++ sys/dev/bnxt/bnxt_hwrm.c @@ -1547,3 +1547,90 @@ req.wol_filter_id = softc->wol_filter_id; 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) +{ + 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); +} + + +int bnxt_hwrm_set_coal(struct bnxt_softc *softc) +{ + 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; + + 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); + + /* 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. + */ + if (softc->rx_coal_usecs < 25) + 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); + + for (i = 0; i < softc->nrxqsets; i++) { + + + req = &req_rx; + /* + * TBD: + * Check if Tx also needs to be done + * So far, Tx processing has been done in softirq contest + * + * req = &req_tx; + */ + req->ring_id = htole16(softc->grp_info[i].cp_ring_id); + + rc = hwrm_send_message(softc, req, sizeof(*req)); + if (rc) + break; + } + return rc; +} + Index: sys/dev/bnxt/bnxt_sysctl.c =================================================================== --- sys/dev/bnxt/bnxt_sysctl.c +++ sys/dev/bnxt/bnxt_sysctl.c @@ -549,6 +549,166 @@ return rc; } +static int +bnxt_set_coal_rx_usecs(SYSCTL_HANDLER_ARGS) { + struct bnxt_softc *softc = arg1; + int rc; + int val; + + if (softc == NULL) + return EBUSY; + + val = softc->rx_coal_usecs; + rc = sysctl_handle_int(oidp, &val, 0, req); + if (rc || !req->newptr) + return rc; + + softc->rx_coal_usecs = val; + rc = bnxt_hwrm_set_coal(softc); + + return rc; +} + +static int +bnxt_set_coal_rx_frames(SYSCTL_HANDLER_ARGS) { + struct bnxt_softc *softc = arg1; + int rc; + int val; + + if (softc == NULL) + return EBUSY; + + val = softc->rx_coal_frames; + rc = sysctl_handle_int(oidp, &val, 0, req); + if (rc || !req->newptr) + return rc; + + softc->rx_coal_frames = val; + rc = bnxt_hwrm_set_coal(softc); + + return rc; +} + +static int +bnxt_set_coal_rx_usecs_irq(SYSCTL_HANDLER_ARGS) { + struct bnxt_softc *softc = arg1; + int rc; + int val; + + if (softc == NULL) + return EBUSY; + + val = softc->rx_coal_usecs_irq; + rc = sysctl_handle_int(oidp, &val, 0, req); + if (rc || !req->newptr) + return rc; + + softc->rx_coal_usecs_irq = val; + rc = bnxt_hwrm_set_coal(softc); + + return rc; +} + +static int +bnxt_set_coal_rx_frames_irq(SYSCTL_HANDLER_ARGS) { + struct bnxt_softc *softc = arg1; + int rc; + int val; + + if (softc == NULL) + return EBUSY; + + val = softc->rx_coal_frames_irq; + rc = sysctl_handle_int(oidp, &val, 0, req); + if (rc || !req->newptr) + return rc; + + softc->rx_coal_frames_irq = val; + rc = bnxt_hwrm_set_coal(softc); + + return rc; +} + +static int +bnxt_set_coal_tx_usecs(SYSCTL_HANDLER_ARGS) { + struct bnxt_softc *softc = arg1; + int rc; + int val; + + if (softc == NULL) + return EBUSY; + + val = softc->tx_coal_usecs; + rc = sysctl_handle_int(oidp, &val, 0, req); + if (rc || !req->newptr) + return rc; + + softc->tx_coal_usecs = val; + rc = bnxt_hwrm_set_coal(softc); + + return rc; +} + +static int +bnxt_set_coal_tx_frames(SYSCTL_HANDLER_ARGS) { + struct bnxt_softc *softc = arg1; + int rc; + int val; + + if (softc == NULL) + return EBUSY; + + val = softc->tx_coal_frames; + rc = sysctl_handle_int(oidp, &val, 0, req); + if (rc || !req->newptr) + return rc; + + softc->tx_coal_frames = val; + rc = bnxt_hwrm_set_coal(softc); + + return rc; +} + +static int +bnxt_set_coal_tx_usecs_irq(SYSCTL_HANDLER_ARGS) { + struct bnxt_softc *softc = arg1; + int rc; + int val; + + if (softc == NULL) + return EBUSY; + + val = softc->tx_coal_usecs_irq; + rc = sysctl_handle_int(oidp, &val, 0, req); + if (rc || !req->newptr) + return rc; + + softc->tx_coal_usecs_irq = val; + rc = bnxt_hwrm_set_coal(softc); + + return rc; +} + +static int +bnxt_set_coal_tx_frames_irq(SYSCTL_HANDLER_ARGS) { + struct bnxt_softc *softc = arg1; + int rc; + int val; + + if (softc == NULL) + return EBUSY; + + val = softc->tx_coal_frames_irq; + rc = sysctl_handle_int(oidp, &val, 0, req); + if (rc || !req->newptr) + return rc; + + softc->tx_coal_frames_irq = val; + rc = bnxt_hwrm_set_coal(softc); + + return rc; +} + int bnxt_create_config_sysctls_pre(struct bnxt_softc *softc) { @@ -572,6 +732,31 @@ SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "if_name", CTLFLAG_RD, iflib_get_ifp(softc->ctx)->if_xname, 0, "interface name"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "intr_coal_rx_usecs", + CTLTYPE_INT|CTLFLAG_RWTUN, softc, 0, bnxt_set_coal_rx_usecs, + "I", "interrupt coalescing Rx Usecs"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "intr_coal_rx_frames", + CTLTYPE_INT|CTLFLAG_RWTUN, softc, 0, bnxt_set_coal_rx_frames, + "I", "interrupt coalescing Rx Frames"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "intr_coal_rx_usecs_irq", + CTLTYPE_INT|CTLFLAG_RWTUN, softc, 0, bnxt_set_coal_rx_usecs_irq, + "I", "interrupt coalescing Rx Usecs IRQ"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "intr_coal_rx_frames_irq", + CTLTYPE_INT|CTLFLAG_RWTUN, softc, 0, bnxt_set_coal_rx_frames_irq, + "I", "interrupt coalescing Rx Frames IRQ"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "intr_coal_tx_usecs", + CTLTYPE_INT|CTLFLAG_RWTUN, softc, 0, bnxt_set_coal_tx_usecs, + "I", "interrupt coalescing Tx Usces"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "intr_coal_tx_frames", + CTLTYPE_INT|CTLFLAG_RWTUN, softc, 0, bnxt_set_coal_tx_frames, + "I", "interrupt coalescing Tx Frames"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "intr_coal_tx_usecs_irq", + CTLTYPE_INT|CTLFLAG_RWTUN, softc, 0, bnxt_set_coal_tx_usecs_irq, + "I", "interrupt coalescing Tx Usecs IRQ"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "intr_coal_tx_frames_irq", + CTLTYPE_INT|CTLFLAG_RWTUN, softc, 0, bnxt_set_coal_tx_frames_irq, + "I", "interrupt coalescing Tx Frames IRQ"); + return 0; }