162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/netdevice.h>
562306a36Sopenharmony_ci#include <linux/string.h>
662306a36Sopenharmony_ci#include <linux/bitops.h>
762306a36Sopenharmony_ci#include <net/dcbnl.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include "spectrum.h"
1062306a36Sopenharmony_ci#include "reg.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_cistatic u8 mlxsw_sp_dcbnl_getdcbx(struct net_device __always_unused *dev)
1362306a36Sopenharmony_ci{
1462306a36Sopenharmony_ci	return DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE;
1562306a36Sopenharmony_ci}
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistatic u8 mlxsw_sp_dcbnl_setdcbx(struct net_device __always_unused *dev,
1862306a36Sopenharmony_ci				 u8 mode)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	return (mode != (DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE)) ? 1 : 0;
2162306a36Sopenharmony_ci}
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic int mlxsw_sp_dcbnl_ieee_getets(struct net_device *dev,
2462306a36Sopenharmony_ci				      struct ieee_ets *ets)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	memcpy(ets, mlxsw_sp_port->dcb.ets, sizeof(*ets));
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	return 0;
3162306a36Sopenharmony_ci}
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic int mlxsw_sp_port_ets_validate(struct mlxsw_sp_port *mlxsw_sp_port,
3462306a36Sopenharmony_ci				      struct ieee_ets *ets)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	struct net_device *dev = mlxsw_sp_port->dev;
3762306a36Sopenharmony_ci	bool has_ets_tc = false;
3862306a36Sopenharmony_ci	int i, tx_bw_sum = 0;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
4162306a36Sopenharmony_ci		switch (ets->tc_tsa[i]) {
4262306a36Sopenharmony_ci		case IEEE_8021QAZ_TSA_STRICT:
4362306a36Sopenharmony_ci			break;
4462306a36Sopenharmony_ci		case IEEE_8021QAZ_TSA_ETS:
4562306a36Sopenharmony_ci			has_ets_tc = true;
4662306a36Sopenharmony_ci			tx_bw_sum += ets->tc_tx_bw[i];
4762306a36Sopenharmony_ci			break;
4862306a36Sopenharmony_ci		default:
4962306a36Sopenharmony_ci			netdev_err(dev, "Only strict priority and ETS are supported\n");
5062306a36Sopenharmony_ci			return -EINVAL;
5162306a36Sopenharmony_ci		}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci		if (ets->prio_tc[i] >= IEEE_8021QAZ_MAX_TCS) {
5462306a36Sopenharmony_ci			netdev_err(dev, "Invalid TC\n");
5562306a36Sopenharmony_ci			return -EINVAL;
5662306a36Sopenharmony_ci		}
5762306a36Sopenharmony_ci	}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	if (has_ets_tc && tx_bw_sum != 100) {
6062306a36Sopenharmony_ci		netdev_err(dev, "Total ETS bandwidth should equal 100\n");
6162306a36Sopenharmony_ci		return -EINVAL;
6262306a36Sopenharmony_ci	}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	return 0;
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic int mlxsw_sp_port_headroom_ets_set(struct mlxsw_sp_port *mlxsw_sp_port,
6862306a36Sopenharmony_ci					  struct ieee_ets *ets)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	struct net_device *dev = mlxsw_sp_port->dev;
7162306a36Sopenharmony_ci	struct mlxsw_sp_hdroom hdroom;
7262306a36Sopenharmony_ci	int prio;
7362306a36Sopenharmony_ci	int err;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	hdroom = *mlxsw_sp_port->hdroom;
7662306a36Sopenharmony_ci	for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++)
7762306a36Sopenharmony_ci		hdroom.prios.prio[prio].ets_buf_idx = ets->prio_tc[prio];
7862306a36Sopenharmony_ci	mlxsw_sp_hdroom_prios_reset_buf_idx(&hdroom);
7962306a36Sopenharmony_ci	mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom);
8062306a36Sopenharmony_ci	mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
8362306a36Sopenharmony_ci	if (err) {
8462306a36Sopenharmony_ci		netdev_err(dev, "Failed to configure port's headroom\n");
8562306a36Sopenharmony_ci		return err;
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	return 0;
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic int __mlxsw_sp_dcbnl_ieee_setets(struct mlxsw_sp_port *mlxsw_sp_port,
9262306a36Sopenharmony_ci					struct ieee_ets *ets)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	struct ieee_ets *my_ets = mlxsw_sp_port->dcb.ets;
9562306a36Sopenharmony_ci	struct net_device *dev = mlxsw_sp_port->dev;
9662306a36Sopenharmony_ci	int i, err;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	/* Egress configuration. */
9962306a36Sopenharmony_ci	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
10062306a36Sopenharmony_ci		bool dwrr = ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS;
10162306a36Sopenharmony_ci		u8 weight = ets->tc_tx_bw[i];
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci		err = mlxsw_sp_port_ets_set(mlxsw_sp_port,
10462306a36Sopenharmony_ci					    MLXSW_REG_QEEC_HR_SUBGROUP, i,
10562306a36Sopenharmony_ci					    0, dwrr, weight);
10662306a36Sopenharmony_ci		if (err) {
10762306a36Sopenharmony_ci			netdev_err(dev, "Failed to link subgroup ETS element %d to group\n",
10862306a36Sopenharmony_ci				   i);
10962306a36Sopenharmony_ci			goto err_port_ets_set;
11062306a36Sopenharmony_ci		}
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
11462306a36Sopenharmony_ci		err = mlxsw_sp_port_prio_tc_set(mlxsw_sp_port, i,
11562306a36Sopenharmony_ci						ets->prio_tc[i]);
11662306a36Sopenharmony_ci		if (err) {
11762306a36Sopenharmony_ci			netdev_err(dev, "Failed to map prio %d to TC %d\n", i,
11862306a36Sopenharmony_ci				   ets->prio_tc[i]);
11962306a36Sopenharmony_ci			goto err_port_prio_tc_set;
12062306a36Sopenharmony_ci		}
12162306a36Sopenharmony_ci	}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	/* Ingress configuration. */
12462306a36Sopenharmony_ci	err = mlxsw_sp_port_headroom_ets_set(mlxsw_sp_port, ets);
12562306a36Sopenharmony_ci	if (err)
12662306a36Sopenharmony_ci		goto err_port_headroom_set;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	return 0;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cierr_port_headroom_set:
13162306a36Sopenharmony_ci	i = IEEE_8021QAZ_MAX_TCS;
13262306a36Sopenharmony_cierr_port_prio_tc_set:
13362306a36Sopenharmony_ci	for (i--; i >= 0; i--)
13462306a36Sopenharmony_ci		mlxsw_sp_port_prio_tc_set(mlxsw_sp_port, i, my_ets->prio_tc[i]);
13562306a36Sopenharmony_ci	i = IEEE_8021QAZ_MAX_TCS;
13662306a36Sopenharmony_cierr_port_ets_set:
13762306a36Sopenharmony_ci	for (i--; i >= 0; i--) {
13862306a36Sopenharmony_ci		bool dwrr = my_ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS;
13962306a36Sopenharmony_ci		u8 weight = my_ets->tc_tx_bw[i];
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci		err = mlxsw_sp_port_ets_set(mlxsw_sp_port,
14262306a36Sopenharmony_ci					    MLXSW_REG_QEEC_HR_SUBGROUP, i,
14362306a36Sopenharmony_ci					    0, dwrr, weight);
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci	return err;
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic int mlxsw_sp_dcbnl_ieee_setets(struct net_device *dev,
14962306a36Sopenharmony_ci				      struct ieee_ets *ets)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
15262306a36Sopenharmony_ci	int err;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	err = mlxsw_sp_port_ets_validate(mlxsw_sp_port, ets);
15562306a36Sopenharmony_ci	if (err)
15662306a36Sopenharmony_ci		return err;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	err = __mlxsw_sp_dcbnl_ieee_setets(mlxsw_sp_port, ets);
15962306a36Sopenharmony_ci	if (err)
16062306a36Sopenharmony_ci		return err;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	memcpy(mlxsw_sp_port->dcb.ets, ets, sizeof(*ets));
16362306a36Sopenharmony_ci	mlxsw_sp_port->dcb.ets->ets_cap = IEEE_8021QAZ_MAX_TCS;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	return 0;
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic int mlxsw_sp_dcbnl_app_validate(struct net_device *dev,
16962306a36Sopenharmony_ci				       struct dcb_app *app)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	if (app->priority >= IEEE_8021QAZ_MAX_TCS) {
17262306a36Sopenharmony_ci		netdev_err(dev, "APP entry with priority value %u is invalid\n",
17362306a36Sopenharmony_ci			   app->priority);
17462306a36Sopenharmony_ci		return -EINVAL;
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	switch (app->selector) {
17862306a36Sopenharmony_ci	case IEEE_8021QAZ_APP_SEL_DSCP:
17962306a36Sopenharmony_ci		if (app->protocol >= 64) {
18062306a36Sopenharmony_ci			netdev_err(dev, "DSCP APP entry with protocol value %u is invalid\n",
18162306a36Sopenharmony_ci				   app->protocol);
18262306a36Sopenharmony_ci			return -EINVAL;
18362306a36Sopenharmony_ci		}
18462306a36Sopenharmony_ci		break;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	case IEEE_8021QAZ_APP_SEL_ETHERTYPE:
18762306a36Sopenharmony_ci		if (app->protocol) {
18862306a36Sopenharmony_ci			netdev_err(dev, "EtherType APP entries with protocol value != 0 not supported\n");
18962306a36Sopenharmony_ci			return -EINVAL;
19062306a36Sopenharmony_ci		}
19162306a36Sopenharmony_ci		break;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	default:
19462306a36Sopenharmony_ci		netdev_err(dev, "APP entries with selector %u not supported\n",
19562306a36Sopenharmony_ci			   app->selector);
19662306a36Sopenharmony_ci		return -EINVAL;
19762306a36Sopenharmony_ci	}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	return 0;
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic u8
20362306a36Sopenharmony_cimlxsw_sp_port_dcb_app_default_prio(struct mlxsw_sp_port *mlxsw_sp_port)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	u8 prio_mask;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	prio_mask = dcb_ieee_getapp_default_prio_mask(mlxsw_sp_port->dev);
20862306a36Sopenharmony_ci	if (prio_mask)
20962306a36Sopenharmony_ci		/* Take the highest configured priority. */
21062306a36Sopenharmony_ci		return fls(prio_mask) - 1;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	return 0;
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic void
21662306a36Sopenharmony_cimlxsw_sp_port_dcb_app_dscp_prio_map(struct mlxsw_sp_port *mlxsw_sp_port,
21762306a36Sopenharmony_ci				    u8 default_prio,
21862306a36Sopenharmony_ci				    struct dcb_ieee_app_dscp_map *map)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	int i;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	dcb_ieee_getapp_dscp_prio_mask_map(mlxsw_sp_port->dev, map);
22362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(map->map); ++i) {
22462306a36Sopenharmony_ci		if (map->map[i])
22562306a36Sopenharmony_ci			map->map[i] = fls(map->map[i]) - 1;
22662306a36Sopenharmony_ci		else
22762306a36Sopenharmony_ci			map->map[i] = default_prio;
22862306a36Sopenharmony_ci	}
22962306a36Sopenharmony_ci}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistatic bool
23262306a36Sopenharmony_cimlxsw_sp_port_dcb_app_prio_dscp_map(struct mlxsw_sp_port *mlxsw_sp_port,
23362306a36Sopenharmony_ci				    struct dcb_ieee_app_prio_map *map)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	bool have_dscp = false;
23662306a36Sopenharmony_ci	int i;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	dcb_ieee_getapp_prio_dscp_mask_map(mlxsw_sp_port->dev, map);
23962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(map->map); ++i) {
24062306a36Sopenharmony_ci		if (map->map[i]) {
24162306a36Sopenharmony_ci			map->map[i] = fls64(map->map[i]) - 1;
24262306a36Sopenharmony_ci			have_dscp = true;
24362306a36Sopenharmony_ci		}
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	return have_dscp;
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic int
25062306a36Sopenharmony_cimlxsw_sp_port_dcb_app_update_qpts(struct mlxsw_sp_port *mlxsw_sp_port,
25162306a36Sopenharmony_ci				  enum mlxsw_reg_qpts_trust_state ts)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
25462306a36Sopenharmony_ci	char qpts_pl[MLXSW_REG_QPTS_LEN];
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	mlxsw_reg_qpts_pack(qpts_pl, mlxsw_sp_port->local_port, ts);
25762306a36Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpts), qpts_pl);
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic int
26162306a36Sopenharmony_cimlxsw_sp_port_dcb_app_update_qrwe(struct mlxsw_sp_port *mlxsw_sp_port,
26262306a36Sopenharmony_ci				  bool rewrite_dscp)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
26562306a36Sopenharmony_ci	char qrwe_pl[MLXSW_REG_QRWE_LEN];
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	mlxsw_reg_qrwe_pack(qrwe_pl, mlxsw_sp_port->local_port,
26862306a36Sopenharmony_ci			    false, rewrite_dscp);
26962306a36Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qrwe), qrwe_pl);
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic int
27362306a36Sopenharmony_cimlxsw_sp_port_dcb_toggle_trust(struct mlxsw_sp_port *mlxsw_sp_port,
27462306a36Sopenharmony_ci			       enum mlxsw_reg_qpts_trust_state ts)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	bool rewrite_dscp = ts == MLXSW_REG_QPTS_TRUST_STATE_DSCP;
27762306a36Sopenharmony_ci	int err;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	if (mlxsw_sp_port->dcb.trust_state == ts)
28062306a36Sopenharmony_ci		return 0;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	err = mlxsw_sp_port_dcb_app_update_qpts(mlxsw_sp_port, ts);
28362306a36Sopenharmony_ci	if (err)
28462306a36Sopenharmony_ci		return err;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	err = mlxsw_sp_port_dcb_app_update_qrwe(mlxsw_sp_port, rewrite_dscp);
28762306a36Sopenharmony_ci	if (err)
28862306a36Sopenharmony_ci		goto err_update_qrwe;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	mlxsw_sp_port->dcb.trust_state = ts;
29162306a36Sopenharmony_ci	return 0;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cierr_update_qrwe:
29462306a36Sopenharmony_ci	mlxsw_sp_port_dcb_app_update_qpts(mlxsw_sp_port,
29562306a36Sopenharmony_ci					  mlxsw_sp_port->dcb.trust_state);
29662306a36Sopenharmony_ci	return err;
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic int
30062306a36Sopenharmony_cimlxsw_sp_port_dcb_app_update_qpdp(struct mlxsw_sp_port *mlxsw_sp_port,
30162306a36Sopenharmony_ci				  u8 default_prio)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
30462306a36Sopenharmony_ci	char qpdp_pl[MLXSW_REG_QPDP_LEN];
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	mlxsw_reg_qpdp_pack(qpdp_pl, mlxsw_sp_port->local_port, default_prio);
30762306a36Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpdp), qpdp_pl);
30862306a36Sopenharmony_ci}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_cistatic int
31162306a36Sopenharmony_cimlxsw_sp_port_dcb_app_update_qpdpm(struct mlxsw_sp_port *mlxsw_sp_port,
31262306a36Sopenharmony_ci				   struct dcb_ieee_app_dscp_map *map)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
31562306a36Sopenharmony_ci	char qpdpm_pl[MLXSW_REG_QPDPM_LEN];
31662306a36Sopenharmony_ci	short int i;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	mlxsw_reg_qpdpm_pack(qpdpm_pl, mlxsw_sp_port->local_port);
31962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(map->map); ++i)
32062306a36Sopenharmony_ci		mlxsw_reg_qpdpm_dscp_pack(qpdpm_pl, i, map->map[i]);
32162306a36Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpdpm), qpdpm_pl);
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic int
32562306a36Sopenharmony_cimlxsw_sp_port_dcb_app_update_qpdsm(struct mlxsw_sp_port *mlxsw_sp_port,
32662306a36Sopenharmony_ci				   struct dcb_ieee_app_prio_map *map)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
32962306a36Sopenharmony_ci	char qpdsm_pl[MLXSW_REG_QPDSM_LEN];
33062306a36Sopenharmony_ci	short int i;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	mlxsw_reg_qpdsm_pack(qpdsm_pl, mlxsw_sp_port->local_port);
33362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(map->map); ++i)
33462306a36Sopenharmony_ci		mlxsw_reg_qpdsm_prio_pack(qpdsm_pl, i, map->map[i]);
33562306a36Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpdsm), qpdsm_pl);
33662306a36Sopenharmony_ci}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_cistatic int mlxsw_sp_port_dcb_app_update(struct mlxsw_sp_port *mlxsw_sp_port)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	struct dcb_ieee_app_prio_map prio_map;
34162306a36Sopenharmony_ci	struct dcb_ieee_app_dscp_map dscp_map;
34262306a36Sopenharmony_ci	u8 default_prio;
34362306a36Sopenharmony_ci	bool have_dscp;
34462306a36Sopenharmony_ci	int err;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	default_prio = mlxsw_sp_port_dcb_app_default_prio(mlxsw_sp_port);
34762306a36Sopenharmony_ci	err = mlxsw_sp_port_dcb_app_update_qpdp(mlxsw_sp_port, default_prio);
34862306a36Sopenharmony_ci	if (err) {
34962306a36Sopenharmony_ci		netdev_err(mlxsw_sp_port->dev, "Couldn't configure port default priority\n");
35062306a36Sopenharmony_ci		return err;
35162306a36Sopenharmony_ci	}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	have_dscp = mlxsw_sp_port_dcb_app_prio_dscp_map(mlxsw_sp_port,
35462306a36Sopenharmony_ci							&prio_map);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	mlxsw_sp_port_dcb_app_dscp_prio_map(mlxsw_sp_port, default_prio,
35762306a36Sopenharmony_ci					    &dscp_map);
35862306a36Sopenharmony_ci	err = mlxsw_sp_port_dcb_app_update_qpdpm(mlxsw_sp_port,
35962306a36Sopenharmony_ci						 &dscp_map);
36062306a36Sopenharmony_ci	if (err) {
36162306a36Sopenharmony_ci		netdev_err(mlxsw_sp_port->dev, "Couldn't configure priority map\n");
36262306a36Sopenharmony_ci		return err;
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	err = mlxsw_sp_port_dcb_app_update_qpdsm(mlxsw_sp_port,
36662306a36Sopenharmony_ci						 &prio_map);
36762306a36Sopenharmony_ci	if (err) {
36862306a36Sopenharmony_ci		netdev_err(mlxsw_sp_port->dev, "Couldn't configure DSCP rewrite map\n");
36962306a36Sopenharmony_ci		return err;
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	if (!have_dscp) {
37362306a36Sopenharmony_ci		err = mlxsw_sp_port_dcb_toggle_trust(mlxsw_sp_port,
37462306a36Sopenharmony_ci					MLXSW_REG_QPTS_TRUST_STATE_PCP);
37562306a36Sopenharmony_ci		if (err)
37662306a36Sopenharmony_ci			netdev_err(mlxsw_sp_port->dev, "Couldn't switch to trust L2\n");
37762306a36Sopenharmony_ci		return err;
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	err = mlxsw_sp_port_dcb_toggle_trust(mlxsw_sp_port,
38162306a36Sopenharmony_ci					     MLXSW_REG_QPTS_TRUST_STATE_DSCP);
38262306a36Sopenharmony_ci	if (err) {
38362306a36Sopenharmony_ci		/* A failure to set trust DSCP means that the QPDPM and QPDSM
38462306a36Sopenharmony_ci		 * maps installed above are not in effect. And since we are here
38562306a36Sopenharmony_ci		 * attempting to set trust DSCP, we couldn't have attempted to
38662306a36Sopenharmony_ci		 * switch trust to PCP. Thus no cleanup is necessary.
38762306a36Sopenharmony_ci		 */
38862306a36Sopenharmony_ci		netdev_err(mlxsw_sp_port->dev, "Couldn't switch to trust L3\n");
38962306a36Sopenharmony_ci		return err;
39062306a36Sopenharmony_ci	}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	return 0;
39362306a36Sopenharmony_ci}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_cistatic int mlxsw_sp_dcbnl_ieee_setapp(struct net_device *dev,
39662306a36Sopenharmony_ci				      struct dcb_app *app)
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
39962306a36Sopenharmony_ci	int err;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	err = mlxsw_sp_dcbnl_app_validate(dev, app);
40262306a36Sopenharmony_ci	if (err)
40362306a36Sopenharmony_ci		return err;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	err = dcb_ieee_setapp(dev, app);
40662306a36Sopenharmony_ci	if (err)
40762306a36Sopenharmony_ci		return err;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	err = mlxsw_sp_port_dcb_app_update(mlxsw_sp_port);
41062306a36Sopenharmony_ci	if (err)
41162306a36Sopenharmony_ci		goto err_update;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	return 0;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cierr_update:
41662306a36Sopenharmony_ci	dcb_ieee_delapp(dev, app);
41762306a36Sopenharmony_ci	return err;
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic int mlxsw_sp_dcbnl_ieee_delapp(struct net_device *dev,
42162306a36Sopenharmony_ci				      struct dcb_app *app)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
42462306a36Sopenharmony_ci	int err;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	err = dcb_ieee_delapp(dev, app);
42762306a36Sopenharmony_ci	if (err)
42862306a36Sopenharmony_ci		return err;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	err = mlxsw_sp_port_dcb_app_update(mlxsw_sp_port);
43162306a36Sopenharmony_ci	if (err)
43262306a36Sopenharmony_ci		netdev_err(dev, "Failed to update DCB APP configuration\n");
43362306a36Sopenharmony_ci	return 0;
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic int mlxsw_sp_dcbnl_ieee_getmaxrate(struct net_device *dev,
43762306a36Sopenharmony_ci					  struct ieee_maxrate *maxrate)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	memcpy(maxrate, mlxsw_sp_port->dcb.maxrate, sizeof(*maxrate));
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	return 0;
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_cistatic int mlxsw_sp_dcbnl_ieee_setmaxrate(struct net_device *dev,
44762306a36Sopenharmony_ci					  struct ieee_maxrate *maxrate)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
45062306a36Sopenharmony_ci	struct ieee_maxrate *my_maxrate = mlxsw_sp_port->dcb.maxrate;
45162306a36Sopenharmony_ci	int err, i;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
45462306a36Sopenharmony_ci		err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,
45562306a36Sopenharmony_ci						    MLXSW_REG_QEEC_HR_SUBGROUP,
45662306a36Sopenharmony_ci						    i, 0,
45762306a36Sopenharmony_ci						    maxrate->tc_maxrate[i], 0);
45862306a36Sopenharmony_ci		if (err) {
45962306a36Sopenharmony_ci			netdev_err(dev, "Failed to set maxrate for TC %d\n", i);
46062306a36Sopenharmony_ci			goto err_port_ets_maxrate_set;
46162306a36Sopenharmony_ci		}
46262306a36Sopenharmony_ci	}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	memcpy(mlxsw_sp_port->dcb.maxrate, maxrate, sizeof(*maxrate));
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	return 0;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_cierr_port_ets_maxrate_set:
46962306a36Sopenharmony_ci	for (i--; i >= 0; i--)
47062306a36Sopenharmony_ci		mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,
47162306a36Sopenharmony_ci					      MLXSW_REG_QEEC_HR_SUBGROUP,
47262306a36Sopenharmony_ci					      i, 0,
47362306a36Sopenharmony_ci					      my_maxrate->tc_maxrate[i], 0);
47462306a36Sopenharmony_ci	return err;
47562306a36Sopenharmony_ci}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_cistatic int mlxsw_sp_port_pfc_cnt_get(struct mlxsw_sp_port *mlxsw_sp_port,
47862306a36Sopenharmony_ci				     u8 prio)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
48162306a36Sopenharmony_ci	struct ieee_pfc *my_pfc = mlxsw_sp_port->dcb.pfc;
48262306a36Sopenharmony_ci	char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
48362306a36Sopenharmony_ci	int err;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	mlxsw_reg_ppcnt_pack(ppcnt_pl, mlxsw_sp_port->local_port,
48662306a36Sopenharmony_ci			     MLXSW_REG_PPCNT_PRIO_CNT, prio);
48762306a36Sopenharmony_ci	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ppcnt), ppcnt_pl);
48862306a36Sopenharmony_ci	if (err)
48962306a36Sopenharmony_ci		return err;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	my_pfc->requests[prio] = mlxsw_reg_ppcnt_tx_pause_get(ppcnt_pl);
49262306a36Sopenharmony_ci	my_pfc->indications[prio] = mlxsw_reg_ppcnt_rx_pause_get(ppcnt_pl);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	return 0;
49562306a36Sopenharmony_ci}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_cistatic int mlxsw_sp_dcbnl_ieee_getpfc(struct net_device *dev,
49862306a36Sopenharmony_ci				      struct ieee_pfc *pfc)
49962306a36Sopenharmony_ci{
50062306a36Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
50162306a36Sopenharmony_ci	int err, i;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
50462306a36Sopenharmony_ci		err = mlxsw_sp_port_pfc_cnt_get(mlxsw_sp_port, i);
50562306a36Sopenharmony_ci		if (err) {
50662306a36Sopenharmony_ci			netdev_err(dev, "Failed to get PFC count for priority %d\n",
50762306a36Sopenharmony_ci				   i);
50862306a36Sopenharmony_ci			return err;
50962306a36Sopenharmony_ci		}
51062306a36Sopenharmony_ci	}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	memcpy(pfc, mlxsw_sp_port->dcb.pfc, sizeof(*pfc));
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	return 0;
51562306a36Sopenharmony_ci}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_cistatic int mlxsw_sp_port_pfc_set(struct mlxsw_sp_port *mlxsw_sp_port,
51862306a36Sopenharmony_ci				 struct ieee_pfc *pfc)
51962306a36Sopenharmony_ci{
52062306a36Sopenharmony_ci	char pfcc_pl[MLXSW_REG_PFCC_LEN];
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	mlxsw_reg_pfcc_pack(pfcc_pl, mlxsw_sp_port->local_port);
52362306a36Sopenharmony_ci	mlxsw_reg_pfcc_pprx_set(pfcc_pl, mlxsw_sp_port->link.rx_pause);
52462306a36Sopenharmony_ci	mlxsw_reg_pfcc_pptx_set(pfcc_pl, mlxsw_sp_port->link.tx_pause);
52562306a36Sopenharmony_ci	mlxsw_reg_pfcc_prio_pack(pfcc_pl, pfc->pfc_en);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pfcc),
52862306a36Sopenharmony_ci			       pfcc_pl);
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cistatic int mlxsw_sp_dcbnl_ieee_setpfc(struct net_device *dev,
53262306a36Sopenharmony_ci				      struct ieee_pfc *pfc)
53362306a36Sopenharmony_ci{
53462306a36Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
53562306a36Sopenharmony_ci	bool pause_en = mlxsw_sp_port_is_pause_en(mlxsw_sp_port);
53662306a36Sopenharmony_ci	struct mlxsw_sp_hdroom orig_hdroom;
53762306a36Sopenharmony_ci	struct mlxsw_sp_hdroom hdroom;
53862306a36Sopenharmony_ci	int prio;
53962306a36Sopenharmony_ci	int err;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	if (pause_en && pfc->pfc_en) {
54262306a36Sopenharmony_ci		netdev_err(dev, "PAUSE frames already enabled on port\n");
54362306a36Sopenharmony_ci		return -EINVAL;
54462306a36Sopenharmony_ci	}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	orig_hdroom = *mlxsw_sp_port->hdroom;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	hdroom = orig_hdroom;
54962306a36Sopenharmony_ci	if (pfc->pfc_en)
55062306a36Sopenharmony_ci		hdroom.delay_bytes = DIV_ROUND_UP(pfc->delay, BITS_PER_BYTE);
55162306a36Sopenharmony_ci	else
55262306a36Sopenharmony_ci		hdroom.delay_bytes = 0;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++)
55562306a36Sopenharmony_ci		hdroom.prios.prio[prio].lossy = !(pfc->pfc_en & BIT(prio));
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom);
55862306a36Sopenharmony_ci	mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
56162306a36Sopenharmony_ci	if (err) {
56262306a36Sopenharmony_ci		netdev_err(dev, "Failed to configure port's headroom for PFC\n");
56362306a36Sopenharmony_ci		return err;
56462306a36Sopenharmony_ci	}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	err = mlxsw_sp_port_pfc_set(mlxsw_sp_port, pfc);
56762306a36Sopenharmony_ci	if (err) {
56862306a36Sopenharmony_ci		netdev_err(dev, "Failed to configure PFC\n");
56962306a36Sopenharmony_ci		goto err_port_pfc_set;
57062306a36Sopenharmony_ci	}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	memcpy(mlxsw_sp_port->dcb.pfc, pfc, sizeof(*pfc));
57362306a36Sopenharmony_ci	mlxsw_sp_port->dcb.pfc->pfc_cap = IEEE_8021QAZ_MAX_TCS;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	return 0;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_cierr_port_pfc_set:
57862306a36Sopenharmony_ci	mlxsw_sp_hdroom_configure(mlxsw_sp_port, &orig_hdroom);
57962306a36Sopenharmony_ci	return err;
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic int mlxsw_sp_dcbnl_getbuffer(struct net_device *dev, struct dcbnl_buffer *buf)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
58562306a36Sopenharmony_ci	struct mlxsw_sp_hdroom *hdroom = mlxsw_sp_port->hdroom;
58662306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
58762306a36Sopenharmony_ci	int prio;
58862306a36Sopenharmony_ci	int i;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	buf->total_size = 0;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	BUILD_BUG_ON(DCBX_MAX_BUFFERS > MLXSW_SP_PB_COUNT);
59362306a36Sopenharmony_ci	for (i = 0; i < MLXSW_SP_PB_COUNT; i++) {
59462306a36Sopenharmony_ci		u32 bytes = mlxsw_sp_cells_bytes(mlxsw_sp, hdroom->bufs.buf[i].size_cells);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci		if (i < DCBX_MAX_BUFFERS)
59762306a36Sopenharmony_ci			buf->buffer_size[i] = bytes;
59862306a36Sopenharmony_ci		buf->total_size += bytes;
59962306a36Sopenharmony_ci	}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	buf->total_size += mlxsw_sp_cells_bytes(mlxsw_sp, hdroom->int_buf.size_cells);
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	for (prio = 0; prio < IEEE_8021Q_MAX_PRIORITIES; prio++)
60462306a36Sopenharmony_ci		buf->prio2buffer[prio] = hdroom->prios.prio[prio].buf_idx;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	return 0;
60762306a36Sopenharmony_ci}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_cistatic int mlxsw_sp_dcbnl_setbuffer(struct net_device *dev, struct dcbnl_buffer *buf)
61062306a36Sopenharmony_ci{
61162306a36Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
61262306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
61362306a36Sopenharmony_ci	struct mlxsw_sp_hdroom hdroom;
61462306a36Sopenharmony_ci	int prio;
61562306a36Sopenharmony_ci	int i;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	hdroom = *mlxsw_sp_port->hdroom;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	if (hdroom.mode != MLXSW_SP_HDROOM_MODE_TC) {
62062306a36Sopenharmony_ci		netdev_err(dev, "The use of dcbnl_setbuffer is only allowed if egress is configured using TC\n");
62162306a36Sopenharmony_ci		return -EINVAL;
62262306a36Sopenharmony_ci	}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	for (prio = 0; prio < IEEE_8021Q_MAX_PRIORITIES; prio++)
62562306a36Sopenharmony_ci		hdroom.prios.prio[prio].set_buf_idx = buf->prio2buffer[prio];
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	BUILD_BUG_ON(DCBX_MAX_BUFFERS > MLXSW_SP_PB_COUNT);
62862306a36Sopenharmony_ci	for (i = 0; i < DCBX_MAX_BUFFERS; i++)
62962306a36Sopenharmony_ci		hdroom.bufs.buf[i].set_size_cells = mlxsw_sp_bytes_cells(mlxsw_sp,
63062306a36Sopenharmony_ci									 buf->buffer_size[i]);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	mlxsw_sp_hdroom_prios_reset_buf_idx(&hdroom);
63362306a36Sopenharmony_ci	mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom);
63462306a36Sopenharmony_ci	mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
63562306a36Sopenharmony_ci	return mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_cistatic const struct dcbnl_rtnl_ops mlxsw_sp_dcbnl_ops = {
63962306a36Sopenharmony_ci	.ieee_getets		= mlxsw_sp_dcbnl_ieee_getets,
64062306a36Sopenharmony_ci	.ieee_setets		= mlxsw_sp_dcbnl_ieee_setets,
64162306a36Sopenharmony_ci	.ieee_getmaxrate	= mlxsw_sp_dcbnl_ieee_getmaxrate,
64262306a36Sopenharmony_ci	.ieee_setmaxrate	= mlxsw_sp_dcbnl_ieee_setmaxrate,
64362306a36Sopenharmony_ci	.ieee_getpfc		= mlxsw_sp_dcbnl_ieee_getpfc,
64462306a36Sopenharmony_ci	.ieee_setpfc		= mlxsw_sp_dcbnl_ieee_setpfc,
64562306a36Sopenharmony_ci	.ieee_setapp		= mlxsw_sp_dcbnl_ieee_setapp,
64662306a36Sopenharmony_ci	.ieee_delapp		= mlxsw_sp_dcbnl_ieee_delapp,
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	.getdcbx		= mlxsw_sp_dcbnl_getdcbx,
64962306a36Sopenharmony_ci	.setdcbx		= mlxsw_sp_dcbnl_setdcbx,
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	.dcbnl_getbuffer	= mlxsw_sp_dcbnl_getbuffer,
65262306a36Sopenharmony_ci	.dcbnl_setbuffer	= mlxsw_sp_dcbnl_setbuffer,
65362306a36Sopenharmony_ci};
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_cistatic int mlxsw_sp_port_ets_init(struct mlxsw_sp_port *mlxsw_sp_port)
65662306a36Sopenharmony_ci{
65762306a36Sopenharmony_ci	mlxsw_sp_port->dcb.ets = kzalloc(sizeof(*mlxsw_sp_port->dcb.ets),
65862306a36Sopenharmony_ci					 GFP_KERNEL);
65962306a36Sopenharmony_ci	if (!mlxsw_sp_port->dcb.ets)
66062306a36Sopenharmony_ci		return -ENOMEM;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	mlxsw_sp_port->dcb.ets->ets_cap = IEEE_8021QAZ_MAX_TCS;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	return 0;
66562306a36Sopenharmony_ci}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_cistatic void mlxsw_sp_port_ets_fini(struct mlxsw_sp_port *mlxsw_sp_port)
66862306a36Sopenharmony_ci{
66962306a36Sopenharmony_ci	kfree(mlxsw_sp_port->dcb.ets);
67062306a36Sopenharmony_ci}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_cistatic int mlxsw_sp_port_maxrate_init(struct mlxsw_sp_port *mlxsw_sp_port)
67362306a36Sopenharmony_ci{
67462306a36Sopenharmony_ci	int i;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	mlxsw_sp_port->dcb.maxrate = kmalloc(sizeof(*mlxsw_sp_port->dcb.maxrate),
67762306a36Sopenharmony_ci					     GFP_KERNEL);
67862306a36Sopenharmony_ci	if (!mlxsw_sp_port->dcb.maxrate)
67962306a36Sopenharmony_ci		return -ENOMEM;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
68262306a36Sopenharmony_ci		mlxsw_sp_port->dcb.maxrate->tc_maxrate[i] = MLXSW_REG_QEEC_MAS_DIS;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	return 0;
68562306a36Sopenharmony_ci}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_cistatic void mlxsw_sp_port_maxrate_fini(struct mlxsw_sp_port *mlxsw_sp_port)
68862306a36Sopenharmony_ci{
68962306a36Sopenharmony_ci	kfree(mlxsw_sp_port->dcb.maxrate);
69062306a36Sopenharmony_ci}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_cistatic int mlxsw_sp_port_pfc_init(struct mlxsw_sp_port *mlxsw_sp_port)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	mlxsw_sp_port->dcb.pfc = kzalloc(sizeof(*mlxsw_sp_port->dcb.pfc),
69562306a36Sopenharmony_ci					 GFP_KERNEL);
69662306a36Sopenharmony_ci	if (!mlxsw_sp_port->dcb.pfc)
69762306a36Sopenharmony_ci		return -ENOMEM;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	mlxsw_sp_port->dcb.pfc->pfc_cap = IEEE_8021QAZ_MAX_TCS;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	return 0;
70262306a36Sopenharmony_ci}
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_cistatic void mlxsw_sp_port_pfc_fini(struct mlxsw_sp_port *mlxsw_sp_port)
70562306a36Sopenharmony_ci{
70662306a36Sopenharmony_ci	kfree(mlxsw_sp_port->dcb.pfc);
70762306a36Sopenharmony_ci}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ciint mlxsw_sp_port_dcb_init(struct mlxsw_sp_port *mlxsw_sp_port)
71062306a36Sopenharmony_ci{
71162306a36Sopenharmony_ci	int err;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	err = mlxsw_sp_port_ets_init(mlxsw_sp_port);
71462306a36Sopenharmony_ci	if (err)
71562306a36Sopenharmony_ci		return err;
71662306a36Sopenharmony_ci	err = mlxsw_sp_port_maxrate_init(mlxsw_sp_port);
71762306a36Sopenharmony_ci	if (err)
71862306a36Sopenharmony_ci		goto err_port_maxrate_init;
71962306a36Sopenharmony_ci	err = mlxsw_sp_port_pfc_init(mlxsw_sp_port);
72062306a36Sopenharmony_ci	if (err)
72162306a36Sopenharmony_ci		goto err_port_pfc_init;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	mlxsw_sp_port->dcb.trust_state = MLXSW_REG_QPTS_TRUST_STATE_PCP;
72462306a36Sopenharmony_ci	mlxsw_sp_port->dev->dcbnl_ops = &mlxsw_sp_dcbnl_ops;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	return 0;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_cierr_port_pfc_init:
72962306a36Sopenharmony_ci	mlxsw_sp_port_maxrate_fini(mlxsw_sp_port);
73062306a36Sopenharmony_cierr_port_maxrate_init:
73162306a36Sopenharmony_ci	mlxsw_sp_port_ets_fini(mlxsw_sp_port);
73262306a36Sopenharmony_ci	return err;
73362306a36Sopenharmony_ci}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_civoid mlxsw_sp_port_dcb_fini(struct mlxsw_sp_port *mlxsw_sp_port)
73662306a36Sopenharmony_ci{
73762306a36Sopenharmony_ci	mlxsw_sp_port_pfc_fini(mlxsw_sp_port);
73862306a36Sopenharmony_ci	mlxsw_sp_port_maxrate_fini(mlxsw_sp_port);
73962306a36Sopenharmony_ci	mlxsw_sp_port_ets_fini(mlxsw_sp_port);
74062306a36Sopenharmony_ci}
741