18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
58c2ecf20Sopenharmony_ci#include <linux/string.h>
68c2ecf20Sopenharmony_ci#include <linux/bitops.h>
78c2ecf20Sopenharmony_ci#include <net/dcbnl.h>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include "spectrum.h"
108c2ecf20Sopenharmony_ci#include "reg.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_cistatic u8 mlxsw_sp_dcbnl_getdcbx(struct net_device __always_unused *dev)
138c2ecf20Sopenharmony_ci{
148c2ecf20Sopenharmony_ci	return DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE;
158c2ecf20Sopenharmony_ci}
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cistatic u8 mlxsw_sp_dcbnl_setdcbx(struct net_device __always_unused *dev,
188c2ecf20Sopenharmony_ci				 u8 mode)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci	return (mode != (DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE)) ? 1 : 0;
218c2ecf20Sopenharmony_ci}
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic int mlxsw_sp_dcbnl_ieee_getets(struct net_device *dev,
248c2ecf20Sopenharmony_ci				      struct ieee_ets *ets)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	memcpy(ets, mlxsw_sp_port->dcb.ets, sizeof(*ets));
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	return 0;
318c2ecf20Sopenharmony_ci}
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_ets_validate(struct mlxsw_sp_port *mlxsw_sp_port,
348c2ecf20Sopenharmony_ci				      struct ieee_ets *ets)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	struct net_device *dev = mlxsw_sp_port->dev;
378c2ecf20Sopenharmony_ci	bool has_ets_tc = false;
388c2ecf20Sopenharmony_ci	int i, tx_bw_sum = 0;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
418c2ecf20Sopenharmony_ci		switch (ets->tc_tsa[i]) {
428c2ecf20Sopenharmony_ci		case IEEE_8021QAZ_TSA_STRICT:
438c2ecf20Sopenharmony_ci			break;
448c2ecf20Sopenharmony_ci		case IEEE_8021QAZ_TSA_ETS:
458c2ecf20Sopenharmony_ci			has_ets_tc = true;
468c2ecf20Sopenharmony_ci			tx_bw_sum += ets->tc_tx_bw[i];
478c2ecf20Sopenharmony_ci			break;
488c2ecf20Sopenharmony_ci		default:
498c2ecf20Sopenharmony_ci			netdev_err(dev, "Only strict priority and ETS are supported\n");
508c2ecf20Sopenharmony_ci			return -EINVAL;
518c2ecf20Sopenharmony_ci		}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci		if (ets->prio_tc[i] >= IEEE_8021QAZ_MAX_TCS) {
548c2ecf20Sopenharmony_ci			netdev_err(dev, "Invalid TC\n");
558c2ecf20Sopenharmony_ci			return -EINVAL;
568c2ecf20Sopenharmony_ci		}
578c2ecf20Sopenharmony_ci	}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	if (has_ets_tc && tx_bw_sum != 100) {
608c2ecf20Sopenharmony_ci		netdev_err(dev, "Total ETS bandwidth should equal 100\n");
618c2ecf20Sopenharmony_ci		return -EINVAL;
628c2ecf20Sopenharmony_ci	}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	return 0;
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_headroom_ets_set(struct mlxsw_sp_port *mlxsw_sp_port,
688c2ecf20Sopenharmony_ci					  struct ieee_ets *ets)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	struct net_device *dev = mlxsw_sp_port->dev;
718c2ecf20Sopenharmony_ci	struct mlxsw_sp_hdroom hdroom;
728c2ecf20Sopenharmony_ci	int prio;
738c2ecf20Sopenharmony_ci	int err;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	hdroom = *mlxsw_sp_port->hdroom;
768c2ecf20Sopenharmony_ci	for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++)
778c2ecf20Sopenharmony_ci		hdroom.prios.prio[prio].ets_buf_idx = ets->prio_tc[prio];
788c2ecf20Sopenharmony_ci	mlxsw_sp_hdroom_prios_reset_buf_idx(&hdroom);
798c2ecf20Sopenharmony_ci	mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom);
808c2ecf20Sopenharmony_ci	mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
838c2ecf20Sopenharmony_ci	if (err) {
848c2ecf20Sopenharmony_ci		netdev_err(dev, "Failed to configure port's headroom\n");
858c2ecf20Sopenharmony_ci		return err;
868c2ecf20Sopenharmony_ci	}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	return 0;
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic int __mlxsw_sp_dcbnl_ieee_setets(struct mlxsw_sp_port *mlxsw_sp_port,
928c2ecf20Sopenharmony_ci					struct ieee_ets *ets)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	struct ieee_ets *my_ets = mlxsw_sp_port->dcb.ets;
958c2ecf20Sopenharmony_ci	struct net_device *dev = mlxsw_sp_port->dev;
968c2ecf20Sopenharmony_ci	int i, err;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	/* Egress configuration. */
998c2ecf20Sopenharmony_ci	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
1008c2ecf20Sopenharmony_ci		bool dwrr = ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS;
1018c2ecf20Sopenharmony_ci		u8 weight = ets->tc_tx_bw[i];
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci		err = mlxsw_sp_port_ets_set(mlxsw_sp_port,
1048c2ecf20Sopenharmony_ci					    MLXSW_REG_QEEC_HR_SUBGROUP, i,
1058c2ecf20Sopenharmony_ci					    0, dwrr, weight);
1068c2ecf20Sopenharmony_ci		if (err) {
1078c2ecf20Sopenharmony_ci			netdev_err(dev, "Failed to link subgroup ETS element %d to group\n",
1088c2ecf20Sopenharmony_ci				   i);
1098c2ecf20Sopenharmony_ci			goto err_port_ets_set;
1108c2ecf20Sopenharmony_ci		}
1118c2ecf20Sopenharmony_ci	}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
1148c2ecf20Sopenharmony_ci		err = mlxsw_sp_port_prio_tc_set(mlxsw_sp_port, i,
1158c2ecf20Sopenharmony_ci						ets->prio_tc[i]);
1168c2ecf20Sopenharmony_ci		if (err) {
1178c2ecf20Sopenharmony_ci			netdev_err(dev, "Failed to map prio %d to TC %d\n", i,
1188c2ecf20Sopenharmony_ci				   ets->prio_tc[i]);
1198c2ecf20Sopenharmony_ci			goto err_port_prio_tc_set;
1208c2ecf20Sopenharmony_ci		}
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	/* Ingress configuration. */
1248c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_headroom_ets_set(mlxsw_sp_port, ets);
1258c2ecf20Sopenharmony_ci	if (err)
1268c2ecf20Sopenharmony_ci		goto err_port_headroom_set;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	return 0;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cierr_port_headroom_set:
1318c2ecf20Sopenharmony_ci	i = IEEE_8021QAZ_MAX_TCS;
1328c2ecf20Sopenharmony_cierr_port_prio_tc_set:
1338c2ecf20Sopenharmony_ci	for (i--; i >= 0; i--)
1348c2ecf20Sopenharmony_ci		mlxsw_sp_port_prio_tc_set(mlxsw_sp_port, i, my_ets->prio_tc[i]);
1358c2ecf20Sopenharmony_ci	i = IEEE_8021QAZ_MAX_TCS;
1368c2ecf20Sopenharmony_cierr_port_ets_set:
1378c2ecf20Sopenharmony_ci	for (i--; i >= 0; i--) {
1388c2ecf20Sopenharmony_ci		bool dwrr = my_ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS;
1398c2ecf20Sopenharmony_ci		u8 weight = my_ets->tc_tx_bw[i];
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci		err = mlxsw_sp_port_ets_set(mlxsw_sp_port,
1428c2ecf20Sopenharmony_ci					    MLXSW_REG_QEEC_HR_SUBGROUP, i,
1438c2ecf20Sopenharmony_ci					    0, dwrr, weight);
1448c2ecf20Sopenharmony_ci	}
1458c2ecf20Sopenharmony_ci	return err;
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic int mlxsw_sp_dcbnl_ieee_setets(struct net_device *dev,
1498c2ecf20Sopenharmony_ci				      struct ieee_ets *ets)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
1528c2ecf20Sopenharmony_ci	int err;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_ets_validate(mlxsw_sp_port, ets);
1558c2ecf20Sopenharmony_ci	if (err)
1568c2ecf20Sopenharmony_ci		return err;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	err = __mlxsw_sp_dcbnl_ieee_setets(mlxsw_sp_port, ets);
1598c2ecf20Sopenharmony_ci	if (err)
1608c2ecf20Sopenharmony_ci		return err;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	memcpy(mlxsw_sp_port->dcb.ets, ets, sizeof(*ets));
1638c2ecf20Sopenharmony_ci	mlxsw_sp_port->dcb.ets->ets_cap = IEEE_8021QAZ_MAX_TCS;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	return 0;
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic int mlxsw_sp_dcbnl_app_validate(struct net_device *dev,
1698c2ecf20Sopenharmony_ci				       struct dcb_app *app)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	if (app->priority >= IEEE_8021QAZ_MAX_TCS) {
1728c2ecf20Sopenharmony_ci		netdev_err(dev, "APP entry with priority value %u is invalid\n",
1738c2ecf20Sopenharmony_ci			   app->priority);
1748c2ecf20Sopenharmony_ci		return -EINVAL;
1758c2ecf20Sopenharmony_ci	}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	switch (app->selector) {
1788c2ecf20Sopenharmony_ci	case IEEE_8021QAZ_APP_SEL_DSCP:
1798c2ecf20Sopenharmony_ci		if (app->protocol >= 64) {
1808c2ecf20Sopenharmony_ci			netdev_err(dev, "DSCP APP entry with protocol value %u is invalid\n",
1818c2ecf20Sopenharmony_ci				   app->protocol);
1828c2ecf20Sopenharmony_ci			return -EINVAL;
1838c2ecf20Sopenharmony_ci		}
1848c2ecf20Sopenharmony_ci		break;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	case IEEE_8021QAZ_APP_SEL_ETHERTYPE:
1878c2ecf20Sopenharmony_ci		if (app->protocol) {
1888c2ecf20Sopenharmony_ci			netdev_err(dev, "EtherType APP entries with protocol value != 0 not supported\n");
1898c2ecf20Sopenharmony_ci			return -EINVAL;
1908c2ecf20Sopenharmony_ci		}
1918c2ecf20Sopenharmony_ci		break;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	default:
1948c2ecf20Sopenharmony_ci		netdev_err(dev, "APP entries with selector %u not supported\n",
1958c2ecf20Sopenharmony_ci			   app->selector);
1968c2ecf20Sopenharmony_ci		return -EINVAL;
1978c2ecf20Sopenharmony_ci	}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	return 0;
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic u8
2038c2ecf20Sopenharmony_cimlxsw_sp_port_dcb_app_default_prio(struct mlxsw_sp_port *mlxsw_sp_port)
2048c2ecf20Sopenharmony_ci{
2058c2ecf20Sopenharmony_ci	u8 prio_mask;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	prio_mask = dcb_ieee_getapp_default_prio_mask(mlxsw_sp_port->dev);
2088c2ecf20Sopenharmony_ci	if (prio_mask)
2098c2ecf20Sopenharmony_ci		/* Take the highest configured priority. */
2108c2ecf20Sopenharmony_ci		return fls(prio_mask) - 1;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	return 0;
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic void
2168c2ecf20Sopenharmony_cimlxsw_sp_port_dcb_app_dscp_prio_map(struct mlxsw_sp_port *mlxsw_sp_port,
2178c2ecf20Sopenharmony_ci				    u8 default_prio,
2188c2ecf20Sopenharmony_ci				    struct dcb_ieee_app_dscp_map *map)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	int i;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	dcb_ieee_getapp_dscp_prio_mask_map(mlxsw_sp_port->dev, map);
2238c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(map->map); ++i) {
2248c2ecf20Sopenharmony_ci		if (map->map[i])
2258c2ecf20Sopenharmony_ci			map->map[i] = fls(map->map[i]) - 1;
2268c2ecf20Sopenharmony_ci		else
2278c2ecf20Sopenharmony_ci			map->map[i] = default_prio;
2288c2ecf20Sopenharmony_ci	}
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic bool
2328c2ecf20Sopenharmony_cimlxsw_sp_port_dcb_app_prio_dscp_map(struct mlxsw_sp_port *mlxsw_sp_port,
2338c2ecf20Sopenharmony_ci				    struct dcb_ieee_app_prio_map *map)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	bool have_dscp = false;
2368c2ecf20Sopenharmony_ci	int i;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	dcb_ieee_getapp_prio_dscp_mask_map(mlxsw_sp_port->dev, map);
2398c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(map->map); ++i) {
2408c2ecf20Sopenharmony_ci		if (map->map[i]) {
2418c2ecf20Sopenharmony_ci			map->map[i] = fls64(map->map[i]) - 1;
2428c2ecf20Sopenharmony_ci			have_dscp = true;
2438c2ecf20Sopenharmony_ci		}
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	return have_dscp;
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_cistatic int
2508c2ecf20Sopenharmony_cimlxsw_sp_port_dcb_app_update_qpts(struct mlxsw_sp_port *mlxsw_sp_port,
2518c2ecf20Sopenharmony_ci				  enum mlxsw_reg_qpts_trust_state ts)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
2548c2ecf20Sopenharmony_ci	char qpts_pl[MLXSW_REG_QPTS_LEN];
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	mlxsw_reg_qpts_pack(qpts_pl, mlxsw_sp_port->local_port, ts);
2578c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpts), qpts_pl);
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistatic int
2618c2ecf20Sopenharmony_cimlxsw_sp_port_dcb_app_update_qrwe(struct mlxsw_sp_port *mlxsw_sp_port,
2628c2ecf20Sopenharmony_ci				  bool rewrite_dscp)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
2658c2ecf20Sopenharmony_ci	char qrwe_pl[MLXSW_REG_QRWE_LEN];
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	mlxsw_reg_qrwe_pack(qrwe_pl, mlxsw_sp_port->local_port,
2688c2ecf20Sopenharmony_ci			    false, rewrite_dscp);
2698c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qrwe), qrwe_pl);
2708c2ecf20Sopenharmony_ci}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_cistatic int
2738c2ecf20Sopenharmony_cimlxsw_sp_port_dcb_toggle_trust(struct mlxsw_sp_port *mlxsw_sp_port,
2748c2ecf20Sopenharmony_ci			       enum mlxsw_reg_qpts_trust_state ts)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	bool rewrite_dscp = ts == MLXSW_REG_QPTS_TRUST_STATE_DSCP;
2778c2ecf20Sopenharmony_ci	int err;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	if (mlxsw_sp_port->dcb.trust_state == ts)
2808c2ecf20Sopenharmony_ci		return 0;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_dcb_app_update_qpts(mlxsw_sp_port, ts);
2838c2ecf20Sopenharmony_ci	if (err)
2848c2ecf20Sopenharmony_ci		return err;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_dcb_app_update_qrwe(mlxsw_sp_port, rewrite_dscp);
2878c2ecf20Sopenharmony_ci	if (err)
2888c2ecf20Sopenharmony_ci		goto err_update_qrwe;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	mlxsw_sp_port->dcb.trust_state = ts;
2918c2ecf20Sopenharmony_ci	return 0;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_cierr_update_qrwe:
2948c2ecf20Sopenharmony_ci	mlxsw_sp_port_dcb_app_update_qpts(mlxsw_sp_port,
2958c2ecf20Sopenharmony_ci					  mlxsw_sp_port->dcb.trust_state);
2968c2ecf20Sopenharmony_ci	return err;
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_cistatic int
3008c2ecf20Sopenharmony_cimlxsw_sp_port_dcb_app_update_qpdp(struct mlxsw_sp_port *mlxsw_sp_port,
3018c2ecf20Sopenharmony_ci				  u8 default_prio)
3028c2ecf20Sopenharmony_ci{
3038c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
3048c2ecf20Sopenharmony_ci	char qpdp_pl[MLXSW_REG_QPDP_LEN];
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	mlxsw_reg_qpdp_pack(qpdp_pl, mlxsw_sp_port->local_port, default_prio);
3078c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpdp), qpdp_pl);
3088c2ecf20Sopenharmony_ci}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_cistatic int
3118c2ecf20Sopenharmony_cimlxsw_sp_port_dcb_app_update_qpdpm(struct mlxsw_sp_port *mlxsw_sp_port,
3128c2ecf20Sopenharmony_ci				   struct dcb_ieee_app_dscp_map *map)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
3158c2ecf20Sopenharmony_ci	char qpdpm_pl[MLXSW_REG_QPDPM_LEN];
3168c2ecf20Sopenharmony_ci	short int i;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	mlxsw_reg_qpdpm_pack(qpdpm_pl, mlxsw_sp_port->local_port);
3198c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(map->map); ++i)
3208c2ecf20Sopenharmony_ci		mlxsw_reg_qpdpm_dscp_pack(qpdpm_pl, i, map->map[i]);
3218c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpdpm), qpdpm_pl);
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_cistatic int
3258c2ecf20Sopenharmony_cimlxsw_sp_port_dcb_app_update_qpdsm(struct mlxsw_sp_port *mlxsw_sp_port,
3268c2ecf20Sopenharmony_ci				   struct dcb_ieee_app_prio_map *map)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
3298c2ecf20Sopenharmony_ci	char qpdsm_pl[MLXSW_REG_QPDSM_LEN];
3308c2ecf20Sopenharmony_ci	short int i;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	mlxsw_reg_qpdsm_pack(qpdsm_pl, mlxsw_sp_port->local_port);
3338c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(map->map); ++i)
3348c2ecf20Sopenharmony_ci		mlxsw_reg_qpdsm_prio_pack(qpdsm_pl, i, map->map[i]);
3358c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpdsm), qpdsm_pl);
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_dcb_app_update(struct mlxsw_sp_port *mlxsw_sp_port)
3398c2ecf20Sopenharmony_ci{
3408c2ecf20Sopenharmony_ci	struct dcb_ieee_app_prio_map prio_map;
3418c2ecf20Sopenharmony_ci	struct dcb_ieee_app_dscp_map dscp_map;
3428c2ecf20Sopenharmony_ci	u8 default_prio;
3438c2ecf20Sopenharmony_ci	bool have_dscp;
3448c2ecf20Sopenharmony_ci	int err;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	default_prio = mlxsw_sp_port_dcb_app_default_prio(mlxsw_sp_port);
3478c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_dcb_app_update_qpdp(mlxsw_sp_port, default_prio);
3488c2ecf20Sopenharmony_ci	if (err) {
3498c2ecf20Sopenharmony_ci		netdev_err(mlxsw_sp_port->dev, "Couldn't configure port default priority\n");
3508c2ecf20Sopenharmony_ci		return err;
3518c2ecf20Sopenharmony_ci	}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	have_dscp = mlxsw_sp_port_dcb_app_prio_dscp_map(mlxsw_sp_port,
3548c2ecf20Sopenharmony_ci							&prio_map);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	mlxsw_sp_port_dcb_app_dscp_prio_map(mlxsw_sp_port, default_prio,
3578c2ecf20Sopenharmony_ci					    &dscp_map);
3588c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_dcb_app_update_qpdpm(mlxsw_sp_port,
3598c2ecf20Sopenharmony_ci						 &dscp_map);
3608c2ecf20Sopenharmony_ci	if (err) {
3618c2ecf20Sopenharmony_ci		netdev_err(mlxsw_sp_port->dev, "Couldn't configure priority map\n");
3628c2ecf20Sopenharmony_ci		return err;
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_dcb_app_update_qpdsm(mlxsw_sp_port,
3668c2ecf20Sopenharmony_ci						 &prio_map);
3678c2ecf20Sopenharmony_ci	if (err) {
3688c2ecf20Sopenharmony_ci		netdev_err(mlxsw_sp_port->dev, "Couldn't configure DSCP rewrite map\n");
3698c2ecf20Sopenharmony_ci		return err;
3708c2ecf20Sopenharmony_ci	}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	if (!have_dscp) {
3738c2ecf20Sopenharmony_ci		err = mlxsw_sp_port_dcb_toggle_trust(mlxsw_sp_port,
3748c2ecf20Sopenharmony_ci					MLXSW_REG_QPTS_TRUST_STATE_PCP);
3758c2ecf20Sopenharmony_ci		if (err)
3768c2ecf20Sopenharmony_ci			netdev_err(mlxsw_sp_port->dev, "Couldn't switch to trust L2\n");
3778c2ecf20Sopenharmony_ci		return err;
3788c2ecf20Sopenharmony_ci	}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_dcb_toggle_trust(mlxsw_sp_port,
3818c2ecf20Sopenharmony_ci					     MLXSW_REG_QPTS_TRUST_STATE_DSCP);
3828c2ecf20Sopenharmony_ci	if (err) {
3838c2ecf20Sopenharmony_ci		/* A failure to set trust DSCP means that the QPDPM and QPDSM
3848c2ecf20Sopenharmony_ci		 * maps installed above are not in effect. And since we are here
3858c2ecf20Sopenharmony_ci		 * attempting to set trust DSCP, we couldn't have attempted to
3868c2ecf20Sopenharmony_ci		 * switch trust to PCP. Thus no cleanup is necessary.
3878c2ecf20Sopenharmony_ci		 */
3888c2ecf20Sopenharmony_ci		netdev_err(mlxsw_sp_port->dev, "Couldn't switch to trust L3\n");
3898c2ecf20Sopenharmony_ci		return err;
3908c2ecf20Sopenharmony_ci	}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	return 0;
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_cistatic int mlxsw_sp_dcbnl_ieee_setapp(struct net_device *dev,
3968c2ecf20Sopenharmony_ci				      struct dcb_app *app)
3978c2ecf20Sopenharmony_ci{
3988c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
3998c2ecf20Sopenharmony_ci	int err;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	err = mlxsw_sp_dcbnl_app_validate(dev, app);
4028c2ecf20Sopenharmony_ci	if (err)
4038c2ecf20Sopenharmony_ci		return err;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	err = dcb_ieee_setapp(dev, app);
4068c2ecf20Sopenharmony_ci	if (err)
4078c2ecf20Sopenharmony_ci		return err;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_dcb_app_update(mlxsw_sp_port);
4108c2ecf20Sopenharmony_ci	if (err)
4118c2ecf20Sopenharmony_ci		goto err_update;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	return 0;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_cierr_update:
4168c2ecf20Sopenharmony_ci	dcb_ieee_delapp(dev, app);
4178c2ecf20Sopenharmony_ci	return err;
4188c2ecf20Sopenharmony_ci}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_cistatic int mlxsw_sp_dcbnl_ieee_delapp(struct net_device *dev,
4218c2ecf20Sopenharmony_ci				      struct dcb_app *app)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
4248c2ecf20Sopenharmony_ci	int err;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	err = dcb_ieee_delapp(dev, app);
4278c2ecf20Sopenharmony_ci	if (err)
4288c2ecf20Sopenharmony_ci		return err;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_dcb_app_update(mlxsw_sp_port);
4318c2ecf20Sopenharmony_ci	if (err)
4328c2ecf20Sopenharmony_ci		netdev_err(dev, "Failed to update DCB APP configuration\n");
4338c2ecf20Sopenharmony_ci	return 0;
4348c2ecf20Sopenharmony_ci}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_cistatic int mlxsw_sp_dcbnl_ieee_getmaxrate(struct net_device *dev,
4378c2ecf20Sopenharmony_ci					  struct ieee_maxrate *maxrate)
4388c2ecf20Sopenharmony_ci{
4398c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	memcpy(maxrate, mlxsw_sp_port->dcb.maxrate, sizeof(*maxrate));
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	return 0;
4448c2ecf20Sopenharmony_ci}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_cistatic int mlxsw_sp_dcbnl_ieee_setmaxrate(struct net_device *dev,
4478c2ecf20Sopenharmony_ci					  struct ieee_maxrate *maxrate)
4488c2ecf20Sopenharmony_ci{
4498c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
4508c2ecf20Sopenharmony_ci	struct ieee_maxrate *my_maxrate = mlxsw_sp_port->dcb.maxrate;
4518c2ecf20Sopenharmony_ci	int err, i;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
4548c2ecf20Sopenharmony_ci		err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,
4558c2ecf20Sopenharmony_ci						    MLXSW_REG_QEEC_HR_SUBGROUP,
4568c2ecf20Sopenharmony_ci						    i, 0,
4578c2ecf20Sopenharmony_ci						    maxrate->tc_maxrate[i], 0);
4588c2ecf20Sopenharmony_ci		if (err) {
4598c2ecf20Sopenharmony_ci			netdev_err(dev, "Failed to set maxrate for TC %d\n", i);
4608c2ecf20Sopenharmony_ci			goto err_port_ets_maxrate_set;
4618c2ecf20Sopenharmony_ci		}
4628c2ecf20Sopenharmony_ci	}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	memcpy(mlxsw_sp_port->dcb.maxrate, maxrate, sizeof(*maxrate));
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	return 0;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_cierr_port_ets_maxrate_set:
4698c2ecf20Sopenharmony_ci	for (i--; i >= 0; i--)
4708c2ecf20Sopenharmony_ci		mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,
4718c2ecf20Sopenharmony_ci					      MLXSW_REG_QEEC_HR_SUBGROUP,
4728c2ecf20Sopenharmony_ci					      i, 0,
4738c2ecf20Sopenharmony_ci					      my_maxrate->tc_maxrate[i], 0);
4748c2ecf20Sopenharmony_ci	return err;
4758c2ecf20Sopenharmony_ci}
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_pfc_cnt_get(struct mlxsw_sp_port *mlxsw_sp_port,
4788c2ecf20Sopenharmony_ci				     u8 prio)
4798c2ecf20Sopenharmony_ci{
4808c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
4818c2ecf20Sopenharmony_ci	struct ieee_pfc *my_pfc = mlxsw_sp_port->dcb.pfc;
4828c2ecf20Sopenharmony_ci	char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
4838c2ecf20Sopenharmony_ci	int err;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	mlxsw_reg_ppcnt_pack(ppcnt_pl, mlxsw_sp_port->local_port,
4868c2ecf20Sopenharmony_ci			     MLXSW_REG_PPCNT_PRIO_CNT, prio);
4878c2ecf20Sopenharmony_ci	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ppcnt), ppcnt_pl);
4888c2ecf20Sopenharmony_ci	if (err)
4898c2ecf20Sopenharmony_ci		return err;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	my_pfc->requests[prio] = mlxsw_reg_ppcnt_tx_pause_get(ppcnt_pl);
4928c2ecf20Sopenharmony_ci	my_pfc->indications[prio] = mlxsw_reg_ppcnt_rx_pause_get(ppcnt_pl);
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	return 0;
4958c2ecf20Sopenharmony_ci}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_cistatic int mlxsw_sp_dcbnl_ieee_getpfc(struct net_device *dev,
4988c2ecf20Sopenharmony_ci				      struct ieee_pfc *pfc)
4998c2ecf20Sopenharmony_ci{
5008c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
5018c2ecf20Sopenharmony_ci	int err, i;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
5048c2ecf20Sopenharmony_ci		err = mlxsw_sp_port_pfc_cnt_get(mlxsw_sp_port, i);
5058c2ecf20Sopenharmony_ci		if (err) {
5068c2ecf20Sopenharmony_ci			netdev_err(dev, "Failed to get PFC count for priority %d\n",
5078c2ecf20Sopenharmony_ci				   i);
5088c2ecf20Sopenharmony_ci			return err;
5098c2ecf20Sopenharmony_ci		}
5108c2ecf20Sopenharmony_ci	}
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	memcpy(pfc, mlxsw_sp_port->dcb.pfc, sizeof(*pfc));
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	return 0;
5158c2ecf20Sopenharmony_ci}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_pfc_set(struct mlxsw_sp_port *mlxsw_sp_port,
5188c2ecf20Sopenharmony_ci				 struct ieee_pfc *pfc)
5198c2ecf20Sopenharmony_ci{
5208c2ecf20Sopenharmony_ci	char pfcc_pl[MLXSW_REG_PFCC_LEN];
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	mlxsw_reg_pfcc_pack(pfcc_pl, mlxsw_sp_port->local_port);
5238c2ecf20Sopenharmony_ci	mlxsw_reg_pfcc_pprx_set(pfcc_pl, mlxsw_sp_port->link.rx_pause);
5248c2ecf20Sopenharmony_ci	mlxsw_reg_pfcc_pptx_set(pfcc_pl, mlxsw_sp_port->link.tx_pause);
5258c2ecf20Sopenharmony_ci	mlxsw_reg_pfcc_prio_pack(pfcc_pl, pfc->pfc_en);
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pfcc),
5288c2ecf20Sopenharmony_ci			       pfcc_pl);
5298c2ecf20Sopenharmony_ci}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_cistatic int mlxsw_sp_dcbnl_ieee_setpfc(struct net_device *dev,
5328c2ecf20Sopenharmony_ci				      struct ieee_pfc *pfc)
5338c2ecf20Sopenharmony_ci{
5348c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
5358c2ecf20Sopenharmony_ci	bool pause_en = mlxsw_sp_port_is_pause_en(mlxsw_sp_port);
5368c2ecf20Sopenharmony_ci	struct mlxsw_sp_hdroom orig_hdroom;
5378c2ecf20Sopenharmony_ci	struct mlxsw_sp_hdroom hdroom;
5388c2ecf20Sopenharmony_ci	int prio;
5398c2ecf20Sopenharmony_ci	int err;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	if (pause_en && pfc->pfc_en) {
5428c2ecf20Sopenharmony_ci		netdev_err(dev, "PAUSE frames already enabled on port\n");
5438c2ecf20Sopenharmony_ci		return -EINVAL;
5448c2ecf20Sopenharmony_ci	}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	orig_hdroom = *mlxsw_sp_port->hdroom;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	hdroom = orig_hdroom;
5498c2ecf20Sopenharmony_ci	if (pfc->pfc_en)
5508c2ecf20Sopenharmony_ci		hdroom.delay_bytes = DIV_ROUND_UP(pfc->delay, BITS_PER_BYTE);
5518c2ecf20Sopenharmony_ci	else
5528c2ecf20Sopenharmony_ci		hdroom.delay_bytes = 0;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++)
5558c2ecf20Sopenharmony_ci		hdroom.prios.prio[prio].lossy = !(pfc->pfc_en & BIT(prio));
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom);
5588c2ecf20Sopenharmony_ci	mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
5618c2ecf20Sopenharmony_ci	if (err) {
5628c2ecf20Sopenharmony_ci		netdev_err(dev, "Failed to configure port's headroom for PFC\n");
5638c2ecf20Sopenharmony_ci		return err;
5648c2ecf20Sopenharmony_ci	}
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_pfc_set(mlxsw_sp_port, pfc);
5678c2ecf20Sopenharmony_ci	if (err) {
5688c2ecf20Sopenharmony_ci		netdev_err(dev, "Failed to configure PFC\n");
5698c2ecf20Sopenharmony_ci		goto err_port_pfc_set;
5708c2ecf20Sopenharmony_ci	}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	memcpy(mlxsw_sp_port->dcb.pfc, pfc, sizeof(*pfc));
5738c2ecf20Sopenharmony_ci	mlxsw_sp_port->dcb.pfc->pfc_cap = IEEE_8021QAZ_MAX_TCS;
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	return 0;
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_cierr_port_pfc_set:
5788c2ecf20Sopenharmony_ci	mlxsw_sp_hdroom_configure(mlxsw_sp_port, &orig_hdroom);
5798c2ecf20Sopenharmony_ci	return err;
5808c2ecf20Sopenharmony_ci}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_cistatic int mlxsw_sp_dcbnl_getbuffer(struct net_device *dev, struct dcbnl_buffer *buf)
5838c2ecf20Sopenharmony_ci{
5848c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
5858c2ecf20Sopenharmony_ci	struct mlxsw_sp_hdroom *hdroom = mlxsw_sp_port->hdroom;
5868c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
5878c2ecf20Sopenharmony_ci	int prio;
5888c2ecf20Sopenharmony_ci	int i;
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	buf->total_size = 0;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	BUILD_BUG_ON(DCBX_MAX_BUFFERS > MLXSW_SP_PB_COUNT);
5938c2ecf20Sopenharmony_ci	for (i = 0; i < MLXSW_SP_PB_COUNT; i++) {
5948c2ecf20Sopenharmony_ci		u32 bytes = mlxsw_sp_cells_bytes(mlxsw_sp, hdroom->bufs.buf[i].size_cells);
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci		if (i < DCBX_MAX_BUFFERS)
5978c2ecf20Sopenharmony_ci			buf->buffer_size[i] = bytes;
5988c2ecf20Sopenharmony_ci		buf->total_size += bytes;
5998c2ecf20Sopenharmony_ci	}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	buf->total_size += mlxsw_sp_cells_bytes(mlxsw_sp, hdroom->int_buf.size_cells);
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	for (prio = 0; prio < IEEE_8021Q_MAX_PRIORITIES; prio++)
6048c2ecf20Sopenharmony_ci		buf->prio2buffer[prio] = hdroom->prios.prio[prio].buf_idx;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	return 0;
6078c2ecf20Sopenharmony_ci}
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_cistatic int mlxsw_sp_dcbnl_setbuffer(struct net_device *dev, struct dcbnl_buffer *buf)
6108c2ecf20Sopenharmony_ci{
6118c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
6128c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
6138c2ecf20Sopenharmony_ci	struct mlxsw_sp_hdroom hdroom;
6148c2ecf20Sopenharmony_ci	int prio;
6158c2ecf20Sopenharmony_ci	int i;
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	hdroom = *mlxsw_sp_port->hdroom;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	if (hdroom.mode != MLXSW_SP_HDROOM_MODE_TC) {
6208c2ecf20Sopenharmony_ci		netdev_err(dev, "The use of dcbnl_setbuffer is only allowed if egress is configured using TC\n");
6218c2ecf20Sopenharmony_ci		return -EINVAL;
6228c2ecf20Sopenharmony_ci	}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	for (prio = 0; prio < IEEE_8021Q_MAX_PRIORITIES; prio++)
6258c2ecf20Sopenharmony_ci		hdroom.prios.prio[prio].set_buf_idx = buf->prio2buffer[prio];
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	BUILD_BUG_ON(DCBX_MAX_BUFFERS > MLXSW_SP_PB_COUNT);
6288c2ecf20Sopenharmony_ci	for (i = 0; i < DCBX_MAX_BUFFERS; i++)
6298c2ecf20Sopenharmony_ci		hdroom.bufs.buf[i].set_size_cells = mlxsw_sp_bytes_cells(mlxsw_sp,
6308c2ecf20Sopenharmony_ci									 buf->buffer_size[i]);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	mlxsw_sp_hdroom_prios_reset_buf_idx(&hdroom);
6338c2ecf20Sopenharmony_ci	mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom);
6348c2ecf20Sopenharmony_ci	mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
6358c2ecf20Sopenharmony_ci	return mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
6368c2ecf20Sopenharmony_ci}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_cistatic const struct dcbnl_rtnl_ops mlxsw_sp_dcbnl_ops = {
6398c2ecf20Sopenharmony_ci	.ieee_getets		= mlxsw_sp_dcbnl_ieee_getets,
6408c2ecf20Sopenharmony_ci	.ieee_setets		= mlxsw_sp_dcbnl_ieee_setets,
6418c2ecf20Sopenharmony_ci	.ieee_getmaxrate	= mlxsw_sp_dcbnl_ieee_getmaxrate,
6428c2ecf20Sopenharmony_ci	.ieee_setmaxrate	= mlxsw_sp_dcbnl_ieee_setmaxrate,
6438c2ecf20Sopenharmony_ci	.ieee_getpfc		= mlxsw_sp_dcbnl_ieee_getpfc,
6448c2ecf20Sopenharmony_ci	.ieee_setpfc		= mlxsw_sp_dcbnl_ieee_setpfc,
6458c2ecf20Sopenharmony_ci	.ieee_setapp		= mlxsw_sp_dcbnl_ieee_setapp,
6468c2ecf20Sopenharmony_ci	.ieee_delapp		= mlxsw_sp_dcbnl_ieee_delapp,
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	.getdcbx		= mlxsw_sp_dcbnl_getdcbx,
6498c2ecf20Sopenharmony_ci	.setdcbx		= mlxsw_sp_dcbnl_setdcbx,
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	.dcbnl_getbuffer	= mlxsw_sp_dcbnl_getbuffer,
6528c2ecf20Sopenharmony_ci	.dcbnl_setbuffer	= mlxsw_sp_dcbnl_setbuffer,
6538c2ecf20Sopenharmony_ci};
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_ets_init(struct mlxsw_sp_port *mlxsw_sp_port)
6568c2ecf20Sopenharmony_ci{
6578c2ecf20Sopenharmony_ci	mlxsw_sp_port->dcb.ets = kzalloc(sizeof(*mlxsw_sp_port->dcb.ets),
6588c2ecf20Sopenharmony_ci					 GFP_KERNEL);
6598c2ecf20Sopenharmony_ci	if (!mlxsw_sp_port->dcb.ets)
6608c2ecf20Sopenharmony_ci		return -ENOMEM;
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	mlxsw_sp_port->dcb.ets->ets_cap = IEEE_8021QAZ_MAX_TCS;
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	return 0;
6658c2ecf20Sopenharmony_ci}
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_cistatic void mlxsw_sp_port_ets_fini(struct mlxsw_sp_port *mlxsw_sp_port)
6688c2ecf20Sopenharmony_ci{
6698c2ecf20Sopenharmony_ci	kfree(mlxsw_sp_port->dcb.ets);
6708c2ecf20Sopenharmony_ci}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_maxrate_init(struct mlxsw_sp_port *mlxsw_sp_port)
6738c2ecf20Sopenharmony_ci{
6748c2ecf20Sopenharmony_ci	int i;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	mlxsw_sp_port->dcb.maxrate = kmalloc(sizeof(*mlxsw_sp_port->dcb.maxrate),
6778c2ecf20Sopenharmony_ci					     GFP_KERNEL);
6788c2ecf20Sopenharmony_ci	if (!mlxsw_sp_port->dcb.maxrate)
6798c2ecf20Sopenharmony_ci		return -ENOMEM;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
6828c2ecf20Sopenharmony_ci		mlxsw_sp_port->dcb.maxrate->tc_maxrate[i] = MLXSW_REG_QEEC_MAS_DIS;
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	return 0;
6858c2ecf20Sopenharmony_ci}
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_cistatic void mlxsw_sp_port_maxrate_fini(struct mlxsw_sp_port *mlxsw_sp_port)
6888c2ecf20Sopenharmony_ci{
6898c2ecf20Sopenharmony_ci	kfree(mlxsw_sp_port->dcb.maxrate);
6908c2ecf20Sopenharmony_ci}
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_pfc_init(struct mlxsw_sp_port *mlxsw_sp_port)
6938c2ecf20Sopenharmony_ci{
6948c2ecf20Sopenharmony_ci	mlxsw_sp_port->dcb.pfc = kzalloc(sizeof(*mlxsw_sp_port->dcb.pfc),
6958c2ecf20Sopenharmony_ci					 GFP_KERNEL);
6968c2ecf20Sopenharmony_ci	if (!mlxsw_sp_port->dcb.pfc)
6978c2ecf20Sopenharmony_ci		return -ENOMEM;
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	mlxsw_sp_port->dcb.pfc->pfc_cap = IEEE_8021QAZ_MAX_TCS;
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	return 0;
7028c2ecf20Sopenharmony_ci}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_cistatic void mlxsw_sp_port_pfc_fini(struct mlxsw_sp_port *mlxsw_sp_port)
7058c2ecf20Sopenharmony_ci{
7068c2ecf20Sopenharmony_ci	kfree(mlxsw_sp_port->dcb.pfc);
7078c2ecf20Sopenharmony_ci}
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ciint mlxsw_sp_port_dcb_init(struct mlxsw_sp_port *mlxsw_sp_port)
7108c2ecf20Sopenharmony_ci{
7118c2ecf20Sopenharmony_ci	int err;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_ets_init(mlxsw_sp_port);
7148c2ecf20Sopenharmony_ci	if (err)
7158c2ecf20Sopenharmony_ci		return err;
7168c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_maxrate_init(mlxsw_sp_port);
7178c2ecf20Sopenharmony_ci	if (err)
7188c2ecf20Sopenharmony_ci		goto err_port_maxrate_init;
7198c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_pfc_init(mlxsw_sp_port);
7208c2ecf20Sopenharmony_ci	if (err)
7218c2ecf20Sopenharmony_ci		goto err_port_pfc_init;
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	mlxsw_sp_port->dcb.trust_state = MLXSW_REG_QPTS_TRUST_STATE_PCP;
7248c2ecf20Sopenharmony_ci	mlxsw_sp_port->dev->dcbnl_ops = &mlxsw_sp_dcbnl_ops;
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	return 0;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_cierr_port_pfc_init:
7298c2ecf20Sopenharmony_ci	mlxsw_sp_port_maxrate_fini(mlxsw_sp_port);
7308c2ecf20Sopenharmony_cierr_port_maxrate_init:
7318c2ecf20Sopenharmony_ci	mlxsw_sp_port_ets_fini(mlxsw_sp_port);
7328c2ecf20Sopenharmony_ci	return err;
7338c2ecf20Sopenharmony_ci}
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_civoid mlxsw_sp_port_dcb_fini(struct mlxsw_sp_port *mlxsw_sp_port)
7368c2ecf20Sopenharmony_ci{
7378c2ecf20Sopenharmony_ci	mlxsw_sp_port_pfc_fini(mlxsw_sp_port);
7388c2ecf20Sopenharmony_ci	mlxsw_sp_port_maxrate_fini(mlxsw_sp_port);
7398c2ecf20Sopenharmony_ci	mlxsw_sp_port_ets_fini(mlxsw_sp_port);
7408c2ecf20Sopenharmony_ci}
741