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