aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Kravkov <dmitry@broadcom.com>2011-06-13 21:34:42 -0400
committerDavid S. Miller <davem@conan.davemloft.net>2011-06-15 10:56:59 -0400
commitd1976b2e6478a1b8ff2dc35979e7791e2d668285 (patch)
tree43c83d26dd26aec6e6c81ac3869bf24f2f101518
parent60d2fe0312b3301fb5a65e9ed0b44465c8237055 (diff)
bnx2x: PFC support for 578xx
Add supoprt for 3 COSes for 578xx devices. Fix HW configuration for PFC feature according to new HSI in link layer. Signed-off-by: Dmitry Kravkov <dmitry@broadcom.com> Signed-off-by: Vladislav Zolotarov <vladz@broadcom.com> Signed-off-by: Eilon Greenstein <eilong@broadcom.com> Signed-off-by: David S. Miller <davem@conan.davemloft.net>
-rw-r--r--drivers/net/bnx2x/bnx2x_dcb.c504
-rw-r--r--drivers/net/bnx2x/bnx2x_dcb.h23
2 files changed, 406 insertions, 121 deletions
diff --git a/drivers/net/bnx2x/bnx2x_dcb.c b/drivers/net/bnx2x/bnx2x_dcb.c
index 50a5c4f3d58..b51a759c103 100644
--- a/drivers/net/bnx2x/bnx2x_dcb.c
+++ b/drivers/net/bnx2x/bnx2x_dcb.c
@@ -47,33 +47,39 @@ static void bnx2x_dcbx_separate_pauseable_from_non(struct bnx2x *bp,
47 struct cos_help_data *cos_data, 47 struct cos_help_data *cos_data,
48 u32 *pg_pri_orginal_spread, 48 u32 *pg_pri_orginal_spread,
49 struct dcbx_ets_feature *ets); 49 struct dcbx_ets_feature *ets);
50static void bnx2x_pfc_fw_struct_e2(struct bnx2x *bp); 50static void bnx2x_dcbx_fw_struct(struct bnx2x *bp);
51 51
52 52
53static void bnx2x_pfc_set(struct bnx2x *bp) 53static void bnx2x_pfc_set(struct bnx2x *bp)
54{ 54{
55 struct bnx2x_nig_brb_pfc_port_params pfc_params = {0}; 55 struct bnx2x_nig_brb_pfc_port_params pfc_params = {0};
56 u32 pri_bit, val = 0; 56 u32 pri_bit, val = 0;
57 u8 pri;
58 int i; 57 int i;
59 58
59 pfc_params.num_of_rx_cos_priority_mask =
60 bp->dcbx_port_params.ets.num_of_cos;
61
60 /* Tx COS configuration */ 62 /* Tx COS configuration */
61 for (i = 0; i < bp->dcbx_port_params.ets.num_of_cos; i++) 63 for (i = 0; i < bp->dcbx_port_params.ets.num_of_cos; i++)
62 if (bp->dcbx_port_params.ets.cos_params[i].pauseable) 64 /*
63 pfc_params.rx_cos_priority_mask[i] = 65 * We configure only the pauseable bits (non pauseable aren't
64 bp->dcbx_port_params.ets. 66 * configured at all) it's done to avoid false pauses from
65 cos_params[i].pri_bitmask; 67 * network
68 */
69 pfc_params.rx_cos_priority_mask[i] =
70 bp->dcbx_port_params.ets.cos_params[i].pri_bitmask
71 & DCBX_PFC_PRI_PAUSE_MASK(bp);
66 72
67 /** 73 /*
68 * Rx COS configuration 74 * Rx COS configuration
69 * Changing PFC RX configuration . 75 * Changing PFC RX configuration .
70 * In RX COS0 will always be configured to lossy and COS1 to lossless 76 * In RX COS0 will always be configured to lossy and COS1 to lossless
71 */ 77 */
72 for (pri = 0 ; pri < MAX_PFC_PRIORITIES ; pri++) { 78 for (i = 0 ; i < MAX_PFC_PRIORITIES ; i++) {
73 pri_bit = 1 << pri; 79 pri_bit = 1 << i;
74 80
75 if (pri_bit & DCBX_PFC_PRI_PAUSE_MASK(bp)) 81 if (pri_bit & DCBX_PFC_PRI_PAUSE_MASK(bp))
76 val |= 1 << (pri * 4); 82 val |= 1 << (i * 4);
77 } 83 }
78 84
79 pfc_params.pkt_priority_to_cos = val; 85 pfc_params.pkt_priority_to_cos = val;
@@ -252,12 +258,11 @@ static void bnx2x_dcbx_get_ets_feature(struct bnx2x *bp,
252 258
253 259
254 /* Clean up old settings of ets on COS */ 260 /* Clean up old settings of ets on COS */
255 for (i = 0; i < E2_NUM_OF_COS ; i++) { 261 for (i = 0; i < ARRAY_SIZE(bp->dcbx_port_params.ets.cos_params) ; i++) {
256
257 cos_params[i].pauseable = false; 262 cos_params[i].pauseable = false;
258 cos_params[i].strict = BNX2X_DCBX_COS_NOT_STRICT; 263 cos_params[i].strict = BNX2X_DCBX_STRICT_INVALID;
259 cos_params[i].bw_tbl = DCBX_INVALID_COS_BW; 264 cos_params[i].bw_tbl = DCBX_INVALID_COS_BW;
260 cos_params[i].pri_bitmask = DCBX_PFC_PRI_GET_NON_PAUSE(bp, 0); 265 cos_params[i].pri_bitmask = 0;
261 } 266 }
262 267
263 if (bp->dcbx_port_params.app.enabled && 268 if (bp->dcbx_port_params.app.enabled &&
@@ -377,25 +382,19 @@ static int bnx2x_dcbx_read_mib(struct bnx2x *bp,
377 382
378static void bnx2x_pfc_set_pfc(struct bnx2x *bp) 383static void bnx2x_pfc_set_pfc(struct bnx2x *bp)
379{ 384{
380 if (!CHIP_IS_E1x(bp)) { 385 if (BP_PORT(bp)) {
381 if (BP_PORT(bp)) { 386 BNX2X_ERR("4 port mode is not supported");
382 BNX2X_ERR("4 port mode is not supported"); 387 return;
383 return;
384 }
385
386 if (bp->dcbx_port_params.pfc.enabled)
387
388 /* 1. Fills up common PFC structures if required.*/
389 /* 2. Configure NIG, MAC and BRB via the elink:
390 * elink must first check if BMAC is not in reset
391 * and only then configures the BMAC
392 * Or, configure EMAC.
393 */
394 bnx2x_pfc_set(bp);
395
396 else
397 bnx2x_pfc_clear(bp);
398 } 388 }
389
390 if (bp->dcbx_port_params.pfc.enabled)
391 /*
392 * 1. Fills up common PFC structures if required
393 * 2. Configure NIG, MAC and BRB via the elink
394 */
395 bnx2x_pfc_set(bp);
396 else
397 bnx2x_pfc_clear(bp);
399} 398}
400 399
401static void bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp) 400static void bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp)
@@ -410,7 +409,7 @@ static void bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp)
410 409
411static void bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp) 410static void bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp)
412{ 411{
413 bnx2x_pfc_fw_struct_e2(bp); 412 bnx2x_dcbx_fw_struct(bp);
414 DP(NETIF_MSG_LINK, "sending START TRAFFIC\n"); 413 DP(NETIF_MSG_LINK, "sending START TRAFFIC\n");
415 bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_START_TRAFFIC, 414 bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_START_TRAFFIC,
416 0, /* connectionless */ 415 0, /* connectionless */
@@ -419,18 +418,13 @@ static void bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp)
419 NONE_CONNECTION_TYPE); 418 NONE_CONNECTION_TYPE);
420} 419}
421 420
422static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp) 421static void bnx2x_dcbx_2cos_limit_update_ets_config(struct bnx2x *bp)
423{ 422{
424 struct bnx2x_dcbx_pg_params *ets = &(bp->dcbx_port_params.ets); 423 struct bnx2x_dcbx_pg_params *ets = &(bp->dcbx_port_params.ets);
425 u8 status = 0; 424 int rc = 0;
426
427 bnx2x_ets_disabled(&bp->link_params, &bp->link_vars);
428
429 if (!ets->enabled)
430 return;
431 425
432 if ((ets->num_of_cos == 0) || (ets->num_of_cos > E2_NUM_OF_COS)) { 426 if (ets->num_of_cos == 0 || ets->num_of_cos > DCBX_COS_MAX_NUM_E2) {
433 BNX2X_ERR("illegal num of cos= %x", ets->num_of_cos); 427 BNX2X_ERR("Illegal number of COSes %d\n", ets->num_of_cos);
434 return; 428 return;
435 } 429 }
436 430
@@ -439,9 +433,9 @@ static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp)
439 return; 433 return;
440 434
441 /* sanity */ 435 /* sanity */
442 if (((BNX2X_DCBX_COS_NOT_STRICT == ets->cos_params[0].strict) && 436 if (((BNX2X_DCBX_STRICT_INVALID == ets->cos_params[0].strict) &&
443 (DCBX_INVALID_COS_BW == ets->cos_params[0].bw_tbl)) || 437 (DCBX_INVALID_COS_BW == ets->cos_params[0].bw_tbl)) ||
444 ((BNX2X_DCBX_COS_NOT_STRICT == ets->cos_params[1].strict) && 438 ((BNX2X_DCBX_STRICT_INVALID == ets->cos_params[1].strict) &&
445 (DCBX_INVALID_COS_BW == ets->cos_params[1].bw_tbl))) { 439 (DCBX_INVALID_COS_BW == ets->cos_params[1].bw_tbl))) {
446 BNX2X_ERR("all COS should have at least bw_limit or strict" 440 BNX2X_ERR("all COS should have at least bw_limit or strict"
447 "ets->cos_params[0].strict= %x" 441 "ets->cos_params[0].strict= %x"
@@ -473,17 +467,70 @@ static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp)
473 467
474 bnx2x_ets_bw_limit(&bp->link_params, bw_tbl_0, bw_tbl_1); 468 bnx2x_ets_bw_limit(&bp->link_params, bw_tbl_0, bw_tbl_1);
475 } else { 469 } else {
476 if (ets->cos_params[0].strict == BNX2X_DCBX_COS_HIGH_STRICT) 470 if (ets->cos_params[0].strict == BNX2X_DCBX_STRICT_COS_HIGHEST)
477 status = bnx2x_ets_strict(&bp->link_params, 0); 471 rc = bnx2x_ets_strict(&bp->link_params, 0);
478 else if (ets->cos_params[1].strict 472 else if (ets->cos_params[1].strict
479 == BNX2X_DCBX_COS_HIGH_STRICT) 473 == BNX2X_DCBX_STRICT_COS_HIGHEST)
480 status = bnx2x_ets_strict(&bp->link_params, 1); 474 rc = bnx2x_ets_strict(&bp->link_params, 1);
481 475 if (rc)
482 if (status)
483 BNX2X_ERR("update_ets_params failed\n"); 476 BNX2X_ERR("update_ets_params failed\n");
484 } 477 }
485} 478}
486 479
480/*
481 * In E3B0 the configuration may have more than 2 COS.
482 */
483void bnx2x_dcbx_update_ets_config(struct bnx2x *bp)
484{
485 struct bnx2x_dcbx_pg_params *ets = &(bp->dcbx_port_params.ets);
486 struct bnx2x_ets_params ets_params = { 0 };
487 u8 i;
488
489 ets_params.num_of_cos = ets->num_of_cos;
490
491 for (i = 0; i < ets->num_of_cos; i++) {
492 /* COS is SP */
493 if (ets->cos_params[i].strict != BNX2X_DCBX_STRICT_INVALID) {
494 if (ets->cos_params[i].bw_tbl != DCBX_INVALID_COS_BW) {
495 BNX2X_ERR("COS can't be not BW and not SP\n");
496 return;
497 }
498
499 ets_params.cos[i].state = bnx2x_cos_state_strict;
500 ets_params.cos[i].params.sp_params.pri =
501 ets->cos_params[i].strict;
502 } else { /* COS is BW */
503 if (ets->cos_params[i].bw_tbl == DCBX_INVALID_COS_BW) {
504 BNX2X_ERR("COS can't be not BW and not SP\n");
505 return;
506 }
507 ets_params.cos[i].state = bnx2x_cos_state_bw;
508 ets_params.cos[i].params.bw_params.bw =
509 (u8)ets->cos_params[i].bw_tbl;
510 }
511 }
512
513 /* Configure the ETS in HW */
514 if (bnx2x_ets_e3b0_config(&bp->link_params, &bp->link_vars,
515 &ets_params)) {
516 BNX2X_ERR("bnx2x_ets_e3b0_config failed\n");
517 bnx2x_ets_disabled(&bp->link_params, &bp->link_vars);
518 }
519}
520
521static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp)
522{
523 bnx2x_ets_disabled(&bp->link_params, &bp->link_vars);
524
525 if (!bp->dcbx_port_params.ets.enabled)
526 return;
527
528 if (CHIP_IS_E3B0(bp))
529 bnx2x_dcbx_update_ets_config(bp);
530 else
531 bnx2x_dcbx_2cos_limit_update_ets_config(bp);
532}
533
487#ifdef BCM_DCBNL 534#ifdef BCM_DCBNL
488static int bnx2x_dcbx_read_shmem_remote_mib(struct bnx2x *bp) 535static int bnx2x_dcbx_read_shmem_remote_mib(struct bnx2x *bp)
489{ 536{
@@ -1113,7 +1160,7 @@ static void bnx2x_dcbx_separate_pauseable_from_non(struct bnx2x *bp,
1113 /* If we join a group and one is strict 1160 /* If we join a group and one is strict
1114 * than the bw rulls */ 1161 * than the bw rulls */
1115 cos_data->data[entry].strict = 1162 cos_data->data[entry].strict =
1116 BNX2X_DCBX_COS_HIGH_STRICT; 1163 BNX2X_DCBX_STRICT_COS_HIGHEST;
1117 } 1164 }
1118 if ((0 == cos_data->data[0].pri_join_mask) && 1165 if ((0 == cos_data->data[0].pri_join_mask) &&
1119 (0 == cos_data->data[1].pri_join_mask)) 1166 (0 == cos_data->data[1].pri_join_mask))
@@ -1125,7 +1172,7 @@ static void bnx2x_dcbx_separate_pauseable_from_non(struct bnx2x *bp,
1125#define POWER_OF_2(x) ((0 != x) && (0 == (x & (x-1)))) 1172#define POWER_OF_2(x) ((0 != x) && (0 == (x & (x-1))))
1126#endif 1173#endif
1127 1174
1128static void bxn2x_dcbx_single_pg_to_cos_params(struct bnx2x *bp, 1175static void bnx2x_dcbx_2cos_limit_cee_single_pg_to_cos_params(struct bnx2x *bp,
1129 struct pg_help_data *pg_help_data, 1176 struct pg_help_data *pg_help_data,
1130 struct cos_help_data *cos_data, 1177 struct cos_help_data *cos_data,
1131 u32 pri_join_mask, 1178 u32 pri_join_mask,
@@ -1205,14 +1252,16 @@ static void bxn2x_dcbx_single_pg_to_cos_params(struct bnx2x *bp,
1205 if (DCBX_PFC_PRI_GET_PAUSE(bp, pri_join_mask) > 1252 if (DCBX_PFC_PRI_GET_PAUSE(bp, pri_join_mask) >
1206 DCBX_PFC_PRI_GET_NON_PAUSE(bp, pri_join_mask)) { 1253 DCBX_PFC_PRI_GET_NON_PAUSE(bp, pri_join_mask)) {
1207 cos_data->data[0].strict = 1254 cos_data->data[0].strict =
1208 BNX2X_DCBX_COS_HIGH_STRICT; 1255 BNX2X_DCBX_STRICT_COS_HIGHEST;
1209 cos_data->data[1].strict = 1256 cos_data->data[1].strict =
1210 BNX2X_DCBX_COS_LOW_STRICT; 1257 BNX2X_DCBX_STRICT_COS_NEXT_LOWER_PRI(
1258 BNX2X_DCBX_STRICT_COS_HIGHEST);
1211 } else { 1259 } else {
1212 cos_data->data[0].strict = 1260 cos_data->data[0].strict =
1213 BNX2X_DCBX_COS_LOW_STRICT; 1261 BNX2X_DCBX_STRICT_COS_NEXT_LOWER_PRI(
1262 BNX2X_DCBX_STRICT_COS_HIGHEST);
1214 cos_data->data[1].strict = 1263 cos_data->data[1].strict =
1215 BNX2X_DCBX_COS_HIGH_STRICT; 1264 BNX2X_DCBX_STRICT_COS_HIGHEST;
1216 } 1265 }
1217 /* Pauseable */ 1266 /* Pauseable */
1218 cos_data->data[0].pausable = true; 1267 cos_data->data[0].pausable = true;
@@ -1248,13 +1297,16 @@ static void bxn2x_dcbx_single_pg_to_cos_params(struct bnx2x *bp,
1248 * and that with the highest priority 1297 * and that with the highest priority
1249 * gets the highest strict priority in the arbiter. 1298 * gets the highest strict priority in the arbiter.
1250 */ 1299 */
1251 cos_data->data[0].strict = BNX2X_DCBX_COS_LOW_STRICT; 1300 cos_data->data[0].strict =
1252 cos_data->data[1].strict = BNX2X_DCBX_COS_HIGH_STRICT; 1301 BNX2X_DCBX_STRICT_COS_NEXT_LOWER_PRI(
1302 BNX2X_DCBX_STRICT_COS_HIGHEST);
1303 cos_data->data[1].strict =
1304 BNX2X_DCBX_STRICT_COS_HIGHEST;
1253 } 1305 }
1254 } 1306 }
1255} 1307}
1256 1308
1257static void bnx2x_dcbx_two_pg_to_cos_params( 1309static void bnx2x_dcbx_2cos_limit_cee_two_pg_to_cos_params(
1258 struct bnx2x *bp, 1310 struct bnx2x *bp,
1259 struct pg_help_data *pg_help_data, 1311 struct pg_help_data *pg_help_data,
1260 struct dcbx_ets_feature *ets, 1312 struct dcbx_ets_feature *ets,
@@ -1264,7 +1316,7 @@ static void bnx2x_dcbx_two_pg_to_cos_params(
1264 u8 num_of_dif_pri) 1316 u8 num_of_dif_pri)
1265{ 1317{
1266 u8 i = 0; 1318 u8 i = 0;
1267 u8 pg[E2_NUM_OF_COS] = {0}; 1319 u8 pg[DCBX_COS_MAX_NUM_E2] = { 0 };
1268 1320
1269 /* If there are both pauseable and non-pauseable priorities, 1321 /* If there are both pauseable and non-pauseable priorities,
1270 * the pauseable priorities go to the first queue and 1322 * the pauseable priorities go to the first queue and
@@ -1320,16 +1372,68 @@ static void bnx2x_dcbx_two_pg_to_cos_params(
1320 } 1372 }
1321 1373
1322 /* There can be only one strict pg */ 1374 /* There can be only one strict pg */
1323 for (i = 0 ; i < E2_NUM_OF_COS; i++) { 1375 for (i = 0 ; i < ARRAY_SIZE(pg); i++) {
1324 if (pg[i] < DCBX_MAX_NUM_PG_BW_ENTRIES) 1376 if (pg[i] < DCBX_MAX_NUM_PG_BW_ENTRIES)
1325 cos_data->data[i].cos_bw = 1377 cos_data->data[i].cos_bw =
1326 DCBX_PG_BW_GET(ets->pg_bw_tbl, pg[i]); 1378 DCBX_PG_BW_GET(ets->pg_bw_tbl, pg[i]);
1327 else 1379 else
1328 cos_data->data[i].strict = BNX2X_DCBX_COS_HIGH_STRICT; 1380 cos_data->data[i].strict =
1381 BNX2X_DCBX_STRICT_COS_HIGHEST;
1382 }
1383}
1384
1385static int bnx2x_dcbx_join_pgs(
1386 struct bnx2x *bp,
1387 struct dcbx_ets_feature *ets,
1388 struct pg_help_data *pg_help_data,
1389 u8 required_num_of_pg)
1390{
1391 u8 entry_joined = pg_help_data->num_of_pg - 1;
1392 u8 entry_removed = entry_joined + 1;
1393 u8 pg_joined = 0;
1394
1395 if (required_num_of_pg == 0 || ARRAY_SIZE(pg_help_data->data)
1396 <= pg_help_data->num_of_pg) {
1397
1398 BNX2X_ERR("required_num_of_pg can't be zero\n");
1399 return -EINVAL;
1329 } 1400 }
1401
1402 while (required_num_of_pg < pg_help_data->num_of_pg) {
1403 entry_joined = pg_help_data->num_of_pg - 2;
1404 entry_removed = entry_joined + 1;
1405 /* protect index */
1406 entry_removed %= ARRAY_SIZE(pg_help_data->data);
1407
1408 pg_help_data->data[entry_joined].pg_priority |=
1409 pg_help_data->data[entry_removed].pg_priority;
1410
1411 pg_help_data->data[entry_joined].num_of_dif_pri +=
1412 pg_help_data->data[entry_removed].num_of_dif_pri;
1413
1414 if (pg_help_data->data[entry_joined].pg == DCBX_STRICT_PRI_PG ||
1415 pg_help_data->data[entry_removed].pg == DCBX_STRICT_PRI_PG)
1416 /* Entries joined strict priority rules */
1417 pg_help_data->data[entry_joined].pg =
1418 DCBX_STRICT_PRI_PG;
1419 else {
1420 /* Entries can be joined join BW */
1421 pg_joined = DCBX_PG_BW_GET(ets->pg_bw_tbl,
1422 pg_help_data->data[entry_joined].pg) +
1423 DCBX_PG_BW_GET(ets->pg_bw_tbl,
1424 pg_help_data->data[entry_removed].pg);
1425
1426 DCBX_PG_BW_SET(ets->pg_bw_tbl,
1427 pg_help_data->data[entry_joined].pg, pg_joined);
1428 }
1429 /* Joined the entries */
1430 pg_help_data->num_of_pg--;
1431 }
1432
1433 return 0;
1330} 1434}
1331 1435
1332static void bnx2x_dcbx_three_pg_to_cos_params( 1436static void bnx2x_dcbx_2cos_limit_cee_three_pg_to_cos_params(
1333 struct bnx2x *bp, 1437 struct bnx2x *bp,
1334 struct pg_help_data *pg_help_data, 1438 struct pg_help_data *pg_help_data,
1335 struct dcbx_ets_feature *ets, 1439 struct dcbx_ets_feature *ets,
@@ -1401,102 +1505,272 @@ static void bnx2x_dcbx_three_pg_to_cos_params(
1401 /* If we join a group and one is strict 1505 /* If we join a group and one is strict
1402 * than the bw rulls */ 1506 * than the bw rulls */
1403 cos_data->data[1].strict = 1507 cos_data->data[1].strict =
1404 BNX2X_DCBX_COS_HIGH_STRICT; 1508 BNX2X_DCBX_STRICT_COS_HIGHEST;
1405 } 1509 }
1406 } 1510 }
1407 } 1511 }
1408} 1512}
1409 1513
1410 1514
1411static void bnx2x_dcbx_fill_cos_params(struct bnx2x *bp, 1515static void bnx2x_dcbx_2cos_limit_cee_fill_cos_params(struct bnx2x *bp,
1412 struct pg_help_data *help_data, 1516 struct pg_help_data *help_data,
1413 struct dcbx_ets_feature *ets, 1517 struct dcbx_ets_feature *ets,
1414 u32 *pg_pri_orginal_spread) 1518 struct cos_help_data *cos_data,
1519 u32 *pg_pri_orginal_spread,
1520 u32 pri_join_mask,
1521 u8 num_of_dif_pri)
1415{ 1522{
1416 struct cos_help_data cos_data ;
1417 u8 i = 0;
1418 u32 pri_join_mask = 0;
1419 u8 num_of_dif_pri = 0;
1420 1523
1421 memset(&cos_data, 0, sizeof(cos_data)); 1524 /* default E2 settings */
1422 /* Validate the pg value */ 1525 cos_data->num_of_cos = DCBX_COS_MAX_NUM_E2;
1423 for (i = 0; i < help_data->num_of_pg ; i++) {
1424 if (DCBX_STRICT_PRIORITY != help_data->data[i].pg &&
1425 DCBX_MAX_NUM_PG_BW_ENTRIES <= help_data->data[i].pg)
1426 BNX2X_ERR("Invalid pg[%d] data %x\n", i,
1427 help_data->data[i].pg);
1428 pri_join_mask |= help_data->data[i].pg_priority;
1429 num_of_dif_pri += help_data->data[i].num_of_dif_pri;
1430 }
1431
1432 /* default settings */
1433 cos_data.num_of_cos = 2;
1434 for (i = 0; i < E2_NUM_OF_COS ; i++) {
1435 cos_data.data[i].pri_join_mask = pri_join_mask;
1436 cos_data.data[i].pausable = false;
1437 cos_data.data[i].strict = BNX2X_DCBX_COS_NOT_STRICT;
1438 cos_data.data[i].cos_bw = DCBX_INVALID_COS_BW;
1439 }
1440 1526
1441 switch (help_data->num_of_pg) { 1527 switch (help_data->num_of_pg) {
1442 case 1: 1528 case 1:
1443 1529 bnx2x_dcbx_2cos_limit_cee_single_pg_to_cos_params(
1444 bxn2x_dcbx_single_pg_to_cos_params(
1445 bp, 1530 bp,
1446 help_data, 1531 help_data,
1447 &cos_data, 1532 cos_data,
1448 pri_join_mask, 1533 pri_join_mask,
1449 num_of_dif_pri); 1534 num_of_dif_pri);
1450 break; 1535 break;
1451 case 2: 1536 case 2:
1452 bnx2x_dcbx_two_pg_to_cos_params( 1537 bnx2x_dcbx_2cos_limit_cee_two_pg_to_cos_params(
1453 bp, 1538 bp,
1454 help_data, 1539 help_data,
1455 ets, 1540 ets,
1456 &cos_data, 1541 cos_data,
1457 pg_pri_orginal_spread, 1542 pg_pri_orginal_spread,
1458 pri_join_mask, 1543 pri_join_mask,
1459 num_of_dif_pri); 1544 num_of_dif_pri);
1460 break; 1545 break;
1461 1546
1462 case 3: 1547 case 3:
1463 bnx2x_dcbx_three_pg_to_cos_params( 1548 bnx2x_dcbx_2cos_limit_cee_three_pg_to_cos_params(
1464 bp, 1549 bp,
1465 help_data, 1550 help_data,
1466 ets, 1551 ets,
1467 &cos_data, 1552 cos_data,
1468 pg_pri_orginal_spread, 1553 pg_pri_orginal_spread,
1469 pri_join_mask, 1554 pri_join_mask,
1470 num_of_dif_pri); 1555 num_of_dif_pri);
1471
1472 break; 1556 break;
1473 default: 1557 default:
1474 BNX2X_ERR("Wrong pg_help_data.num_of_pg\n"); 1558 BNX2X_ERR("Wrong pg_help_data.num_of_pg\n");
1475 bnx2x_dcbx_ets_disabled_entry_data(bp, 1559 bnx2x_dcbx_ets_disabled_entry_data(bp,
1476 &cos_data, pri_join_mask); 1560 cos_data, pri_join_mask);
1561 }
1562}
1563
1564static int bnx2x_dcbx_spread_strict_pri(struct bnx2x *bp,
1565 struct cos_help_data *cos_data,
1566 u8 entry,
1567 u8 num_spread_of_entries,
1568 u8 strict_app_pris)
1569{
1570 u8 strict_pri = BNX2X_DCBX_STRICT_COS_HIGHEST;
1571 u8 num_of_app_pri = MAX_PFC_PRIORITIES;
1572 u8 app_pri_bit = 0;
1573
1574 while (num_spread_of_entries && num_of_app_pri > 0) {
1575 app_pri_bit = 1 << (num_of_app_pri - 1);
1576 if (app_pri_bit & strict_app_pris) {
1577 struct cos_entry_help_data *data = &cos_data->
1578 data[entry];
1579 num_spread_of_entries--;
1580 if (num_spread_of_entries == 0) {
1581 /* last entry needed put all the entries left */
1582 data->cos_bw = DCBX_INVALID_COS_BW;
1583 data->strict = strict_pri;
1584 data->pri_join_mask = strict_app_pris;
1585 data->pausable = DCBX_IS_PFC_PRI_SOME_PAUSE(bp,
1586 data->pri_join_mask);
1587 } else {
1588 strict_app_pris &= ~app_pri_bit;
1589
1590 data->cos_bw = DCBX_INVALID_COS_BW;
1591 data->strict = strict_pri;
1592 data->pri_join_mask = app_pri_bit;
1593 data->pausable = DCBX_IS_PFC_PRI_SOME_PAUSE(bp,
1594 data->pri_join_mask);
1595 }
1596
1597 strict_pri =
1598 BNX2X_DCBX_STRICT_COS_NEXT_LOWER_PRI(strict_pri);
1599 entry++;
1600 }
1601
1602 num_of_app_pri--;
1603 }
1604
1605 if (num_spread_of_entries)
1606 return -EINVAL;
1607
1608 return 0;
1609}
1610
1611static u8 bnx2x_dcbx_cee_fill_strict_pri(struct bnx2x *bp,
1612 struct cos_help_data *cos_data,
1613 u8 entry,
1614 u8 num_spread_of_entries,
1615 u8 strict_app_pris)
1616{
1617
1618 if (bnx2x_dcbx_spread_strict_pri(bp, cos_data, entry,
1619 num_spread_of_entries,
1620 strict_app_pris)) {
1621 struct cos_entry_help_data *data = &cos_data->
1622 data[entry];
1623 /* Fill BW entry */
1624 data->cos_bw = DCBX_INVALID_COS_BW;
1625 data->strict = BNX2X_DCBX_STRICT_COS_HIGHEST;
1626 data->pri_join_mask = strict_app_pris;
1627 data->pausable = DCBX_IS_PFC_PRI_SOME_PAUSE(bp,
1628 data->pri_join_mask);
1629 return 1;
1630 }
1631
1632 return num_spread_of_entries;
1633}
1634
1635static void bnx2x_dcbx_cee_fill_cos_params(struct bnx2x *bp,
1636 struct pg_help_data *help_data,
1637 struct dcbx_ets_feature *ets,
1638 struct cos_help_data *cos_data,
1639 u32 pri_join_mask)
1640
1641{
1642 u8 need_num_of_entries = 0;
1643 u8 i = 0;
1644 u8 entry = 0;
1645
1646 /*
1647 * if the number of requested PG-s in CEE is greater than 3
1648 * then the results are not determined since this is a violation
1649 * of the standard.
1650 */
1651 if (help_data->num_of_pg > DCBX_COS_MAX_NUM_E3B0) {
1652 if (bnx2x_dcbx_join_pgs(bp, ets, help_data,
1653 DCBX_COS_MAX_NUM_E3B0)) {
1654 BNX2X_ERR("Unable to reduce the number of PGs -"
1655 "we will disables ETS\n");
1656 bnx2x_dcbx_ets_disabled_entry_data(bp, cos_data,
1657 pri_join_mask);
1658 return;
1659 }
1660 }
1661
1662 for (i = 0 ; i < help_data->num_of_pg; i++) {
1663 struct pg_entry_help_data *pg = &help_data->data[i];
1664 if (pg->pg < DCBX_MAX_NUM_PG_BW_ENTRIES) {
1665 struct cos_entry_help_data *data = &cos_data->
1666 data[entry];
1667 /* Fill BW entry */
1668 data->cos_bw = DCBX_PG_BW_GET(ets->pg_bw_tbl, pg->pg);
1669 data->strict = BNX2X_DCBX_STRICT_INVALID;
1670 data->pri_join_mask = pg->pg_priority;
1671 data->pausable = DCBX_IS_PFC_PRI_SOME_PAUSE(bp,
1672 data->pri_join_mask);
1673
1674 entry++;
1675 } else {
1676 need_num_of_entries = min_t(u8,
1677 (u8)pg->num_of_dif_pri,
1678 (u8)DCBX_COS_MAX_NUM_E3B0 -
1679 help_data->num_of_pg + 1);
1680 /*
1681 * If there are still VOQ-s which have no associated PG,
1682 * then associate these VOQ-s to PG15. These PG-s will
1683 * be used for SP between priorities on PG15.
1684 */
1685 entry += bnx2x_dcbx_cee_fill_strict_pri(bp, cos_data,
1686 entry, need_num_of_entries, pg->pg_priority);
1687 }
1688 }
1689
1690 /* the entry will represent the number of COSes used */
1691 cos_data->num_of_cos = entry;
1692}
1693static void bnx2x_dcbx_fill_cos_params(struct bnx2x *bp,
1694 struct pg_help_data *help_data,
1695 struct dcbx_ets_feature *ets,
1696 u32 *pg_pri_orginal_spread)
1697{
1698 struct cos_help_data cos_data;
1699 u8 i = 0;
1700 u32 pri_join_mask = 0;
1701 u8 num_of_dif_pri = 0;
1702
1703 memset(&cos_data, 0, sizeof(cos_data));
1704
1705 /* Validate the pg value */
1706 for (i = 0; i < help_data->num_of_pg ; i++) {
1707 if (DCBX_STRICT_PRIORITY != help_data->data[i].pg &&
1708 DCBX_MAX_NUM_PG_BW_ENTRIES <= help_data->data[i].pg)
1709 BNX2X_ERR("Invalid pg[%d] data %x\n", i,
1710 help_data->data[i].pg);
1711 pri_join_mask |= help_data->data[i].pg_priority;
1712 num_of_dif_pri += help_data->data[i].num_of_dif_pri;
1713 }
1714
1715 /* defaults */
1716 cos_data.num_of_cos = 1;
1717 for (i = 0; i < ARRAY_SIZE(cos_data.data); i++) {
1718 cos_data.data[i].pri_join_mask = 0;
1719 cos_data.data[i].pausable = false;
1720 cos_data.data[i].strict = BNX2X_DCBX_STRICT_INVALID;
1721 cos_data.data[i].cos_bw = DCBX_INVALID_COS_BW;
1477 } 1722 }
1478 1723
1724 if (CHIP_IS_E3B0(bp))
1725 bnx2x_dcbx_cee_fill_cos_params(bp, help_data, ets,
1726 &cos_data, pri_join_mask);
1727 else /* E2 + E3A0 */
1728 bnx2x_dcbx_2cos_limit_cee_fill_cos_params(bp,
1729 help_data, ets,
1730 &cos_data,
1731 pg_pri_orginal_spread,
1732 pri_join_mask,
1733 num_of_dif_pri);
1734
1735
1479 for (i = 0; i < cos_data.num_of_cos ; i++) { 1736 for (i = 0; i < cos_data.num_of_cos ; i++) {
1480 struct bnx2x_dcbx_cos_params *params = 1737 struct bnx2x_dcbx_cos_params *p =
1481 &bp->dcbx_port_params.ets.cos_params[i]; 1738 &bp->dcbx_port_params.ets.cos_params[i];
1482 1739
1483 params->pauseable = cos_data.data[i].pausable; 1740 p->strict = cos_data.data[i].strict;
1484 params->strict = cos_data.data[i].strict; 1741 p->bw_tbl = cos_data.data[i].cos_bw;
1485 params->bw_tbl = cos_data.data[i].cos_bw; 1742 p->pri_bitmask = cos_data.data[i].pri_join_mask;
1486 if (params->pauseable) { 1743 p->pauseable = cos_data.data[i].pausable;
1487 params->pri_bitmask = 1744
1488 DCBX_PFC_PRI_GET_PAUSE(bp, 1745 /* sanity */
1489 cos_data.data[i].pri_join_mask); 1746 if (p->bw_tbl != DCBX_INVALID_COS_BW ||
1747 p->strict != BNX2X_DCBX_STRICT_INVALID) {
1748 if (p->pri_bitmask == 0)
1749 BNX2X_ERR("Invalid pri_bitmask for %d\n", i);
1750
1751 if (CHIP_IS_E2(bp) || CHIP_IS_E3A0(bp)) {
1752
1753 if (p->pauseable &&
1754 DCBX_PFC_PRI_GET_NON_PAUSE(bp,
1755 p->pri_bitmask) != 0)
1756 BNX2X_ERR("Inconsistent config for "
1757 "pausable COS %d\n", i);
1758
1759 if (!p->pauseable &&
1760 DCBX_PFC_PRI_GET_PAUSE(bp,
1761 p->pri_bitmask) != 0)
1762 BNX2X_ERR("Inconsistent config for "
1763 "nonpausable COS %d\n", i);
1764 }
1765 }
1766
1767 if (p->pauseable)
1490 DP(NETIF_MSG_LINK, "COS %d PAUSABLE prijoinmask 0x%x\n", 1768 DP(NETIF_MSG_LINK, "COS %d PAUSABLE prijoinmask 0x%x\n",
1491 i, cos_data.data[i].pri_join_mask); 1769 i, cos_data.data[i].pri_join_mask);
1492 } else { 1770 else
1493 params->pri_bitmask =
1494 DCBX_PFC_PRI_GET_NON_PAUSE(bp,
1495 cos_data.data[i].pri_join_mask);
1496 DP(NETIF_MSG_LINK, "COS %d NONPAUSABLE prijoinmask " 1771 DP(NETIF_MSG_LINK, "COS %d NONPAUSABLE prijoinmask "
1497 "0x%x\n", 1772 "0x%x\n",
1498 i, cos_data.data[i].pri_join_mask); 1773 i, cos_data.data[i].pri_join_mask);
1499 }
1500 } 1774 }
1501 1775
1502 bp->dcbx_port_params.ets.num_of_cos = cos_data.num_of_cos ; 1776 bp->dcbx_port_params.ets.num_of_cos = cos_data.num_of_cos ;
@@ -1516,7 +1790,7 @@ static void bnx2x_dcbx_get_ets_pri_pg_tbl(struct bnx2x *bp,
1516 } 1790 }
1517} 1791}
1518 1792
1519static void bnx2x_pfc_fw_struct_e2(struct bnx2x *bp) 1793static void bnx2x_dcbx_fw_struct(struct bnx2x *bp)
1520{ 1794{
1521 struct flow_control_configuration *pfc_fw_cfg = NULL; 1795 struct flow_control_configuration *pfc_fw_cfg = NULL;
1522 u16 pri_bit = 0; 1796 u16 pri_bit = 0;
@@ -1838,10 +2112,12 @@ static u8 bnx2x_dcbnl_get_numtcs(struct net_device *netdev, int tcid, u8 *num)
1838 if (bp->dcb_state) { 2112 if (bp->dcb_state) {
1839 switch (tcid) { 2113 switch (tcid) {
1840 case DCB_NUMTCS_ATTR_PG: 2114 case DCB_NUMTCS_ATTR_PG:
1841 *num = E2_NUM_OF_COS; 2115 *num = CHIP_IS_E3B0(bp) ? DCBX_COS_MAX_NUM_E3B0 :
2116 DCBX_COS_MAX_NUM_E2;
1842 break; 2117 break;
1843 case DCB_NUMTCS_ATTR_PFC: 2118 case DCB_NUMTCS_ATTR_PFC:
1844 *num = E2_NUM_OF_COS; 2119 *num = CHIP_IS_E3B0(bp) ? DCBX_COS_MAX_NUM_E3B0 :
2120 DCBX_COS_MAX_NUM_E2;
1845 break; 2121 break;
1846 default: 2122 default:
1847 rval = -EINVAL; 2123 rval = -EINVAL;
diff --git a/drivers/net/bnx2x/bnx2x_dcb.h b/drivers/net/bnx2x/bnx2x_dcb.h
index b3a655ff2ba..2c6a3bca6f2 100644
--- a/drivers/net/bnx2x/bnx2x_dcb.h
+++ b/drivers/net/bnx2x/bnx2x_dcb.h
@@ -27,22 +27,30 @@ struct bnx2x_dcbx_app_params {
27 u32 traffic_type_priority[LLFC_DRIVER_TRAFFIC_TYPE_MAX]; 27 u32 traffic_type_priority[LLFC_DRIVER_TRAFFIC_TYPE_MAX];
28}; 28};
29 29
30#define E2_NUM_OF_COS 2 30#define DCBX_COS_MAX_NUM_E2 DCBX_E2E3_MAX_NUM_COS
31#define BNX2X_DCBX_COS_NOT_STRICT 0 31/* bnx2x currently limits numbers of supported COSes to 3 to be extended to 6 */
32#define BNX2X_DCBX_COS_LOW_STRICT 1 32#define BNX2X_MAX_COS_SUPPORT 3
33#define BNX2X_DCBX_COS_HIGH_STRICT 2 33#define DCBX_COS_MAX_NUM_E3B0 BNX2X_MAX_COS_SUPPORT
34#define DCBX_COS_MAX_NUM BNX2X_MAX_COS_SUPPORT
34 35
35struct bnx2x_dcbx_cos_params { 36struct bnx2x_dcbx_cos_params {
36 u32 bw_tbl; 37 u32 bw_tbl;
37 u32 pri_bitmask; 38 u32 pri_bitmask;
39 /*
40 * strict priority: valid values are 0..5; 0 is highest priority.
41 * There can't be two COSes with the same priority.
42 */
38 u8 strict; 43 u8 strict;
44#define BNX2X_DCBX_STRICT_INVALID DCBX_COS_MAX_NUM
45#define BNX2X_DCBX_STRICT_COS_HIGHEST 0
46#define BNX2X_DCBX_STRICT_COS_NEXT_LOWER_PRI(sp) ((sp) + 1)
39 u8 pauseable; 47 u8 pauseable;
40}; 48};
41 49
42struct bnx2x_dcbx_pg_params { 50struct bnx2x_dcbx_pg_params {
43 u32 enabled; 51 u32 enabled;
44 u8 num_of_cos; /* valid COS entries */ 52 u8 num_of_cos; /* valid COS entries */
45 struct bnx2x_dcbx_cos_params cos_params[E2_NUM_OF_COS]; 53 struct bnx2x_dcbx_cos_params cos_params[DCBX_COS_MAX_NUM];
46}; 54};
47 55
48struct bnx2x_dcbx_pfc_params { 56struct bnx2x_dcbx_pfc_params {
@@ -134,7 +142,7 @@ struct cos_entry_help_data {
134}; 142};
135 143
136struct cos_help_data { 144struct cos_help_data {
137 struct cos_entry_help_data data[E2_NUM_OF_COS]; 145 struct cos_entry_help_data data[DCBX_COS_MAX_NUM];
138 u8 num_of_cos; 146 u8 num_of_cos;
139}; 147};
140 148
@@ -150,6 +158,8 @@ struct cos_help_data {
150 ((pg_pri) & (DCBX_PFC_PRI_PAUSE_MASK(bp))) 158 ((pg_pri) & (DCBX_PFC_PRI_PAUSE_MASK(bp)))
151#define DCBX_PFC_PRI_GET_NON_PAUSE(bp, pg_pri) \ 159#define DCBX_PFC_PRI_GET_NON_PAUSE(bp, pg_pri) \
152 (DCBX_PFC_PRI_NON_PAUSE_MASK(bp) & (pg_pri)) 160 (DCBX_PFC_PRI_NON_PAUSE_MASK(bp) & (pg_pri))
161#define DCBX_IS_PFC_PRI_SOME_PAUSE(bp, pg_pri) \
162 (0 != DCBX_PFC_PRI_GET_PAUSE(bp, pg_pri))
153#define IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pg_pri) \ 163#define IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pg_pri) \
154 (pg_pri == DCBX_PFC_PRI_GET_PAUSE((bp), (pg_pri))) 164 (pg_pri == DCBX_PFC_PRI_GET_PAUSE((bp), (pg_pri)))
155#define IS_DCBX_PFC_PRI_ONLY_NON_PAUSE(bp, pg_pri)\ 165#define IS_DCBX_PFC_PRI_ONLY_NON_PAUSE(bp, pg_pri)\
@@ -172,7 +182,6 @@ struct pg_help_data {
172 182
173/* forward DCB/PFC related declarations */ 183/* forward DCB/PFC related declarations */
174struct bnx2x; 184struct bnx2x;
175void bnx2x_dcb_init_intmem_pfc(struct bnx2x *bp);
176void bnx2x_dcbx_update(struct work_struct *work); 185void bnx2x_dcbx_update(struct work_struct *work);
177void bnx2x_dcbx_init_params(struct bnx2x *bp); 186void bnx2x_dcbx_init_params(struct bnx2x *bp);
178void bnx2x_dcbx_set_state(struct bnx2x *bp, bool dcb_on, u32 dcbx_enabled); 187void bnx2x_dcbx_set_state(struct bnx2x *bp, bool dcb_on, u32 dcbx_enabled);