572 lines · c
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)2/* Copyright (C) 2023 Corigine, Inc. */3 4#include <linux/device.h>5#include <linux/netdevice.h>6#include <net/dcbnl.h>7 8#include "../nfp_app.h"9#include "../nfp_net.h"10#include "../nfp_main.h"11#include "../nfpcore/nfp_cpp.h"12#include "../nfpcore/nfp_nffw.h"13#include "../nfp_net_sriov.h"14 15#include "main.h"16 17#define NFP_DCB_TRUST_PCP 118#define NFP_DCB_TRUST_DSCP 219#define NFP_DCB_TRUST_INVALID 0xff20 21#define NFP_DCB_TSA_VENDOR 122#define NFP_DCB_TSA_STRICT 223#define NFP_DCB_TSA_ETS 324 25#define NFP_DCB_GBL_ENABLE BIT(0)26#define NFP_DCB_QOS_ENABLE BIT(1)27#define NFP_DCB_DISABLE 028#define NFP_DCB_ALL_QOS_ENABLE (NFP_DCB_GBL_ENABLE | NFP_DCB_QOS_ENABLE)29 30#define NFP_DCB_UPDATE_MSK_SZ 431#define NFP_DCB_TC_RATE_MAX 0xffff32 33#define NFP_DCB_DATA_OFF_DSCP2IDX 034#define NFP_DCB_DATA_OFF_PCP2IDX 6435#define NFP_DCB_DATA_OFF_TSA 8036#define NFP_DCB_DATA_OFF_IDX_BW_PCT 8837#define NFP_DCB_DATA_OFF_RATE 9638#define NFP_DCB_DATA_OFF_CAP 11239#define NFP_DCB_DATA_OFF_ENABLE 11640#define NFP_DCB_DATA_OFF_TRUST 12041 42#define NFP_DCB_MSG_MSK_ENABLE BIT(31)43#define NFP_DCB_MSG_MSK_TRUST BIT(30)44#define NFP_DCB_MSG_MSK_TSA BIT(29)45#define NFP_DCB_MSG_MSK_DSCP BIT(28)46#define NFP_DCB_MSG_MSK_PCP BIT(27)47#define NFP_DCB_MSG_MSK_RATE BIT(26)48#define NFP_DCB_MSG_MSK_PCT BIT(25)49 50static struct nfp_dcb *get_dcb_priv(struct nfp_net *nn)51{52 struct nfp_dcb *dcb = &((struct nfp_app_nic_private *)nn->app_priv)->dcb;53 54 return dcb;55}56 57static u8 nfp_tsa_ieee2nfp(u8 tsa)58{59 switch (tsa) {60 case IEEE_8021QAZ_TSA_STRICT:61 return NFP_DCB_TSA_STRICT;62 case IEEE_8021QAZ_TSA_ETS:63 return NFP_DCB_TSA_ETS;64 default:65 return NFP_DCB_TSA_VENDOR;66 }67}68 69static int nfp_nic_dcbnl_ieee_getets(struct net_device *dev,70 struct ieee_ets *ets)71{72 struct nfp_net *nn = netdev_priv(dev);73 struct nfp_dcb *dcb;74 75 dcb = get_dcb_priv(nn);76 77 for (unsigned int i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {78 ets->prio_tc[i] = dcb->prio2tc[i];79 ets->tc_tx_bw[i] = dcb->tc_tx_pct[i];80 ets->tc_tsa[i] = dcb->tc_tsa[i];81 }82 83 return 0;84}85 86static bool nfp_refresh_tc2idx(struct nfp_net *nn)87{88 u8 tc2idx[IEEE_8021QAZ_MAX_TCS];89 bool change = false;90 struct nfp_dcb *dcb;91 int maxstrict = 0;92 93 dcb = get_dcb_priv(nn);94 95 for (unsigned int i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {96 tc2idx[i] = i;97 if (dcb->tc_tsa[i] == IEEE_8021QAZ_TSA_STRICT)98 maxstrict = i;99 }100 101 if (maxstrict > 0 && dcb->tc_tsa[0] != IEEE_8021QAZ_TSA_STRICT) {102 tc2idx[0] = maxstrict;103 tc2idx[maxstrict] = 0;104 }105 106 for (unsigned int j = 0; j < IEEE_8021QAZ_MAX_TCS; j++) {107 if (dcb->tc2idx[j] != tc2idx[j]) {108 change = true;109 dcb->tc2idx[j] = tc2idx[j];110 }111 }112 113 return change;114}115 116static int nfp_fill_maxrate(struct nfp_net *nn, u64 *max_rate_array)117{118 struct nfp_app *app = nn->app;119 struct nfp_dcb *dcb;120 u32 ratembps;121 122 dcb = get_dcb_priv(nn);123 124 for (unsigned int i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {125 /* Convert bandwidth from kbps to mbps. */126 ratembps = max_rate_array[i] / 1024;127 128 /* Reject input values >= NFP_DCB_TC_RATE_MAX */129 if (ratembps >= NFP_DCB_TC_RATE_MAX) {130 nfp_warn(app->cpp, "ratembps(%d) must less than %d.",131 ratembps, NFP_DCB_TC_RATE_MAX);132 return -EINVAL;133 }134 /* Input value 0 mapped to NFP_DCB_TC_RATE_MAX for firmware. */135 if (ratembps == 0)136 ratembps = NFP_DCB_TC_RATE_MAX;137 138 writew((u16)ratembps, dcb->dcbcfg_tbl +139 dcb->cfg_offset + NFP_DCB_DATA_OFF_RATE + dcb->tc2idx[i] * 2);140 /* for rate value from user space, need to sync to dcb structure */141 if (dcb->tc_maxrate != max_rate_array)142 dcb->tc_maxrate[i] = max_rate_array[i];143 }144 145 return 0;146}147 148static int update_dscp_maxrate(struct net_device *dev, u32 *update)149{150 struct nfp_net *nn = netdev_priv(dev);151 struct nfp_dcb *dcb;152 int err;153 154 dcb = get_dcb_priv(nn);155 156 err = nfp_fill_maxrate(nn, dcb->tc_maxrate);157 if (err)158 return err;159 160 *update |= NFP_DCB_MSG_MSK_RATE;161 162 /* We only refresh dscp in dscp trust mode. */163 if (dcb->dscp_cnt > 0) {164 for (unsigned int i = 0; i < NFP_NET_MAX_DSCP; i++) {165 writeb(dcb->tc2idx[dcb->prio2tc[dcb->dscp2prio[i]]],166 dcb->dcbcfg_tbl + dcb->cfg_offset +167 NFP_DCB_DATA_OFF_DSCP2IDX + i);168 }169 *update |= NFP_DCB_MSG_MSK_DSCP;170 }171 172 return 0;173}174 175static void nfp_nic_set_trust(struct nfp_net *nn, u32 *update)176{177 struct nfp_dcb *dcb;178 u8 trust;179 180 dcb = get_dcb_priv(nn);181 182 if (dcb->trust_status != NFP_DCB_TRUST_INVALID)183 return;184 185 trust = dcb->dscp_cnt > 0 ? NFP_DCB_TRUST_DSCP : NFP_DCB_TRUST_PCP;186 writeb(trust, dcb->dcbcfg_tbl + dcb->cfg_offset +187 NFP_DCB_DATA_OFF_TRUST);188 189 dcb->trust_status = trust;190 *update |= NFP_DCB_MSG_MSK_TRUST;191}192 193static void nfp_nic_set_enable(struct nfp_net *nn, u32 enable, u32 *update)194{195 struct nfp_dcb *dcb;196 u32 value = 0;197 198 dcb = get_dcb_priv(nn);199 200 value = readl(dcb->dcbcfg_tbl + dcb->cfg_offset +201 NFP_DCB_DATA_OFF_ENABLE);202 if (value != enable) {203 writel(enable, dcb->dcbcfg_tbl + dcb->cfg_offset +204 NFP_DCB_DATA_OFF_ENABLE);205 *update |= NFP_DCB_MSG_MSK_ENABLE;206 }207}208 209static int dcb_ets_check(struct net_device *dev, struct ieee_ets *ets)210{211 struct nfp_net *nn = netdev_priv(dev);212 struct nfp_app *app = nn->app;213 bool ets_exists = false;214 int sum = 0;215 216 for (unsigned int i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {217 /* For ets mode, check bw percentage sum. */218 if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS) {219 ets_exists = true;220 sum += ets->tc_tx_bw[i];221 } else if (ets->tc_tx_bw[i]) {222 nfp_warn(app->cpp, "ETS BW for strict/vendor TC must be 0.");223 return -EINVAL;224 }225 }226 227 if (ets_exists && sum != 100) {228 nfp_warn(app->cpp, "Failed to validate ETS BW: sum must be 100.");229 return -EINVAL;230 }231 232 return 0;233}234 235static void nfp_nic_fill_ets(struct nfp_net *nn)236{237 struct nfp_dcb *dcb;238 239 dcb = get_dcb_priv(nn);240 241 for (unsigned int i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {242 writeb(dcb->tc2idx[dcb->prio2tc[i]],243 dcb->dcbcfg_tbl + dcb->cfg_offset + NFP_DCB_DATA_OFF_PCP2IDX + i);244 writeb(dcb->tc_tx_pct[i], dcb->dcbcfg_tbl +245 dcb->cfg_offset + NFP_DCB_DATA_OFF_IDX_BW_PCT + dcb->tc2idx[i]);246 writeb(nfp_tsa_ieee2nfp(dcb->tc_tsa[i]), dcb->dcbcfg_tbl +247 dcb->cfg_offset + NFP_DCB_DATA_OFF_TSA + dcb->tc2idx[i]);248 }249}250 251static void nfp_nic_ets_init(struct nfp_net *nn, u32 *update)252{253 struct nfp_dcb *dcb = get_dcb_priv(nn);254 255 if (dcb->ets_init)256 return;257 258 nfp_nic_fill_ets(nn);259 dcb->ets_init = true;260 *update |= NFP_DCB_MSG_MSK_TSA | NFP_DCB_MSG_MSK_PCT | NFP_DCB_MSG_MSK_PCP;261}262 263static int nfp_nic_dcbnl_ieee_setets(struct net_device *dev,264 struct ieee_ets *ets)265{266 const u32 cmd = NFP_NET_CFG_MBOX_CMD_DCB_UPDATE;267 struct nfp_net *nn = netdev_priv(dev);268 struct nfp_app *app = nn->app;269 struct nfp_dcb *dcb;270 u32 update = 0;271 bool change;272 int err;273 274 err = dcb_ets_check(dev, ets);275 if (err)276 return err;277 278 dcb = get_dcb_priv(nn);279 280 for (unsigned int i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {281 dcb->prio2tc[i] = ets->prio_tc[i];282 dcb->tc_tx_pct[i] = ets->tc_tx_bw[i];283 dcb->tc_tsa[i] = ets->tc_tsa[i];284 }285 286 change = nfp_refresh_tc2idx(nn);287 nfp_nic_fill_ets(nn);288 dcb->ets_init = true;289 if (change || !dcb->rate_init) {290 err = update_dscp_maxrate(dev, &update);291 if (err) {292 nfp_warn(app->cpp,293 "nfp dcbnl ieee setets ERROR:%d.",294 err);295 return err;296 }297 298 dcb->rate_init = true;299 }300 nfp_nic_set_enable(nn, NFP_DCB_ALL_QOS_ENABLE, &update);301 nfp_nic_set_trust(nn, &update);302 err = nfp_net_mbox_lock(nn, NFP_DCB_UPDATE_MSK_SZ);303 if (err)304 return err;305 306 nn_writel(nn, nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL,307 update | NFP_DCB_MSG_MSK_TSA | NFP_DCB_MSG_MSK_PCT |308 NFP_DCB_MSG_MSK_PCP);309 310 return nfp_net_mbox_reconfig_and_unlock(nn, cmd);311}312 313static int nfp_nic_dcbnl_ieee_getmaxrate(struct net_device *dev,314 struct ieee_maxrate *maxrate)315{316 struct nfp_net *nn = netdev_priv(dev);317 struct nfp_dcb *dcb;318 319 dcb = get_dcb_priv(nn);320 321 for (unsigned int i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)322 maxrate->tc_maxrate[i] = dcb->tc_maxrate[i];323 324 return 0;325}326 327static int nfp_nic_dcbnl_ieee_setmaxrate(struct net_device *dev,328 struct ieee_maxrate *maxrate)329{330 const u32 cmd = NFP_NET_CFG_MBOX_CMD_DCB_UPDATE;331 struct nfp_net *nn = netdev_priv(dev);332 struct nfp_app *app = nn->app;333 struct nfp_dcb *dcb;334 u32 update = 0;335 int err;336 337 err = nfp_fill_maxrate(nn, maxrate->tc_maxrate);338 if (err) {339 nfp_warn(app->cpp,340 "nfp dcbnl ieee setmaxrate ERROR:%d.",341 err);342 return err;343 }344 345 dcb = get_dcb_priv(nn);346 347 dcb->rate_init = true;348 nfp_nic_set_enable(nn, NFP_DCB_ALL_QOS_ENABLE, &update);349 nfp_nic_set_trust(nn, &update);350 nfp_nic_ets_init(nn, &update);351 352 err = nfp_net_mbox_lock(nn, NFP_DCB_UPDATE_MSK_SZ);353 if (err)354 return err;355 356 nn_writel(nn, nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL,357 update | NFP_DCB_MSG_MSK_RATE);358 359 return nfp_net_mbox_reconfig_and_unlock(nn, cmd);360}361 362static int nfp_nic_set_trust_status(struct nfp_net *nn, u8 status)363{364 const u32 cmd = NFP_NET_CFG_MBOX_CMD_DCB_UPDATE;365 struct nfp_dcb *dcb;366 u32 update = 0;367 int err;368 369 dcb = get_dcb_priv(nn);370 if (!dcb->rate_init) {371 err = nfp_fill_maxrate(nn, dcb->tc_maxrate);372 if (err)373 return err;374 375 update |= NFP_DCB_MSG_MSK_RATE;376 dcb->rate_init = true;377 }378 379 err = nfp_net_mbox_lock(nn, NFP_DCB_UPDATE_MSK_SZ);380 if (err)381 return err;382 383 nfp_nic_ets_init(nn, &update);384 writeb(status, dcb->dcbcfg_tbl + dcb->cfg_offset +385 NFP_DCB_DATA_OFF_TRUST);386 nfp_nic_set_enable(nn, NFP_DCB_ALL_QOS_ENABLE, &update);387 nn_writel(nn, nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL,388 update | NFP_DCB_MSG_MSK_TRUST);389 390 err = nfp_net_mbox_reconfig_and_unlock(nn, cmd);391 if (err)392 return err;393 394 dcb->trust_status = status;395 396 return 0;397}398 399static int nfp_nic_set_dscp2prio(struct nfp_net *nn, u8 dscp, u8 prio)400{401 const u32 cmd = NFP_NET_CFG_MBOX_CMD_DCB_UPDATE;402 struct nfp_dcb *dcb;403 u8 idx, tc;404 int err;405 406 err = nfp_net_mbox_lock(nn, NFP_DCB_UPDATE_MSK_SZ);407 if (err)408 return err;409 410 dcb = get_dcb_priv(nn);411 412 tc = dcb->prio2tc[prio];413 idx = dcb->tc2idx[tc];414 415 writeb(idx, dcb->dcbcfg_tbl + dcb->cfg_offset +416 NFP_DCB_DATA_OFF_DSCP2IDX + dscp);417 418 nn_writel(nn, nn->tlv_caps.mbox_off +419 NFP_NET_CFG_MBOX_SIMPLE_VAL, NFP_DCB_MSG_MSK_DSCP);420 421 err = nfp_net_mbox_reconfig_and_unlock(nn, cmd);422 if (err)423 return err;424 425 dcb->dscp2prio[dscp] = prio;426 427 return 0;428}429 430static int nfp_nic_dcbnl_ieee_setapp(struct net_device *dev,431 struct dcb_app *app)432{433 struct nfp_net *nn = netdev_priv(dev);434 struct dcb_app old_app;435 struct nfp_dcb *dcb;436 bool is_new;437 int err;438 439 if (app->selector != IEEE_8021QAZ_APP_SEL_DSCP)440 return -EINVAL;441 442 dcb = get_dcb_priv(nn);443 444 /* Save the old entry info */445 old_app.selector = IEEE_8021QAZ_APP_SEL_DSCP;446 old_app.protocol = app->protocol;447 old_app.priority = dcb->dscp2prio[app->protocol];448 449 /* Check trust status */450 if (!dcb->dscp_cnt) {451 err = nfp_nic_set_trust_status(nn, NFP_DCB_TRUST_DSCP);452 if (err)453 return err;454 }455 456 /* Check if the new mapping is same as old or in init stage */457 if (app->priority != old_app.priority || app->priority == 0) {458 err = nfp_nic_set_dscp2prio(nn, app->protocol, app->priority);459 if (err)460 return err;461 }462 463 /* Delete the old entry if exists */464 is_new = !!dcb_ieee_delapp(dev, &old_app);465 466 /* Add new entry and update counter */467 err = dcb_ieee_setapp(dev, app);468 if (err)469 return err;470 471 if (is_new)472 dcb->dscp_cnt++;473 474 return 0;475}476 477static int nfp_nic_dcbnl_ieee_delapp(struct net_device *dev,478 struct dcb_app *app)479{480 struct nfp_net *nn = netdev_priv(dev);481 struct nfp_dcb *dcb;482 int err;483 484 if (app->selector != IEEE_8021QAZ_APP_SEL_DSCP)485 return -EINVAL;486 487 dcb = get_dcb_priv(nn);488 489 /* Check if the dcb_app param match fw */490 if (app->priority != dcb->dscp2prio[app->protocol])491 return -ENOENT;492 493 /* Set fw dscp mapping to 0 */494 err = nfp_nic_set_dscp2prio(nn, app->protocol, 0);495 if (err)496 return err;497 498 /* Delete app from dcb list */499 err = dcb_ieee_delapp(dev, app);500 if (err)501 return err;502 503 /* Decrease dscp counter */504 dcb->dscp_cnt--;505 506 /* If no dscp mapping is configured, trust pcp */507 if (dcb->dscp_cnt == 0)508 return nfp_nic_set_trust_status(nn, NFP_DCB_TRUST_PCP);509 510 return 0;511}512 513static const struct dcbnl_rtnl_ops nfp_nic_dcbnl_ops = {514 /* ieee 802.1Qaz std */515 .ieee_getets = nfp_nic_dcbnl_ieee_getets,516 .ieee_setets = nfp_nic_dcbnl_ieee_setets,517 .ieee_getmaxrate = nfp_nic_dcbnl_ieee_getmaxrate,518 .ieee_setmaxrate = nfp_nic_dcbnl_ieee_setmaxrate,519 .ieee_setapp = nfp_nic_dcbnl_ieee_setapp,520 .ieee_delapp = nfp_nic_dcbnl_ieee_delapp,521};522 523int nfp_nic_dcb_init(struct nfp_net *nn)524{525 struct nfp_app *app = nn->app;526 struct nfp_dcb *dcb;527 int err;528 529 dcb = get_dcb_priv(nn);530 dcb->cfg_offset = NFP_DCB_CFG_STRIDE * nn->id;531 dcb->dcbcfg_tbl = nfp_pf_map_rtsym(app->pf, "net.dcbcfg_tbl",532 "_abi_dcb_cfg",533 dcb->cfg_offset, &dcb->dcbcfg_tbl_area);534 if (IS_ERR(dcb->dcbcfg_tbl)) {535 if (PTR_ERR(dcb->dcbcfg_tbl) != -ENOENT) {536 err = PTR_ERR(dcb->dcbcfg_tbl);537 dcb->dcbcfg_tbl = NULL;538 nfp_err(app->cpp,539 "Failed to map dcbcfg_tbl area, min_size %u.\n",540 dcb->cfg_offset);541 return err;542 }543 dcb->dcbcfg_tbl = NULL;544 }545 546 if (dcb->dcbcfg_tbl) {547 for (unsigned int i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {548 dcb->prio2tc[i] = i;549 dcb->tc2idx[i] = i;550 dcb->tc_tx_pct[i] = 0;551 dcb->tc_maxrate[i] = 0;552 dcb->tc_tsa[i] = IEEE_8021QAZ_TSA_VENDOR;553 }554 dcb->trust_status = NFP_DCB_TRUST_INVALID;555 dcb->rate_init = false;556 dcb->ets_init = false;557 558 nn->dp.netdev->dcbnl_ops = &nfp_nic_dcbnl_ops;559 }560 561 return 0;562}563 564void nfp_nic_dcb_clean(struct nfp_net *nn)565{566 struct nfp_dcb *dcb;567 568 dcb = get_dcb_priv(nn);569 if (dcb->dcbcfg_tbl_area)570 nfp_cpp_area_release_free(dcb->dcbcfg_tbl_area);571}572