git: 35b53f8c989f - main - bnxt_en: Add PFC, ETS & App TLVs protocols support
Date: Tue, 28 May 2024 10:17:45 UTC
The branch main has been updated by ssaxena: URL: https://cgit.FreeBSD.org/src/commit/?id=35b53f8c989f62286aad075ef2e97bba358144f8 commit 35b53f8c989f62286aad075ef2e97bba358144f8 Author: Chandrakanth patil <chandrakanth.patil@broadcom.com> AuthorDate: 2024-04-28 09:24:30 +0000 Commit: Sumit Saxena <ssaxena@FreeBSD.org> CommitDate: 2024-05-28 10:15:29 +0000 bnxt_en: Add PFC, ETS & App TLVs protocols support Created new directory "bnxt_en" in /dev/bnxt and /modules/bnxt and moved source files and Makefile into respective directory. ETS support: - Added new files bnxt_dcb.c & bnxt_dcb.h - Added sysctl node 'dcb' and created handlers 'ets' and 'dcbx_cap' - Add logic to validate user input and configure ETS in the firmware - Updated makefile to include bnxt_dcb.c & bnxt_dcb.h PFC support: - Created sysctl handlers 'pfc' under node 'dcb' - Added logic to validate user input and configure PFC in the firmware. App TLV support: - Created 3 new sysctl handlers under node 'dcb' - set_apptlv (write only): Sets a specified TLV - del_apptlv (write only): Deletes a specified TLV - list_apptlv (read only): Lists all APP TLVs configured - Added logic to validate user input and configure APP TLVs in the firmware. Added Below DCB ops for management interface: - Set PFC, Get PFC, Set ETS, Get ETS, Add App_TLV, Del App_TLV Lst App_TLV Reviewed by: imp Approved by: imp Differential revision: https://reviews.freebsd.org/D45005 --- sys/dev/bnxt/{ => bnxt_en}/bnxt.h | 196 +++++-- sys/dev/bnxt/bnxt_en/bnxt_dcb.c | 861 ++++++++++++++++++++++++++++ sys/dev/bnxt/bnxt_en/bnxt_dcb.h | 127 ++++ sys/dev/bnxt/{ => bnxt_en}/bnxt_hwrm.c | 408 ++++++++----- sys/dev/bnxt/{ => bnxt_en}/bnxt_hwrm.h | 7 +- sys/dev/bnxt/{ => bnxt_en}/bnxt_ioctl.h | 0 sys/dev/bnxt/{ => bnxt_en}/bnxt_mgmt.c | 69 ++- sys/dev/bnxt/{ => bnxt_en}/bnxt_mgmt.h | 31 +- sys/dev/bnxt/{ => bnxt_en}/bnxt_sysctl.c | 429 +++++++++++++- sys/dev/bnxt/{ => bnxt_en}/bnxt_sysctl.h | 2 + sys/dev/bnxt/{ => bnxt_en}/bnxt_txrx.c | 0 sys/dev/bnxt/{ => bnxt_en}/convert_hsi.pl | 0 sys/dev/bnxt/{ => bnxt_en}/hsi_struct_def.h | 0 sys/dev/bnxt/{ => bnxt_en}/if_bnxt.c | 48 +- sys/modules/bnxt/{ => bnxt_en}/Makefile | 4 +- 15 files changed, 1978 insertions(+), 204 deletions(-) diff --git a/sys/dev/bnxt/bnxt.h b/sys/dev/bnxt/bnxt_en/bnxt.h similarity index 78% rename from sys/dev/bnxt/bnxt.h rename to sys/dev/bnxt/bnxt_en/bnxt.h index 0547bae91e09..e68943fd6286 100644 --- a/sys/dev/bnxt/bnxt.h +++ b/sys/dev/bnxt/bnxt_en/bnxt.h @@ -44,6 +44,7 @@ #include <net/iflib.h> #include "hsi_struct_def.h" +#include "bnxt_dcb.h" /* PCI IDs */ #define BROADCOM_VENDOR_ID 0x14E4 @@ -359,9 +360,9 @@ enum bnxt_cp_type { BNXT_SHARED }; -struct bnxt_cos_queue { - uint8_t id; - uint8_t profile; +struct bnxt_queue_info { + uint8_t queue_id; + uint8_t queue_profile; }; struct bnxt_func_info { @@ -532,6 +533,13 @@ struct bnxt_ver_info { uint8_t hwrm_min_major; uint8_t hwrm_min_minor; uint8_t hwrm_min_update; + uint64_t fw_ver_code; +#define BNXT_FW_VER_CODE(maj, min, bld, rsv) \ + ((uint64_t)(maj) << 48 | (uint64_t)(min) << 32 | (uint64_t)(bld) << 16 | (rsv)) +#define BNXT_FW_MAJ(softc) ((softc)->ver_info->fw_ver_code >> 48) +#define BNXT_FW_MIN(softc) (((softc)->ver_info->fw_ver_code >> 32) & 0xffff) +#define BNXT_FW_BLD(softc) (((softc)->ver_info->fw_ver_code >> 16) & 0xffff) +#define BNXT_FW_RSV(softc) (((softc)->ver_info->fw_ver_code) & 0xffff) struct sysctl_ctx_list ver_ctx; struct sysctl_oid *ver_oid; @@ -644,38 +652,52 @@ struct bnxt_ctx_mem_info { }; struct bnxt_hw_resc { - uint16_t min_rsscos_ctxs; - uint16_t max_rsscos_ctxs; - uint16_t min_cp_rings; - uint16_t max_cp_rings; - uint16_t resv_cp_rings; - uint16_t min_tx_rings; - uint16_t max_tx_rings; - uint16_t resv_tx_rings; - uint16_t max_tx_sch_inputs; - uint16_t min_rx_rings; - uint16_t max_rx_rings; - uint16_t resv_rx_rings; - uint16_t min_hw_ring_grps; - uint16_t max_hw_ring_grps; - uint16_t resv_hw_ring_grps; - uint16_t min_l2_ctxs; - uint16_t max_l2_ctxs; - uint16_t min_vnics; - uint16_t max_vnics; - uint16_t resv_vnics; - uint16_t min_stat_ctxs; - uint16_t max_stat_ctxs; - uint16_t resv_stat_ctxs; - uint16_t max_nqs; - uint16_t max_irqs; - uint16_t resv_irqs; + uint16_t min_rsscos_ctxs; + uint16_t max_rsscos_ctxs; + uint16_t min_cp_rings; + uint16_t max_cp_rings; + uint16_t resv_cp_rings; + uint16_t min_tx_rings; + uint16_t max_tx_rings; + uint16_t resv_tx_rings; + uint16_t max_tx_sch_inputs; + uint16_t min_rx_rings; + uint16_t max_rx_rings; + uint16_t resv_rx_rings; + uint16_t min_hw_ring_grps; + uint16_t max_hw_ring_grps; + uint16_t resv_hw_ring_grps; + uint16_t min_l2_ctxs; + uint16_t max_l2_ctxs; + uint16_t min_vnics; + uint16_t max_vnics; + uint16_t resv_vnics; + uint16_t min_stat_ctxs; + uint16_t max_stat_ctxs; + uint16_t resv_stat_ctxs; + uint16_t max_nqs; + uint16_t max_irqs; + uint16_t resv_irqs; +} + +enum bnxt_type_ets { + BNXT_TYPE_ETS_TSA = 0, + BNXT_TYPE_ETS_PRI2TC, + BNXT_TYPE_ETS_TCBW, + BNXT_TYPE_ETS_MAX }; -#define BNXT_LLQ(q_profile) \ - ((q_profile) == HWRM_QUEUE_QPORTCFG_OUTPUT_QUEUE_ID0_SERVICE_PROFILE_LOSSLESS_ROCE) -#define BNXT_CNPQ(q_profile) \ - ((q_profile) == HWRM_QUEUE_QPORTCFG_OUTPUT_QUEUE_ID0_SERVICE_PROFILE_LOSSY_ROCE_CNP) +static const char *const BNXT_ETS_TYPE_STR[] = { + "tsa", + "pri2tc", + "tcbw", +}; + +static const char *const BNXT_ETS_HELP_STR[] = { + "X is 1 (strict), 0 (ets)", + "TC values for pri 0 to 7", + "TC BW values for pri 0 to 7, Sum should be 100", +}; #define BNXT_HWRM_MAX_REQ_LEN (softc->hwrm_max_req_len) @@ -684,6 +706,10 @@ struct bnxt_softc_list { struct bnxt_softc *softc; }; +#ifndef BIT_ULL +#define BIT_ULL(nr) (1ULL << (nr)) +#endif + struct bnxt_softc { device_t dev; if_ctx_t ctx; @@ -710,6 +736,8 @@ struct bnxt_softc { #define BNXT_FLAG_CHIP_P5 0x0020 #define BNXT_FLAG_TPA 0x0040 #define BNXT_FLAG_FW_CAP_EXT_STATS 0x0080 +#define BNXT_FLAG_MULTI_HOST 0x0100 +#define BNXT_FLAG_MULTI_ROOT 0x0200 uint32_t flags; #define BNXT_STATE_LINK_CHANGE (0) #define BNXT_STATE_MAX (BNXT_STATE_LINK_CHANGE + 1) @@ -732,13 +760,23 @@ struct bnxt_softc { uint16_t hwrm_max_ext_req_len; uint32_t hwrm_spec_code; -#define BNXT_MAX_COS_QUEUE 8 +#define BNXT_MAX_QUEUE 8 uint8_t max_tc; - uint8_t max_lltc; /* lossless TCs */ - struct bnxt_cos_queue q_info[BNXT_MAX_COS_QUEUE]; - uint8_t tc_to_qidx[BNXT_MAX_COS_QUEUE]; - uint8_t q_ids[BNXT_MAX_COS_QUEUE]; - uint8_t max_q; + uint8_t max_lltc; + struct bnxt_queue_info tx_q_info[BNXT_MAX_QUEUE]; + struct bnxt_queue_info rx_q_info[BNXT_MAX_QUEUE]; + uint8_t tc_to_qidx[BNXT_MAX_QUEUE]; + uint8_t tx_q_ids[BNXT_MAX_QUEUE]; + uint8_t rx_q_ids[BNXT_MAX_QUEUE]; + uint8_t tx_max_q; + uint8_t rx_max_q; + uint8_t is_asym_q; + + struct bnxt_ieee_ets *ieee_ets; + struct bnxt_ieee_pfc *ieee_pfc; + uint8_t dcbx_cap; + uint8_t default_pri; + uint8_t max_dscp_value; uint64_t admin_ticks; struct iflib_dma_info hw_rx_port_stats; @@ -782,6 +820,8 @@ struct bnxt_softc { struct sysctl_oid *hw_lro_oid; struct sysctl_ctx_list flow_ctrl_ctx; struct sysctl_oid *flow_ctrl_oid; + struct sysctl_ctx_list dcb_ctx; + struct sysctl_oid *dcb_oid; struct bnxt_ver_info *ver_info; struct bnxt_nvram_info *nvm_info; @@ -796,13 +836,78 @@ struct bnxt_softc { uint16_t tx_coal_usecs; uint16_t tx_coal_usecs_irq; uint16_t tx_coal_frames; - uint16_t tx_coal_frames_irq; + 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 + uint64_t fw_cap; + #define BNXT_FW_CAP_SHORT_CMD BIT_ULL(0) + #define BNXT_FW_CAP_LLDP_AGENT BIT_ULL(1) + #define BNXT_FW_CAP_DCBX_AGENT BIT_ULL(2) + #define BNXT_FW_CAP_NEW_RM BIT_ULL(3) + #define BNXT_FW_CAP_IF_CHANGE BIT_ULL(4) + #define BNXT_FW_CAP_LINK_ADMIN BIT_ULL(5) + #define BNXT_FW_CAP_VF_RES_MIN_GUARANTEED BIT_ULL(6) + #define BNXT_FW_CAP_KONG_MB_CHNL BIT_ULL(7) + #define BNXT_FW_CAP_ADMIN_MTU BIT_ULL(8) + #define BNXT_FW_CAP_ADMIN_PF BIT_ULL(9) + #define BNXT_FW_CAP_OVS_64BIT_HANDLE BIT_ULL(10) + #define BNXT_FW_CAP_TRUSTED_VF BIT_ULL(11) + #define BNXT_FW_CAP_VF_VNIC_NOTIFY BIT_ULL(12) + #define BNXT_FW_CAP_ERROR_RECOVERY BIT_ULL(13) + #define BNXT_FW_CAP_PKG_VER BIT_ULL(14) + #define BNXT_FW_CAP_CFA_ADV_FLOW BIT_ULL(15) + #define BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V2 BIT_ULL(16) + #define BNXT_FW_CAP_PCIE_STATS_SUPPORTED BIT_ULL(17) + #define BNXT_FW_CAP_EXT_STATS_SUPPORTED BIT_ULL(18) + #define BNXT_FW_CAP_SECURE_MODE BIT_ULL(19) + #define BNXT_FW_CAP_ERR_RECOVER_RELOAD BIT_ULL(20) + #define BNXT_FW_CAP_HOT_RESET BIT_ULL(21) + #define BNXT_FW_CAP_CRASHDUMP BIT_ULL(23) + #define BNXT_FW_CAP_VLAN_RX_STRIP BIT_ULL(24) + #define BNXT_FW_CAP_VLAN_TX_INSERT BIT_ULL(25) + #define BNXT_FW_CAP_EXT_HW_STATS_SUPPORTED BIT_ULL(26) + #define BNXT_FW_CAP_CFA_EEM BIT_ULL(27) + #define BNXT_FW_CAP_DBG_QCAPS BIT_ULL(29) + #define BNXT_FW_CAP_RING_MONITOR BIT_ULL(30) + #define BNXT_FW_CAP_ECN_STATS BIT_ULL(31) + #define BNXT_FW_CAP_TRUFLOW BIT_ULL(32) + #define BNXT_FW_CAP_VF_CFG_FOR_PF BIT_ULL(33) + #define BNXT_FW_CAP_PTP_PPS BIT_ULL(34) + #define BNXT_FW_CAP_HOT_RESET_IF BIT_ULL(35) + #define BNXT_FW_CAP_LIVEPATCH BIT_ULL(36) + #define BNXT_FW_CAP_NPAR_1_2 BIT_ULL(37) + #define BNXT_FW_CAP_RSS_HASH_TYPE_DELTA BIT_ULL(38) + #define BNXT_FW_CAP_PTP_RTC BIT_ULL(39) + #define BNXT_FW_CAP_TRUFLOW_EN BIT_ULL(40) + #define BNXT_TRUFLOW_EN(bp) ((bp)->fw_cap & BNXT_FW_CAP_TRUFLOW_EN) + #define BNXT_FW_CAP_RX_ALL_PKT_TS BIT_ULL(41) + #define BNXT_FW_CAP_BACKING_STORE_V2 BIT_ULL(42) + #define BNXT_FW_CAP_DBR_SUPPORTED BIT_ULL(43) + #define BNXT_FW_CAP_GENERIC_STATS BIT_ULL(44) + #define BNXT_FW_CAP_DBR_PACING_SUPPORTED BIT_ULL(45) + #define BNXT_FW_CAP_PTP_PTM BIT_ULL(46) + #define BNXT_FW_CAP_CFA_NTUPLE_RX_EXT_IP_PROTO BIT_ULL(47) + #define BNXT_FW_CAP_ENABLE_RDMA_SRIOV BIT_ULL(48) + #define BNXT_FW_CAP_RSS_TCAM BIT_ULL(49) + uint32_t lpi_tmr_lo; + uint32_t lpi_tmr_hi; + /* copied from flags and flags2 in hwrm_port_phy_qcaps_output */ + uint16_t phy_flags; +#define BNXT_PHY_FL_EEE_CAP HWRM_PORT_PHY_QCAPS_OUTPUT_FLAGS_EEE_SUPPORTED +#define BNXT_PHY_FL_EXT_LPBK HWRM_PORT_PHY_QCAPS_OUTPUT_FLAGS_EXTERNAL_LPBK_SUPPORTED +#define BNXT_PHY_FL_AN_PHY_LPBK HWRM_PORT_PHY_QCAPS_OUTPUT_FLAGS_AUTONEG_LPBK_SUPPORTED +#define BNXT_PHY_FL_SHARED_PORT_CFG HWRM_PORT_PHY_QCAPS_OUTPUT_FLAGS_SHARED_PHY_CFG_SUPPORTED +#define BNXT_PHY_FL_PORT_STATS_NO_RESET HWRM_PORT_PHY_QCAPS_OUTPUT_FLAGS_CUMULATIVE_COUNTERS_ON_RESET +#define BNXT_PHY_FL_NO_PHY_LPBK HWRM_PORT_PHY_QCAPS_OUTPUT_FLAGS_LOCAL_LPBK_NOT_SUPPORTED +#define BNXT_PHY_FL_FW_MANAGED_LKDN HWRM_PORT_PHY_QCAPS_OUTPUT_FLAGS_FW_MANAGED_LINK_DOWN +#define BNXT_PHY_FL_NO_FCS HWRM_PORT_PHY_QCAPS_OUTPUT_FLAGS_NO_FCS +#define BNXT_PHY_FL_NO_PAUSE (HWRM_PORT_PHY_QCAPS_OUTPUT_FLAGS2_PAUSE_UNSUPPORTED << 8) +#define BNXT_PHY_FL_NO_PFC (HWRM_PORT_PHY_QCAPS_OUTPUT_FLAGS2_PFC_UNSUPPORTED << 8) +#define BNXT_PHY_FL_BANK_SEL (HWRM_PORT_PHY_QCAPS_OUTPUT_FLAGS2_BANK_ADDR_SUPPORTED << 8) }; struct bnxt_filter_info { @@ -843,6 +948,17 @@ struct bnxt_softc *bnxt_find_dev(uint32_t domain, uint32_t bus, uint32_t dev_fn, int bnxt_read_sfp_module_eeprom_info(struct bnxt_softc *bp, uint16_t i2c_addr, uint16_t page_number, uint8_t bank, bool bank_sel_en, uint16_t start_addr, uint16_t data_length, uint8_t *buf); +void bnxt_dcb_init(struct bnxt_softc *softc); +void bnxt_dcb_free(struct bnxt_softc *softc); +uint8_t bnxt_dcb_setdcbx(struct bnxt_softc *softc, uint8_t mode); +uint8_t bnxt_dcb_getdcbx(struct bnxt_softc *softc); +int bnxt_dcb_ieee_getets(struct bnxt_softc *softc, struct bnxt_ieee_ets *ets); +int bnxt_dcb_ieee_setets(struct bnxt_softc *softc, struct bnxt_ieee_ets *ets); uint8_t get_phy_type(struct bnxt_softc *softc); +int bnxt_dcb_ieee_getpfc(struct bnxt_softc *softc, struct bnxt_ieee_pfc *pfc); +int bnxt_dcb_ieee_setpfc(struct bnxt_softc *softc, struct bnxt_ieee_pfc *pfc); +int bnxt_dcb_ieee_setapp(struct bnxt_softc *softc, struct bnxt_dcb_app *app); +int bnxt_dcb_ieee_delapp(struct bnxt_softc *softc, struct bnxt_dcb_app *app); +int bnxt_dcb_ieee_listapp(struct bnxt_softc *softc, struct bnxt_dcb_app *app, int *num_inputs); #endif /* _BNXT_H */ diff --git a/sys/dev/bnxt/bnxt_en/bnxt_dcb.c b/sys/dev/bnxt/bnxt_en/bnxt_dcb.c new file mode 100644 index 000000000000..e1e0581d3c24 --- /dev/null +++ b/sys/dev/bnxt/bnxt_en/bnxt_dcb.c @@ -0,0 +1,861 @@ +/*- + * Broadcom NetXtreme-C/E network driver. + * + * Copyright (c) 2024 Broadcom, All Rights Reserved. + * The term Broadcom refers to Broadcom Limited and/or its subsidiaries + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/endian.h> +#include <linux/errno.h> +#include <linux/bitops.h> + +#include "bnxt.h" +#include "bnxt_hwrm.h" +#include "bnxt_dcb.h" +#include "hsi_struct_def.h" + +static int +bnxt_tx_queue_to_tc(struct bnxt_softc *softc, uint8_t queue_id) +{ + int i, j; + + for (i = 0; i < softc->max_tc; i++) { + if (softc->tx_q_info[i].queue_id == queue_id) { + for (j = 0; j < softc->max_tc; j++) { + if (softc->tc_to_qidx[j] == i) + return j; + } + } + } + return -EINVAL; +} + +static int +bnxt_hwrm_queue_pri2cos_cfg(struct bnxt_softc *softc, + struct bnxt_ieee_ets *ets, + uint32_t path_dir) +{ + struct hwrm_queue_pri2cos_cfg_input req = {0}; + struct bnxt_queue_info *q_info; + uint8_t *pri2cos; + int i; + + bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_PRI2COS_CFG); + + req.flags = htole32(path_dir | HWRM_QUEUE_PRI2COS_CFG_INPUT_FLAGS_IVLAN); + if (path_dir == HWRM_QUEUE_PRI2COS_CFG_INPUT_FLAGS_PATH_BIDIR || + path_dir == HWRM_QUEUE_PRI2COS_CFG_INPUT_FLAGS_PATH_TX) + q_info = softc->tx_q_info; + else + q_info = softc->rx_q_info; + pri2cos = &req.pri0_cos_queue_id; + for (i = 0; i < BNXT_IEEE_8021QAZ_MAX_TCS; i++) { + uint8_t qidx; + + req.enables |= htole32(HWRM_QUEUE_PRI2COS_CFG_INPUT_ENABLES_PRI0_COS_QUEUE_ID << i); + + qidx = softc->tc_to_qidx[ets->prio_tc[i]]; + pri2cos[i] = q_info[qidx].queue_id; + } + return _hwrm_send_message(softc, &req, sizeof(req)); +} + +static int +bnxt_hwrm_queue_pri2cos_qcfg(struct bnxt_softc *softc, struct bnxt_ieee_ets *ets) +{ + struct hwrm_queue_pri2cos_qcfg_output *resp = + (void *)softc->hwrm_cmd_resp.idi_vaddr; + struct hwrm_queue_pri2cos_qcfg_input req = {0}; + int rc; + + bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_PRI2COS_QCFG); + + req.flags = htole32(HWRM_QUEUE_PRI2COS_QCFG_INPUT_FLAGS_IVLAN); + rc = _hwrm_send_message(softc, &req, sizeof(req)); + if (!rc) { + uint8_t *pri2cos = &resp->pri0_cos_queue_id; + int i; + + for (i = 0; i < BNXT_IEEE_8021QAZ_MAX_TCS; i++) { + uint8_t queue_id = pri2cos[i]; + int tc; + + tc = bnxt_tx_queue_to_tc(softc, queue_id); + if (tc >= 0) + ets->prio_tc[i] = tc; + } + } + return rc; +} + +static int +bnxt_hwrm_queue_cos2bw_cfg(struct bnxt_softc *softc, struct bnxt_ieee_ets *ets, + uint8_t max_tc) +{ + struct hwrm_queue_cos2bw_cfg_input req = {0}; + struct bnxt_cos2bw_cfg cos2bw; + void *data; + int i; + + bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_COS2BW_CFG); + + for (i = 0; i < max_tc; i++) { + uint8_t qidx = softc->tc_to_qidx[i]; + + req.enables |= + htole32(HWRM_QUEUE_COS2BW_CFG_INPUT_ENABLES_COS_QUEUE_ID0_VALID << qidx); + + memset(&cos2bw, 0, sizeof(cos2bw)); + cos2bw.queue_id = softc->tx_q_info[qidx].queue_id; + if (ets->tc_tsa[i] == BNXT_IEEE_8021QAZ_TSA_STRICT) { + cos2bw.tsa = + HWRM_QUEUE_COS2BW_QCFG_OUTPUT_QUEUE_ID0_TSA_ASSIGN_SP; + cos2bw.pri_lvl = i; + } else { + cos2bw.tsa = + HWRM_QUEUE_COS2BW_QCFG_OUTPUT_QUEUE_ID0_TSA_ASSIGN_ETS; + cos2bw.bw_weight = ets->tc_tx_bw[i]; + /* older firmware requires min_bw to be set to the + * same weight value in percent. + */ + if (BNXT_FW_MAJ(softc) < 218) { + cos2bw.min_bw = + htole32((ets->tc_tx_bw[i] * 100) | + BW_VALUE_UNIT_PERCENT1_100); + } + } + data = &req.unused_0 + qidx * (sizeof(cos2bw) - 4); + memcpy(data, &cos2bw.queue_id, sizeof(cos2bw) - 4); + if (qidx == 0) { + req.queue_id0 = cos2bw.queue_id; + req.unused_0 = 0; + } + } + return _hwrm_send_message(softc, &req, sizeof(req)); +} + +static int +bnxt_hwrm_queue_cos2bw_qcfg(struct bnxt_softc *softc, struct bnxt_ieee_ets *ets) +{ + struct hwrm_queue_cos2bw_qcfg_output *resp = + (void *)softc->hwrm_cmd_resp.idi_vaddr; + struct hwrm_queue_cos2bw_qcfg_input req = {0}; + struct bnxt_cos2bw_cfg cos2bw; + uint8_t *data; + int rc, i; + + bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_COS2BW_QCFG); + + rc = _hwrm_send_message(softc, &req, sizeof(req)); + if (rc) { + return rc; + } + + data = &resp->queue_id0 + offsetof(struct bnxt_cos2bw_cfg, queue_id); + for (i = 0; i < softc->max_tc; i++, data += sizeof(cos2bw.cfg)) { + int tc; + + memcpy(&cos2bw.cfg, data, sizeof(cos2bw.cfg)); + if (i == 0) + cos2bw.queue_id = resp->queue_id0; + + tc = bnxt_tx_queue_to_tc(softc, cos2bw.queue_id); + if (tc < 0) + continue; + + if (cos2bw.tsa == HWRM_QUEUE_COS2BW_QCFG_OUTPUT_QUEUE_ID0_TSA_ASSIGN_SP) { + ets->tc_tsa[tc] = BNXT_IEEE_8021QAZ_TSA_STRICT; + } else { + ets->tc_tsa[tc] = BNXT_IEEE_8021QAZ_TSA_ETS; + ets->tc_tx_bw[tc] = cos2bw.bw_weight; + } + } + return 0; +} + +static int +bnxt_queue_remap(struct bnxt_softc *softc, unsigned int lltc_mask) +{ + unsigned long qmap = 0; + int max = softc->max_tc; + int i, j, rc; + + /* Assign lossless TCs first */ + for (i = 0, j = 0; i < max; ) { + if (lltc_mask & (1 << i)) { + if (BNXT_LLQ(softc->rx_q_info[j].queue_profile)) { + softc->tc_to_qidx[i] = j; + __set_bit(j, &qmap); + i++; + } + j++; + continue; + } + i++; + } + + for (i = 0, j = 0; i < max; i++) { + if (lltc_mask & (1 << i)) + continue; + j = find_next_zero_bit(&qmap, max, j); + softc->tc_to_qidx[i] = j; + __set_bit(j, &qmap); + j++; + } + + if (softc->ieee_ets) { + rc = bnxt_hwrm_queue_cos2bw_cfg(softc, softc->ieee_ets, softc->max_tc); + if (rc) { + device_printf(softc->dev, "failed to config BW, rc = %d\n", rc); + return rc; + } + rc = bnxt_hwrm_queue_pri2cos_cfg(softc, softc->ieee_ets, + HWRM_QUEUE_PRI2COS_CFG_INPUT_FLAGS_PATH_BIDIR); + if (rc) { + device_printf(softc->dev, "failed to config prio, rc = %d\n", rc); + return rc; + } + } + return 0; +} + +static int +bnxt_hwrm_queue_pfc_cfg(struct bnxt_softc *softc, struct bnxt_ieee_pfc *pfc) +{ + struct hwrm_queue_pfcenable_cfg_input req = {0}; + struct bnxt_ieee_ets *my_ets = softc->ieee_ets; + unsigned int tc_mask = 0, pri_mask = 0; + uint8_t i, pri, lltc_count = 0; + bool need_q_remap = false; + + if (!my_ets) + return -EINVAL; + + for (i = 0; i < softc->max_tc; i++) { + for (pri = 0; pri < BNXT_IEEE_8021QAZ_MAX_TCS; pri++) { + if ((pfc->pfc_en & (1 << pri)) && + (my_ets->prio_tc[pri] == i)) { + pri_mask |= 1 << pri; + tc_mask |= 1 << i; + } + } + if (tc_mask & (1 << i)) + lltc_count++; + } + + if (lltc_count > softc->max_lltc) { + device_printf(softc->dev, + "Hardware doesn't support %d lossless queues " + "to configure PFC (cap %d)\n", lltc_count, softc->max_lltc); + return -EINVAL; + } + + for (i = 0; i < softc->max_tc; i++) { + if (tc_mask & (1 << i)) { + uint8_t qidx = softc->tc_to_qidx[i]; + + if (!BNXT_LLQ(softc->rx_q_info[qidx].queue_profile)) { + need_q_remap = true; + break; + } + } + } + + if (need_q_remap) + bnxt_queue_remap(softc, tc_mask); + + bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_PFCENABLE_CFG); + + req.flags = htole32(pri_mask); + return _hwrm_send_message(softc, &req, sizeof(req)); +} + +static int +bnxt_hwrm_queue_pfc_qcfg(struct bnxt_softc *softc, struct bnxt_ieee_pfc *pfc) +{ + struct hwrm_queue_pfcenable_qcfg_output *resp = + (void *)softc->hwrm_cmd_resp.idi_vaddr; + struct hwrm_queue_pfcenable_qcfg_input req = {0}; + uint8_t pri_mask; + int rc; + + bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_PFCENABLE_QCFG); + + rc = _hwrm_send_message(softc, &req, sizeof(req)); + if (rc) { + return rc; + } + + pri_mask = le32toh(resp->flags); + pfc->pfc_en = pri_mask; + return 0; +} + +static int +bnxt_hwrm_get_dcbx_app(struct bnxt_softc *softc, struct bnxt_dcb_app *app, int *num_inputs) +{ + struct hwrm_fw_get_structured_data_input get = {0}; + struct hwrm_struct_data_dcbx_app *fw_app; + struct hwrm_struct_hdr *data; + struct iflib_dma_info dma_data; + size_t data_len; + int rc, n, i; + + if (softc->hwrm_spec_code < 0x10601) + return 0; + + bnxt_hwrm_cmd_hdr_init(softc, &get, HWRM_FW_GET_STRUCTURED_DATA); + + n = BNXT_IEEE_8021QAZ_MAX_TCS; + data_len = sizeof(*data) + sizeof(*fw_app) * n; + rc = iflib_dma_alloc(softc->ctx, data_len, &dma_data, + BUS_DMA_NOWAIT); + if (rc) + return ENOMEM; + get.dest_data_addr = htole64(dma_data.idi_paddr); + get.structure_id = htole16(HWRM_STRUCT_HDR_STRUCT_ID_DCBX_APP); + get.subtype = htole16(HWRM_STRUCT_DATA_SUBTYPE_HOST_OPERATIONAL); + get.count = 0; + rc = _hwrm_send_message(softc, &get, sizeof(get)); + if (rc) + goto set_app_exit; + + data = (void *)dma_data.idi_vaddr; + fw_app = (struct hwrm_struct_data_dcbx_app *)(data + 1); + + if (data->struct_id != htole16(HWRM_STRUCT_HDR_STRUCT_ID_DCBX_APP)) { + rc = -ENODEV; + goto set_app_exit; + } + + n = data->count; + for (i = 0; i < n; i++, fw_app++) { + app[*num_inputs].priority = fw_app->priority; + app[*num_inputs].protocol = htobe16(fw_app->protocol_id); + app[*num_inputs].selector = fw_app->protocol_selector; + (*num_inputs)++; + } + +set_app_exit: + iflib_dma_free(&dma_data); + return rc; +} + +static int +bnxt_hwrm_set_dcbx_app(struct bnxt_softc *softc, struct bnxt_dcb_app *app, + bool add) +{ + struct hwrm_fw_set_structured_data_input set = {0}; + struct hwrm_fw_get_structured_data_input get = {0}; + struct hwrm_struct_data_dcbx_app *fw_app; + struct hwrm_struct_hdr *data; + struct iflib_dma_info dma_data; + size_t data_len; + int rc, n, i; + + if (softc->hwrm_spec_code < 0x10601) + return 0; + + bnxt_hwrm_cmd_hdr_init(softc, &get, HWRM_FW_GET_STRUCTURED_DATA); + + n = BNXT_IEEE_8021QAZ_MAX_TCS; + data_len = sizeof(*data) + sizeof(*fw_app) * n; + rc = iflib_dma_alloc(softc->ctx, data_len, &dma_data, + BUS_DMA_NOWAIT); + if (rc) + return ENOMEM; + get.dest_data_addr = htole64(dma_data.idi_paddr); + get.structure_id = htole16(HWRM_STRUCT_HDR_STRUCT_ID_DCBX_APP); + get.subtype = htole16(HWRM_STRUCT_DATA_SUBTYPE_HOST_OPERATIONAL); + get.count = 0; + rc = _hwrm_send_message(softc, &get, sizeof(get)); + if (rc) + goto set_app_exit; + + data = (void *)dma_data.idi_vaddr; + fw_app = (struct hwrm_struct_data_dcbx_app *)(data + 1); + + if (data->struct_id != htole16(HWRM_STRUCT_HDR_STRUCT_ID_DCBX_APP)) { + rc = -ENODEV; + goto set_app_exit; + } + + n = data->count; + for (i = 0; i < n; i++, fw_app++) { + if (fw_app->protocol_id == htobe16(app->protocol) && + fw_app->protocol_selector == app->selector && + fw_app->priority == app->priority) { + if (add) + goto set_app_exit; + else + break; + } + } + if (add) { + /* append */ + n++; + fw_app->protocol_id = htobe16(app->protocol); + fw_app->protocol_selector = app->selector; + fw_app->priority = app->priority; + fw_app->valid = 1; + } else { + size_t len = 0; + + /* not found, nothing to delete */ + if (n == i) + goto set_app_exit; + + len = (n - 1 - i) * sizeof(*fw_app); + if (len) + memmove(fw_app, fw_app + 1, len); + n--; + memset(fw_app + n, 0, sizeof(*fw_app)); + } + data->count = n; + data->len = htole16(sizeof(*fw_app) * n); + data->subtype = htole16(HWRM_STRUCT_DATA_SUBTYPE_HOST_OPERATIONAL); + + bnxt_hwrm_cmd_hdr_init(softc, &set, HWRM_FW_SET_STRUCTURED_DATA); + + set.src_data_addr = htole64(dma_data.idi_paddr); + set.data_len = htole16(sizeof(*data) + sizeof(*fw_app) * n); + set.hdr_cnt = 1; + rc = _hwrm_send_message(softc, &set, sizeof(set)); + +set_app_exit: + iflib_dma_free(&dma_data); + return rc; +} + +static int +bnxt_hwrm_queue_dscp_qcaps(struct bnxt_softc *softc) +{ + struct hwrm_queue_dscp_qcaps_output *resp = + (void *)softc->hwrm_cmd_resp.idi_vaddr; + struct hwrm_queue_dscp_qcaps_input req = {0}; + int rc; + + softc->max_dscp_value = 0; + if (softc->hwrm_spec_code < 0x10800 || BNXT_VF(softc)) + return 0; + + bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_DSCP_QCAPS); + + rc = _hwrm_send_message(softc, &req, sizeof(req)); + if (!rc) { + softc->max_dscp_value = (1 << resp->num_dscp_bits) - 1; + if (softc->max_dscp_value < 0x3f) + softc->max_dscp_value = 0; + } + return rc; +} + +static int +bnxt_hwrm_queue_dscp2pri_qcfg(struct bnxt_softc *softc, struct bnxt_dcb_app *app, int *num_inputs) +{ + struct hwrm_queue_dscp2pri_qcfg_input req = {0}; + struct hwrm_queue_dscp2pri_qcfg_output *resp = + (void *)softc->hwrm_cmd_resp.idi_vaddr; + struct bnxt_dscp2pri_entry *dscp2pri; + struct iflib_dma_info dma_data; + int rc, entry_cnt; + int i; + + if (softc->hwrm_spec_code < 0x10800) + return 0; + + rc = iflib_dma_alloc(softc->ctx, sizeof(*dscp2pri) * 128, &dma_data, + BUS_DMA_NOWAIT); + if (rc) + return ENOMEM; + + dscp2pri = (void *)dma_data.idi_vaddr; + + bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_DSCP2PRI_QCFG); + + req.dest_data_addr = htole64(dma_data.idi_paddr); + req.dest_data_buffer_size = htole16(sizeof(*dscp2pri) * 64); + req.port_id = htole16(softc->pf.port_id); + rc = _hwrm_send_message(softc, &req, sizeof(req)); + + if (rc) + goto end; + + entry_cnt = le16toh(resp->entry_cnt); + for (i = 0; i < entry_cnt; i++) { + app[*num_inputs].priority = dscp2pri[i].pri; + app[*num_inputs].protocol = dscp2pri[i].dscp; + app[*num_inputs].selector = BNXT_IEEE_8021QAZ_APP_SEL_DSCP; + (*num_inputs)++; + } + +end: + iflib_dma_free(&dma_data); + return rc; +} + +static int +bnxt_hwrm_queue_dscp2pri_cfg(struct bnxt_softc *softc, struct bnxt_dcb_app *app, + bool add) +{ + struct hwrm_queue_dscp2pri_cfg_input req = {0}; + struct bnxt_dscp2pri_entry *dscp2pri; + struct iflib_dma_info dma_data; + int rc; + + if (softc->hwrm_spec_code < 0x10800) + return 0; + + rc = iflib_dma_alloc(softc->ctx, sizeof(*dscp2pri), &dma_data, + BUS_DMA_NOWAIT); + if (rc) + return ENOMEM; + + bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_DSCP2PRI_CFG); + + req.src_data_addr = htole64(dma_data.idi_paddr); + dscp2pri = (void *)dma_data.idi_vaddr; + dscp2pri->dscp = app->protocol; + if (add) + dscp2pri->mask = 0x3f; + else + dscp2pri->mask = 0; + dscp2pri->pri = app->priority; + req.entry_cnt = htole16(1); + req.port_id = htole16(softc->pf.port_id); + rc = _hwrm_send_message(softc, &req, sizeof(req)); + + iflib_dma_free(&dma_data); + return rc; +} + +static int +bnxt_ets_validate(struct bnxt_softc *softc, struct bnxt_ieee_ets *ets, uint8_t *tc) +{ + int total_ets_bw = 0; + bool zero = false; + uint8_t max_tc = 0; + int i; + + for (i = 0; i < BNXT_IEEE_8021QAZ_MAX_TCS; i++) { + if (ets->prio_tc[i] > softc->max_tc) { + device_printf(softc->dev, "priority to TC mapping exceeds TC count %d\n", + ets->prio_tc[i]); + return -EINVAL; + } + if (ets->prio_tc[i] > max_tc) + max_tc = ets->prio_tc[i]; + + if ((ets->tc_tx_bw[i] || ets->tc_tsa[i]) && i > softc->max_tc) + return -EINVAL; + + switch (ets->tc_tsa[i]) { + case BNXT_IEEE_8021QAZ_TSA_STRICT: + break; + case BNXT_IEEE_8021QAZ_TSA_ETS: + total_ets_bw += ets->tc_tx_bw[i]; + zero = zero || !ets->tc_tx_bw[i]; + break; + default: + return -ENOTSUPP; + } + } + if (total_ets_bw > 100) { + device_printf(softc->dev, "rejecting ETS config exceeding available bandwidth\n"); + return -EINVAL; + } + if (zero && total_ets_bw == 100) { + device_printf(softc->dev, "rejecting ETS config starving a TC\n"); + return -EINVAL; + } + + if (max_tc >= softc->max_tc) + *tc = softc->max_tc; + else + *tc = max_tc + 1; + return 0; +} + +int +bnxt_dcb_ieee_getets(struct bnxt_softc *softc, struct bnxt_ieee_ets *ets) +{ + struct bnxt_ieee_ets *my_ets = softc->ieee_ets; + int rc; + + if (!my_ets) + return 0; + + rc = bnxt_hwrm_queue_cos2bw_qcfg(softc, my_ets); + if (rc) + goto error; + rc = bnxt_hwrm_queue_pri2cos_qcfg(softc, my_ets); + if (rc) + goto error; + + if (ets) { + ets->cbs = my_ets->cbs; + ets->ets_cap = softc->max_tc; + memcpy(ets->tc_tx_bw, my_ets->tc_tx_bw, sizeof(ets->tc_tx_bw)); + memcpy(ets->tc_rx_bw, my_ets->tc_rx_bw, sizeof(ets->tc_rx_bw)); + memcpy(ets->tc_tsa, my_ets->tc_tsa, sizeof(ets->tc_tsa)); + memcpy(ets->prio_tc, my_ets->prio_tc, sizeof(ets->prio_tc)); + } + return 0; +error: + return rc; +} + +int +bnxt_dcb_ieee_setets(struct bnxt_softc *softc, struct bnxt_ieee_ets *ets) +{ + uint8_t max_tc = 0; + int rc; *** 1821 LINES SKIPPED ***