2585 lines · c
1/* bnx2x_dcb.c: QLogic Everest network driver.2 *3 * Copyright 2009-2013 Broadcom Corporation4 * Copyright 2014 QLogic Corporation5 * All rights reserved6 *7 * Unless you and QLogic execute a separate written software license8 * agreement governing use of this software, this software is licensed to you9 * under the terms of the GNU General Public License version 2, available10 * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").11 *12 * Notwithstanding the above, under no circumstances may you combine this13 * software in any way with any other QLogic software provided under a14 * license other than the GPL, without QLogic's express prior written15 * consent.16 *17 * Maintained by: Ariel Elior <ariel.elior@qlogic.com>18 * Written by: Dmitry Kravkov19 *20 */21 22#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt23 24#include <linux/netdevice.h>25#include <linux/types.h>26#include <linux/errno.h>27#include <linux/rtnetlink.h>28#include <net/dcbnl.h>29 30#include "bnx2x.h"31#include "bnx2x_cmn.h"32#include "bnx2x_dcb.h"33 34/* forward declarations of dcbx related functions */35static void bnx2x_pfc_set_pfc(struct bnx2x *bp);36static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp);37static void bnx2x_dcbx_get_ets_pri_pg_tbl(struct bnx2x *bp,38 u32 *set_configuration_ets_pg,39 u32 *pri_pg_tbl);40static void bnx2x_dcbx_get_num_pg_traf_type(struct bnx2x *bp,41 u32 *pg_pri_orginal_spread,42 struct pg_help_data *help_data);43static void bnx2x_dcbx_fill_cos_params(struct bnx2x *bp,44 struct pg_help_data *help_data,45 struct dcbx_ets_feature *ets,46 u32 *pg_pri_orginal_spread);47static void bnx2x_dcbx_separate_pauseable_from_non(struct bnx2x *bp,48 struct cos_help_data *cos_data,49 u32 *pg_pri_orginal_spread,50 struct dcbx_ets_feature *ets);51static void bnx2x_dcbx_fw_struct(struct bnx2x *bp,52 struct bnx2x_func_tx_start_params*);53 54/* helpers: read/write len bytes from addr into buff by REG_RD/REG_WR */55static void bnx2x_read_data(struct bnx2x *bp, u32 *buff,56 u32 addr, u32 len)57{58 int i;59 for (i = 0; i < len; i += 4, buff++)60 *buff = REG_RD(bp, addr + i);61}62 63static void bnx2x_write_data(struct bnx2x *bp, u32 *buff,64 u32 addr, u32 len)65{66 int i;67 for (i = 0; i < len; i += 4, buff++)68 REG_WR(bp, addr + i, *buff);69}70 71static void bnx2x_pfc_set(struct bnx2x *bp)72{73 struct bnx2x_nig_brb_pfc_port_params pfc_params = {0};74 u32 pri_bit, val = 0;75 int i;76 77 pfc_params.num_of_rx_cos_priority_mask =78 bp->dcbx_port_params.ets.num_of_cos;79 80 /* Tx COS configuration */81 for (i = 0; i < bp->dcbx_port_params.ets.num_of_cos; i++)82 /*83 * We configure only the pauseable bits (non pauseable aren't84 * configured at all) it's done to avoid false pauses from85 * network86 */87 pfc_params.rx_cos_priority_mask[i] =88 bp->dcbx_port_params.ets.cos_params[i].pri_bitmask89 & DCBX_PFC_PRI_PAUSE_MASK(bp);90 91 /*92 * Rx COS configuration93 * Changing PFC RX configuration .94 * In RX COS0 will always be configured to lossless and COS1 to lossy95 */96 for (i = 0 ; i < MAX_PFC_PRIORITIES ; i++) {97 pri_bit = 1 << i;98 99 if (!(pri_bit & DCBX_PFC_PRI_PAUSE_MASK(bp)))100 val |= 1 << (i * 4);101 }102 103 pfc_params.pkt_priority_to_cos = val;104 105 /* RX COS0 */106 pfc_params.llfc_low_priority_classes = DCBX_PFC_PRI_PAUSE_MASK(bp);107 /* RX COS1 */108 pfc_params.llfc_high_priority_classes = 0;109 110 bnx2x_acquire_phy_lock(bp);111 bp->link_params.feature_config_flags |= FEATURE_CONFIG_PFC_ENABLED;112 bnx2x_update_pfc(&bp->link_params, &bp->link_vars, &pfc_params);113 bnx2x_release_phy_lock(bp);114}115 116static void bnx2x_pfc_clear(struct bnx2x *bp)117{118 struct bnx2x_nig_brb_pfc_port_params nig_params = {0};119 nig_params.pause_enable = 1;120 bnx2x_acquire_phy_lock(bp);121 bp->link_params.feature_config_flags &= ~FEATURE_CONFIG_PFC_ENABLED;122 bnx2x_update_pfc(&bp->link_params, &bp->link_vars, &nig_params);123 bnx2x_release_phy_lock(bp);124}125 126static void bnx2x_dump_dcbx_drv_param(struct bnx2x *bp,127 struct dcbx_features *features,128 u32 error)129{130 u8 i = 0;131 DP(NETIF_MSG_LINK, "local_mib.error %x\n", error);132 133 /* PG */134 DP(NETIF_MSG_LINK,135 "local_mib.features.ets.enabled %x\n", features->ets.enabled);136 for (i = 0; i < DCBX_MAX_NUM_PG_BW_ENTRIES; i++)137 DP(NETIF_MSG_LINK,138 "local_mib.features.ets.pg_bw_tbl[%d] %d\n", i,139 DCBX_PG_BW_GET(features->ets.pg_bw_tbl, i));140 for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES; i++)141 DP(NETIF_MSG_LINK,142 "local_mib.features.ets.pri_pg_tbl[%d] %d\n", i,143 DCBX_PRI_PG_GET(features->ets.pri_pg_tbl, i));144 145 /* pfc */146 DP(BNX2X_MSG_DCB, "dcbx_features.pfc.pri_en_bitmap %x\n",147 features->pfc.pri_en_bitmap);148 DP(BNX2X_MSG_DCB, "dcbx_features.pfc.pfc_caps %x\n",149 features->pfc.pfc_caps);150 DP(BNX2X_MSG_DCB, "dcbx_features.pfc.enabled %x\n",151 features->pfc.enabled);152 153 DP(BNX2X_MSG_DCB, "dcbx_features.app.default_pri %x\n",154 features->app.default_pri);155 DP(BNX2X_MSG_DCB, "dcbx_features.app.tc_supported %x\n",156 features->app.tc_supported);157 DP(BNX2X_MSG_DCB, "dcbx_features.app.enabled %x\n",158 features->app.enabled);159 for (i = 0; i < DCBX_MAX_APP_PROTOCOL; i++) {160 DP(BNX2X_MSG_DCB,161 "dcbx_features.app.app_pri_tbl[%x].app_id %x\n",162 i, features->app.app_pri_tbl[i].app_id);163 DP(BNX2X_MSG_DCB,164 "dcbx_features.app.app_pri_tbl[%x].pri_bitmap %x\n",165 i, features->app.app_pri_tbl[i].pri_bitmap);166 DP(BNX2X_MSG_DCB,167 "dcbx_features.app.app_pri_tbl[%x].appBitfield %x\n",168 i, features->app.app_pri_tbl[i].appBitfield);169 }170}171 172static void bnx2x_dcbx_get_ap_priority(struct bnx2x *bp,173 u8 pri_bitmap,174 u8 llfc_traf_type)175{176 u32 pri = MAX_PFC_PRIORITIES;177 u32 index = MAX_PFC_PRIORITIES - 1;178 u32 pri_mask;179 u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;180 181 /* Choose the highest priority */182 while ((MAX_PFC_PRIORITIES == pri) && (0 != index)) {183 pri_mask = 1 << index;184 if (GET_FLAGS(pri_bitmap, pri_mask))185 pri = index ;186 index--;187 }188 189 if (pri < MAX_PFC_PRIORITIES)190 ttp[llfc_traf_type] = max_t(u32, ttp[llfc_traf_type], pri);191}192 193static void bnx2x_dcbx_get_ap_feature(struct bnx2x *bp,194 struct dcbx_app_priority_feature *app,195 u32 error) {196 u8 index;197 u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;198 u8 iscsi_pri_found = 0, fcoe_pri_found = 0;199 200 if (GET_FLAGS(error, DCBX_LOCAL_APP_ERROR))201 DP(BNX2X_MSG_DCB, "DCBX_LOCAL_APP_ERROR\n");202 203 if (GET_FLAGS(error, DCBX_LOCAL_APP_MISMATCH))204 DP(BNX2X_MSG_DCB, "DCBX_LOCAL_APP_MISMATCH\n");205 206 if (GET_FLAGS(error, DCBX_REMOTE_APP_TLV_NOT_FOUND))207 DP(BNX2X_MSG_DCB, "DCBX_REMOTE_APP_TLV_NOT_FOUND\n");208 if (app->enabled &&209 !GET_FLAGS(error, DCBX_LOCAL_APP_ERROR | DCBX_LOCAL_APP_MISMATCH |210 DCBX_REMOTE_APP_TLV_NOT_FOUND)) {211 212 bp->dcbx_port_params.app.enabled = true;213 214 /* Use 0 as the default application priority for all. */215 for (index = 0 ; index < LLFC_DRIVER_TRAFFIC_TYPE_MAX; index++)216 ttp[index] = 0;217 218 for (index = 0 ; index < DCBX_MAX_APP_PROTOCOL; index++) {219 struct dcbx_app_priority_entry *entry =220 app->app_pri_tbl;221 enum traffic_type type = MAX_TRAFFIC_TYPE;222 223 if (GET_FLAGS(entry[index].appBitfield,224 DCBX_APP_SF_DEFAULT) &&225 GET_FLAGS(entry[index].appBitfield,226 DCBX_APP_SF_ETH_TYPE)) {227 type = LLFC_TRAFFIC_TYPE_NW;228 } else if (GET_FLAGS(entry[index].appBitfield,229 DCBX_APP_SF_PORT) &&230 TCP_PORT_ISCSI == entry[index].app_id) {231 type = LLFC_TRAFFIC_TYPE_ISCSI;232 iscsi_pri_found = 1;233 } else if (GET_FLAGS(entry[index].appBitfield,234 DCBX_APP_SF_ETH_TYPE) &&235 ETH_TYPE_FCOE == entry[index].app_id) {236 type = LLFC_TRAFFIC_TYPE_FCOE;237 fcoe_pri_found = 1;238 }239 240 if (type == MAX_TRAFFIC_TYPE)241 continue;242 243 bnx2x_dcbx_get_ap_priority(bp,244 entry[index].pri_bitmap,245 type);246 }247 248 /* If we have received a non-zero default application249 * priority, then use that for applications which are250 * not configured with any priority.251 */252 if (ttp[LLFC_TRAFFIC_TYPE_NW] != 0) {253 if (!iscsi_pri_found) {254 ttp[LLFC_TRAFFIC_TYPE_ISCSI] =255 ttp[LLFC_TRAFFIC_TYPE_NW];256 DP(BNX2X_MSG_DCB,257 "ISCSI is using default priority.\n");258 }259 if (!fcoe_pri_found) {260 ttp[LLFC_TRAFFIC_TYPE_FCOE] =261 ttp[LLFC_TRAFFIC_TYPE_NW];262 DP(BNX2X_MSG_DCB,263 "FCoE is using default priority.\n");264 }265 }266 } else {267 DP(BNX2X_MSG_DCB, "DCBX_LOCAL_APP_DISABLED\n");268 bp->dcbx_port_params.app.enabled = false;269 for (index = 0 ; index < LLFC_DRIVER_TRAFFIC_TYPE_MAX; index++)270 ttp[index] = INVALID_TRAFFIC_TYPE_PRIORITY;271 }272}273 274static void bnx2x_dcbx_get_ets_feature(struct bnx2x *bp,275 struct dcbx_ets_feature *ets,276 u32 error) {277 int i = 0;278 u32 pg_pri_orginal_spread[DCBX_MAX_NUM_PG_BW_ENTRIES] = {0};279 struct pg_help_data pg_help_data;280 struct bnx2x_dcbx_cos_params *cos_params =281 bp->dcbx_port_params.ets.cos_params;282 283 memset(&pg_help_data, 0, sizeof(struct pg_help_data));284 285 if (GET_FLAGS(error, DCBX_LOCAL_ETS_ERROR))286 DP(BNX2X_MSG_DCB, "DCBX_LOCAL_ETS_ERROR\n");287 288 if (GET_FLAGS(error, DCBX_REMOTE_ETS_TLV_NOT_FOUND))289 DP(BNX2X_MSG_DCB, "DCBX_REMOTE_ETS_TLV_NOT_FOUND\n");290 291 /* Clean up old settings of ets on COS */292 for (i = 0; i < ARRAY_SIZE(bp->dcbx_port_params.ets.cos_params) ; i++) {293 cos_params[i].pauseable = false;294 cos_params[i].strict = BNX2X_DCBX_STRICT_INVALID;295 cos_params[i].bw_tbl = DCBX_INVALID_COS_BW;296 cos_params[i].pri_bitmask = 0;297 }298 299 if (bp->dcbx_port_params.app.enabled && ets->enabled &&300 !GET_FLAGS(error,301 DCBX_LOCAL_ETS_ERROR | DCBX_REMOTE_ETS_TLV_NOT_FOUND)) {302 DP(BNX2X_MSG_DCB, "DCBX_LOCAL_ETS_ENABLE\n");303 bp->dcbx_port_params.ets.enabled = true;304 305 bnx2x_dcbx_get_ets_pri_pg_tbl(bp,306 pg_pri_orginal_spread,307 ets->pri_pg_tbl);308 309 bnx2x_dcbx_get_num_pg_traf_type(bp,310 pg_pri_orginal_spread,311 &pg_help_data);312 313 bnx2x_dcbx_fill_cos_params(bp, &pg_help_data,314 ets, pg_pri_orginal_spread);315 316 } else {317 DP(BNX2X_MSG_DCB, "DCBX_LOCAL_ETS_DISABLED\n");318 bp->dcbx_port_params.ets.enabled = false;319 ets->pri_pg_tbl[0] = 0;320 321 for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES ; i++)322 DCBX_PG_BW_SET(ets->pg_bw_tbl, i, 1);323 }324}325 326static void bnx2x_dcbx_get_pfc_feature(struct bnx2x *bp,327 struct dcbx_pfc_feature *pfc, u32 error)328{329 if (GET_FLAGS(error, DCBX_LOCAL_PFC_ERROR))330 DP(BNX2X_MSG_DCB, "DCBX_LOCAL_PFC_ERROR\n");331 332 if (GET_FLAGS(error, DCBX_REMOTE_PFC_TLV_NOT_FOUND))333 DP(BNX2X_MSG_DCB, "DCBX_REMOTE_PFC_TLV_NOT_FOUND\n");334 if (bp->dcbx_port_params.app.enabled && pfc->enabled &&335 !GET_FLAGS(error, DCBX_LOCAL_PFC_ERROR | DCBX_LOCAL_PFC_MISMATCH |336 DCBX_REMOTE_PFC_TLV_NOT_FOUND)) {337 bp->dcbx_port_params.pfc.enabled = true;338 bp->dcbx_port_params.pfc.priority_non_pauseable_mask =339 ~(pfc->pri_en_bitmap);340 } else {341 DP(BNX2X_MSG_DCB, "DCBX_LOCAL_PFC_DISABLED\n");342 bp->dcbx_port_params.pfc.enabled = false;343 bp->dcbx_port_params.pfc.priority_non_pauseable_mask = 0;344 }345}346 347/* maps unmapped priorities to to the same COS as L2 */348static void bnx2x_dcbx_map_nw(struct bnx2x *bp)349{350 int i;351 u32 unmapped = (1 << MAX_PFC_PRIORITIES) - 1; /* all ones */352 u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;353 u32 nw_prio = 1 << ttp[LLFC_TRAFFIC_TYPE_NW];354 struct bnx2x_dcbx_cos_params *cos_params =355 bp->dcbx_port_params.ets.cos_params;356 357 /* get unmapped priorities by clearing mapped bits */358 for (i = 0; i < LLFC_DRIVER_TRAFFIC_TYPE_MAX; i++)359 unmapped &= ~(1 << ttp[i]);360 361 /* find cos for nw prio and extend it with unmapped */362 for (i = 0; i < ARRAY_SIZE(bp->dcbx_port_params.ets.cos_params); i++) {363 if (cos_params[i].pri_bitmask & nw_prio) {364 /* extend the bitmask with unmapped */365 DP(BNX2X_MSG_DCB,366 "cos %d extended with 0x%08x\n", i, unmapped);367 cos_params[i].pri_bitmask |= unmapped;368 break;369 }370 }371}372 373static void bnx2x_get_dcbx_drv_param(struct bnx2x *bp,374 struct dcbx_features *features,375 u32 error)376{377 bnx2x_dcbx_get_ap_feature(bp, &features->app, error);378 379 bnx2x_dcbx_get_pfc_feature(bp, &features->pfc, error);380 381 bnx2x_dcbx_get_ets_feature(bp, &features->ets, error);382 383 bnx2x_dcbx_map_nw(bp);384}385 386#define DCBX_LOCAL_MIB_MAX_TRY_READ (100)387static int bnx2x_dcbx_read_mib(struct bnx2x *bp,388 u32 *base_mib_addr,389 u32 offset,390 int read_mib_type)391{392 int max_try_read = 0;393 u32 mib_size, prefix_seq_num, suffix_seq_num;394 struct lldp_remote_mib *remote_mib ;395 struct lldp_local_mib *local_mib;396 397 switch (read_mib_type) {398 case DCBX_READ_LOCAL_MIB:399 mib_size = sizeof(struct lldp_local_mib);400 break;401 case DCBX_READ_REMOTE_MIB:402 mib_size = sizeof(struct lldp_remote_mib);403 break;404 default:405 return 1; /*error*/406 }407 408 offset += BP_PORT(bp) * mib_size;409 410 do {411 bnx2x_read_data(bp, base_mib_addr, offset, mib_size);412 413 max_try_read++;414 415 switch (read_mib_type) {416 case DCBX_READ_LOCAL_MIB:417 local_mib = (struct lldp_local_mib *) base_mib_addr;418 prefix_seq_num = local_mib->prefix_seq_num;419 suffix_seq_num = local_mib->suffix_seq_num;420 break;421 case DCBX_READ_REMOTE_MIB:422 remote_mib = (struct lldp_remote_mib *) base_mib_addr;423 prefix_seq_num = remote_mib->prefix_seq_num;424 suffix_seq_num = remote_mib->suffix_seq_num;425 break;426 default:427 return 1; /*error*/428 }429 } while ((prefix_seq_num != suffix_seq_num) &&430 (max_try_read < DCBX_LOCAL_MIB_MAX_TRY_READ));431 432 if (max_try_read >= DCBX_LOCAL_MIB_MAX_TRY_READ) {433 BNX2X_ERR("MIB could not be read\n");434 return 1;435 }436 437 return 0;438}439 440static void bnx2x_pfc_set_pfc(struct bnx2x *bp)441{442 int mfw_configured = SHMEM2_HAS(bp, drv_flags) &&443 GET_FLAGS(SHMEM2_RD(bp, drv_flags),444 1 << DRV_FLAGS_DCB_MFW_CONFIGURED);445 446 if (bp->dcbx_port_params.pfc.enabled &&447 (!(bp->dcbx_error & DCBX_REMOTE_MIB_ERROR) || mfw_configured))448 /*449 * 1. Fills up common PFC structures if required450 * 2. Configure NIG, MAC and BRB via the elink451 */452 bnx2x_pfc_set(bp);453 else454 bnx2x_pfc_clear(bp);455}456 457int bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp)458{459 struct bnx2x_func_state_params func_params = {NULL};460 int rc;461 462 func_params.f_obj = &bp->func_obj;463 func_params.cmd = BNX2X_F_CMD_TX_STOP;464 465 __set_bit(RAMROD_COMP_WAIT, &func_params.ramrod_flags);466 __set_bit(RAMROD_RETRY, &func_params.ramrod_flags);467 468 DP(BNX2X_MSG_DCB, "STOP TRAFFIC\n");469 470 rc = bnx2x_func_state_change(bp, &func_params);471 if (rc) {472 BNX2X_ERR("Unable to hold traffic for HW configuration\n");473 bnx2x_panic();474 }475 476 return rc;477}478 479int bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp)480{481 struct bnx2x_func_state_params func_params = {NULL};482 struct bnx2x_func_tx_start_params *tx_params =483 &func_params.params.tx_start;484 int rc;485 486 func_params.f_obj = &bp->func_obj;487 func_params.cmd = BNX2X_F_CMD_TX_START;488 489 __set_bit(RAMROD_COMP_WAIT, &func_params.ramrod_flags);490 __set_bit(RAMROD_RETRY, &func_params.ramrod_flags);491 492 bnx2x_dcbx_fw_struct(bp, tx_params);493 494 DP(BNX2X_MSG_DCB, "START TRAFFIC\n");495 496 rc = bnx2x_func_state_change(bp, &func_params);497 if (rc) {498 BNX2X_ERR("Unable to resume traffic after HW configuration\n");499 bnx2x_panic();500 }501 502 return rc;503}504 505static void bnx2x_dcbx_2cos_limit_update_ets_config(struct bnx2x *bp)506{507 struct bnx2x_dcbx_pg_params *ets = &(bp->dcbx_port_params.ets);508 int rc = 0;509 510 if (ets->num_of_cos == 0 || ets->num_of_cos > DCBX_COS_MAX_NUM_E2) {511 BNX2X_ERR("Illegal number of COSes %d\n", ets->num_of_cos);512 return;513 }514 515 /* valid COS entries */516 if (ets->num_of_cos == 1) /* no ETS */517 return;518 519 /* sanity */520 if (((BNX2X_DCBX_STRICT_INVALID == ets->cos_params[0].strict) &&521 (DCBX_INVALID_COS_BW == ets->cos_params[0].bw_tbl)) ||522 ((BNX2X_DCBX_STRICT_INVALID == ets->cos_params[1].strict) &&523 (DCBX_INVALID_COS_BW == ets->cos_params[1].bw_tbl))) {524 BNX2X_ERR("all COS should have at least bw_limit or strict"525 "ets->cos_params[0].strict= %x"526 "ets->cos_params[0].bw_tbl= %x"527 "ets->cos_params[1].strict= %x"528 "ets->cos_params[1].bw_tbl= %x",529 ets->cos_params[0].strict,530 ets->cos_params[0].bw_tbl,531 ets->cos_params[1].strict,532 ets->cos_params[1].bw_tbl);533 return;534 }535 /* If we join a group and there is bw_tbl and strict then bw rules */536 if ((DCBX_INVALID_COS_BW != ets->cos_params[0].bw_tbl) &&537 (DCBX_INVALID_COS_BW != ets->cos_params[1].bw_tbl)) {538 u32 bw_tbl_0 = ets->cos_params[0].bw_tbl;539 u32 bw_tbl_1 = ets->cos_params[1].bw_tbl;540 /* Do not allow 0-100 configuration541 * since PBF does not support it542 * force 1-99 instead543 */544 if (bw_tbl_0 == 0) {545 bw_tbl_0 = 1;546 bw_tbl_1 = 99;547 } else if (bw_tbl_1 == 0) {548 bw_tbl_1 = 1;549 bw_tbl_0 = 99;550 }551 552 bnx2x_ets_bw_limit(&bp->link_params, bw_tbl_0, bw_tbl_1);553 } else {554 if (ets->cos_params[0].strict == BNX2X_DCBX_STRICT_COS_HIGHEST)555 rc = bnx2x_ets_strict(&bp->link_params, 0);556 else if (ets->cos_params[1].strict557 == BNX2X_DCBX_STRICT_COS_HIGHEST)558 rc = bnx2x_ets_strict(&bp->link_params, 1);559 if (rc)560 BNX2X_ERR("update_ets_params failed\n");561 }562}563 564/*565 * In E3B0 the configuration may have more than 2 COS.566 */567static void bnx2x_dcbx_update_ets_config(struct bnx2x *bp)568{569 struct bnx2x_dcbx_pg_params *ets = &(bp->dcbx_port_params.ets);570 struct bnx2x_ets_params ets_params = { 0 };571 u8 i;572 573 ets_params.num_of_cos = ets->num_of_cos;574 575 for (i = 0; i < ets->num_of_cos; i++) {576 /* COS is SP */577 if (ets->cos_params[i].strict != BNX2X_DCBX_STRICT_INVALID) {578 if (ets->cos_params[i].bw_tbl != DCBX_INVALID_COS_BW) {579 BNX2X_ERR("COS can't be not BW and not SP\n");580 return;581 }582 583 ets_params.cos[i].state = bnx2x_cos_state_strict;584 ets_params.cos[i].params.sp_params.pri =585 ets->cos_params[i].strict;586 } else { /* COS is BW */587 if (ets->cos_params[i].bw_tbl == DCBX_INVALID_COS_BW) {588 BNX2X_ERR("COS can't be not BW and not SP\n");589 return;590 }591 ets_params.cos[i].state = bnx2x_cos_state_bw;592 ets_params.cos[i].params.bw_params.bw =593 (u8)ets->cos_params[i].bw_tbl;594 }595 }596 597 /* Configure the ETS in HW */598 if (bnx2x_ets_e3b0_config(&bp->link_params, &bp->link_vars,599 &ets_params)) {600 BNX2X_ERR("bnx2x_ets_e3b0_config failed\n");601 bnx2x_ets_disabled(&bp->link_params, &bp->link_vars);602 }603}604 605static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp)606{607 int mfw_configured = SHMEM2_HAS(bp, drv_flags) &&608 GET_FLAGS(SHMEM2_RD(bp, drv_flags),609 1 << DRV_FLAGS_DCB_MFW_CONFIGURED);610 611 bnx2x_ets_disabled(&bp->link_params, &bp->link_vars);612 613 if (!bp->dcbx_port_params.ets.enabled ||614 ((bp->dcbx_error & DCBX_REMOTE_MIB_ERROR) && !mfw_configured))615 return;616 617 if (CHIP_IS_E3B0(bp))618 bnx2x_dcbx_update_ets_config(bp);619 else620 bnx2x_dcbx_2cos_limit_update_ets_config(bp);621}622 623#ifdef BCM_DCBNL624static int bnx2x_dcbx_read_shmem_remote_mib(struct bnx2x *bp)625{626 struct lldp_remote_mib remote_mib = {0};627 u32 dcbx_remote_mib_offset = SHMEM2_RD(bp, dcbx_remote_mib_offset);628 int rc;629 630 DP(BNX2X_MSG_DCB, "dcbx_remote_mib_offset 0x%x\n",631 dcbx_remote_mib_offset);632 633 if (SHMEM_DCBX_REMOTE_MIB_NONE == dcbx_remote_mib_offset) {634 BNX2X_ERR("FW doesn't support dcbx_remote_mib_offset\n");635 return -EINVAL;636 }637 638 rc = bnx2x_dcbx_read_mib(bp, (u32 *)&remote_mib, dcbx_remote_mib_offset,639 DCBX_READ_REMOTE_MIB);640 641 if (rc) {642 BNX2X_ERR("Failed to read remote mib from FW\n");643 return rc;644 }645 646 /* save features and flags */647 bp->dcbx_remote_feat = remote_mib.features;648 bp->dcbx_remote_flags = remote_mib.flags;649 return 0;650}651#endif652 653static int bnx2x_dcbx_read_shmem_neg_results(struct bnx2x *bp)654{655 struct lldp_local_mib local_mib = {0};656 u32 dcbx_neg_res_offset = SHMEM2_RD(bp, dcbx_neg_res_offset);657 int rc;658 659 DP(BNX2X_MSG_DCB, "dcbx_neg_res_offset 0x%x\n", dcbx_neg_res_offset);660 661 if (SHMEM_DCBX_NEG_RES_NONE == dcbx_neg_res_offset) {662 BNX2X_ERR("FW doesn't support dcbx_neg_res_offset\n");663 return -EINVAL;664 }665 666 rc = bnx2x_dcbx_read_mib(bp, (u32 *)&local_mib, dcbx_neg_res_offset,667 DCBX_READ_LOCAL_MIB);668 669 if (rc) {670 BNX2X_ERR("Failed to read local mib from FW\n");671 return rc;672 }673 674 /* save features and error */675 bp->dcbx_local_feat = local_mib.features;676 bp->dcbx_error = local_mib.error;677 return 0;678}679 680#ifdef BCM_DCBNL681static inline682u8 bnx2x_dcbx_dcbnl_app_up(struct dcbx_app_priority_entry *ent)683{684 u8 pri;685 686 /* Choose the highest priority */687 for (pri = MAX_PFC_PRIORITIES - 1; pri > 0; pri--)688 if (ent->pri_bitmap & (1 << pri))689 break;690 return pri;691}692 693static inline694u8 bnx2x_dcbx_dcbnl_app_idtype(struct dcbx_app_priority_entry *ent)695{696 return ((ent->appBitfield & DCBX_APP_ENTRY_SF_MASK) ==697 DCBX_APP_SF_PORT) ? DCB_APP_IDTYPE_PORTNUM :698 DCB_APP_IDTYPE_ETHTYPE;699}700 701int bnx2x_dcbnl_update_applist(struct bnx2x *bp, bool delall)702{703 int i, err = 0;704 705 for (i = 0; i < DCBX_MAX_APP_PROTOCOL && err == 0; i++) {706 struct dcbx_app_priority_entry *ent =707 &bp->dcbx_local_feat.app.app_pri_tbl[i];708 709 if (ent->appBitfield & DCBX_APP_ENTRY_VALID) {710 u8 up = bnx2x_dcbx_dcbnl_app_up(ent);711 712 /* avoid invalid user-priority */713 if (up) {714 struct dcb_app app;715 app.selector = bnx2x_dcbx_dcbnl_app_idtype(ent);716 app.protocol = ent->app_id;717 app.priority = delall ? 0 : up;718 err = dcb_setapp(bp->dev, &app);719 }720 }721 }722 return err;723}724#endif725 726static inline void bnx2x_dcbx_update_tc_mapping(struct bnx2x *bp)727{728 u8 prio, cos;729 for (cos = 0; cos < bp->dcbx_port_params.ets.num_of_cos; cos++) {730 for (prio = 0; prio < BNX2X_MAX_PRIORITY; prio++) {731 if (bp->dcbx_port_params.ets.cos_params[cos].pri_bitmask732 & (1 << prio)) {733 bp->prio_to_cos[prio] = cos;734 DP(BNX2X_MSG_DCB,735 "tx_mapping %d --> %d\n", prio, cos);736 }737 }738 }739 740 /* setup tc must be called under rtnl lock, but we can't take it here741 * as we are handling an attention on a work queue which must be742 * flushed at some rtnl-locked contexts (e.g. if down)743 */744 bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_SETUP_TC, 0);745}746 747void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state)748{749 switch (state) {750 case BNX2X_DCBX_STATE_NEG_RECEIVED:751 {752 DP(BNX2X_MSG_DCB, "BNX2X_DCBX_STATE_NEG_RECEIVED\n");753#ifdef BCM_DCBNL754 /**755 * Delete app tlvs from dcbnl before reading new756 * negotiation results757 */758 bnx2x_dcbnl_update_applist(bp, true);759 760 /* Read remote mib if dcbx is in the FW */761 if (bnx2x_dcbx_read_shmem_remote_mib(bp))762 return;763#endif764 /* Read neg results if dcbx is in the FW */765 if (bnx2x_dcbx_read_shmem_neg_results(bp))766 return;767 768 bnx2x_dump_dcbx_drv_param(bp, &bp->dcbx_local_feat,769 bp->dcbx_error);770 771 bnx2x_get_dcbx_drv_param(bp, &bp->dcbx_local_feat,772 bp->dcbx_error);773 774 /* mark DCBX result for PMF migration */775 bnx2x_update_drv_flags(bp,776 1 << DRV_FLAGS_DCB_CONFIGURED,777 1);778#ifdef BCM_DCBNL779 /*780 * Add new app tlvs to dcbnl781 */782 bnx2x_dcbnl_update_applist(bp, false);783#endif784 /*785 * reconfigure the netdevice with the results of the new786 * dcbx negotiation.787 */788 bnx2x_dcbx_update_tc_mapping(bp);789 790 /*791 * allow other functions to update their netdevices792 * accordingly793 */794 if (IS_MF(bp))795 bnx2x_link_sync_notify(bp);796 797 bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_TX_STOP, 0);798 return;799 }800 case BNX2X_DCBX_STATE_TX_PAUSED:801 DP(BNX2X_MSG_DCB, "BNX2X_DCBX_STATE_TX_PAUSED\n");802 bnx2x_pfc_set_pfc(bp);803 804 bnx2x_dcbx_update_ets_params(bp);805 806 /* ets may affect cmng configuration: reinit it in hw */807 bnx2x_set_local_cmng(bp);808 return;809 case BNX2X_DCBX_STATE_TX_RELEASED:810 DP(BNX2X_MSG_DCB, "BNX2X_DCBX_STATE_TX_RELEASED\n");811 bnx2x_fw_command(bp, DRV_MSG_CODE_DCBX_PMF_DRV_OK, 0);812#ifdef BCM_DCBNL813 /*814 * Send a notification for the new negotiated parameters815 */816 dcbnl_cee_notify(bp->dev, RTM_GETDCB, DCB_CMD_CEE_GET, 0, 0);817#endif818 return;819 default:820 BNX2X_ERR("Unknown DCBX_STATE\n");821 }822}823 824#define LLDP_ADMIN_MIB_OFFSET(bp) (PORT_MAX*sizeof(struct lldp_params) + \825 BP_PORT(bp)*sizeof(struct lldp_admin_mib))826 827static void bnx2x_dcbx_admin_mib_updated_params(struct bnx2x *bp,828 u32 dcbx_lldp_params_offset)829{830 struct lldp_admin_mib admin_mib;831 u32 i, other_traf_type = PREDEFINED_APP_IDX_MAX, traf_type = 0;832 u32 offset = dcbx_lldp_params_offset + LLDP_ADMIN_MIB_OFFSET(bp);833 834 /*shortcuts*/835 struct dcbx_features *af = &admin_mib.features;836 struct bnx2x_config_dcbx_params *dp = &bp->dcbx_config_params;837 838 memset(&admin_mib, 0, sizeof(struct lldp_admin_mib));839 840 /* Read the data first */841 bnx2x_read_data(bp, (u32 *)&admin_mib, offset,842 sizeof(struct lldp_admin_mib));843 844 if (bp->dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_ON)845 SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_DCBX_ENABLED);846 else847 RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_DCBX_ENABLED);848 849 if (dp->overwrite_settings == BNX2X_DCBX_OVERWRITE_SETTINGS_ENABLE) {850 851 RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_CEE_VERSION_MASK);852 admin_mib.ver_cfg_flags |=853 (dp->admin_dcbx_version << DCBX_CEE_VERSION_SHIFT) &854 DCBX_CEE_VERSION_MASK;855 856 af->ets.enabled = (u8)dp->admin_ets_enable;857 858 af->pfc.enabled = (u8)dp->admin_pfc_enable;859 860 /* FOR IEEE dp->admin_tc_supported_tx_enable */861 if (dp->admin_ets_configuration_tx_enable)862 SET_FLAGS(admin_mib.ver_cfg_flags,863 DCBX_ETS_CONFIG_TX_ENABLED);864 else865 RESET_FLAGS(admin_mib.ver_cfg_flags,866 DCBX_ETS_CONFIG_TX_ENABLED);867 /* For IEEE admin_ets_recommendation_tx_enable */868 if (dp->admin_pfc_tx_enable)869 SET_FLAGS(admin_mib.ver_cfg_flags,870 DCBX_PFC_CONFIG_TX_ENABLED);871 else872 RESET_FLAGS(admin_mib.ver_cfg_flags,873 DCBX_PFC_CONFIG_TX_ENABLED);874 875 if (dp->admin_application_priority_tx_enable)876 SET_FLAGS(admin_mib.ver_cfg_flags,877 DCBX_APP_CONFIG_TX_ENABLED);878 else879 RESET_FLAGS(admin_mib.ver_cfg_flags,880 DCBX_APP_CONFIG_TX_ENABLED);881 882 if (dp->admin_ets_willing)883 SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_ETS_WILLING);884 else885 RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_ETS_WILLING);886 /* For IEEE admin_ets_reco_valid */887 if (dp->admin_pfc_willing)888 SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_PFC_WILLING);889 else890 RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_PFC_WILLING);891 892 if (dp->admin_app_priority_willing)893 SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_APP_WILLING);894 else895 RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_APP_WILLING);896 897 for (i = 0 ; i < DCBX_MAX_NUM_PG_BW_ENTRIES; i++) {898 DCBX_PG_BW_SET(af->ets.pg_bw_tbl, i,899 (u8)dp->admin_configuration_bw_precentage[i]);900 901 DP(BNX2X_MSG_DCB, "pg_bw_tbl[%d] = %02x\n",902 i, DCBX_PG_BW_GET(af->ets.pg_bw_tbl, i));903 }904 905 for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES; i++) {906 DCBX_PRI_PG_SET(af->ets.pri_pg_tbl, i,907 (u8)dp->admin_configuration_ets_pg[i]);908 909 DP(BNX2X_MSG_DCB, "pri_pg_tbl[%d] = %02x\n",910 i, DCBX_PRI_PG_GET(af->ets.pri_pg_tbl, i));911 }912 913 /*For IEEE admin_recommendation_bw_percentage914 *For IEEE admin_recommendation_ets_pg */915 af->pfc.pri_en_bitmap = (u8)dp->admin_pfc_bitmap;916 for (i = 0; i < DCBX_CONFIG_MAX_APP_PROTOCOL; i++) {917 if (dp->admin_priority_app_table[i].valid) {918 struct bnx2x_admin_priority_app_table *table =919 dp->admin_priority_app_table;920 if ((ETH_TYPE_FCOE == table[i].app_id) &&921 (TRAFFIC_TYPE_ETH == table[i].traffic_type))922 traf_type = FCOE_APP_IDX;923 else if ((TCP_PORT_ISCSI == table[i].app_id) &&924 (TRAFFIC_TYPE_PORT == table[i].traffic_type))925 traf_type = ISCSI_APP_IDX;926 else927 traf_type = other_traf_type++;928 929 af->app.app_pri_tbl[traf_type].app_id =930 table[i].app_id;931 932 af->app.app_pri_tbl[traf_type].pri_bitmap =933 (u8)(1 << table[i].priority);934 935 af->app.app_pri_tbl[traf_type].appBitfield =936 (DCBX_APP_ENTRY_VALID);937 938 af->app.app_pri_tbl[traf_type].appBitfield |=939 (TRAFFIC_TYPE_ETH == table[i].traffic_type) ?940 DCBX_APP_SF_ETH_TYPE : DCBX_APP_SF_PORT;941 }942 }943 944 af->app.default_pri = (u8)dp->admin_default_priority;945 }946 947 /* Write the data. */948 bnx2x_write_data(bp, (u32 *)&admin_mib, offset,949 sizeof(struct lldp_admin_mib));950}951 952void bnx2x_dcbx_set_state(struct bnx2x *bp, bool dcb_on, u32 dcbx_enabled)953{954 if (!CHIP_IS_E1x(bp)) {955 bp->dcb_state = dcb_on;956 bp->dcbx_enabled = dcbx_enabled;957 } else {958 bp->dcb_state = false;959 bp->dcbx_enabled = BNX2X_DCBX_ENABLED_INVALID;960 }961 DP(BNX2X_MSG_DCB, "DCB state [%s:%s]\n",962 dcb_on ? "ON" : "OFF",963 dcbx_enabled == BNX2X_DCBX_ENABLED_OFF ? "user-mode" :964 dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_OFF ? "on-chip static" :965 dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_ON ?966 "on-chip with negotiation" : "invalid");967}968 969void bnx2x_dcbx_init_params(struct bnx2x *bp)970{971 bp->dcbx_config_params.admin_dcbx_version = 0x0; /* 0 - CEE; 1 - IEEE */972 bp->dcbx_config_params.admin_ets_willing = 1;973 bp->dcbx_config_params.admin_pfc_willing = 1;974 bp->dcbx_config_params.overwrite_settings = 1;975 bp->dcbx_config_params.admin_ets_enable = 1;976 bp->dcbx_config_params.admin_pfc_enable = 1;977 bp->dcbx_config_params.admin_tc_supported_tx_enable = 1;978 bp->dcbx_config_params.admin_ets_configuration_tx_enable = 1;979 bp->dcbx_config_params.admin_pfc_tx_enable = 1;980 bp->dcbx_config_params.admin_application_priority_tx_enable = 1;981 bp->dcbx_config_params.admin_ets_reco_valid = 1;982 bp->dcbx_config_params.admin_app_priority_willing = 1;983 bp->dcbx_config_params.admin_configuration_bw_precentage[0] = 100;984 bp->dcbx_config_params.admin_configuration_bw_precentage[1] = 0;985 bp->dcbx_config_params.admin_configuration_bw_precentage[2] = 0;986 bp->dcbx_config_params.admin_configuration_bw_precentage[3] = 0;987 bp->dcbx_config_params.admin_configuration_bw_precentage[4] = 0;988 bp->dcbx_config_params.admin_configuration_bw_precentage[5] = 0;989 bp->dcbx_config_params.admin_configuration_bw_precentage[6] = 0;990 bp->dcbx_config_params.admin_configuration_bw_precentage[7] = 0;991 bp->dcbx_config_params.admin_configuration_ets_pg[0] = 0;992 bp->dcbx_config_params.admin_configuration_ets_pg[1] = 0;993 bp->dcbx_config_params.admin_configuration_ets_pg[2] = 0;994 bp->dcbx_config_params.admin_configuration_ets_pg[3] = 0;995 bp->dcbx_config_params.admin_configuration_ets_pg[4] = 0;996 bp->dcbx_config_params.admin_configuration_ets_pg[5] = 0;997 bp->dcbx_config_params.admin_configuration_ets_pg[6] = 0;998 bp->dcbx_config_params.admin_configuration_ets_pg[7] = 0;999 bp->dcbx_config_params.admin_recommendation_bw_precentage[0] = 100;1000 bp->dcbx_config_params.admin_recommendation_bw_precentage[1] = 0;1001 bp->dcbx_config_params.admin_recommendation_bw_precentage[2] = 0;1002 bp->dcbx_config_params.admin_recommendation_bw_precentage[3] = 0;1003 bp->dcbx_config_params.admin_recommendation_bw_precentage[4] = 0;1004 bp->dcbx_config_params.admin_recommendation_bw_precentage[5] = 0;1005 bp->dcbx_config_params.admin_recommendation_bw_precentage[6] = 0;1006 bp->dcbx_config_params.admin_recommendation_bw_precentage[7] = 0;1007 bp->dcbx_config_params.admin_recommendation_ets_pg[0] = 0;1008 bp->dcbx_config_params.admin_recommendation_ets_pg[1] = 1;1009 bp->dcbx_config_params.admin_recommendation_ets_pg[2] = 2;1010 bp->dcbx_config_params.admin_recommendation_ets_pg[3] = 3;1011 bp->dcbx_config_params.admin_recommendation_ets_pg[4] = 4;1012 bp->dcbx_config_params.admin_recommendation_ets_pg[5] = 5;1013 bp->dcbx_config_params.admin_recommendation_ets_pg[6] = 6;1014 bp->dcbx_config_params.admin_recommendation_ets_pg[7] = 7;1015 bp->dcbx_config_params.admin_pfc_bitmap = 0x0;1016 bp->dcbx_config_params.admin_priority_app_table[0].valid = 0;1017 bp->dcbx_config_params.admin_priority_app_table[1].valid = 0;1018 bp->dcbx_config_params.admin_priority_app_table[2].valid = 0;1019 bp->dcbx_config_params.admin_priority_app_table[3].valid = 0;1020 bp->dcbx_config_params.admin_default_priority = 0;1021}1022 1023void bnx2x_dcbx_init(struct bnx2x *bp, bool update_shmem)1024{1025 u32 dcbx_lldp_params_offset = SHMEM_LLDP_DCBX_PARAMS_NONE;1026 1027 /* only PMF can send ADMIN msg to MFW in old MFW versions */1028 if ((!bp->port.pmf) && (!(bp->flags & BC_SUPPORTS_DCBX_MSG_NON_PMF)))1029 return;1030 1031 if (bp->dcbx_enabled <= 0)1032 return;1033 1034 /* validate:1035 * chip of good for dcbx version,1036 * dcb is wanted1037 * shmem2 contains DCBX support fields1038 */1039 DP(BNX2X_MSG_DCB, "dcb_state %d bp->port.pmf %d\n",1040 bp->dcb_state, bp->port.pmf);1041 1042 if (bp->dcb_state == BNX2X_DCB_STATE_ON &&1043 SHMEM2_HAS(bp, dcbx_lldp_params_offset)) {1044 dcbx_lldp_params_offset =1045 SHMEM2_RD(bp, dcbx_lldp_params_offset);1046 1047 DP(BNX2X_MSG_DCB, "dcbx_lldp_params_offset 0x%x\n",1048 dcbx_lldp_params_offset);1049 1050 bnx2x_update_drv_flags(bp, 1 << DRV_FLAGS_DCB_CONFIGURED, 0);1051 1052 if (SHMEM_LLDP_DCBX_PARAMS_NONE != dcbx_lldp_params_offset) {1053 /* need HW lock to avoid scenario of two drivers1054 * writing in parallel to shmem1055 */1056 bnx2x_acquire_hw_lock(bp,1057 HW_LOCK_RESOURCE_DCBX_ADMIN_MIB);1058 if (update_shmem)1059 bnx2x_dcbx_admin_mib_updated_params(bp,1060 dcbx_lldp_params_offset);1061 1062 /* Let HW start negotiation */1063 bnx2x_fw_command(bp,1064 DRV_MSG_CODE_DCBX_ADMIN_PMF_MSG, 0);1065 /* release HW lock only after MFW acks that it finished1066 * reading values from shmem1067 */1068 bnx2x_release_hw_lock(bp,1069 HW_LOCK_RESOURCE_DCBX_ADMIN_MIB);1070 }1071 }1072}1073static void1074bnx2x_dcbx_print_cos_params(struct bnx2x *bp,1075 struct bnx2x_func_tx_start_params *pfc_fw_cfg)1076{1077 u8 pri = 0;1078 u8 cos = 0;1079 1080 DP(BNX2X_MSG_DCB,1081 "pfc_fw_cfg->dcb_version %x\n", pfc_fw_cfg->dcb_version);1082 DP(BNX2X_MSG_DCB,1083 "pdev->params.dcbx_port_params.pfc.priority_non_pauseable_mask %x\n",1084 bp->dcbx_port_params.pfc.priority_non_pauseable_mask);1085 1086 for (cos = 0 ; cos < bp->dcbx_port_params.ets.num_of_cos ; cos++) {1087 DP(BNX2X_MSG_DCB,1088 "pdev->params.dcbx_port_params.ets.cos_params[%d].pri_bitmask %x\n",1089 cos, bp->dcbx_port_params.ets.cos_params[cos].pri_bitmask);1090 1091 DP(BNX2X_MSG_DCB,1092 "pdev->params.dcbx_port_params.ets.cos_params[%d].bw_tbl %x\n",1093 cos, bp->dcbx_port_params.ets.cos_params[cos].bw_tbl);1094 1095 DP(BNX2X_MSG_DCB,1096 "pdev->params.dcbx_port_params.ets.cos_params[%d].strict %x\n",1097 cos, bp->dcbx_port_params.ets.cos_params[cos].strict);1098 1099 DP(BNX2X_MSG_DCB,1100 "pdev->params.dcbx_port_params.ets.cos_params[%d].pauseable %x\n",1101 cos, bp->dcbx_port_params.ets.cos_params[cos].pauseable);1102 }1103 1104 for (pri = 0; pri < LLFC_DRIVER_TRAFFIC_TYPE_MAX; pri++) {1105 DP(BNX2X_MSG_DCB,1106 "pfc_fw_cfg->traffic_type_to_priority_cos[%d].priority %x\n",1107 pri, pfc_fw_cfg->traffic_type_to_priority_cos[pri].priority);1108 1109 DP(BNX2X_MSG_DCB,1110 "pfc_fw_cfg->traffic_type_to_priority_cos[%d].cos %x\n",1111 pri, pfc_fw_cfg->traffic_type_to_priority_cos[pri].cos);1112 }1113}1114 1115/* fills help_data according to pg_info */1116static void bnx2x_dcbx_get_num_pg_traf_type(struct bnx2x *bp,1117 u32 *pg_pri_orginal_spread,1118 struct pg_help_data *help_data)1119{1120 bool pg_found = false;1121 u32 i, traf_type, add_traf_type, add_pg;1122 u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;1123 struct pg_entry_help_data *data = help_data->data; /*shortcut*/1124 1125 /* Set to invalid */1126 for (i = 0; i < LLFC_DRIVER_TRAFFIC_TYPE_MAX; i++)1127 data[i].pg = DCBX_ILLEGAL_PG;1128 1129 for (add_traf_type = 0;1130 add_traf_type < LLFC_DRIVER_TRAFFIC_TYPE_MAX; add_traf_type++) {1131 pg_found = false;1132 if (ttp[add_traf_type] < MAX_PFC_PRIORITIES) {1133 add_pg = (u8)pg_pri_orginal_spread[ttp[add_traf_type]];1134 for (traf_type = 0;1135 traf_type < LLFC_DRIVER_TRAFFIC_TYPE_MAX;1136 traf_type++) {1137 if (data[traf_type].pg == add_pg) {1138 if (!(data[traf_type].pg_priority &1139 (1 << ttp[add_traf_type])))1140 data[traf_type].1141 num_of_dif_pri++;1142 data[traf_type].pg_priority |=1143 (1 << ttp[add_traf_type]);1144 pg_found = true;1145 break;1146 }1147 }1148 if (!pg_found) {1149 data[help_data->num_of_pg].pg = add_pg;1150 data[help_data->num_of_pg].pg_priority =1151 (1 << ttp[add_traf_type]);1152 data[help_data->num_of_pg].num_of_dif_pri = 1;1153 help_data->num_of_pg++;1154 }1155 }1156 DP(BNX2X_MSG_DCB,1157 "add_traf_type %d pg_found %s num_of_pg %d\n",1158 add_traf_type, !pg_found ? "NO" : "YES",1159 help_data->num_of_pg);1160 }1161}1162 1163static void bnx2x_dcbx_ets_disabled_entry_data(struct bnx2x *bp,1164 struct cos_help_data *cos_data,1165 u32 pri_join_mask)1166{1167 /* Only one priority than only one COS */1168 cos_data->data[0].pausable =1169 IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask);1170 cos_data->data[0].pri_join_mask = pri_join_mask;1171 cos_data->data[0].cos_bw = 100;1172 cos_data->num_of_cos = 1;1173}1174 1175static inline void bnx2x_dcbx_add_to_cos_bw(struct bnx2x *bp,1176 struct cos_entry_help_data *data,1177 u8 pg_bw)1178{1179 if (data->cos_bw == DCBX_INVALID_COS_BW)1180 data->cos_bw = pg_bw;1181 else1182 data->cos_bw += pg_bw;1183}1184 1185static void bnx2x_dcbx_separate_pauseable_from_non(struct bnx2x *bp,1186 struct cos_help_data *cos_data,1187 u32 *pg_pri_orginal_spread,1188 struct dcbx_ets_feature *ets)1189{1190 u32 pri_tested = 0;1191 u8 i = 0;1192 u8 entry = 0;1193 u8 pg_entry = 0;1194 u8 num_of_pri = LLFC_DRIVER_TRAFFIC_TYPE_MAX;1195 1196 cos_data->data[0].pausable = true;1197 cos_data->data[1].pausable = false;1198 cos_data->data[0].pri_join_mask = cos_data->data[1].pri_join_mask = 0;1199 1200 for (i = 0 ; i < num_of_pri ; i++) {1201 pri_tested = 1 << bp->dcbx_port_params.1202 app.traffic_type_priority[i];1203 1204 if (pri_tested & DCBX_PFC_PRI_NON_PAUSE_MASK(bp)) {1205 cos_data->data[1].pri_join_mask |= pri_tested;1206 entry = 1;1207 } else {1208 cos_data->data[0].pri_join_mask |= pri_tested;1209 entry = 0;1210 }1211 pg_entry = (u8)pg_pri_orginal_spread[bp->dcbx_port_params.1212 app.traffic_type_priority[i]];1213 /* There can be only one strict pg */1214 if (pg_entry < DCBX_MAX_NUM_PG_BW_ENTRIES)1215 bnx2x_dcbx_add_to_cos_bw(bp, &cos_data->data[entry],1216 DCBX_PG_BW_GET(ets->pg_bw_tbl, pg_entry));1217 else1218 /* If we join a group and one is strict1219 * than the bw rules1220 */1221 cos_data->data[entry].strict =1222 BNX2X_DCBX_STRICT_COS_HIGHEST;1223 }1224 if ((0 == cos_data->data[0].pri_join_mask) &&1225 (0 == cos_data->data[1].pri_join_mask))1226 BNX2X_ERR("dcbx error: Both groups must have priorities\n");1227}1228 1229#ifndef POWER_OF_21230#define POWER_OF_2(x) ((0 != x) && (0 == (x & (x-1))))1231#endif1232 1233static void bnx2x_dcbx_2cos_limit_cee_single_pg_to_cos_params(struct bnx2x *bp,1234 struct pg_help_data *pg_help_data,1235 struct cos_help_data *cos_data,1236 u32 pri_join_mask,1237 u8 num_of_dif_pri)1238{1239 u8 i = 0;1240 u32 pri_tested = 0;1241 u32 pri_mask_without_pri = 0;1242 u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;1243 /*debug*/1244 if (num_of_dif_pri == 1) {1245 bnx2x_dcbx_ets_disabled_entry_data(bp, cos_data, pri_join_mask);1246 return;1247 }1248 /* single priority group */1249 if (pg_help_data->data[0].pg < DCBX_MAX_NUM_PG_BW_ENTRIES) {1250 /* If there are both pauseable and non-pauseable priorities,1251 * the pauseable priorities go to the first queue and1252 * the non-pauseable priorities go to the second queue.1253 */1254 if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask)) {1255 /* Pauseable */1256 cos_data->data[0].pausable = true;1257 /* Non pauseable.*/1258 cos_data->data[1].pausable = false;1259 1260 if (2 == num_of_dif_pri) {1261 cos_data->data[0].cos_bw = 50;1262 cos_data->data[1].cos_bw = 50;1263 }1264 1265 if (3 == num_of_dif_pri) {1266 if (POWER_OF_2(DCBX_PFC_PRI_GET_PAUSE(bp,1267 pri_join_mask))) {1268 cos_data->data[0].cos_bw = 33;1269 cos_data->data[1].cos_bw = 67;1270 } else {1271 cos_data->data[0].cos_bw = 67;1272 cos_data->data[1].cos_bw = 33;1273 }1274 }1275 1276 } else if (IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask)) {1277 /* If there are only pauseable priorities,1278 * then one/two priorities go to the first queue1279 * and one priority goes to the second queue.1280 */1281 if (2 == num_of_dif_pri) {1282 cos_data->data[0].cos_bw = 50;1283 cos_data->data[1].cos_bw = 50;1284 } else {1285 cos_data->data[0].cos_bw = 67;1286 cos_data->data[1].cos_bw = 33;1287 }1288 cos_data->data[1].pausable = true;1289 cos_data->data[0].pausable = true;1290 /* All priorities except FCOE */1291 cos_data->data[0].pri_join_mask = (pri_join_mask &1292 ((u8)~(1 << ttp[LLFC_TRAFFIC_TYPE_FCOE])));1293 /* Only FCOE priority.*/1294 cos_data->data[1].pri_join_mask =1295 (1 << ttp[LLFC_TRAFFIC_TYPE_FCOE]);1296 } else1297 /* If there are only non-pauseable priorities,1298 * they will all go to the same queue.1299 */1300 bnx2x_dcbx_ets_disabled_entry_data(bp,1301 cos_data, pri_join_mask);1302 } else {1303 /* priority group which is not BW limited (PG#15):*/1304 if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask)) {1305 /* If there are both pauseable and non-pauseable1306 * priorities, the pauseable priorities go to the first1307 * queue and the non-pauseable priorities1308 * go to the second queue.1309 */1310 if (DCBX_PFC_PRI_GET_PAUSE(bp, pri_join_mask) >1311 DCBX_PFC_PRI_GET_NON_PAUSE(bp, pri_join_mask)) {1312 cos_data->data[0].strict =1313 BNX2X_DCBX_STRICT_COS_HIGHEST;1314 cos_data->data[1].strict =1315 BNX2X_DCBX_STRICT_COS_NEXT_LOWER_PRI(1316 BNX2X_DCBX_STRICT_COS_HIGHEST);1317 } else {1318 cos_data->data[0].strict =1319 BNX2X_DCBX_STRICT_COS_NEXT_LOWER_PRI(1320 BNX2X_DCBX_STRICT_COS_HIGHEST);1321 cos_data->data[1].strict =1322 BNX2X_DCBX_STRICT_COS_HIGHEST;1323 }1324 /* Pauseable */1325 cos_data->data[0].pausable = true;1326 /* Non pause-able.*/1327 cos_data->data[1].pausable = false;1328 } else {1329 /* If there are only pauseable priorities or1330 * only non-pauseable,* the lower priorities go1331 * to the first queue and the higher priorities go1332 * to the second queue.1333 */1334 cos_data->data[0].pausable =1335 cos_data->data[1].pausable =1336 IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask);1337 1338 for (i = 0 ; i < LLFC_DRIVER_TRAFFIC_TYPE_MAX; i++) {1339 pri_tested = 1 << bp->dcbx_port_params.1340 app.traffic_type_priority[i];1341 /* Remove priority tested */1342 pri_mask_without_pri =1343 (pri_join_mask & ((u8)(~pri_tested)));1344 if (pri_mask_without_pri < pri_tested)1345 break;1346 }1347 1348 if (i == LLFC_DRIVER_TRAFFIC_TYPE_MAX)1349 BNX2X_ERR("Invalid value for pri_join_mask - could not find a priority\n");1350 1351 cos_data->data[0].pri_join_mask = pri_mask_without_pri;1352 cos_data->data[1].pri_join_mask = pri_tested;1353 /* Both queues are strict priority,1354 * and that with the highest priority1355 * gets the highest strict priority in the arbiter.1356 */1357 cos_data->data[0].strict =1358 BNX2X_DCBX_STRICT_COS_NEXT_LOWER_PRI(1359 BNX2X_DCBX_STRICT_COS_HIGHEST);1360 cos_data->data[1].strict =1361 BNX2X_DCBX_STRICT_COS_HIGHEST;1362 }1363 }1364}1365 1366static void bnx2x_dcbx_2cos_limit_cee_two_pg_to_cos_params(1367 struct bnx2x *bp,1368 struct pg_help_data *pg_help_data,1369 struct dcbx_ets_feature *ets,1370 struct cos_help_data *cos_data,1371 u32 *pg_pri_orginal_spread,1372 u32 pri_join_mask,1373 u8 num_of_dif_pri)1374{1375 u8 i = 0;1376 u8 pg[DCBX_COS_MAX_NUM_E2] = { 0 };1377 1378 /* If there are both pauseable and non-pauseable priorities,1379 * the pauseable priorities go to the first queue and1380 * the non-pauseable priorities go to the second queue.1381 */1382 if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask)) {1383 if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp,1384 pg_help_data->data[0].pg_priority) ||1385 IS_DCBX_PFC_PRI_MIX_PAUSE(bp,1386 pg_help_data->data[1].pg_priority)) {1387 /* If one PG contains both pauseable and1388 * non-pauseable priorities then ETS is disabled.1389 */1390 bnx2x_dcbx_separate_pauseable_from_non(bp, cos_data,1391 pg_pri_orginal_spread, ets);1392 bp->dcbx_port_params.ets.enabled = false;1393 return;1394 }1395 1396 /* Pauseable */1397 cos_data->data[0].pausable = true;1398 /* Non pauseable. */1399 cos_data->data[1].pausable = false;1400 if (IS_DCBX_PFC_PRI_ONLY_PAUSE(bp,1401 pg_help_data->data[0].pg_priority)) {1402 /* 0 is pauseable */1403 cos_data->data[0].pri_join_mask =1404 pg_help_data->data[0].pg_priority;1405 pg[0] = pg_help_data->data[0].pg;1406 cos_data->data[1].pri_join_mask =1407 pg_help_data->data[1].pg_priority;1408 pg[1] = pg_help_data->data[1].pg;1409 } else {/* 1 is pauseable */1410 cos_data->data[0].pri_join_mask =1411 pg_help_data->data[1].pg_priority;1412 pg[0] = pg_help_data->data[1].pg;1413 cos_data->data[1].pri_join_mask =1414 pg_help_data->data[0].pg_priority;1415 pg[1] = pg_help_data->data[0].pg;1416 }1417 } else {1418 /* If there are only pauseable priorities or1419 * only non-pauseable, each PG goes to a queue.1420 */1421 cos_data->data[0].pausable = cos_data->data[1].pausable =1422 IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask);1423 cos_data->data[0].pri_join_mask =1424 pg_help_data->data[0].pg_priority;1425 pg[0] = pg_help_data->data[0].pg;1426 cos_data->data[1].pri_join_mask =1427 pg_help_data->data[1].pg_priority;1428 pg[1] = pg_help_data->data[1].pg;1429 }1430 1431 /* There can be only one strict pg */1432 for (i = 0 ; i < ARRAY_SIZE(pg); i++) {1433 if (pg[i] < DCBX_MAX_NUM_PG_BW_ENTRIES)1434 cos_data->data[i].cos_bw =1435 DCBX_PG_BW_GET(ets->pg_bw_tbl, pg[i]);1436 else1437 cos_data->data[i].strict =1438 BNX2X_DCBX_STRICT_COS_HIGHEST;1439 }1440}1441 1442static int bnx2x_dcbx_join_pgs(1443 struct bnx2x *bp,1444 struct dcbx_ets_feature *ets,1445 struct pg_help_data *pg_help_data,1446 u8 required_num_of_pg)1447{1448 u8 entry_joined = pg_help_data->num_of_pg - 1;1449 u8 entry_removed = entry_joined + 1;1450 u8 pg_joined = 0;1451 1452 if (required_num_of_pg == 0 || ARRAY_SIZE(pg_help_data->data)1453 <= pg_help_data->num_of_pg) {1454 1455 BNX2X_ERR("required_num_of_pg can't be zero\n");1456 return -EINVAL;1457 }1458 1459 while (required_num_of_pg < pg_help_data->num_of_pg) {1460 entry_joined = pg_help_data->num_of_pg - 2;1461 entry_removed = entry_joined + 1;1462 /* protect index */1463 entry_removed %= ARRAY_SIZE(pg_help_data->data);1464 1465 pg_help_data->data[entry_joined].pg_priority |=1466 pg_help_data->data[entry_removed].pg_priority;1467 1468 pg_help_data->data[entry_joined].num_of_dif_pri +=1469 pg_help_data->data[entry_removed].num_of_dif_pri;1470 1471 if (pg_help_data->data[entry_joined].pg == DCBX_STRICT_PRI_PG ||1472 pg_help_data->data[entry_removed].pg == DCBX_STRICT_PRI_PG)1473 /* Entries joined strict priority rules */1474 pg_help_data->data[entry_joined].pg =1475 DCBX_STRICT_PRI_PG;1476 else {1477 /* Entries can be joined join BW */1478 pg_joined = DCBX_PG_BW_GET(ets->pg_bw_tbl,1479 pg_help_data->data[entry_joined].pg) +1480 DCBX_PG_BW_GET(ets->pg_bw_tbl,1481 pg_help_data->data[entry_removed].pg);1482 1483 DCBX_PG_BW_SET(ets->pg_bw_tbl,1484 pg_help_data->data[entry_joined].pg, pg_joined);1485 }1486 /* Joined the entries */1487 pg_help_data->num_of_pg--;1488 }1489 1490 return 0;1491}1492 1493static void bnx2x_dcbx_2cos_limit_cee_three_pg_to_cos_params(1494 struct bnx2x *bp,1495 struct pg_help_data *pg_help_data,1496 struct dcbx_ets_feature *ets,1497 struct cos_help_data *cos_data,1498 u32 *pg_pri_orginal_spread,1499 u32 pri_join_mask,1500 u8 num_of_dif_pri)1501{1502 u8 i = 0;1503 u32 pri_tested = 0;1504 u8 entry = 0;1505 u8 pg_entry = 0;1506 bool b_found_strict = false;1507 u8 num_of_pri = LLFC_DRIVER_TRAFFIC_TYPE_MAX;1508 1509 cos_data->data[0].pri_join_mask = cos_data->data[1].pri_join_mask = 0;1510 /* If there are both pauseable and non-pauseable priorities,1511 * the pauseable priorities go to the first queue and the1512 * non-pauseable priorities go to the second queue.1513 */1514 if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask))1515 bnx2x_dcbx_separate_pauseable_from_non(bp,1516 cos_data, pg_pri_orginal_spread, ets);1517 else {1518 /* If two BW-limited PG-s were combined to one queue,1519 * the BW is their sum.1520 *1521 * If there are only pauseable priorities or only non-pauseable,1522 * and there are both BW-limited and non-BW-limited PG-s,1523 * the BW-limited PG/s go to one queue and the non-BW-limited1524 * PG/s go to the second queue.1525 *1526 * If there are only pauseable priorities or only non-pauseable1527 * and all are BW limited, then two priorities go to the first1528 * queue and one priority goes to the second queue.1529 *1530 * We will join this two cases:1531 * if one is BW limited it will go to the second queue1532 * otherwise the last priority will get it1533 */1534 1535 cos_data->data[0].pausable = cos_data->data[1].pausable =1536 IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask);1537 1538 for (i = 0 ; i < num_of_pri; i++) {1539 pri_tested = 1 << bp->dcbx_port_params.1540 app.traffic_type_priority[i];1541 pg_entry = (u8)pg_pri_orginal_spread[bp->1542 dcbx_port_params.app.traffic_type_priority[i]];1543 1544 if (pg_entry < DCBX_MAX_NUM_PG_BW_ENTRIES) {1545 entry = 0;1546 1547 if (i == (num_of_pri-1) && !b_found_strict)1548 /* last entry will be handled separately1549 * If no priority is strict than last1550 * entry goes to last queue.1551 */1552 entry = 1;1553 cos_data->data[entry].pri_join_mask |=1554 pri_tested;1555 bnx2x_dcbx_add_to_cos_bw(bp,1556 &cos_data->data[entry],1557 DCBX_PG_BW_GET(ets->pg_bw_tbl,1558 pg_entry));1559 } else {1560 b_found_strict = true;1561 cos_data->data[1].pri_join_mask |= pri_tested;1562 /* If we join a group and one is strict1563 * than the bw rules1564 */1565 cos_data->data[1].strict =1566 BNX2X_DCBX_STRICT_COS_HIGHEST;1567 }1568 }1569 }1570}1571 1572static void bnx2x_dcbx_2cos_limit_cee_fill_cos_params(struct bnx2x *bp,1573 struct pg_help_data *help_data,1574 struct dcbx_ets_feature *ets,1575 struct cos_help_data *cos_data,1576 u32 *pg_pri_orginal_spread,1577 u32 pri_join_mask,1578 u8 num_of_dif_pri)1579{1580 /* default E2 settings */1581 cos_data->num_of_cos = DCBX_COS_MAX_NUM_E2;1582 1583 switch (help_data->num_of_pg) {1584 case 1:1585 bnx2x_dcbx_2cos_limit_cee_single_pg_to_cos_params(1586 bp,1587 help_data,1588 cos_data,1589 pri_join_mask,1590 num_of_dif_pri);1591 break;1592 case 2:1593 bnx2x_dcbx_2cos_limit_cee_two_pg_to_cos_params(1594 bp,1595 help_data,1596 ets,1597 cos_data,1598 pg_pri_orginal_spread,1599 pri_join_mask,1600 num_of_dif_pri);1601 break;1602 1603 case 3:1604 bnx2x_dcbx_2cos_limit_cee_three_pg_to_cos_params(1605 bp,1606 help_data,1607 ets,1608 cos_data,1609 pg_pri_orginal_spread,1610 pri_join_mask,1611 num_of_dif_pri);1612 break;1613 default:1614 BNX2X_ERR("Wrong pg_help_data.num_of_pg\n");1615 bnx2x_dcbx_ets_disabled_entry_data(bp,1616 cos_data, pri_join_mask);1617 }1618}1619 1620static int bnx2x_dcbx_spread_strict_pri(struct bnx2x *bp,1621 struct cos_help_data *cos_data,1622 u8 entry,1623 u8 num_spread_of_entries,1624 u8 strict_app_pris)1625{1626 u8 strict_pri = BNX2X_DCBX_STRICT_COS_HIGHEST;1627 u8 num_of_app_pri = MAX_PFC_PRIORITIES;1628 u8 app_pri_bit = 0;1629 1630 while (num_spread_of_entries && num_of_app_pri > 0) {1631 app_pri_bit = 1 << (num_of_app_pri - 1);1632 if (app_pri_bit & strict_app_pris) {1633 struct cos_entry_help_data *data = &cos_data->1634 data[entry];1635 num_spread_of_entries--;1636 if (num_spread_of_entries == 0) {1637 /* last entry needed put all the entries left */1638 data->cos_bw = DCBX_INVALID_COS_BW;1639 data->strict = strict_pri;1640 data->pri_join_mask = strict_app_pris;1641 data->pausable = DCBX_IS_PFC_PRI_SOME_PAUSE(bp,1642 data->pri_join_mask);1643 } else {1644 strict_app_pris &= ~app_pri_bit;1645 1646 data->cos_bw = DCBX_INVALID_COS_BW;1647 data->strict = strict_pri;1648 data->pri_join_mask = app_pri_bit;1649 data->pausable = DCBX_IS_PFC_PRI_SOME_PAUSE(bp,1650 data->pri_join_mask);1651 }1652 1653 strict_pri =1654 BNX2X_DCBX_STRICT_COS_NEXT_LOWER_PRI(strict_pri);1655 entry++;1656 }1657 1658 num_of_app_pri--;1659 }1660 1661 if (num_spread_of_entries) {1662 BNX2X_ERR("Didn't succeed to spread strict priorities\n");1663 return -EINVAL;1664 }1665 1666 return 0;1667}1668 1669static u8 bnx2x_dcbx_cee_fill_strict_pri(struct bnx2x *bp,1670 struct cos_help_data *cos_data,1671 u8 entry,1672 u8 num_spread_of_entries,1673 u8 strict_app_pris)1674{1675 if (bnx2x_dcbx_spread_strict_pri(bp, cos_data, entry,1676 num_spread_of_entries,1677 strict_app_pris)) {1678 struct cos_entry_help_data *data = &cos_data->1679 data[entry];1680 /* Fill BW entry */1681 data->cos_bw = DCBX_INVALID_COS_BW;1682 data->strict = BNX2X_DCBX_STRICT_COS_HIGHEST;1683 data->pri_join_mask = strict_app_pris;1684 data->pausable = DCBX_IS_PFC_PRI_SOME_PAUSE(bp,1685 data->pri_join_mask);1686 return 1;1687 }1688 1689 return num_spread_of_entries;1690}1691 1692static void bnx2x_dcbx_cee_fill_cos_params(struct bnx2x *bp,1693 struct pg_help_data *help_data,1694 struct dcbx_ets_feature *ets,1695 struct cos_help_data *cos_data,1696 u32 pri_join_mask)1697 1698{1699 u8 need_num_of_entries = 0;1700 u8 i = 0;1701 u8 entry = 0;1702 1703 /*1704 * if the number of requested PG-s in CEE is greater than 31705 * then the results are not determined since this is a violation1706 * of the standard.1707 */1708 if (help_data->num_of_pg > DCBX_COS_MAX_NUM_E3B0) {1709 if (bnx2x_dcbx_join_pgs(bp, ets, help_data,1710 DCBX_COS_MAX_NUM_E3B0)) {1711 BNX2X_ERR("Unable to reduce the number of PGs - we will disables ETS\n");1712 bnx2x_dcbx_ets_disabled_entry_data(bp, cos_data,1713 pri_join_mask);1714 return;1715 }1716 }1717 1718 for (i = 0 ; i < help_data->num_of_pg; i++) {1719 struct pg_entry_help_data *pg = &help_data->data[i];1720 if (pg->pg < DCBX_MAX_NUM_PG_BW_ENTRIES) {1721 struct cos_entry_help_data *data = &cos_data->1722 data[entry];1723 /* Fill BW entry */1724 data->cos_bw = DCBX_PG_BW_GET(ets->pg_bw_tbl, pg->pg);1725 data->strict = BNX2X_DCBX_STRICT_INVALID;1726 data->pri_join_mask = pg->pg_priority;1727 data->pausable = DCBX_IS_PFC_PRI_SOME_PAUSE(bp,1728 data->pri_join_mask);1729 1730 entry++;1731 } else {1732 need_num_of_entries = min_t(u8,1733 (u8)pg->num_of_dif_pri,1734 (u8)DCBX_COS_MAX_NUM_E3B0 -1735 help_data->num_of_pg + 1);1736 /*1737 * If there are still VOQ-s which have no associated PG,1738 * then associate these VOQ-s to PG15. These PG-s will1739 * be used for SP between priorities on PG15.1740 */1741 entry += bnx2x_dcbx_cee_fill_strict_pri(bp, cos_data,1742 entry, need_num_of_entries, pg->pg_priority);1743 }1744 }1745 1746 /* the entry will represent the number of COSes used */1747 cos_data->num_of_cos = entry;1748}1749static void bnx2x_dcbx_fill_cos_params(struct bnx2x *bp,1750 struct pg_help_data *help_data,1751 struct dcbx_ets_feature *ets,1752 u32 *pg_pri_orginal_spread)1753{1754 struct cos_help_data cos_data;1755 u8 i = 0;1756 u32 pri_join_mask = 0;1757 u8 num_of_dif_pri = 0;1758 1759 memset(&cos_data, 0, sizeof(cos_data));1760 1761 /* Validate the pg value */1762 for (i = 0; i < help_data->num_of_pg ; i++) {1763 if (DCBX_STRICT_PRIORITY != help_data->data[i].pg &&1764 DCBX_MAX_NUM_PG_BW_ENTRIES <= help_data->data[i].pg)1765 BNX2X_ERR("Invalid pg[%d] data %x\n", i,1766 help_data->data[i].pg);1767 pri_join_mask |= help_data->data[i].pg_priority;1768 num_of_dif_pri += help_data->data[i].num_of_dif_pri;1769 }1770 1771 /* defaults */1772 cos_data.num_of_cos = 1;1773 for (i = 0; i < ARRAY_SIZE(cos_data.data); i++) {1774 cos_data.data[i].pri_join_mask = 0;1775 cos_data.data[i].pausable = false;1776 cos_data.data[i].strict = BNX2X_DCBX_STRICT_INVALID;1777 cos_data.data[i].cos_bw = DCBX_INVALID_COS_BW;1778 }1779 1780 if (CHIP_IS_E3B0(bp))1781 bnx2x_dcbx_cee_fill_cos_params(bp, help_data, ets,1782 &cos_data, pri_join_mask);1783 else /* E2 + E3A0 */1784 bnx2x_dcbx_2cos_limit_cee_fill_cos_params(bp,1785 help_data, ets,1786 &cos_data,1787 pg_pri_orginal_spread,1788 pri_join_mask,1789 num_of_dif_pri);1790 1791 for (i = 0; i < cos_data.num_of_cos ; i++) {1792 struct bnx2x_dcbx_cos_params *p =1793 &bp->dcbx_port_params.ets.cos_params[i];1794 1795 p->strict = cos_data.data[i].strict;1796 p->bw_tbl = cos_data.data[i].cos_bw;1797 p->pri_bitmask = cos_data.data[i].pri_join_mask;1798 p->pauseable = cos_data.data[i].pausable;1799 1800 /* sanity */1801 if (p->bw_tbl != DCBX_INVALID_COS_BW ||1802 p->strict != BNX2X_DCBX_STRICT_INVALID) {1803 if (p->pri_bitmask == 0)1804 BNX2X_ERR("Invalid pri_bitmask for %d\n", i);1805 1806 if (CHIP_IS_E2(bp) || CHIP_IS_E3A0(bp)) {1807 1808 if (p->pauseable &&1809 DCBX_PFC_PRI_GET_NON_PAUSE(bp,1810 p->pri_bitmask) != 0)1811 BNX2X_ERR("Inconsistent config for pausable COS %d\n",1812 i);1813 1814 if (!p->pauseable &&1815 DCBX_PFC_PRI_GET_PAUSE(bp,1816 p->pri_bitmask) != 0)1817 BNX2X_ERR("Inconsistent config for nonpausable COS %d\n",1818 i);1819 }1820 }1821 1822 if (p->pauseable)1823 DP(BNX2X_MSG_DCB, "COS %d PAUSABLE prijoinmask 0x%x\n",1824 i, cos_data.data[i].pri_join_mask);1825 else1826 DP(BNX2X_MSG_DCB,1827 "COS %d NONPAUSABLE prijoinmask 0x%x\n",1828 i, cos_data.data[i].pri_join_mask);1829 }1830 1831 bp->dcbx_port_params.ets.num_of_cos = cos_data.num_of_cos ;1832}1833 1834static void bnx2x_dcbx_get_ets_pri_pg_tbl(struct bnx2x *bp,1835 u32 *set_configuration_ets_pg,1836 u32 *pri_pg_tbl)1837{1838 int i;1839 1840 for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES; i++) {1841 set_configuration_ets_pg[i] = DCBX_PRI_PG_GET(pri_pg_tbl, i);1842 1843 DP(BNX2X_MSG_DCB, "set_configuration_ets_pg[%d] = 0x%x\n",1844 i, set_configuration_ets_pg[i]);1845 }1846}1847 1848static void bnx2x_dcbx_fw_struct(struct bnx2x *bp,1849 struct bnx2x_func_tx_start_params *pfc_fw_cfg)1850{1851 u16 pri_bit = 0;1852 u8 cos = 0, pri = 0;1853 struct priority_cos *tt2cos;1854 u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;1855 int mfw_configured = SHMEM2_HAS(bp, drv_flags) &&1856 GET_FLAGS(SHMEM2_RD(bp, drv_flags),1857 1 << DRV_FLAGS_DCB_MFW_CONFIGURED);1858 1859 memset(pfc_fw_cfg, 0, sizeof(*pfc_fw_cfg));1860 1861 /* to disable DCB - the structure must be zeroed */1862 if ((bp->dcbx_error & DCBX_REMOTE_MIB_ERROR) && !mfw_configured)1863 return;1864 1865 /*shortcut*/1866 tt2cos = pfc_fw_cfg->traffic_type_to_priority_cos;1867 1868 /* Fw version should be incremented each update */1869 pfc_fw_cfg->dcb_version = ++bp->dcb_version;1870 pfc_fw_cfg->dcb_enabled = 1;1871 1872 /* Fill priority parameters */1873 for (pri = 0; pri < LLFC_DRIVER_TRAFFIC_TYPE_MAX; pri++) {1874 tt2cos[pri].priority = ttp[pri];1875 pri_bit = 1 << tt2cos[pri].priority;1876 1877 /* Fill COS parameters based on COS calculated to1878 * make it more general for future use */1879 for (cos = 0; cos < bp->dcbx_port_params.ets.num_of_cos; cos++)1880 if (bp->dcbx_port_params.ets.cos_params[cos].1881 pri_bitmask & pri_bit)1882 tt2cos[pri].cos = cos;1883 1884 pfc_fw_cfg->dcb_outer_pri[pri] = ttp[pri];1885 }1886 1887 /* we never want the FW to add a 0 vlan tag */1888 pfc_fw_cfg->dont_add_pri_0_en = 1;1889 1890 bnx2x_dcbx_print_cos_params(bp, pfc_fw_cfg);1891}1892 1893void bnx2x_dcbx_pmf_update(struct bnx2x *bp)1894{1895 /* if we need to synchronize DCBX result from prev PMF1896 * read it from shmem and update bp and netdev accordingly1897 */1898 if (SHMEM2_HAS(bp, drv_flags) &&1899 GET_FLAGS(SHMEM2_RD(bp, drv_flags), 1 << DRV_FLAGS_DCB_CONFIGURED)) {1900 /* Read neg results if dcbx is in the FW */1901 if (bnx2x_dcbx_read_shmem_neg_results(bp))1902 return;1903 1904 bnx2x_dump_dcbx_drv_param(bp, &bp->dcbx_local_feat,1905 bp->dcbx_error);1906 bnx2x_get_dcbx_drv_param(bp, &bp->dcbx_local_feat,1907 bp->dcbx_error);1908#ifdef BCM_DCBNL1909 /*1910 * Add new app tlvs to dcbnl1911 */1912 bnx2x_dcbnl_update_applist(bp, false);1913 /*1914 * Send a notification for the new negotiated parameters1915 */1916 dcbnl_cee_notify(bp->dev, RTM_GETDCB, DCB_CMD_CEE_GET, 0, 0);1917#endif1918 /*1919 * reconfigure the netdevice with the results of the new1920 * dcbx negotiation.1921 */1922 bnx2x_dcbx_update_tc_mapping(bp);1923 }1924}1925 1926/* DCB netlink */1927#ifdef BCM_DCBNL1928 1929#define BNX2X_DCBX_CAPS (DCB_CAP_DCBX_LLD_MANAGED | \1930 DCB_CAP_DCBX_VER_CEE | DCB_CAP_DCBX_STATIC)1931 1932static inline bool bnx2x_dcbnl_set_valid(struct bnx2x *bp)1933{1934 /* validate dcbnl call that may change HW state:1935 * DCB is on and DCBX mode was SUCCESSFULLY set by the user.1936 */1937 return bp->dcb_state && bp->dcbx_mode_uset;1938}1939 1940static u8 bnx2x_dcbnl_get_state(struct net_device *netdev)1941{1942 struct bnx2x *bp = netdev_priv(netdev);1943 DP(BNX2X_MSG_DCB, "state = %d\n", bp->dcb_state);1944 return bp->dcb_state;1945}1946 1947static u8 bnx2x_dcbnl_set_state(struct net_device *netdev, u8 state)1948{1949 struct bnx2x *bp = netdev_priv(netdev);1950 DP(BNX2X_MSG_DCB, "state = %s\n", state ? "on" : "off");1951 1952 /* Fail to set state to "enabled" if dcbx is disabled in nvram */1953 if (state && ((bp->dcbx_enabled == BNX2X_DCBX_ENABLED_OFF) ||1954 (bp->dcbx_enabled == BNX2X_DCBX_ENABLED_INVALID))) {1955 DP(BNX2X_MSG_DCB, "Can not set dcbx to enabled while it is disabled in nvm\n");1956 return 1;1957 }1958 1959 bnx2x_dcbx_set_state(bp, (state ? true : false), bp->dcbx_enabled);1960 return 0;1961}1962 1963static void bnx2x_dcbnl_get_perm_hw_addr(struct net_device *netdev,1964 u8 *perm_addr)1965{1966 struct bnx2x *bp = netdev_priv(netdev);1967 DP(BNX2X_MSG_DCB, "GET-PERM-ADDR\n");1968 1969 /* first the HW mac address */1970 memcpy(perm_addr, netdev->dev_addr, netdev->addr_len);1971 1972 if (CNIC_LOADED(bp))1973 /* second SAN address */1974 memcpy(perm_addr+netdev->addr_len, bp->fip_mac,1975 netdev->addr_len);1976}1977 1978static void bnx2x_dcbnl_set_pg_tccfg_tx(struct net_device *netdev, int prio,1979 u8 prio_type, u8 pgid, u8 bw_pct,1980 u8 up_map)1981{1982 struct bnx2x *bp = netdev_priv(netdev);1983 1984 DP(BNX2X_MSG_DCB, "prio[%d] = %d\n", prio, pgid);1985 if (!bnx2x_dcbnl_set_valid(bp) || prio >= DCBX_MAX_NUM_PRI_PG_ENTRIES)1986 return;1987 1988 /**1989 * bw_pct ignored - band-width percentage devision between user1990 * priorities within the same group is not1991 * standard and hence not supported1992 *1993 * prio_type ignored - priority levels within the same group are not1994 * standard and hence are not supported. According1995 * to the standard pgid 15 is dedicated to strict1996 * priority traffic (on the port level).1997 *1998 * up_map ignored1999 */2000 2001 bp->dcbx_config_params.admin_configuration_ets_pg[prio] = pgid;2002 bp->dcbx_config_params.admin_ets_configuration_tx_enable = 1;2003}2004 2005static void bnx2x_dcbnl_set_pg_bwgcfg_tx(struct net_device *netdev,2006 int pgid, u8 bw_pct)2007{2008 struct bnx2x *bp = netdev_priv(netdev);2009 DP(BNX2X_MSG_DCB, "pgid[%d] = %d\n", pgid, bw_pct);2010 2011 if (!bnx2x_dcbnl_set_valid(bp) || pgid >= DCBX_MAX_NUM_PG_BW_ENTRIES)2012 return;2013 2014 bp->dcbx_config_params.admin_configuration_bw_precentage[pgid] = bw_pct;2015 bp->dcbx_config_params.admin_ets_configuration_tx_enable = 1;2016}2017 2018static void bnx2x_dcbnl_set_pg_tccfg_rx(struct net_device *netdev, int prio,2019 u8 prio_type, u8 pgid, u8 bw_pct,2020 u8 up_map)2021{2022 struct bnx2x *bp = netdev_priv(netdev);2023 DP(BNX2X_MSG_DCB, "Nothing to set; No RX support\n");2024}2025 2026static void bnx2x_dcbnl_set_pg_bwgcfg_rx(struct net_device *netdev,2027 int pgid, u8 bw_pct)2028{2029 struct bnx2x *bp = netdev_priv(netdev);2030 DP(BNX2X_MSG_DCB, "Nothing to set; No RX support\n");2031}2032 2033static void bnx2x_dcbnl_get_pg_tccfg_tx(struct net_device *netdev, int prio,2034 u8 *prio_type, u8 *pgid, u8 *bw_pct,2035 u8 *up_map)2036{2037 struct bnx2x *bp = netdev_priv(netdev);2038 DP(BNX2X_MSG_DCB, "prio = %d\n", prio);2039 2040 /**2041 * bw_pct ignored - band-width percentage devision between user2042 * priorities within the same group is not2043 * standard and hence not supported2044 *2045 * prio_type ignored - priority levels within the same group are not2046 * standard and hence are not supported. According2047 * to the standard pgid 15 is dedicated to strict2048 * priority traffic (on the port level).2049 *2050 * up_map ignored2051 */2052 *up_map = *bw_pct = *prio_type = *pgid = 0;2053 2054 if (!bp->dcb_state || prio >= DCBX_MAX_NUM_PRI_PG_ENTRIES)2055 return;2056 2057 *pgid = DCBX_PRI_PG_GET(bp->dcbx_local_feat.ets.pri_pg_tbl, prio);2058}2059 2060static void bnx2x_dcbnl_get_pg_bwgcfg_tx(struct net_device *netdev,2061 int pgid, u8 *bw_pct)2062{2063 struct bnx2x *bp = netdev_priv(netdev);2064 DP(BNX2X_MSG_DCB, "pgid = %d\n", pgid);2065 2066 *bw_pct = 0;2067 2068 if (!bp->dcb_state || pgid >= DCBX_MAX_NUM_PG_BW_ENTRIES)2069 return;2070 2071 *bw_pct = DCBX_PG_BW_GET(bp->dcbx_local_feat.ets.pg_bw_tbl, pgid);2072}2073 2074static void bnx2x_dcbnl_get_pg_tccfg_rx(struct net_device *netdev, int prio,2075 u8 *prio_type, u8 *pgid, u8 *bw_pct,2076 u8 *up_map)2077{2078 struct bnx2x *bp = netdev_priv(netdev);2079 DP(BNX2X_MSG_DCB, "Nothing to get; No RX support\n");2080 2081 *prio_type = *pgid = *bw_pct = *up_map = 0;2082}2083 2084static void bnx2x_dcbnl_get_pg_bwgcfg_rx(struct net_device *netdev,2085 int pgid, u8 *bw_pct)2086{2087 struct bnx2x *bp = netdev_priv(netdev);2088 DP(BNX2X_MSG_DCB, "Nothing to get; No RX support\n");2089 2090 *bw_pct = 0;2091}2092 2093static void bnx2x_dcbnl_set_pfc_cfg(struct net_device *netdev, int prio,2094 u8 setting)2095{2096 struct bnx2x *bp = netdev_priv(netdev);2097 DP(BNX2X_MSG_DCB, "prio[%d] = %d\n", prio, setting);2098 2099 if (!bnx2x_dcbnl_set_valid(bp) || prio >= MAX_PFC_PRIORITIES)2100 return;2101 2102 if (setting) {2103 bp->dcbx_config_params.admin_pfc_bitmap |= (1 << prio);2104 bp->dcbx_config_params.admin_pfc_tx_enable = 1;2105 } else {2106 bp->dcbx_config_params.admin_pfc_bitmap &= ~(1 << prio);2107 }2108}2109 2110static void bnx2x_dcbnl_get_pfc_cfg(struct net_device *netdev, int prio,2111 u8 *setting)2112{2113 struct bnx2x *bp = netdev_priv(netdev);2114 DP(BNX2X_MSG_DCB, "prio = %d\n", prio);2115 2116 *setting = 0;2117 2118 if (!bp->dcb_state || prio >= MAX_PFC_PRIORITIES)2119 return;2120 2121 *setting = (bp->dcbx_local_feat.pfc.pri_en_bitmap >> prio) & 0x1;2122}2123 2124static u8 bnx2x_dcbnl_set_all(struct net_device *netdev)2125{2126 struct bnx2x *bp = netdev_priv(netdev);2127 2128 DP(BNX2X_MSG_DCB, "SET-ALL\n");2129 2130 if (!bnx2x_dcbnl_set_valid(bp))2131 return 1;2132 2133 if (bp->recovery_state != BNX2X_RECOVERY_DONE) {2134 netdev_err(bp->dev,2135 "Handling parity error recovery. Try again later\n");2136 return 1;2137 }2138 if (netif_running(bp->dev)) {2139 bnx2x_update_drv_flags(bp,2140 1 << DRV_FLAGS_DCB_MFW_CONFIGURED,2141 1);2142 bnx2x_dcbx_init(bp, true);2143 }2144 DP(BNX2X_MSG_DCB, "set_dcbx_params done\n");2145 2146 return 0;2147}2148 2149static u8 bnx2x_dcbnl_get_cap(struct net_device *netdev, int capid, u8 *cap)2150{2151 struct bnx2x *bp = netdev_priv(netdev);2152 u8 rval = 0;2153 2154 if (bp->dcb_state) {2155 switch (capid) {2156 case DCB_CAP_ATTR_PG:2157 *cap = true;2158 break;2159 case DCB_CAP_ATTR_PFC:2160 *cap = true;2161 break;2162 case DCB_CAP_ATTR_UP2TC:2163 *cap = false;2164 break;2165 case DCB_CAP_ATTR_PG_TCS:2166 *cap = 0x80; /* 8 priorities for PGs */2167 break;2168 case DCB_CAP_ATTR_PFC_TCS:2169 *cap = 0x80; /* 8 priorities for PFC */2170 break;2171 case DCB_CAP_ATTR_GSP:2172 *cap = true;2173 break;2174 case DCB_CAP_ATTR_BCN:2175 *cap = false;2176 break;2177 case DCB_CAP_ATTR_DCBX:2178 *cap = BNX2X_DCBX_CAPS;2179 break;2180 default:2181 BNX2X_ERR("Non valid capability ID\n");2182 rval = 1;2183 break;2184 }2185 } else {2186 DP(BNX2X_MSG_DCB, "DCB disabled\n");2187 rval = 1;2188 }2189 2190 DP(BNX2X_MSG_DCB, "capid %d:%x\n", capid, *cap);2191 return rval;2192}2193 2194static int bnx2x_dcbnl_get_numtcs(struct net_device *netdev, int tcid, u8 *num)2195{2196 struct bnx2x *bp = netdev_priv(netdev);2197 u8 rval = 0;2198 2199 DP(BNX2X_MSG_DCB, "tcid %d\n", tcid);2200 2201 if (bp->dcb_state) {2202 switch (tcid) {2203 case DCB_NUMTCS_ATTR_PG:2204 *num = CHIP_IS_E3B0(bp) ? DCBX_COS_MAX_NUM_E3B0 :2205 DCBX_COS_MAX_NUM_E2;2206 break;2207 case DCB_NUMTCS_ATTR_PFC:2208 *num = CHIP_IS_E3B0(bp) ? DCBX_COS_MAX_NUM_E3B0 :2209 DCBX_COS_MAX_NUM_E2;2210 break;2211 default:2212 BNX2X_ERR("Non valid TC-ID\n");2213 rval = 1;2214 break;2215 }2216 } else {2217 DP(BNX2X_MSG_DCB, "DCB disabled\n");2218 rval = 1;2219 }2220 2221 return rval;2222}2223 2224static int bnx2x_dcbnl_set_numtcs(struct net_device *netdev, int tcid, u8 num)2225{2226 struct bnx2x *bp = netdev_priv(netdev);2227 DP(BNX2X_MSG_DCB, "num tcs = %d; Not supported\n", num);2228 return -EINVAL;2229}2230 2231static u8 bnx2x_dcbnl_get_pfc_state(struct net_device *netdev)2232{2233 struct bnx2x *bp = netdev_priv(netdev);2234 DP(BNX2X_MSG_DCB, "state = %d\n", bp->dcbx_local_feat.pfc.enabled);2235 2236 if (!bp->dcb_state)2237 return 0;2238 2239 return bp->dcbx_local_feat.pfc.enabled;2240}2241 2242static void bnx2x_dcbnl_set_pfc_state(struct net_device *netdev, u8 state)2243{2244 struct bnx2x *bp = netdev_priv(netdev);2245 DP(BNX2X_MSG_DCB, "state = %s\n", state ? "on" : "off");2246 2247 if (!bnx2x_dcbnl_set_valid(bp))2248 return;2249 2250 bp->dcbx_config_params.admin_pfc_tx_enable =2251 bp->dcbx_config_params.admin_pfc_enable = (state ? 1 : 0);2252}2253 2254static void bnx2x_admin_app_set_ent(2255 struct bnx2x_admin_priority_app_table *app_ent,2256 u8 idtype, u16 idval, u8 up)2257{2258 app_ent->valid = 1;2259 2260 switch (idtype) {2261 case DCB_APP_IDTYPE_ETHTYPE:2262 app_ent->traffic_type = TRAFFIC_TYPE_ETH;2263 break;2264 case DCB_APP_IDTYPE_PORTNUM:2265 app_ent->traffic_type = TRAFFIC_TYPE_PORT;2266 break;2267 default:2268 break; /* never gets here */2269 }2270 app_ent->app_id = idval;2271 app_ent->priority = up;2272}2273 2274static bool bnx2x_admin_app_is_equal(2275 struct bnx2x_admin_priority_app_table *app_ent,2276 u8 idtype, u16 idval)2277{2278 if (!app_ent->valid)2279 return false;2280 2281 switch (idtype) {2282 case DCB_APP_IDTYPE_ETHTYPE:2283 if (app_ent->traffic_type != TRAFFIC_TYPE_ETH)2284 return false;2285 break;2286 case DCB_APP_IDTYPE_PORTNUM:2287 if (app_ent->traffic_type != TRAFFIC_TYPE_PORT)2288 return false;2289 break;2290 default:2291 return false;2292 }2293 if (app_ent->app_id != idval)2294 return false;2295 2296 return true;2297}2298 2299static int bnx2x_set_admin_app_up(struct bnx2x *bp, u8 idtype, u16 idval, u8 up)2300{2301 int i, ff;2302 2303 /* iterate over the app entries looking for idtype and idval */2304 for (i = 0, ff = -1; i < DCBX_CONFIG_MAX_APP_PROTOCOL; i++) {2305 struct bnx2x_admin_priority_app_table *app_ent =2306 &bp->dcbx_config_params.admin_priority_app_table[i];2307 if (bnx2x_admin_app_is_equal(app_ent, idtype, idval))2308 break;2309 2310 if (ff < 0 && !app_ent->valid)2311 ff = i;2312 }2313 if (i < DCBX_CONFIG_MAX_APP_PROTOCOL)2314 /* if found overwrite up */2315 bp->dcbx_config_params.2316 admin_priority_app_table[i].priority = up;2317 else if (ff >= 0)2318 /* not found use first-free */2319 bnx2x_admin_app_set_ent(2320 &bp->dcbx_config_params.admin_priority_app_table[ff],2321 idtype, idval, up);2322 else {2323 /* app table is full */2324 BNX2X_ERR("Application table is too large\n");2325 return -EBUSY;2326 }2327 2328 /* up configured, if not 0 make sure feature is enabled */2329 if (up)2330 bp->dcbx_config_params.admin_application_priority_tx_enable = 1;2331 2332 return 0;2333}2334 2335static int bnx2x_dcbnl_set_app_up(struct net_device *netdev, u8 idtype,2336 u16 idval, u8 up)2337{2338 struct bnx2x *bp = netdev_priv(netdev);2339 2340 DP(BNX2X_MSG_DCB, "app_type %d, app_id %x, prio bitmap %d\n",2341 idtype, idval, up);2342 2343 if (!bnx2x_dcbnl_set_valid(bp)) {2344 DP(BNX2X_MSG_DCB, "dcbnl call not valid\n");2345 return -EINVAL;2346 }2347 2348 /* verify idtype */2349 switch (idtype) {2350 case DCB_APP_IDTYPE_ETHTYPE:2351 case DCB_APP_IDTYPE_PORTNUM:2352 break;2353 default:2354 DP(BNX2X_MSG_DCB, "Wrong ID type\n");2355 return -EINVAL;2356 }2357 return bnx2x_set_admin_app_up(bp, idtype, idval, up);2358}2359 2360static u8 bnx2x_dcbnl_get_dcbx(struct net_device *netdev)2361{2362 struct bnx2x *bp = netdev_priv(netdev);2363 u8 state;2364 2365 state = DCB_CAP_DCBX_LLD_MANAGED | DCB_CAP_DCBX_VER_CEE;2366 2367 if (bp->dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_OFF)2368 state |= DCB_CAP_DCBX_STATIC;2369 2370 return state;2371}2372 2373static u8 bnx2x_dcbnl_set_dcbx(struct net_device *netdev, u8 state)2374{2375 struct bnx2x *bp = netdev_priv(netdev);2376 DP(BNX2X_MSG_DCB, "state = %02x\n", state);2377 2378 /* set dcbx mode */2379 2380 if ((state & BNX2X_DCBX_CAPS) != state) {2381 BNX2X_ERR("Requested DCBX mode %x is beyond advertised capabilities\n",2382 state);2383 return 1;2384 }2385 2386 if (bp->dcb_state != BNX2X_DCB_STATE_ON) {2387 BNX2X_ERR("DCB turned off, DCBX configuration is invalid\n");2388 return 1;2389 }2390 2391 if (state & DCB_CAP_DCBX_STATIC)2392 bp->dcbx_enabled = BNX2X_DCBX_ENABLED_ON_NEG_OFF;2393 else2394 bp->dcbx_enabled = BNX2X_DCBX_ENABLED_ON_NEG_ON;2395 2396 bp->dcbx_mode_uset = true;2397 return 0;2398}2399 2400static u8 bnx2x_dcbnl_get_featcfg(struct net_device *netdev, int featid,2401 u8 *flags)2402{2403 struct bnx2x *bp = netdev_priv(netdev);2404 u8 rval = 0;2405 2406 DP(BNX2X_MSG_DCB, "featid %d\n", featid);2407 2408 if (bp->dcb_state) {2409 *flags = 0;2410 switch (featid) {2411 case DCB_FEATCFG_ATTR_PG:2412 if (bp->dcbx_local_feat.ets.enabled)2413 *flags |= DCB_FEATCFG_ENABLE;2414 if (bp->dcbx_error & (DCBX_LOCAL_ETS_ERROR |2415 DCBX_REMOTE_MIB_ERROR))2416 *flags |= DCB_FEATCFG_ERROR;2417 break;2418 case DCB_FEATCFG_ATTR_PFC:2419 if (bp->dcbx_local_feat.pfc.enabled)2420 *flags |= DCB_FEATCFG_ENABLE;2421 if (bp->dcbx_error & (DCBX_LOCAL_PFC_ERROR |2422 DCBX_LOCAL_PFC_MISMATCH |2423 DCBX_REMOTE_MIB_ERROR))2424 *flags |= DCB_FEATCFG_ERROR;2425 break;2426 case DCB_FEATCFG_ATTR_APP:2427 if (bp->dcbx_local_feat.app.enabled)2428 *flags |= DCB_FEATCFG_ENABLE;2429 if (bp->dcbx_error & (DCBX_LOCAL_APP_ERROR |2430 DCBX_LOCAL_APP_MISMATCH |2431 DCBX_REMOTE_MIB_ERROR))2432 *flags |= DCB_FEATCFG_ERROR;2433 break;2434 default:2435 BNX2X_ERR("Non valid feature-ID\n");2436 rval = 1;2437 break;2438 }2439 } else {2440 DP(BNX2X_MSG_DCB, "DCB disabled\n");2441 rval = 1;2442 }2443 2444 return rval;2445}2446 2447static u8 bnx2x_dcbnl_set_featcfg(struct net_device *netdev, int featid,2448 u8 flags)2449{2450 struct bnx2x *bp = netdev_priv(netdev);2451 u8 rval = 0;2452 2453 DP(BNX2X_MSG_DCB, "featid = %d flags = %02x\n", featid, flags);2454 2455 /* ignore the 'advertise' flag */2456 if (bnx2x_dcbnl_set_valid(bp)) {2457 switch (featid) {2458 case DCB_FEATCFG_ATTR_PG:2459 bp->dcbx_config_params.admin_ets_enable =2460 flags & DCB_FEATCFG_ENABLE ? 1 : 0;2461 bp->dcbx_config_params.admin_ets_willing =2462 flags & DCB_FEATCFG_WILLING ? 1 : 0;2463 break;2464 case DCB_FEATCFG_ATTR_PFC:2465 bp->dcbx_config_params.admin_pfc_enable =2466 flags & DCB_FEATCFG_ENABLE ? 1 : 0;2467 bp->dcbx_config_params.admin_pfc_willing =2468 flags & DCB_FEATCFG_WILLING ? 1 : 0;2469 break;2470 case DCB_FEATCFG_ATTR_APP:2471 /* ignore enable, always enabled */2472 bp->dcbx_config_params.admin_app_priority_willing =2473 flags & DCB_FEATCFG_WILLING ? 1 : 0;2474 break;2475 default:2476 BNX2X_ERR("Non valid feature-ID\n");2477 rval = 1;2478 break;2479 }2480 } else {2481 DP(BNX2X_MSG_DCB, "dcbnl call not valid\n");2482 rval = 1;2483 }2484 2485 return rval;2486}2487 2488static int bnx2x_peer_appinfo(struct net_device *netdev,2489 struct dcb_peer_app_info *info, u16* app_count)2490{2491 int i;2492 struct bnx2x *bp = netdev_priv(netdev);2493 2494 DP(BNX2X_MSG_DCB, "APP-INFO\n");2495 2496 info->willing = (bp->dcbx_remote_flags & DCBX_APP_REM_WILLING) ?: 0;2497 info->error = (bp->dcbx_remote_flags & DCBX_APP_RX_ERROR) ?: 0;2498 *app_count = 0;2499 2500 for (i = 0; i < DCBX_MAX_APP_PROTOCOL; i++)2501 if (bp->dcbx_remote_feat.app.app_pri_tbl[i].appBitfield &2502 DCBX_APP_ENTRY_VALID)2503 (*app_count)++;2504 return 0;2505}2506 2507static int bnx2x_peer_apptable(struct net_device *netdev,2508 struct dcb_app *table)2509{2510 int i, j;2511 struct bnx2x *bp = netdev_priv(netdev);2512 2513 DP(BNX2X_MSG_DCB, "APP-TABLE\n");2514 2515 for (i = 0, j = 0; i < DCBX_MAX_APP_PROTOCOL; i++) {2516 struct dcbx_app_priority_entry *ent =2517 &bp->dcbx_remote_feat.app.app_pri_tbl[i];2518 2519 if (ent->appBitfield & DCBX_APP_ENTRY_VALID) {2520 table[j].selector = bnx2x_dcbx_dcbnl_app_idtype(ent);2521 table[j].priority = bnx2x_dcbx_dcbnl_app_up(ent);2522 table[j++].protocol = ent->app_id;2523 }2524 }2525 return 0;2526}2527 2528static int bnx2x_cee_peer_getpg(struct net_device *netdev, struct cee_pg *pg)2529{2530 int i;2531 struct bnx2x *bp = netdev_priv(netdev);2532 2533 pg->willing = (bp->dcbx_remote_flags & DCBX_ETS_REM_WILLING) ?: 0;2534 2535 for (i = 0; i < CEE_DCBX_MAX_PGS; i++) {2536 pg->pg_bw[i] =2537 DCBX_PG_BW_GET(bp->dcbx_remote_feat.ets.pg_bw_tbl, i);2538 pg->prio_pg[i] =2539 DCBX_PRI_PG_GET(bp->dcbx_remote_feat.ets.pri_pg_tbl, i);2540 }2541 return 0;2542}2543 2544static int bnx2x_cee_peer_getpfc(struct net_device *netdev,2545 struct cee_pfc *pfc)2546{2547 struct bnx2x *bp = netdev_priv(netdev);2548 pfc->tcs_supported = bp->dcbx_remote_feat.pfc.pfc_caps;2549 pfc->pfc_en = bp->dcbx_remote_feat.pfc.pri_en_bitmap;2550 return 0;2551}2552 2553const struct dcbnl_rtnl_ops bnx2x_dcbnl_ops = {2554 .getstate = bnx2x_dcbnl_get_state,2555 .setstate = bnx2x_dcbnl_set_state,2556 .getpermhwaddr = bnx2x_dcbnl_get_perm_hw_addr,2557 .setpgtccfgtx = bnx2x_dcbnl_set_pg_tccfg_tx,2558 .setpgbwgcfgtx = bnx2x_dcbnl_set_pg_bwgcfg_tx,2559 .setpgtccfgrx = bnx2x_dcbnl_set_pg_tccfg_rx,2560 .setpgbwgcfgrx = bnx2x_dcbnl_set_pg_bwgcfg_rx,2561 .getpgtccfgtx = bnx2x_dcbnl_get_pg_tccfg_tx,2562 .getpgbwgcfgtx = bnx2x_dcbnl_get_pg_bwgcfg_tx,2563 .getpgtccfgrx = bnx2x_dcbnl_get_pg_tccfg_rx,2564 .getpgbwgcfgrx = bnx2x_dcbnl_get_pg_bwgcfg_rx,2565 .setpfccfg = bnx2x_dcbnl_set_pfc_cfg,2566 .getpfccfg = bnx2x_dcbnl_get_pfc_cfg,2567 .setall = bnx2x_dcbnl_set_all,2568 .getcap = bnx2x_dcbnl_get_cap,2569 .getnumtcs = bnx2x_dcbnl_get_numtcs,2570 .setnumtcs = bnx2x_dcbnl_set_numtcs,2571 .getpfcstate = bnx2x_dcbnl_get_pfc_state,2572 .setpfcstate = bnx2x_dcbnl_set_pfc_state,2573 .setapp = bnx2x_dcbnl_set_app_up,2574 .getdcbx = bnx2x_dcbnl_get_dcbx,2575 .setdcbx = bnx2x_dcbnl_set_dcbx,2576 .getfeatcfg = bnx2x_dcbnl_get_featcfg,2577 .setfeatcfg = bnx2x_dcbnl_set_featcfg,2578 .peer_getappinfo = bnx2x_peer_appinfo,2579 .peer_getapptable = bnx2x_peer_apptable,2580 .cee_peer_getpg = bnx2x_cee_peer_getpg,2581 .cee_peer_getpfc = bnx2x_cee_peer_getpfc,2582};2583 2584#endif /* BCM_DCBNL */2585