162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 262306a36Sopenharmony_ci/* Copyright (C) 2023 Corigine, Inc. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/device.h> 562306a36Sopenharmony_ci#include <linux/netdevice.h> 662306a36Sopenharmony_ci#include <net/dcbnl.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "../nfp_app.h" 962306a36Sopenharmony_ci#include "../nfp_net.h" 1062306a36Sopenharmony_ci#include "../nfp_main.h" 1162306a36Sopenharmony_ci#include "../nfpcore/nfp_cpp.h" 1262306a36Sopenharmony_ci#include "../nfpcore/nfp_nffw.h" 1362306a36Sopenharmony_ci#include "../nfp_net_sriov.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "main.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define NFP_DCB_TRUST_PCP 1 1862306a36Sopenharmony_ci#define NFP_DCB_TRUST_DSCP 2 1962306a36Sopenharmony_ci#define NFP_DCB_TRUST_INVALID 0xff 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define NFP_DCB_TSA_VENDOR 1 2262306a36Sopenharmony_ci#define NFP_DCB_TSA_STRICT 2 2362306a36Sopenharmony_ci#define NFP_DCB_TSA_ETS 3 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define NFP_DCB_GBL_ENABLE BIT(0) 2662306a36Sopenharmony_ci#define NFP_DCB_QOS_ENABLE BIT(1) 2762306a36Sopenharmony_ci#define NFP_DCB_DISABLE 0 2862306a36Sopenharmony_ci#define NFP_DCB_ALL_QOS_ENABLE (NFP_DCB_GBL_ENABLE | NFP_DCB_QOS_ENABLE) 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define NFP_DCB_UPDATE_MSK_SZ 4 3162306a36Sopenharmony_ci#define NFP_DCB_TC_RATE_MAX 0xffff 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define NFP_DCB_DATA_OFF_DSCP2IDX 0 3462306a36Sopenharmony_ci#define NFP_DCB_DATA_OFF_PCP2IDX 64 3562306a36Sopenharmony_ci#define NFP_DCB_DATA_OFF_TSA 80 3662306a36Sopenharmony_ci#define NFP_DCB_DATA_OFF_IDX_BW_PCT 88 3762306a36Sopenharmony_ci#define NFP_DCB_DATA_OFF_RATE 96 3862306a36Sopenharmony_ci#define NFP_DCB_DATA_OFF_CAP 112 3962306a36Sopenharmony_ci#define NFP_DCB_DATA_OFF_ENABLE 116 4062306a36Sopenharmony_ci#define NFP_DCB_DATA_OFF_TRUST 120 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define NFP_DCB_MSG_MSK_ENABLE BIT(31) 4362306a36Sopenharmony_ci#define NFP_DCB_MSG_MSK_TRUST BIT(30) 4462306a36Sopenharmony_ci#define NFP_DCB_MSG_MSK_TSA BIT(29) 4562306a36Sopenharmony_ci#define NFP_DCB_MSG_MSK_DSCP BIT(28) 4662306a36Sopenharmony_ci#define NFP_DCB_MSG_MSK_PCP BIT(27) 4762306a36Sopenharmony_ci#define NFP_DCB_MSG_MSK_RATE BIT(26) 4862306a36Sopenharmony_ci#define NFP_DCB_MSG_MSK_PCT BIT(25) 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic struct nfp_dcb *get_dcb_priv(struct nfp_net *nn) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci struct nfp_dcb *dcb = &((struct nfp_app_nic_private *)nn->app_priv)->dcb; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci return dcb; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic u8 nfp_tsa_ieee2nfp(u8 tsa) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci switch (tsa) { 6062306a36Sopenharmony_ci case IEEE_8021QAZ_TSA_STRICT: 6162306a36Sopenharmony_ci return NFP_DCB_TSA_STRICT; 6262306a36Sopenharmony_ci case IEEE_8021QAZ_TSA_ETS: 6362306a36Sopenharmony_ci return NFP_DCB_TSA_ETS; 6462306a36Sopenharmony_ci default: 6562306a36Sopenharmony_ci return NFP_DCB_TSA_VENDOR; 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic int nfp_nic_dcbnl_ieee_getets(struct net_device *dev, 7062306a36Sopenharmony_ci struct ieee_ets *ets) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct nfp_net *nn = netdev_priv(dev); 7362306a36Sopenharmony_ci struct nfp_dcb *dcb; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci dcb = get_dcb_priv(nn); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci for (unsigned int i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 7862306a36Sopenharmony_ci ets->prio_tc[i] = dcb->prio2tc[i]; 7962306a36Sopenharmony_ci ets->tc_tx_bw[i] = dcb->tc_tx_pct[i]; 8062306a36Sopenharmony_ci ets->tc_tsa[i] = dcb->tc_tsa[i]; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci return 0; 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic bool nfp_refresh_tc2idx(struct nfp_net *nn) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci u8 tc2idx[IEEE_8021QAZ_MAX_TCS]; 8962306a36Sopenharmony_ci bool change = false; 9062306a36Sopenharmony_ci struct nfp_dcb *dcb; 9162306a36Sopenharmony_ci int maxstrict = 0; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci dcb = get_dcb_priv(nn); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci for (unsigned int i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 9662306a36Sopenharmony_ci tc2idx[i] = i; 9762306a36Sopenharmony_ci if (dcb->tc_tsa[i] == IEEE_8021QAZ_TSA_STRICT) 9862306a36Sopenharmony_ci maxstrict = i; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (maxstrict > 0 && dcb->tc_tsa[0] != IEEE_8021QAZ_TSA_STRICT) { 10262306a36Sopenharmony_ci tc2idx[0] = maxstrict; 10362306a36Sopenharmony_ci tc2idx[maxstrict] = 0; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci for (unsigned int j = 0; j < IEEE_8021QAZ_MAX_TCS; j++) { 10762306a36Sopenharmony_ci if (dcb->tc2idx[j] != tc2idx[j]) { 10862306a36Sopenharmony_ci change = true; 10962306a36Sopenharmony_ci dcb->tc2idx[j] = tc2idx[j]; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return change; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic int nfp_fill_maxrate(struct nfp_net *nn, u64 *max_rate_array) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci struct nfp_app *app = nn->app; 11962306a36Sopenharmony_ci struct nfp_dcb *dcb; 12062306a36Sopenharmony_ci u32 ratembps; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci dcb = get_dcb_priv(nn); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci for (unsigned int i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 12562306a36Sopenharmony_ci /* Convert bandwidth from kbps to mbps. */ 12662306a36Sopenharmony_ci ratembps = max_rate_array[i] / 1024; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci /* Reject input values >= NFP_DCB_TC_RATE_MAX */ 12962306a36Sopenharmony_ci if (ratembps >= NFP_DCB_TC_RATE_MAX) { 13062306a36Sopenharmony_ci nfp_warn(app->cpp, "ratembps(%d) must less than %d.", 13162306a36Sopenharmony_ci ratembps, NFP_DCB_TC_RATE_MAX); 13262306a36Sopenharmony_ci return -EINVAL; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci /* Input value 0 mapped to NFP_DCB_TC_RATE_MAX for firmware. */ 13562306a36Sopenharmony_ci if (ratembps == 0) 13662306a36Sopenharmony_ci ratembps = NFP_DCB_TC_RATE_MAX; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci writew((u16)ratembps, dcb->dcbcfg_tbl + 13962306a36Sopenharmony_ci dcb->cfg_offset + NFP_DCB_DATA_OFF_RATE + dcb->tc2idx[i] * 2); 14062306a36Sopenharmony_ci /* for rate value from user space, need to sync to dcb structure */ 14162306a36Sopenharmony_ci if (dcb->tc_maxrate != max_rate_array) 14262306a36Sopenharmony_ci dcb->tc_maxrate[i] = max_rate_array[i]; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci return 0; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic int update_dscp_maxrate(struct net_device *dev, u32 *update) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci struct nfp_net *nn = netdev_priv(dev); 15162306a36Sopenharmony_ci struct nfp_dcb *dcb; 15262306a36Sopenharmony_ci int err; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci dcb = get_dcb_priv(nn); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci err = nfp_fill_maxrate(nn, dcb->tc_maxrate); 15762306a36Sopenharmony_ci if (err) 15862306a36Sopenharmony_ci return err; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci *update |= NFP_DCB_MSG_MSK_RATE; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* We only refresh dscp in dscp trust mode. */ 16362306a36Sopenharmony_ci if (dcb->dscp_cnt > 0) { 16462306a36Sopenharmony_ci for (unsigned int i = 0; i < NFP_NET_MAX_DSCP; i++) { 16562306a36Sopenharmony_ci writeb(dcb->tc2idx[dcb->prio2tc[dcb->dscp2prio[i]]], 16662306a36Sopenharmony_ci dcb->dcbcfg_tbl + dcb->cfg_offset + 16762306a36Sopenharmony_ci NFP_DCB_DATA_OFF_DSCP2IDX + i); 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci *update |= NFP_DCB_MSG_MSK_DSCP; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci return 0; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic void nfp_nic_set_trust(struct nfp_net *nn, u32 *update) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci struct nfp_dcb *dcb; 17862306a36Sopenharmony_ci u8 trust; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci dcb = get_dcb_priv(nn); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (dcb->trust_status != NFP_DCB_TRUST_INVALID) 18362306a36Sopenharmony_ci return; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci trust = dcb->dscp_cnt > 0 ? NFP_DCB_TRUST_DSCP : NFP_DCB_TRUST_PCP; 18662306a36Sopenharmony_ci writeb(trust, dcb->dcbcfg_tbl + dcb->cfg_offset + 18762306a36Sopenharmony_ci NFP_DCB_DATA_OFF_TRUST); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci dcb->trust_status = trust; 19062306a36Sopenharmony_ci *update |= NFP_DCB_MSG_MSK_TRUST; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic void nfp_nic_set_enable(struct nfp_net *nn, u32 enable, u32 *update) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci struct nfp_dcb *dcb; 19662306a36Sopenharmony_ci u32 value = 0; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci dcb = get_dcb_priv(nn); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci value = readl(dcb->dcbcfg_tbl + dcb->cfg_offset + 20162306a36Sopenharmony_ci NFP_DCB_DATA_OFF_ENABLE); 20262306a36Sopenharmony_ci if (value != enable) { 20362306a36Sopenharmony_ci writel(enable, dcb->dcbcfg_tbl + dcb->cfg_offset + 20462306a36Sopenharmony_ci NFP_DCB_DATA_OFF_ENABLE); 20562306a36Sopenharmony_ci *update |= NFP_DCB_MSG_MSK_ENABLE; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic int dcb_ets_check(struct net_device *dev, struct ieee_ets *ets) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci struct nfp_net *nn = netdev_priv(dev); 21262306a36Sopenharmony_ci struct nfp_app *app = nn->app; 21362306a36Sopenharmony_ci bool ets_exists = false; 21462306a36Sopenharmony_ci int sum = 0; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci for (unsigned int i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 21762306a36Sopenharmony_ci /* For ets mode, check bw percentage sum. */ 21862306a36Sopenharmony_ci if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS) { 21962306a36Sopenharmony_ci ets_exists = true; 22062306a36Sopenharmony_ci sum += ets->tc_tx_bw[i]; 22162306a36Sopenharmony_ci } else if (ets->tc_tx_bw[i]) { 22262306a36Sopenharmony_ci nfp_warn(app->cpp, "ETS BW for strict/vendor TC must be 0."); 22362306a36Sopenharmony_ci return -EINVAL; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (ets_exists && sum != 100) { 22862306a36Sopenharmony_ci nfp_warn(app->cpp, "Failed to validate ETS BW: sum must be 100."); 22962306a36Sopenharmony_ci return -EINVAL; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci return 0; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic void nfp_nic_fill_ets(struct nfp_net *nn) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci struct nfp_dcb *dcb; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci dcb = get_dcb_priv(nn); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci for (unsigned int i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 24262306a36Sopenharmony_ci writeb(dcb->tc2idx[dcb->prio2tc[i]], 24362306a36Sopenharmony_ci dcb->dcbcfg_tbl + dcb->cfg_offset + NFP_DCB_DATA_OFF_PCP2IDX + i); 24462306a36Sopenharmony_ci writeb(dcb->tc_tx_pct[i], dcb->dcbcfg_tbl + 24562306a36Sopenharmony_ci dcb->cfg_offset + NFP_DCB_DATA_OFF_IDX_BW_PCT + dcb->tc2idx[i]); 24662306a36Sopenharmony_ci writeb(nfp_tsa_ieee2nfp(dcb->tc_tsa[i]), dcb->dcbcfg_tbl + 24762306a36Sopenharmony_ci dcb->cfg_offset + NFP_DCB_DATA_OFF_TSA + dcb->tc2idx[i]); 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic void nfp_nic_ets_init(struct nfp_net *nn, u32 *update) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci struct nfp_dcb *dcb = get_dcb_priv(nn); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci if (dcb->ets_init) 25662306a36Sopenharmony_ci return; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci nfp_nic_fill_ets(nn); 25962306a36Sopenharmony_ci dcb->ets_init = true; 26062306a36Sopenharmony_ci *update |= NFP_DCB_MSG_MSK_TSA | NFP_DCB_MSG_MSK_PCT | NFP_DCB_MSG_MSK_PCP; 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic int nfp_nic_dcbnl_ieee_setets(struct net_device *dev, 26462306a36Sopenharmony_ci struct ieee_ets *ets) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci const u32 cmd = NFP_NET_CFG_MBOX_CMD_DCB_UPDATE; 26762306a36Sopenharmony_ci struct nfp_net *nn = netdev_priv(dev); 26862306a36Sopenharmony_ci struct nfp_app *app = nn->app; 26962306a36Sopenharmony_ci struct nfp_dcb *dcb; 27062306a36Sopenharmony_ci u32 update = 0; 27162306a36Sopenharmony_ci bool change; 27262306a36Sopenharmony_ci int err; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci err = dcb_ets_check(dev, ets); 27562306a36Sopenharmony_ci if (err) 27662306a36Sopenharmony_ci return err; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci dcb = get_dcb_priv(nn); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci for (unsigned int i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 28162306a36Sopenharmony_ci dcb->prio2tc[i] = ets->prio_tc[i]; 28262306a36Sopenharmony_ci dcb->tc_tx_pct[i] = ets->tc_tx_bw[i]; 28362306a36Sopenharmony_ci dcb->tc_tsa[i] = ets->tc_tsa[i]; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci change = nfp_refresh_tc2idx(nn); 28762306a36Sopenharmony_ci nfp_nic_fill_ets(nn); 28862306a36Sopenharmony_ci dcb->ets_init = true; 28962306a36Sopenharmony_ci if (change || !dcb->rate_init) { 29062306a36Sopenharmony_ci err = update_dscp_maxrate(dev, &update); 29162306a36Sopenharmony_ci if (err) { 29262306a36Sopenharmony_ci nfp_warn(app->cpp, 29362306a36Sopenharmony_ci "nfp dcbnl ieee setets ERROR:%d.", 29462306a36Sopenharmony_ci err); 29562306a36Sopenharmony_ci return err; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci dcb->rate_init = true; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci nfp_nic_set_enable(nn, NFP_DCB_ALL_QOS_ENABLE, &update); 30162306a36Sopenharmony_ci nfp_nic_set_trust(nn, &update); 30262306a36Sopenharmony_ci err = nfp_net_mbox_lock(nn, NFP_DCB_UPDATE_MSK_SZ); 30362306a36Sopenharmony_ci if (err) 30462306a36Sopenharmony_ci return err; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci nn_writel(nn, nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL, 30762306a36Sopenharmony_ci update | NFP_DCB_MSG_MSK_TSA | NFP_DCB_MSG_MSK_PCT | 30862306a36Sopenharmony_ci NFP_DCB_MSG_MSK_PCP); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci return nfp_net_mbox_reconfig_and_unlock(nn, cmd); 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic int nfp_nic_dcbnl_ieee_getmaxrate(struct net_device *dev, 31462306a36Sopenharmony_ci struct ieee_maxrate *maxrate) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci struct nfp_net *nn = netdev_priv(dev); 31762306a36Sopenharmony_ci struct nfp_dcb *dcb; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci dcb = get_dcb_priv(nn); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci for (unsigned int i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) 32262306a36Sopenharmony_ci maxrate->tc_maxrate[i] = dcb->tc_maxrate[i]; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci return 0; 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic int nfp_nic_dcbnl_ieee_setmaxrate(struct net_device *dev, 32862306a36Sopenharmony_ci struct ieee_maxrate *maxrate) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci const u32 cmd = NFP_NET_CFG_MBOX_CMD_DCB_UPDATE; 33162306a36Sopenharmony_ci struct nfp_net *nn = netdev_priv(dev); 33262306a36Sopenharmony_ci struct nfp_app *app = nn->app; 33362306a36Sopenharmony_ci struct nfp_dcb *dcb; 33462306a36Sopenharmony_ci u32 update = 0; 33562306a36Sopenharmony_ci int err; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci err = nfp_fill_maxrate(nn, maxrate->tc_maxrate); 33862306a36Sopenharmony_ci if (err) { 33962306a36Sopenharmony_ci nfp_warn(app->cpp, 34062306a36Sopenharmony_ci "nfp dcbnl ieee setmaxrate ERROR:%d.", 34162306a36Sopenharmony_ci err); 34262306a36Sopenharmony_ci return err; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci dcb = get_dcb_priv(nn); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci dcb->rate_init = true; 34862306a36Sopenharmony_ci nfp_nic_set_enable(nn, NFP_DCB_ALL_QOS_ENABLE, &update); 34962306a36Sopenharmony_ci nfp_nic_set_trust(nn, &update); 35062306a36Sopenharmony_ci nfp_nic_ets_init(nn, &update); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci err = nfp_net_mbox_lock(nn, NFP_DCB_UPDATE_MSK_SZ); 35362306a36Sopenharmony_ci if (err) 35462306a36Sopenharmony_ci return err; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci nn_writel(nn, nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL, 35762306a36Sopenharmony_ci update | NFP_DCB_MSG_MSK_RATE); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci return nfp_net_mbox_reconfig_and_unlock(nn, cmd); 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic int nfp_nic_set_trust_status(struct nfp_net *nn, u8 status) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci const u32 cmd = NFP_NET_CFG_MBOX_CMD_DCB_UPDATE; 36562306a36Sopenharmony_ci struct nfp_dcb *dcb; 36662306a36Sopenharmony_ci u32 update = 0; 36762306a36Sopenharmony_ci int err; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci dcb = get_dcb_priv(nn); 37062306a36Sopenharmony_ci if (!dcb->rate_init) { 37162306a36Sopenharmony_ci err = nfp_fill_maxrate(nn, dcb->tc_maxrate); 37262306a36Sopenharmony_ci if (err) 37362306a36Sopenharmony_ci return err; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci update |= NFP_DCB_MSG_MSK_RATE; 37662306a36Sopenharmony_ci dcb->rate_init = true; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci err = nfp_net_mbox_lock(nn, NFP_DCB_UPDATE_MSK_SZ); 38062306a36Sopenharmony_ci if (err) 38162306a36Sopenharmony_ci return err; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci nfp_nic_ets_init(nn, &update); 38462306a36Sopenharmony_ci writeb(status, dcb->dcbcfg_tbl + dcb->cfg_offset + 38562306a36Sopenharmony_ci NFP_DCB_DATA_OFF_TRUST); 38662306a36Sopenharmony_ci nfp_nic_set_enable(nn, NFP_DCB_ALL_QOS_ENABLE, &update); 38762306a36Sopenharmony_ci nn_writel(nn, nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL, 38862306a36Sopenharmony_ci update | NFP_DCB_MSG_MSK_TRUST); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci err = nfp_net_mbox_reconfig_and_unlock(nn, cmd); 39162306a36Sopenharmony_ci if (err) 39262306a36Sopenharmony_ci return err; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci dcb->trust_status = status; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci return 0; 39762306a36Sopenharmony_ci} 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cistatic int nfp_nic_set_dscp2prio(struct nfp_net *nn, u8 dscp, u8 prio) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci const u32 cmd = NFP_NET_CFG_MBOX_CMD_DCB_UPDATE; 40262306a36Sopenharmony_ci struct nfp_dcb *dcb; 40362306a36Sopenharmony_ci u8 idx, tc; 40462306a36Sopenharmony_ci int err; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci err = nfp_net_mbox_lock(nn, NFP_DCB_UPDATE_MSK_SZ); 40762306a36Sopenharmony_ci if (err) 40862306a36Sopenharmony_ci return err; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci dcb = get_dcb_priv(nn); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci tc = dcb->prio2tc[prio]; 41362306a36Sopenharmony_ci idx = dcb->tc2idx[tc]; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci writeb(idx, dcb->dcbcfg_tbl + dcb->cfg_offset + 41662306a36Sopenharmony_ci NFP_DCB_DATA_OFF_DSCP2IDX + dscp); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci nn_writel(nn, nn->tlv_caps.mbox_off + 41962306a36Sopenharmony_ci NFP_NET_CFG_MBOX_SIMPLE_VAL, NFP_DCB_MSG_MSK_DSCP); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci err = nfp_net_mbox_reconfig_and_unlock(nn, cmd); 42262306a36Sopenharmony_ci if (err) 42362306a36Sopenharmony_ci return err; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci dcb->dscp2prio[dscp] = prio; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci return 0; 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic int nfp_nic_dcbnl_ieee_setapp(struct net_device *dev, 43162306a36Sopenharmony_ci struct dcb_app *app) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci struct nfp_net *nn = netdev_priv(dev); 43462306a36Sopenharmony_ci struct dcb_app old_app; 43562306a36Sopenharmony_ci struct nfp_dcb *dcb; 43662306a36Sopenharmony_ci bool is_new; 43762306a36Sopenharmony_ci int err; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (app->selector != IEEE_8021QAZ_APP_SEL_DSCP) 44062306a36Sopenharmony_ci return -EINVAL; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci dcb = get_dcb_priv(nn); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci /* Save the old entry info */ 44562306a36Sopenharmony_ci old_app.selector = IEEE_8021QAZ_APP_SEL_DSCP; 44662306a36Sopenharmony_ci old_app.protocol = app->protocol; 44762306a36Sopenharmony_ci old_app.priority = dcb->dscp2prio[app->protocol]; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci /* Check trust status */ 45062306a36Sopenharmony_ci if (!dcb->dscp_cnt) { 45162306a36Sopenharmony_ci err = nfp_nic_set_trust_status(nn, NFP_DCB_TRUST_DSCP); 45262306a36Sopenharmony_ci if (err) 45362306a36Sopenharmony_ci return err; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci /* Check if the new mapping is same as old or in init stage */ 45762306a36Sopenharmony_ci if (app->priority != old_app.priority || app->priority == 0) { 45862306a36Sopenharmony_ci err = nfp_nic_set_dscp2prio(nn, app->protocol, app->priority); 45962306a36Sopenharmony_ci if (err) 46062306a36Sopenharmony_ci return err; 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci /* Delete the old entry if exists */ 46462306a36Sopenharmony_ci is_new = !!dcb_ieee_delapp(dev, &old_app); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci /* Add new entry and update counter */ 46762306a36Sopenharmony_ci err = dcb_ieee_setapp(dev, app); 46862306a36Sopenharmony_ci if (err) 46962306a36Sopenharmony_ci return err; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if (is_new) 47262306a36Sopenharmony_ci dcb->dscp_cnt++; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci return 0; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic int nfp_nic_dcbnl_ieee_delapp(struct net_device *dev, 47862306a36Sopenharmony_ci struct dcb_app *app) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci struct nfp_net *nn = netdev_priv(dev); 48162306a36Sopenharmony_ci struct nfp_dcb *dcb; 48262306a36Sopenharmony_ci int err; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci if (app->selector != IEEE_8021QAZ_APP_SEL_DSCP) 48562306a36Sopenharmony_ci return -EINVAL; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci dcb = get_dcb_priv(nn); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci /* Check if the dcb_app param match fw */ 49062306a36Sopenharmony_ci if (app->priority != dcb->dscp2prio[app->protocol]) 49162306a36Sopenharmony_ci return -ENOENT; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci /* Set fw dscp mapping to 0 */ 49462306a36Sopenharmony_ci err = nfp_nic_set_dscp2prio(nn, app->protocol, 0); 49562306a36Sopenharmony_ci if (err) 49662306a36Sopenharmony_ci return err; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci /* Delete app from dcb list */ 49962306a36Sopenharmony_ci err = dcb_ieee_delapp(dev, app); 50062306a36Sopenharmony_ci if (err) 50162306a36Sopenharmony_ci return err; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci /* Decrease dscp counter */ 50462306a36Sopenharmony_ci dcb->dscp_cnt--; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci /* If no dscp mapping is configured, trust pcp */ 50762306a36Sopenharmony_ci if (dcb->dscp_cnt == 0) 50862306a36Sopenharmony_ci return nfp_nic_set_trust_status(nn, NFP_DCB_TRUST_PCP); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci return 0; 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_cistatic const struct dcbnl_rtnl_ops nfp_nic_dcbnl_ops = { 51462306a36Sopenharmony_ci /* ieee 802.1Qaz std */ 51562306a36Sopenharmony_ci .ieee_getets = nfp_nic_dcbnl_ieee_getets, 51662306a36Sopenharmony_ci .ieee_setets = nfp_nic_dcbnl_ieee_setets, 51762306a36Sopenharmony_ci .ieee_getmaxrate = nfp_nic_dcbnl_ieee_getmaxrate, 51862306a36Sopenharmony_ci .ieee_setmaxrate = nfp_nic_dcbnl_ieee_setmaxrate, 51962306a36Sopenharmony_ci .ieee_setapp = nfp_nic_dcbnl_ieee_setapp, 52062306a36Sopenharmony_ci .ieee_delapp = nfp_nic_dcbnl_ieee_delapp, 52162306a36Sopenharmony_ci}; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ciint nfp_nic_dcb_init(struct nfp_net *nn) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci struct nfp_app *app = nn->app; 52662306a36Sopenharmony_ci struct nfp_dcb *dcb; 52762306a36Sopenharmony_ci int err; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci dcb = get_dcb_priv(nn); 53062306a36Sopenharmony_ci dcb->cfg_offset = NFP_DCB_CFG_STRIDE * nn->id; 53162306a36Sopenharmony_ci dcb->dcbcfg_tbl = nfp_pf_map_rtsym(app->pf, "net.dcbcfg_tbl", 53262306a36Sopenharmony_ci "_abi_dcb_cfg", 53362306a36Sopenharmony_ci dcb->cfg_offset, &dcb->dcbcfg_tbl_area); 53462306a36Sopenharmony_ci if (IS_ERR(dcb->dcbcfg_tbl)) { 53562306a36Sopenharmony_ci if (PTR_ERR(dcb->dcbcfg_tbl) != -ENOENT) { 53662306a36Sopenharmony_ci err = PTR_ERR(dcb->dcbcfg_tbl); 53762306a36Sopenharmony_ci dcb->dcbcfg_tbl = NULL; 53862306a36Sopenharmony_ci nfp_err(app->cpp, 53962306a36Sopenharmony_ci "Failed to map dcbcfg_tbl area, min_size %u.\n", 54062306a36Sopenharmony_ci dcb->cfg_offset); 54162306a36Sopenharmony_ci return err; 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci dcb->dcbcfg_tbl = NULL; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (dcb->dcbcfg_tbl) { 54762306a36Sopenharmony_ci for (unsigned int i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 54862306a36Sopenharmony_ci dcb->prio2tc[i] = i; 54962306a36Sopenharmony_ci dcb->tc2idx[i] = i; 55062306a36Sopenharmony_ci dcb->tc_tx_pct[i] = 0; 55162306a36Sopenharmony_ci dcb->tc_maxrate[i] = 0; 55262306a36Sopenharmony_ci dcb->tc_tsa[i] = IEEE_8021QAZ_TSA_VENDOR; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci dcb->trust_status = NFP_DCB_TRUST_INVALID; 55562306a36Sopenharmony_ci dcb->rate_init = false; 55662306a36Sopenharmony_ci dcb->ets_init = false; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci nn->dp.netdev->dcbnl_ops = &nfp_nic_dcbnl_ops; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci return 0; 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_civoid nfp_nic_dcb_clean(struct nfp_net *nn) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci struct nfp_dcb *dcb; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci dcb = get_dcb_priv(nn); 56962306a36Sopenharmony_ci if (dcb->dcbcfg_tbl_area) 57062306a36Sopenharmony_ci nfp_cpp_area_release_free(dcb->dcbcfg_tbl_area); 57162306a36Sopenharmony_ci} 572