Index: sys/dev/bnxt/bnxt_en/bnxt.h =================================================================== --- sys/dev/bnxt/bnxt_en/bnxt.h +++ sys/dev/bnxt/bnxt_en/bnxt.h @@ -638,6 +638,52 @@ #define Q_TYPE_RX 2 }; +#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 + +#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; + uint8_t budget; + uint16_t flags; +}; + struct bnxt_full_tpa_start { struct rx_tpa_start_cmpl low; struct rx_tpa_start_cmpl_hi high; @@ -1194,10 +1240,10 @@ bool is_dev_init; 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; + struct bnxt_coal_cap coal_cap; + struct bnxt_coal rx_coal; + + uint32_t stats_coal_ticks; uint16_t tx_coal_usecs; uint16_t tx_coal_usecs_irq; uint16_t tx_coal_frames; @@ -1208,6 +1254,7 @@ #define BNXT_MIN_STATS_COAL_TICKS 250000 #define BNXT_MAX_STATS_COAL_TICKS 1000000 + bool set_coal_pend; uint64_t fw_cap; #define BNXT_FW_CAP_SHORT_CMD BIT_ULL(0) #define BNXT_FW_CAP_LLDP_AGENT BIT_ULL(1) @@ -1295,6 +1342,7 @@ #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; Index: sys/dev/bnxt/bnxt_en/bnxt_hwrm.h =================================================================== --- sys/dev/bnxt/bnxt_en/bnxt_hwrm.h +++ sys/dev/bnxt/bnxt_en/bnxt_hwrm.h @@ -142,4 +142,5 @@ int hwrm_send_message(struct bnxt_softc *, void *, uint32_t); void bnxt_hwrm_cmd_hdr_init(struct bnxt_softc *, void *, uint16_t); int bnxt_hwrm_reserve_vf_rings(struct bnxt_softc *softc); +void bnxt_hwrm_coal_params_qcaps(struct bnxt_softc *softc); #endif Index: sys/dev/bnxt/bnxt_en/bnxt_hwrm.c =================================================================== --- sys/dev/bnxt/bnxt_en/bnxt_hwrm.c +++ sys/dev/bnxt/bnxt_en/bnxt_hwrm.c @@ -3124,81 +3124,178 @@ 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); + + rc = hwrm_send_message(softc, &req, sizeof(req)); + + if (!rc) { + coal_cap->cmpl_params = le32_to_cpu(resp->cmpl_params); + coal_cap->nq_params = le32_to_cpu(resp->nq_params); + coal_cap->num_cmpl_dma_aggr_max = + le16_to_cpu(resp->num_cmpl_dma_aggr_max); + coal_cap->num_cmpl_dma_aggr_during_int_max = + le16_to_cpu(resp->num_cmpl_dma_aggr_during_int_max); + coal_cap->cmpl_aggr_dma_tmr_max = + le16_to_cpu(resp->cmpl_aggr_dma_tmr_max); + coal_cap->cmpl_aggr_dma_tmr_during_int_max = + le16_to_cpu(resp->cmpl_aggr_dma_tmr_during_int_max); + coal_cap->int_lat_tmr_min_max = + le16_to_cpu(resp->int_lat_tmr_min_max); + coal_cap->int_lat_tmr_max_max = + le16_to_cpu(resp->int_lat_tmr_max_max); + coal_cap->num_cmpl_aggr_int_max = + le16_to_cpu(resp->num_cmpl_aggr_int_max); + coal_cap->timer_units = le16_to_cpu(resp->timer_units); + } } -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); +#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) - flags = HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS_INPUT_FLAGS_TIMER_RESET; +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; - /* 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; + 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); - bnxt_hwrm_set_coal_params(softc, max_buf_irq << 16 | max_buf, - buf_tmr_irq << 16 | buf_tmr, flags, &req_rx); + val = clamp_t(uint16_t, hw_coal->coal_bufs, 1, max); + req->num_cmpl_aggr_int = cpu_to_le16(val); + + val = min_t(uint16_t, val, coal_cap->num_cmpl_dma_aggr_max); + req->num_cmpl_dma_aggr = cpu_to_le16(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 = cpu_to_le16(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 = cpu_to_le16(tmr); + + /* min timer set to 1/2 of 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 = cpu_to_le16(val); + req->enables |= cpu_to_le16(BNXT_COAL_CMPL_MIN_TMR_ENABLE); + } - /* 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); + val = clamp_t(uint16_t, tmr / 4, 1, coal_cap->cmpl_aggr_dma_tmr_max); + req->cmpl_aggr_dma_tmr = cpu_to_le16(val); + + if (cmpl_params & + HWRM_RING_AGGINT_QCAPS_OUTPUT_CMPL_PARAMS_NUM_CMPL_DMA_AGGR_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 = cpu_to_le16(val); + req->enables |= + cpu_to_le16(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; + + req->flags = cpu_to_le16(flags); + req->enables |= cpu_to_le16(BNXT_COAL_CMPL_ENABLES); +} + +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; + uint32_t nq_params = coal_cap->nq_params; + uint16_t tmr; + + if (!(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 = cpu_to_le16(ring_id); + req.flags = + cpu_to_le16(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 = cpu_to_le16(tmr); + req.enables |= cpu_to_le16(BNXT_COAL_CMPL_MIN_TMR_ENABLE); + + return hwrm_send_message(softc, &req, sizeof(req)); +} + +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; + + if (!test_bit(BNXT_STATE_UP, &softc->state)) { + if (test_bit(BNXT_STATE_OPEN, &softc->state)) + softc->set_coal_pend = true; + return rc; + } + + bnxt_hwrm_cmd_hdr_init(softc, &req_rx, + HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS); + + bnxt_hwrm_set_coal_params(softc, &softc->rx_coal, &req_rx); for (i = 0; i < softc->nrxqsets; i++) { req = &req_rx; req->ring_id = htole16(softc->grp_info[i].cp_ring_id); - rc = hwrm_send_message(softc, req, sizeof(*req)); - if (rc) - break; - } - return rc; + rc = hwrm_send_message(softc, req, sizeof(*req)); + if (rc) + break; + bnxt_hwrm_set_coal_nq(softc, + softc->nq_rings[i].ring.phys_id, &softc->rx_coal); + } + return rc; } void bnxt_hwrm_ring_info_get(struct bnxt_softc *softc, uint8_t ring_type, Index: sys/dev/bnxt/bnxt_en/bnxt_sysctl.c =================================================================== --- sys/dev/bnxt/bnxt_en/bnxt_sysctl.c +++ sys/dev/bnxt/bnxt_en/bnxt_sysctl.c @@ -1404,12 +1404,12 @@ if (softc == NULL) return EBUSY; - val = softc->rx_coal_usecs; + val = softc->rx_coal.coal_ticks; rc = sysctl_handle_int(oidp, &val, 0, req); if (rc || !req->newptr) return rc; - softc->rx_coal_usecs = val; + softc->rx_coal.coal_ticks = val; rc = bnxt_hwrm_set_coal(softc); return rc; @@ -1424,12 +1424,12 @@ if (softc == NULL) return EBUSY; - val = softc->rx_coal_frames; + val = softc->rx_coal.coal_bufs; rc = sysctl_handle_int(oidp, &val, 0, req); if (rc || !req->newptr) return rc; - softc->rx_coal_frames = val; + softc->rx_coal.coal_bufs = val; rc = bnxt_hwrm_set_coal(softc); return rc; @@ -1444,12 +1444,12 @@ if (softc == NULL) return EBUSY; - val = softc->rx_coal_usecs_irq; + val = softc->rx_coal.coal_ticks_irq; rc = sysctl_handle_int(oidp, &val, 0, req); if (rc || !req->newptr) return rc; - softc->rx_coal_usecs_irq = val; + softc->rx_coal.coal_ticks_irq = val; rc = bnxt_hwrm_set_coal(softc); return rc; @@ -1464,12 +1464,12 @@ if (softc == NULL) return EBUSY; - val = softc->rx_coal_frames_irq; + val = softc->rx_coal.coal_bufs_irq; rc = sysctl_handle_int(oidp, &val, 0, req); if (rc || !req->newptr) return rc; - softc->rx_coal_frames_irq = val; + softc->rx_coal.coal_bufs_irq = val; rc = bnxt_hwrm_set_coal(softc); return rc; Index: sys/dev/bnxt/bnxt_en/if_bnxt.c =================================================================== --- sys/dev/bnxt/bnxt_en/if_bnxt.c +++ sys/dev/bnxt/bnxt_en/if_bnxt.c @@ -3317,6 +3317,7 @@ bnxt_get_port_module_status(softc, false); bnxt_media_status(softc->ctx, &ifmr); bnxt_hwrm_cfa_l2_set_rx_mask(softc, &softc->vnic_info); + bnxt_hwrm_coal_params_qcaps(softc); return; fail: