git: ac940a8b92ac - stable/14 - bnxt_en: Add PFC, ETS & App TLVs protocols support

From: Warner Losh <imp_at_FreeBSD.org>
Date: Mon, 03 Jun 2024 19:25:01 UTC
The branch stable/14 has been updated by imp:

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

commit ac940a8b92ac79df7bab71f50ae3b9aa7cff145d
Author:     Chandrakanth patil <chandrakanth.patil@broadcom.com>
AuthorDate: 2024-04-28 09:24:30 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2024-06-03 19:23:14 +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
    
    (cherry picked from commit 35b53f8c989f62286aad075ef2e97bba358144f8)
---
 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)
+{
*** 1823 LINES SKIPPED ***