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