18c2ecf20Sopenharmony_ci/* Broadcom NetXtreme-C/E network driver.
28c2ecf20Sopenharmony_ci *
38c2ecf20Sopenharmony_ci * Copyright (c) 2014-2016 Broadcom Corporation
48c2ecf20Sopenharmony_ci * Copyright (c) 2016-2017 Broadcom Limited
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify
78c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by
88c2ecf20Sopenharmony_ci * the Free Software Foundation.
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
128c2ecf20Sopenharmony_ci#include <linux/types.h>
138c2ecf20Sopenharmony_ci#include <linux/errno.h>
148c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h>
158c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
168c2ecf20Sopenharmony_ci#include <linux/pci.h>
178c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
188c2ecf20Sopenharmony_ci#include <rdma/ib_verbs.h>
198c2ecf20Sopenharmony_ci#include "bnxt_hsi.h"
208c2ecf20Sopenharmony_ci#include "bnxt.h"
218c2ecf20Sopenharmony_ci#include "bnxt_dcb.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#ifdef CONFIG_BNXT_DCB
248c2ecf20Sopenharmony_cistatic int bnxt_queue_to_tc(struct bnxt *bp, u8 queue_id)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	int i, j;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	for (i = 0; i < bp->max_tc; i++) {
298c2ecf20Sopenharmony_ci		if (bp->q_info[i].queue_id == queue_id) {
308c2ecf20Sopenharmony_ci			for (j = 0; j < bp->max_tc; j++) {
318c2ecf20Sopenharmony_ci				if (bp->tc_to_qidx[j] == i)
328c2ecf20Sopenharmony_ci					return j;
338c2ecf20Sopenharmony_ci			}
348c2ecf20Sopenharmony_ci		}
358c2ecf20Sopenharmony_ci	}
368c2ecf20Sopenharmony_ci	return -EINVAL;
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic int bnxt_hwrm_queue_pri2cos_cfg(struct bnxt *bp, struct ieee_ets *ets)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	struct hwrm_queue_pri2cos_cfg_input req = {0};
428c2ecf20Sopenharmony_ci	u8 *pri2cos;
438c2ecf20Sopenharmony_ci	int i;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_PRI2COS_CFG, -1, -1);
468c2ecf20Sopenharmony_ci	req.flags = cpu_to_le32(QUEUE_PRI2COS_CFG_REQ_FLAGS_PATH_BIDIR |
478c2ecf20Sopenharmony_ci				QUEUE_PRI2COS_CFG_REQ_FLAGS_IVLAN);
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	pri2cos = &req.pri0_cos_queue_id;
508c2ecf20Sopenharmony_ci	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
518c2ecf20Sopenharmony_ci		u8 qidx;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci		req.enables |= cpu_to_le32(
548c2ecf20Sopenharmony_ci			QUEUE_PRI2COS_CFG_REQ_ENABLES_PRI0_COS_QUEUE_ID << i);
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci		qidx = bp->tc_to_qidx[ets->prio_tc[i]];
578c2ecf20Sopenharmony_ci		pri2cos[i] = bp->q_info[qidx].queue_id;
588c2ecf20Sopenharmony_ci	}
598c2ecf20Sopenharmony_ci	return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic int bnxt_hwrm_queue_pri2cos_qcfg(struct bnxt *bp, struct ieee_ets *ets)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	struct hwrm_queue_pri2cos_qcfg_output *resp = bp->hwrm_cmd_resp_addr;
658c2ecf20Sopenharmony_ci	struct hwrm_queue_pri2cos_qcfg_input req = {0};
668c2ecf20Sopenharmony_ci	int rc = 0;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_PRI2COS_QCFG, -1, -1);
698c2ecf20Sopenharmony_ci	req.flags = cpu_to_le32(QUEUE_PRI2COS_QCFG_REQ_FLAGS_IVLAN);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	mutex_lock(&bp->hwrm_cmd_lock);
728c2ecf20Sopenharmony_ci	rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
738c2ecf20Sopenharmony_ci	if (!rc) {
748c2ecf20Sopenharmony_ci		u8 *pri2cos = &resp->pri0_cos_queue_id;
758c2ecf20Sopenharmony_ci		int i;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci		for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
788c2ecf20Sopenharmony_ci			u8 queue_id = pri2cos[i];
798c2ecf20Sopenharmony_ci			int tc;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci			tc = bnxt_queue_to_tc(bp, queue_id);
828c2ecf20Sopenharmony_ci			if (tc >= 0)
838c2ecf20Sopenharmony_ci				ets->prio_tc[i] = tc;
848c2ecf20Sopenharmony_ci		}
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci	mutex_unlock(&bp->hwrm_cmd_lock);
878c2ecf20Sopenharmony_ci	return rc;
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic int bnxt_hwrm_queue_cos2bw_cfg(struct bnxt *bp, struct ieee_ets *ets,
918c2ecf20Sopenharmony_ci				      u8 max_tc)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	struct hwrm_queue_cos2bw_cfg_input req = {0};
948c2ecf20Sopenharmony_ci	struct bnxt_cos2bw_cfg cos2bw;
958c2ecf20Sopenharmony_ci	void *data;
968c2ecf20Sopenharmony_ci	int i;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_COS2BW_CFG, -1, -1);
998c2ecf20Sopenharmony_ci	for (i = 0; i < max_tc; i++) {
1008c2ecf20Sopenharmony_ci		u8 qidx = bp->tc_to_qidx[i];
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci		req.enables |= cpu_to_le32(
1038c2ecf20Sopenharmony_ci			QUEUE_COS2BW_CFG_REQ_ENABLES_COS_QUEUE_ID0_VALID <<
1048c2ecf20Sopenharmony_ci			qidx);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci		memset(&cos2bw, 0, sizeof(cos2bw));
1078c2ecf20Sopenharmony_ci		cos2bw.queue_id = bp->q_info[qidx].queue_id;
1088c2ecf20Sopenharmony_ci		if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_STRICT) {
1098c2ecf20Sopenharmony_ci			cos2bw.tsa =
1108c2ecf20Sopenharmony_ci				QUEUE_COS2BW_QCFG_RESP_QUEUE_ID0_TSA_ASSIGN_SP;
1118c2ecf20Sopenharmony_ci			cos2bw.pri_lvl = i;
1128c2ecf20Sopenharmony_ci		} else {
1138c2ecf20Sopenharmony_ci			cos2bw.tsa =
1148c2ecf20Sopenharmony_ci				QUEUE_COS2BW_QCFG_RESP_QUEUE_ID0_TSA_ASSIGN_ETS;
1158c2ecf20Sopenharmony_ci			cos2bw.bw_weight = ets->tc_tx_bw[i];
1168c2ecf20Sopenharmony_ci			/* older firmware requires min_bw to be set to the
1178c2ecf20Sopenharmony_ci			 * same weight value in percent.
1188c2ecf20Sopenharmony_ci			 */
1198c2ecf20Sopenharmony_ci			cos2bw.min_bw =
1208c2ecf20Sopenharmony_ci				cpu_to_le32((ets->tc_tx_bw[i] * 100) |
1218c2ecf20Sopenharmony_ci					    BW_VALUE_UNIT_PERCENT1_100);
1228c2ecf20Sopenharmony_ci		}
1238c2ecf20Sopenharmony_ci		data = &req.unused_0 + qidx * (sizeof(cos2bw) - 4);
1248c2ecf20Sopenharmony_ci		memcpy(data, &cos2bw.queue_id, sizeof(cos2bw) - 4);
1258c2ecf20Sopenharmony_ci		if (qidx == 0) {
1268c2ecf20Sopenharmony_ci			req.queue_id0 = cos2bw.queue_id;
1278c2ecf20Sopenharmony_ci			req.unused_0 = 0;
1288c2ecf20Sopenharmony_ci		}
1298c2ecf20Sopenharmony_ci	}
1308c2ecf20Sopenharmony_ci	return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic int bnxt_hwrm_queue_cos2bw_qcfg(struct bnxt *bp, struct ieee_ets *ets)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	struct hwrm_queue_cos2bw_qcfg_output *resp = bp->hwrm_cmd_resp_addr;
1368c2ecf20Sopenharmony_ci	struct hwrm_queue_cos2bw_qcfg_input req = {0};
1378c2ecf20Sopenharmony_ci	struct bnxt_cos2bw_cfg cos2bw;
1388c2ecf20Sopenharmony_ci	void *data;
1398c2ecf20Sopenharmony_ci	int rc, i;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_COS2BW_QCFG, -1, -1);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	mutex_lock(&bp->hwrm_cmd_lock);
1448c2ecf20Sopenharmony_ci	rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
1458c2ecf20Sopenharmony_ci	if (rc) {
1468c2ecf20Sopenharmony_ci		mutex_unlock(&bp->hwrm_cmd_lock);
1478c2ecf20Sopenharmony_ci		return rc;
1488c2ecf20Sopenharmony_ci	}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	data = &resp->queue_id0 + offsetof(struct bnxt_cos2bw_cfg, queue_id);
1518c2ecf20Sopenharmony_ci	for (i = 0; i < bp->max_tc; i++, data += sizeof(cos2bw) - 4) {
1528c2ecf20Sopenharmony_ci		int tc;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci		memcpy(&cos2bw.queue_id, data, sizeof(cos2bw) - 4);
1558c2ecf20Sopenharmony_ci		if (i == 0)
1568c2ecf20Sopenharmony_ci			cos2bw.queue_id = resp->queue_id0;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci		tc = bnxt_queue_to_tc(bp, cos2bw.queue_id);
1598c2ecf20Sopenharmony_ci		if (tc < 0)
1608c2ecf20Sopenharmony_ci			continue;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci		if (cos2bw.tsa ==
1638c2ecf20Sopenharmony_ci		    QUEUE_COS2BW_QCFG_RESP_QUEUE_ID0_TSA_ASSIGN_SP) {
1648c2ecf20Sopenharmony_ci			ets->tc_tsa[tc] = IEEE_8021QAZ_TSA_STRICT;
1658c2ecf20Sopenharmony_ci		} else {
1668c2ecf20Sopenharmony_ci			ets->tc_tsa[tc] = IEEE_8021QAZ_TSA_ETS;
1678c2ecf20Sopenharmony_ci			ets->tc_tx_bw[tc] = cos2bw.bw_weight;
1688c2ecf20Sopenharmony_ci		}
1698c2ecf20Sopenharmony_ci	}
1708c2ecf20Sopenharmony_ci	mutex_unlock(&bp->hwrm_cmd_lock);
1718c2ecf20Sopenharmony_ci	return 0;
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic int bnxt_queue_remap(struct bnxt *bp, unsigned int lltc_mask)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	unsigned long qmap = 0;
1778c2ecf20Sopenharmony_ci	int max = bp->max_tc;
1788c2ecf20Sopenharmony_ci	int i, j, rc;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	/* Assign lossless TCs first */
1818c2ecf20Sopenharmony_ci	for (i = 0, j = 0; i < max; ) {
1828c2ecf20Sopenharmony_ci		if (lltc_mask & (1 << i)) {
1838c2ecf20Sopenharmony_ci			if (BNXT_LLQ(bp->q_info[j].queue_profile)) {
1848c2ecf20Sopenharmony_ci				bp->tc_to_qidx[i] = j;
1858c2ecf20Sopenharmony_ci				__set_bit(j, &qmap);
1868c2ecf20Sopenharmony_ci				i++;
1878c2ecf20Sopenharmony_ci			}
1888c2ecf20Sopenharmony_ci			j++;
1898c2ecf20Sopenharmony_ci			continue;
1908c2ecf20Sopenharmony_ci		}
1918c2ecf20Sopenharmony_ci		i++;
1928c2ecf20Sopenharmony_ci	}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	for (i = 0, j = 0; i < max; i++) {
1958c2ecf20Sopenharmony_ci		if (lltc_mask & (1 << i))
1968c2ecf20Sopenharmony_ci			continue;
1978c2ecf20Sopenharmony_ci		j = find_next_zero_bit(&qmap, max, j);
1988c2ecf20Sopenharmony_ci		bp->tc_to_qidx[i] = j;
1998c2ecf20Sopenharmony_ci		__set_bit(j, &qmap);
2008c2ecf20Sopenharmony_ci		j++;
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	if (netif_running(bp->dev)) {
2048c2ecf20Sopenharmony_ci		bnxt_close_nic(bp, false, false);
2058c2ecf20Sopenharmony_ci		rc = bnxt_open_nic(bp, false, false);
2068c2ecf20Sopenharmony_ci		if (rc) {
2078c2ecf20Sopenharmony_ci			netdev_warn(bp->dev, "failed to open NIC, rc = %d\n", rc);
2088c2ecf20Sopenharmony_ci			return rc;
2098c2ecf20Sopenharmony_ci		}
2108c2ecf20Sopenharmony_ci	}
2118c2ecf20Sopenharmony_ci	if (bp->ieee_ets) {
2128c2ecf20Sopenharmony_ci		int tc = netdev_get_num_tc(bp->dev);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci		if (!tc)
2158c2ecf20Sopenharmony_ci			tc = 1;
2168c2ecf20Sopenharmony_ci		rc = bnxt_hwrm_queue_cos2bw_cfg(bp, bp->ieee_ets, tc);
2178c2ecf20Sopenharmony_ci		if (rc) {
2188c2ecf20Sopenharmony_ci			netdev_warn(bp->dev, "failed to config BW, rc = %d\n", rc);
2198c2ecf20Sopenharmony_ci			return rc;
2208c2ecf20Sopenharmony_ci		}
2218c2ecf20Sopenharmony_ci		rc = bnxt_hwrm_queue_pri2cos_cfg(bp, bp->ieee_ets);
2228c2ecf20Sopenharmony_ci		if (rc) {
2238c2ecf20Sopenharmony_ci			netdev_warn(bp->dev, "failed to config prio, rc = %d\n", rc);
2248c2ecf20Sopenharmony_ci			return rc;
2258c2ecf20Sopenharmony_ci		}
2268c2ecf20Sopenharmony_ci	}
2278c2ecf20Sopenharmony_ci	return 0;
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistatic int bnxt_hwrm_queue_pfc_cfg(struct bnxt *bp, struct ieee_pfc *pfc)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	struct hwrm_queue_pfcenable_cfg_input req = {0};
2338c2ecf20Sopenharmony_ci	struct ieee_ets *my_ets = bp->ieee_ets;
2348c2ecf20Sopenharmony_ci	unsigned int tc_mask = 0, pri_mask = 0;
2358c2ecf20Sopenharmony_ci	u8 i, pri, lltc_count = 0;
2368c2ecf20Sopenharmony_ci	bool need_q_remap = false;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	if (!my_ets)
2398c2ecf20Sopenharmony_ci		return -EINVAL;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	for (i = 0; i < bp->max_tc; i++) {
2428c2ecf20Sopenharmony_ci		for (pri = 0; pri < IEEE_8021QAZ_MAX_TCS; pri++) {
2438c2ecf20Sopenharmony_ci			if ((pfc->pfc_en & (1 << pri)) &&
2448c2ecf20Sopenharmony_ci			    (my_ets->prio_tc[pri] == i)) {
2458c2ecf20Sopenharmony_ci				pri_mask |= 1 << pri;
2468c2ecf20Sopenharmony_ci				tc_mask |= 1 << i;
2478c2ecf20Sopenharmony_ci			}
2488c2ecf20Sopenharmony_ci		}
2498c2ecf20Sopenharmony_ci		if (tc_mask & (1 << i))
2508c2ecf20Sopenharmony_ci			lltc_count++;
2518c2ecf20Sopenharmony_ci	}
2528c2ecf20Sopenharmony_ci	if (lltc_count > bp->max_lltc)
2538c2ecf20Sopenharmony_ci		return -EINVAL;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	for (i = 0; i < bp->max_tc; i++) {
2568c2ecf20Sopenharmony_ci		if (tc_mask & (1 << i)) {
2578c2ecf20Sopenharmony_ci			u8 qidx = bp->tc_to_qidx[i];
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci			if (!BNXT_LLQ(bp->q_info[qidx].queue_profile)) {
2608c2ecf20Sopenharmony_ci				need_q_remap = true;
2618c2ecf20Sopenharmony_ci				break;
2628c2ecf20Sopenharmony_ci			}
2638c2ecf20Sopenharmony_ci		}
2648c2ecf20Sopenharmony_ci	}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	if (need_q_remap)
2678c2ecf20Sopenharmony_ci		bnxt_queue_remap(bp, tc_mask);
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_PFCENABLE_CFG, -1, -1);
2708c2ecf20Sopenharmony_ci	req.flags = cpu_to_le32(pri_mask);
2718c2ecf20Sopenharmony_ci	return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cistatic int bnxt_hwrm_queue_pfc_qcfg(struct bnxt *bp, struct ieee_pfc *pfc)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	struct hwrm_queue_pfcenable_qcfg_output *resp = bp->hwrm_cmd_resp_addr;
2778c2ecf20Sopenharmony_ci	struct hwrm_queue_pfcenable_qcfg_input req = {0};
2788c2ecf20Sopenharmony_ci	u8 pri_mask;
2798c2ecf20Sopenharmony_ci	int rc;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_PFCENABLE_QCFG, -1, -1);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	mutex_lock(&bp->hwrm_cmd_lock);
2848c2ecf20Sopenharmony_ci	rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
2858c2ecf20Sopenharmony_ci	if (rc) {
2868c2ecf20Sopenharmony_ci		mutex_unlock(&bp->hwrm_cmd_lock);
2878c2ecf20Sopenharmony_ci		return rc;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	pri_mask = le32_to_cpu(resp->flags);
2918c2ecf20Sopenharmony_ci	pfc->pfc_en = pri_mask;
2928c2ecf20Sopenharmony_ci	mutex_unlock(&bp->hwrm_cmd_lock);
2938c2ecf20Sopenharmony_ci	return 0;
2948c2ecf20Sopenharmony_ci}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_cistatic int bnxt_hwrm_set_dcbx_app(struct bnxt *bp, struct dcb_app *app,
2978c2ecf20Sopenharmony_ci				  bool add)
2988c2ecf20Sopenharmony_ci{
2998c2ecf20Sopenharmony_ci	struct hwrm_fw_set_structured_data_input set = {0};
3008c2ecf20Sopenharmony_ci	struct hwrm_fw_get_structured_data_input get = {0};
3018c2ecf20Sopenharmony_ci	struct hwrm_struct_data_dcbx_app *fw_app;
3028c2ecf20Sopenharmony_ci	struct hwrm_struct_hdr *data;
3038c2ecf20Sopenharmony_ci	dma_addr_t mapping;
3048c2ecf20Sopenharmony_ci	size_t data_len;
3058c2ecf20Sopenharmony_ci	int rc, n, i;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	if (bp->hwrm_spec_code < 0x10601)
3088c2ecf20Sopenharmony_ci		return 0;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	n = IEEE_8021QAZ_MAX_TCS;
3118c2ecf20Sopenharmony_ci	data_len = sizeof(*data) + sizeof(*fw_app) * n;
3128c2ecf20Sopenharmony_ci	data = dma_alloc_coherent(&bp->pdev->dev, data_len, &mapping,
3138c2ecf20Sopenharmony_ci				  GFP_KERNEL);
3148c2ecf20Sopenharmony_ci	if (!data)
3158c2ecf20Sopenharmony_ci		return -ENOMEM;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &get, HWRM_FW_GET_STRUCTURED_DATA, -1, -1);
3188c2ecf20Sopenharmony_ci	get.dest_data_addr = cpu_to_le64(mapping);
3198c2ecf20Sopenharmony_ci	get.structure_id = cpu_to_le16(STRUCT_HDR_STRUCT_ID_DCBX_APP);
3208c2ecf20Sopenharmony_ci	get.subtype = cpu_to_le16(HWRM_STRUCT_DATA_SUBTYPE_HOST_OPERATIONAL);
3218c2ecf20Sopenharmony_ci	get.count = 0;
3228c2ecf20Sopenharmony_ci	rc = hwrm_send_message(bp, &get, sizeof(get), HWRM_CMD_TIMEOUT);
3238c2ecf20Sopenharmony_ci	if (rc)
3248c2ecf20Sopenharmony_ci		goto set_app_exit;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	fw_app = (struct hwrm_struct_data_dcbx_app *)(data + 1);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	if (data->struct_id != cpu_to_le16(STRUCT_HDR_STRUCT_ID_DCBX_APP)) {
3298c2ecf20Sopenharmony_ci		rc = -ENODEV;
3308c2ecf20Sopenharmony_ci		goto set_app_exit;
3318c2ecf20Sopenharmony_ci	}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	n = data->count;
3348c2ecf20Sopenharmony_ci	for (i = 0; i < n; i++, fw_app++) {
3358c2ecf20Sopenharmony_ci		if (fw_app->protocol_id == cpu_to_be16(app->protocol) &&
3368c2ecf20Sopenharmony_ci		    fw_app->protocol_selector == app->selector &&
3378c2ecf20Sopenharmony_ci		    fw_app->priority == app->priority) {
3388c2ecf20Sopenharmony_ci			if (add)
3398c2ecf20Sopenharmony_ci				goto set_app_exit;
3408c2ecf20Sopenharmony_ci			else
3418c2ecf20Sopenharmony_ci				break;
3428c2ecf20Sopenharmony_ci		}
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci	if (add) {
3458c2ecf20Sopenharmony_ci		/* append */
3468c2ecf20Sopenharmony_ci		n++;
3478c2ecf20Sopenharmony_ci		fw_app->protocol_id = cpu_to_be16(app->protocol);
3488c2ecf20Sopenharmony_ci		fw_app->protocol_selector = app->selector;
3498c2ecf20Sopenharmony_ci		fw_app->priority = app->priority;
3508c2ecf20Sopenharmony_ci		fw_app->valid = 1;
3518c2ecf20Sopenharmony_ci	} else {
3528c2ecf20Sopenharmony_ci		size_t len = 0;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci		/* not found, nothing to delete */
3558c2ecf20Sopenharmony_ci		if (n == i)
3568c2ecf20Sopenharmony_ci			goto set_app_exit;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci		len = (n - 1 - i) * sizeof(*fw_app);
3598c2ecf20Sopenharmony_ci		if (len)
3608c2ecf20Sopenharmony_ci			memmove(fw_app, fw_app + 1, len);
3618c2ecf20Sopenharmony_ci		n--;
3628c2ecf20Sopenharmony_ci		memset(fw_app + n, 0, sizeof(*fw_app));
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci	data->count = n;
3658c2ecf20Sopenharmony_ci	data->len = cpu_to_le16(sizeof(*fw_app) * n);
3668c2ecf20Sopenharmony_ci	data->subtype = cpu_to_le16(HWRM_STRUCT_DATA_SUBTYPE_HOST_OPERATIONAL);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &set, HWRM_FW_SET_STRUCTURED_DATA, -1, -1);
3698c2ecf20Sopenharmony_ci	set.src_data_addr = cpu_to_le64(mapping);
3708c2ecf20Sopenharmony_ci	set.data_len = cpu_to_le16(sizeof(*data) + sizeof(*fw_app) * n);
3718c2ecf20Sopenharmony_ci	set.hdr_cnt = 1;
3728c2ecf20Sopenharmony_ci	rc = hwrm_send_message(bp, &set, sizeof(set), HWRM_CMD_TIMEOUT);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ciset_app_exit:
3758c2ecf20Sopenharmony_ci	dma_free_coherent(&bp->pdev->dev, data_len, data, mapping);
3768c2ecf20Sopenharmony_ci	return rc;
3778c2ecf20Sopenharmony_ci}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_cistatic int bnxt_hwrm_queue_dscp_qcaps(struct bnxt *bp)
3808c2ecf20Sopenharmony_ci{
3818c2ecf20Sopenharmony_ci	struct hwrm_queue_dscp_qcaps_output *resp = bp->hwrm_cmd_resp_addr;
3828c2ecf20Sopenharmony_ci	struct hwrm_queue_dscp_qcaps_input req = {0};
3838c2ecf20Sopenharmony_ci	int rc;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	bp->max_dscp_value = 0;
3868c2ecf20Sopenharmony_ci	if (bp->hwrm_spec_code < 0x10800 || BNXT_VF(bp))
3878c2ecf20Sopenharmony_ci		return 0;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_DSCP_QCAPS, -1, -1);
3908c2ecf20Sopenharmony_ci	mutex_lock(&bp->hwrm_cmd_lock);
3918c2ecf20Sopenharmony_ci	rc = _hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
3928c2ecf20Sopenharmony_ci	if (!rc) {
3938c2ecf20Sopenharmony_ci		bp->max_dscp_value = (1 << resp->num_dscp_bits) - 1;
3948c2ecf20Sopenharmony_ci		if (bp->max_dscp_value < 0x3f)
3958c2ecf20Sopenharmony_ci			bp->max_dscp_value = 0;
3968c2ecf20Sopenharmony_ci	}
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	mutex_unlock(&bp->hwrm_cmd_lock);
3998c2ecf20Sopenharmony_ci	return rc;
4008c2ecf20Sopenharmony_ci}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_cistatic int bnxt_hwrm_queue_dscp2pri_cfg(struct bnxt *bp, struct dcb_app *app,
4038c2ecf20Sopenharmony_ci					bool add)
4048c2ecf20Sopenharmony_ci{
4058c2ecf20Sopenharmony_ci	struct hwrm_queue_dscp2pri_cfg_input req = {0};
4068c2ecf20Sopenharmony_ci	struct bnxt_dscp2pri_entry *dscp2pri;
4078c2ecf20Sopenharmony_ci	dma_addr_t mapping;
4088c2ecf20Sopenharmony_ci	int rc;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	if (bp->hwrm_spec_code < 0x10800)
4118c2ecf20Sopenharmony_ci		return 0;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_DSCP2PRI_CFG, -1, -1);
4148c2ecf20Sopenharmony_ci	dscp2pri = dma_alloc_coherent(&bp->pdev->dev, sizeof(*dscp2pri),
4158c2ecf20Sopenharmony_ci				      &mapping, GFP_KERNEL);
4168c2ecf20Sopenharmony_ci	if (!dscp2pri)
4178c2ecf20Sopenharmony_ci		return -ENOMEM;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	req.src_data_addr = cpu_to_le64(mapping);
4208c2ecf20Sopenharmony_ci	dscp2pri->dscp = app->protocol;
4218c2ecf20Sopenharmony_ci	if (add)
4228c2ecf20Sopenharmony_ci		dscp2pri->mask = 0x3f;
4238c2ecf20Sopenharmony_ci	else
4248c2ecf20Sopenharmony_ci		dscp2pri->mask = 0;
4258c2ecf20Sopenharmony_ci	dscp2pri->pri = app->priority;
4268c2ecf20Sopenharmony_ci	req.entry_cnt = cpu_to_le16(1);
4278c2ecf20Sopenharmony_ci	rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
4288c2ecf20Sopenharmony_ci	dma_free_coherent(&bp->pdev->dev, sizeof(*dscp2pri), dscp2pri,
4298c2ecf20Sopenharmony_ci			  mapping);
4308c2ecf20Sopenharmony_ci	return rc;
4318c2ecf20Sopenharmony_ci}
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_cistatic int bnxt_ets_validate(struct bnxt *bp, struct ieee_ets *ets, u8 *tc)
4348c2ecf20Sopenharmony_ci{
4358c2ecf20Sopenharmony_ci	int total_ets_bw = 0;
4368c2ecf20Sopenharmony_ci	u8 max_tc = 0;
4378c2ecf20Sopenharmony_ci	int i;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
4408c2ecf20Sopenharmony_ci		if (ets->prio_tc[i] > bp->max_tc) {
4418c2ecf20Sopenharmony_ci			netdev_err(bp->dev, "priority to TC mapping exceeds TC count %d\n",
4428c2ecf20Sopenharmony_ci				   ets->prio_tc[i]);
4438c2ecf20Sopenharmony_ci			return -EINVAL;
4448c2ecf20Sopenharmony_ci		}
4458c2ecf20Sopenharmony_ci		if (ets->prio_tc[i] > max_tc)
4468c2ecf20Sopenharmony_ci			max_tc = ets->prio_tc[i];
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci		if ((ets->tc_tx_bw[i] || ets->tc_tsa[i]) && i > bp->max_tc)
4498c2ecf20Sopenharmony_ci			return -EINVAL;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci		switch (ets->tc_tsa[i]) {
4528c2ecf20Sopenharmony_ci		case IEEE_8021QAZ_TSA_STRICT:
4538c2ecf20Sopenharmony_ci			break;
4548c2ecf20Sopenharmony_ci		case IEEE_8021QAZ_TSA_ETS:
4558c2ecf20Sopenharmony_ci			total_ets_bw += ets->tc_tx_bw[i];
4568c2ecf20Sopenharmony_ci			break;
4578c2ecf20Sopenharmony_ci		default:
4588c2ecf20Sopenharmony_ci			return -ENOTSUPP;
4598c2ecf20Sopenharmony_ci		}
4608c2ecf20Sopenharmony_ci	}
4618c2ecf20Sopenharmony_ci	if (total_ets_bw > 100)
4628c2ecf20Sopenharmony_ci		return -EINVAL;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	if (max_tc >= bp->max_tc)
4658c2ecf20Sopenharmony_ci		*tc = bp->max_tc;
4668c2ecf20Sopenharmony_ci	else
4678c2ecf20Sopenharmony_ci		*tc = max_tc + 1;
4688c2ecf20Sopenharmony_ci	return 0;
4698c2ecf20Sopenharmony_ci}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_cistatic int bnxt_dcbnl_ieee_getets(struct net_device *dev, struct ieee_ets *ets)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
4748c2ecf20Sopenharmony_ci	struct ieee_ets *my_ets = bp->ieee_ets;
4758c2ecf20Sopenharmony_ci	int rc;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	ets->ets_cap = bp->max_tc;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	if (!my_ets) {
4808c2ecf20Sopenharmony_ci		if (bp->dcbx_cap & DCB_CAP_DCBX_HOST)
4818c2ecf20Sopenharmony_ci			return 0;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci		my_ets = kzalloc(sizeof(*my_ets), GFP_KERNEL);
4848c2ecf20Sopenharmony_ci		if (!my_ets)
4858c2ecf20Sopenharmony_ci			return -ENOMEM;
4868c2ecf20Sopenharmony_ci		rc = bnxt_hwrm_queue_cos2bw_qcfg(bp, my_ets);
4878c2ecf20Sopenharmony_ci		if (rc)
4888c2ecf20Sopenharmony_ci			goto error;
4898c2ecf20Sopenharmony_ci		rc = bnxt_hwrm_queue_pri2cos_qcfg(bp, my_ets);
4908c2ecf20Sopenharmony_ci		if (rc)
4918c2ecf20Sopenharmony_ci			goto error;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci		/* cache result */
4948c2ecf20Sopenharmony_ci		bp->ieee_ets = my_ets;
4958c2ecf20Sopenharmony_ci	}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	ets->cbs = my_ets->cbs;
4988c2ecf20Sopenharmony_ci	memcpy(ets->tc_tx_bw, my_ets->tc_tx_bw, sizeof(ets->tc_tx_bw));
4998c2ecf20Sopenharmony_ci	memcpy(ets->tc_rx_bw, my_ets->tc_rx_bw, sizeof(ets->tc_rx_bw));
5008c2ecf20Sopenharmony_ci	memcpy(ets->tc_tsa, my_ets->tc_tsa, sizeof(ets->tc_tsa));
5018c2ecf20Sopenharmony_ci	memcpy(ets->prio_tc, my_ets->prio_tc, sizeof(ets->prio_tc));
5028c2ecf20Sopenharmony_ci	return 0;
5038c2ecf20Sopenharmony_cierror:
5048c2ecf20Sopenharmony_ci	kfree(my_ets);
5058c2ecf20Sopenharmony_ci	return rc;
5068c2ecf20Sopenharmony_ci}
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_cistatic int bnxt_dcbnl_ieee_setets(struct net_device *dev, struct ieee_ets *ets)
5098c2ecf20Sopenharmony_ci{
5108c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
5118c2ecf20Sopenharmony_ci	struct ieee_ets *my_ets = bp->ieee_ets;
5128c2ecf20Sopenharmony_ci	u8 max_tc = 0;
5138c2ecf20Sopenharmony_ci	int rc, i;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	if (!(bp->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) ||
5168c2ecf20Sopenharmony_ci	    !(bp->dcbx_cap & DCB_CAP_DCBX_HOST))
5178c2ecf20Sopenharmony_ci		return -EINVAL;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	rc = bnxt_ets_validate(bp, ets, &max_tc);
5208c2ecf20Sopenharmony_ci	if (!rc) {
5218c2ecf20Sopenharmony_ci		if (!my_ets) {
5228c2ecf20Sopenharmony_ci			my_ets = kzalloc(sizeof(*my_ets), GFP_KERNEL);
5238c2ecf20Sopenharmony_ci			if (!my_ets)
5248c2ecf20Sopenharmony_ci				return -ENOMEM;
5258c2ecf20Sopenharmony_ci			/* initialize PRI2TC mappings to invalid value */
5268c2ecf20Sopenharmony_ci			for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
5278c2ecf20Sopenharmony_ci				my_ets->prio_tc[i] = IEEE_8021QAZ_MAX_TCS;
5288c2ecf20Sopenharmony_ci			bp->ieee_ets = my_ets;
5298c2ecf20Sopenharmony_ci		}
5308c2ecf20Sopenharmony_ci		rc = bnxt_setup_mq_tc(dev, max_tc);
5318c2ecf20Sopenharmony_ci		if (rc)
5328c2ecf20Sopenharmony_ci			return rc;
5338c2ecf20Sopenharmony_ci		rc = bnxt_hwrm_queue_cos2bw_cfg(bp, ets, max_tc);
5348c2ecf20Sopenharmony_ci		if (rc)
5358c2ecf20Sopenharmony_ci			return rc;
5368c2ecf20Sopenharmony_ci		rc = bnxt_hwrm_queue_pri2cos_cfg(bp, ets);
5378c2ecf20Sopenharmony_ci		if (rc)
5388c2ecf20Sopenharmony_ci			return rc;
5398c2ecf20Sopenharmony_ci		memcpy(my_ets, ets, sizeof(*my_ets));
5408c2ecf20Sopenharmony_ci	}
5418c2ecf20Sopenharmony_ci	return rc;
5428c2ecf20Sopenharmony_ci}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_cistatic int bnxt_dcbnl_ieee_getpfc(struct net_device *dev, struct ieee_pfc *pfc)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
5478c2ecf20Sopenharmony_ci	__le64 *stats = bp->port_stats.hw_stats;
5488c2ecf20Sopenharmony_ci	struct ieee_pfc *my_pfc = bp->ieee_pfc;
5498c2ecf20Sopenharmony_ci	long rx_off, tx_off;
5508c2ecf20Sopenharmony_ci	int i, rc;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	pfc->pfc_cap = bp->max_lltc;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	if (!my_pfc) {
5558c2ecf20Sopenharmony_ci		if (bp->dcbx_cap & DCB_CAP_DCBX_HOST)
5568c2ecf20Sopenharmony_ci			return 0;
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci		my_pfc = kzalloc(sizeof(*my_pfc), GFP_KERNEL);
5598c2ecf20Sopenharmony_ci		if (!my_pfc)
5608c2ecf20Sopenharmony_ci			return 0;
5618c2ecf20Sopenharmony_ci		bp->ieee_pfc = my_pfc;
5628c2ecf20Sopenharmony_ci		rc = bnxt_hwrm_queue_pfc_qcfg(bp, my_pfc);
5638c2ecf20Sopenharmony_ci		if (rc)
5648c2ecf20Sopenharmony_ci			return 0;
5658c2ecf20Sopenharmony_ci	}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	pfc->pfc_en = my_pfc->pfc_en;
5688c2ecf20Sopenharmony_ci	pfc->mbc = my_pfc->mbc;
5698c2ecf20Sopenharmony_ci	pfc->delay = my_pfc->delay;
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	if (!stats)
5728c2ecf20Sopenharmony_ci		return 0;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	rx_off = BNXT_RX_STATS_OFFSET(rx_pfc_ena_frames_pri0);
5758c2ecf20Sopenharmony_ci	tx_off = BNXT_TX_STATS_OFFSET(tx_pfc_ena_frames_pri0);
5768c2ecf20Sopenharmony_ci	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++, rx_off++, tx_off++) {
5778c2ecf20Sopenharmony_ci		pfc->requests[i] = le64_to_cpu(*(stats + tx_off));
5788c2ecf20Sopenharmony_ci		pfc->indications[i] = le64_to_cpu(*(stats + rx_off));
5798c2ecf20Sopenharmony_ci	}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	return 0;
5828c2ecf20Sopenharmony_ci}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_cistatic int bnxt_dcbnl_ieee_setpfc(struct net_device *dev, struct ieee_pfc *pfc)
5858c2ecf20Sopenharmony_ci{
5868c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
5878c2ecf20Sopenharmony_ci	struct ieee_pfc *my_pfc = bp->ieee_pfc;
5888c2ecf20Sopenharmony_ci	int rc;
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	if (!(bp->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) ||
5918c2ecf20Sopenharmony_ci	    !(bp->dcbx_cap & DCB_CAP_DCBX_HOST))
5928c2ecf20Sopenharmony_ci		return -EINVAL;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	if (!my_pfc) {
5958c2ecf20Sopenharmony_ci		my_pfc = kzalloc(sizeof(*my_pfc), GFP_KERNEL);
5968c2ecf20Sopenharmony_ci		if (!my_pfc)
5978c2ecf20Sopenharmony_ci			return -ENOMEM;
5988c2ecf20Sopenharmony_ci		bp->ieee_pfc = my_pfc;
5998c2ecf20Sopenharmony_ci	}
6008c2ecf20Sopenharmony_ci	rc = bnxt_hwrm_queue_pfc_cfg(bp, pfc);
6018c2ecf20Sopenharmony_ci	if (!rc)
6028c2ecf20Sopenharmony_ci		memcpy(my_pfc, pfc, sizeof(*my_pfc));
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	return rc;
6058c2ecf20Sopenharmony_ci}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_cistatic int bnxt_dcbnl_ieee_dscp_app_prep(struct bnxt *bp, struct dcb_app *app)
6088c2ecf20Sopenharmony_ci{
6098c2ecf20Sopenharmony_ci	if (app->selector == IEEE_8021QAZ_APP_SEL_DSCP) {
6108c2ecf20Sopenharmony_ci		if (!bp->max_dscp_value)
6118c2ecf20Sopenharmony_ci			return -ENOTSUPP;
6128c2ecf20Sopenharmony_ci		if (app->protocol > bp->max_dscp_value)
6138c2ecf20Sopenharmony_ci			return -EINVAL;
6148c2ecf20Sopenharmony_ci	}
6158c2ecf20Sopenharmony_ci	return 0;
6168c2ecf20Sopenharmony_ci}
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_cistatic int bnxt_dcbnl_ieee_setapp(struct net_device *dev, struct dcb_app *app)
6198c2ecf20Sopenharmony_ci{
6208c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
6218c2ecf20Sopenharmony_ci	int rc;
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	if (!(bp->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) ||
6248c2ecf20Sopenharmony_ci	    !(bp->dcbx_cap & DCB_CAP_DCBX_HOST))
6258c2ecf20Sopenharmony_ci		return -EINVAL;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	rc = bnxt_dcbnl_ieee_dscp_app_prep(bp, app);
6288c2ecf20Sopenharmony_ci	if (rc)
6298c2ecf20Sopenharmony_ci		return rc;
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	rc = dcb_ieee_setapp(dev, app);
6328c2ecf20Sopenharmony_ci	if (rc)
6338c2ecf20Sopenharmony_ci		return rc;
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	if ((app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
6368c2ecf20Sopenharmony_ci	     app->protocol == ETH_P_IBOE) ||
6378c2ecf20Sopenharmony_ci	    (app->selector == IEEE_8021QAZ_APP_SEL_DGRAM &&
6388c2ecf20Sopenharmony_ci	     app->protocol == ROCE_V2_UDP_DPORT))
6398c2ecf20Sopenharmony_ci		rc = bnxt_hwrm_set_dcbx_app(bp, app, true);
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	if (app->selector == IEEE_8021QAZ_APP_SEL_DSCP)
6428c2ecf20Sopenharmony_ci		rc = bnxt_hwrm_queue_dscp2pri_cfg(bp, app, true);
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	return rc;
6458c2ecf20Sopenharmony_ci}
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_cistatic int bnxt_dcbnl_ieee_delapp(struct net_device *dev, struct dcb_app *app)
6488c2ecf20Sopenharmony_ci{
6498c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
6508c2ecf20Sopenharmony_ci	int rc;
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	if (!(bp->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) ||
6538c2ecf20Sopenharmony_ci	    !(bp->dcbx_cap & DCB_CAP_DCBX_HOST))
6548c2ecf20Sopenharmony_ci		return -EINVAL;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	rc = bnxt_dcbnl_ieee_dscp_app_prep(bp, app);
6578c2ecf20Sopenharmony_ci	if (rc)
6588c2ecf20Sopenharmony_ci		return rc;
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	rc = dcb_ieee_delapp(dev, app);
6618c2ecf20Sopenharmony_ci	if (rc)
6628c2ecf20Sopenharmony_ci		return rc;
6638c2ecf20Sopenharmony_ci	if ((app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
6648c2ecf20Sopenharmony_ci	     app->protocol == ETH_P_IBOE) ||
6658c2ecf20Sopenharmony_ci	    (app->selector == IEEE_8021QAZ_APP_SEL_DGRAM &&
6668c2ecf20Sopenharmony_ci	     app->protocol == ROCE_V2_UDP_DPORT))
6678c2ecf20Sopenharmony_ci		rc = bnxt_hwrm_set_dcbx_app(bp, app, false);
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	if (app->selector == IEEE_8021QAZ_APP_SEL_DSCP)
6708c2ecf20Sopenharmony_ci		rc = bnxt_hwrm_queue_dscp2pri_cfg(bp, app, false);
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	return rc;
6738c2ecf20Sopenharmony_ci}
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_cistatic u8 bnxt_dcbnl_getdcbx(struct net_device *dev)
6768c2ecf20Sopenharmony_ci{
6778c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	return bp->dcbx_cap;
6808c2ecf20Sopenharmony_ci}
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_cistatic u8 bnxt_dcbnl_setdcbx(struct net_device *dev, u8 mode)
6838c2ecf20Sopenharmony_ci{
6848c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	/* All firmware DCBX settings are set in NVRAM */
6878c2ecf20Sopenharmony_ci	if (bp->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED)
6888c2ecf20Sopenharmony_ci		return 1;
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	if (mode & DCB_CAP_DCBX_HOST) {
6918c2ecf20Sopenharmony_ci		if (BNXT_VF(bp) || (bp->fw_cap & BNXT_FW_CAP_LLDP_AGENT))
6928c2ecf20Sopenharmony_ci			return 1;
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci		/* only support IEEE */
6958c2ecf20Sopenharmony_ci		if ((mode & DCB_CAP_DCBX_VER_CEE) ||
6968c2ecf20Sopenharmony_ci		    !(mode & DCB_CAP_DCBX_VER_IEEE))
6978c2ecf20Sopenharmony_ci			return 1;
6988c2ecf20Sopenharmony_ci	}
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	if (mode == bp->dcbx_cap)
7018c2ecf20Sopenharmony_ci		return 0;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	bp->dcbx_cap = mode;
7048c2ecf20Sopenharmony_ci	return 0;
7058c2ecf20Sopenharmony_ci}
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_cistatic const struct dcbnl_rtnl_ops dcbnl_ops = {
7088c2ecf20Sopenharmony_ci	.ieee_getets	= bnxt_dcbnl_ieee_getets,
7098c2ecf20Sopenharmony_ci	.ieee_setets	= bnxt_dcbnl_ieee_setets,
7108c2ecf20Sopenharmony_ci	.ieee_getpfc	= bnxt_dcbnl_ieee_getpfc,
7118c2ecf20Sopenharmony_ci	.ieee_setpfc	= bnxt_dcbnl_ieee_setpfc,
7128c2ecf20Sopenharmony_ci	.ieee_setapp	= bnxt_dcbnl_ieee_setapp,
7138c2ecf20Sopenharmony_ci	.ieee_delapp	= bnxt_dcbnl_ieee_delapp,
7148c2ecf20Sopenharmony_ci	.getdcbx	= bnxt_dcbnl_getdcbx,
7158c2ecf20Sopenharmony_ci	.setdcbx	= bnxt_dcbnl_setdcbx,
7168c2ecf20Sopenharmony_ci};
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_civoid bnxt_dcb_init(struct bnxt *bp)
7198c2ecf20Sopenharmony_ci{
7208c2ecf20Sopenharmony_ci	bp->dcbx_cap = 0;
7218c2ecf20Sopenharmony_ci	if (bp->hwrm_spec_code < 0x10501)
7228c2ecf20Sopenharmony_ci		return;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	bnxt_hwrm_queue_dscp_qcaps(bp);
7258c2ecf20Sopenharmony_ci	bp->dcbx_cap = DCB_CAP_DCBX_VER_IEEE;
7268c2ecf20Sopenharmony_ci	if (BNXT_PF(bp) && !(bp->fw_cap & BNXT_FW_CAP_LLDP_AGENT))
7278c2ecf20Sopenharmony_ci		bp->dcbx_cap |= DCB_CAP_DCBX_HOST;
7288c2ecf20Sopenharmony_ci	else if (bp->fw_cap & BNXT_FW_CAP_DCBX_AGENT)
7298c2ecf20Sopenharmony_ci		bp->dcbx_cap |= DCB_CAP_DCBX_LLD_MANAGED;
7308c2ecf20Sopenharmony_ci	bp->dev->dcbnl_ops = &dcbnl_ops;
7318c2ecf20Sopenharmony_ci}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_civoid bnxt_dcb_free(struct bnxt *bp)
7348c2ecf20Sopenharmony_ci{
7358c2ecf20Sopenharmony_ci	kfree(bp->ieee_pfc);
7368c2ecf20Sopenharmony_ci	kfree(bp->ieee_ets);
7378c2ecf20Sopenharmony_ci	bp->ieee_pfc = NULL;
7388c2ecf20Sopenharmony_ci	bp->ieee_ets = NULL;
7398c2ecf20Sopenharmony_ci}
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci#else
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_civoid bnxt_dcb_init(struct bnxt *bp)
7448c2ecf20Sopenharmony_ci{
7458c2ecf20Sopenharmony_ci}
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_civoid bnxt_dcb_free(struct bnxt *bp)
7488c2ecf20Sopenharmony_ci{
7498c2ecf20Sopenharmony_ci}
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci#endif
752