brd_e2e.c (14355B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * File: brd_e2e.c 8 * Purpose: XGS Board End-to-end flow control programming 9 * Supports boards with up to 4 BCM5695 devices, and 10 * dual BCM56504 board only. 11 * Other XGS1 and XGS2 devices are not end-to-end capable. 12 */ 13 14 #include <soc/drv.h> 15 #include <soc/higig.h> 16 17 #include <bcm/error.h> 18 #include <bcm/stack.h> 19 #include <bcm/link.h> 20 #include <bcm/port.h> 21 #include <bcm/trunk.h> 22 23 #include <appl/cputrans/next_hop.h> 24 #include <appl/stktask/topo_brd.h> 25 26 #define E2E_CAPABLE(_u) (SOC_IS_FB_FX_HX(_u)) 27 28 #ifndef E2E_MAXUNIT 29 #define E2E_MAXUNIT 4 30 #endif 31 32 #define E2E_ETHERTYPE 0x8874 33 #define E2E_OPCODE_HOL 0xbc01 34 #define E2E_OPCODE_IBP 0xbc02 35 36 #ifndef E2E_PKT_DEFRATE 37 #define E2E_PKT_DEFRATE 0x100 38 #endif 39 40 #ifndef E2E_CELL_DEFLIMIT 41 #define E2E_CELL_DEFLIMIT 73 /* cells for a jumbo + 1 */ 42 #endif 43 44 #ifndef E2E_PKT_DEFLIMIT 45 #define E2E_PKT_DEFLIMIT 0x7ff /* no limit */ 46 #endif 47 48 #define E2E_CELL_NOLIMIT 0x1fff 49 50 #define E2E_PKT_NOLIMIT 0x7ff 51 52 53 #ifdef BCM_XGS3_SWITCH_SUPPORT 54 55 #ifndef E2E_MAXUNIT_FB 56 #define E2E_MAXUNIT_FB 2 57 #endif 58 59 #ifndef E2E_FB_PKT_LIMIT 60 #define E2E_FB_PKT_LIMIT 0x90 61 #endif 62 63 #ifndef E2E_FB_CELL_LIMIT 64 #define E2E_FB_CELL_LIMIT 0x180 65 #endif 66 67 #ifndef E2E_CELL_DISCARD_LIMIT 68 #define E2E_CELL_DISCARD_LIMIT 0x300 69 #endif 70 71 #ifndef E2E_PKTCELL_RESET_LIMIT 72 #define E2E_PKTCELL_RESET_LIMIT 0x1 73 #endif 74 75 #ifndef E2E_MAXTIMER_DEFSEL 76 #define E2E_MAXTIMER_DEFSEL 0xb 77 #endif 78 79 #ifndef E2E_MINTIMER_DEFSEL 80 #define E2E_MINTIMER_DEFSEL 0x3 81 #endif 82 83 #endif /* BCM_XGS3_SWITCH)SUPPORT */ 84 85 STATIC int _bcm_e2e_pkt_rate = E2E_PKT_DEFRATE; 86 STATIC int _bcm_e2e_cell_limit = E2E_CELL_DEFLIMIT; 87 STATIC int _bcm_e2e_pkt_limit = E2E_PKT_DEFLIMIT; 88 89 int 90 bcm_board_e2e_config_set(int pkt_rate, int cell_limit, int pkt_limit) 91 { 92 _bcm_e2e_pkt_rate = pkt_rate < 0 ? E2E_PKT_DEFRATE : pkt_rate; 93 _bcm_e2e_cell_limit = cell_limit < 0 ? E2E_CELL_DEFLIMIT : cell_limit; 94 _bcm_e2e_pkt_limit = pkt_limit < 0 ? E2E_PKT_DEFLIMIT : pkt_limit; 95 return BCM_E_NONE; 96 } 97 98 int 99 bcm_board_e2e_config_get(int *pkt_rate, int *cell_limit, int *pkt_limit) 100 { 101 if (pkt_rate != NULL) { 102 *pkt_rate = _bcm_e2e_pkt_rate; 103 } 104 if (cell_limit != NULL) { 105 *cell_limit = _bcm_e2e_cell_limit; 106 } 107 if (pkt_limit != NULL) { 108 *pkt_limit = _bcm_e2e_pkt_limit; 109 } 110 return BCM_E_NONE; 111 } 112 113 #ifdef BCM_FIREBOLT_SUPPORT 114 STATIC int 115 _bcm_board_e2e_fbx_unit(int unit, 116 int lmod, 117 int cos, 118 int vlan, 119 bcm_mac_t mac, 120 int *rmod, 121 int **rpstate) 122 { 123 uint32 val = 0; 124 bcm_port_t port; 125 int cell_limit, pkt_limit; 126 uint32 val0, val1, val2, val3; 127 soc_higig_hdr_t hg; 128 uint32 hgwords[3]; 129 bcm_trunk_t tid; 130 bcm_trunk_info_t ta_info; 131 int member_count; 132 bcm_trunk_member_t member_array[BCM_TRUNK_FABRIC_MAX_PORTCNT]; 133 bcm_port_t local_port; 134 bcm_trunk_chip_info_t ti; 135 int idx, trunk_found = 0; 136 137 if (rmod[0] < 0) { 138 return BCM_E_PARAM; /* or BCM_E_UNAVAIL ?? */ 139 } 140 141 BCM_IF_ERROR_RETURN 142 (bcm_stk_modport_get(unit, rmod[0], &port)); 143 144 sal_memset(&ti, 0, sizeof(bcm_trunk_chip_info_t)); 145 BCM_IF_ERROR_RETURN(bcm_trunk_chip_info_get(unit, &ti)); 146 147 /* 148 * Check for fabric trunk membership, and enable 149 * E2E IBP on all trunk members 150 */ 151 for (tid = ti.trunk_fabric_id_min; 152 tid <= ti.trunk_fabric_id_max; tid++) { 153 sal_memset(&ta_info, 0, sizeof(bcm_trunk_info_t)); 154 if (bcm_trunk_get(unit, tid, &ta_info, BCM_TRUNK_FABRIC_MAX_PORTCNT, 155 member_array, &member_count) >= 0) { 156 for (idx = 0; idx < member_count; idx++) { 157 BCM_IF_ERROR_RETURN(bcm_port_local_get(unit, 158 member_array[idx].gport, &local_port)); 159 if (local_port == port) { 160 trunk_found = 1; 161 break; 162 } 163 } 164 } 165 166 if (trunk_found) { 167 break; 168 } 169 } 170 171 /* 172 * If fabric trunk not found for some reason, populate 173 * the single HG port for IBP programming 174 */ 175 if (!trunk_found) { 176 member_count = 1; 177 bcm_trunk_member_t_init(&member_array[0]); 178 member_array[0].gport = BCM_GPORT_DEVPORT(unit, port); 179 } 180 181 SOC_IF_ERROR_RETURN(READ_E2ECONFIGr(unit, &val)); 182 183 /* 184 * set remote module id 185 */ 186 soc_reg_field_set(unit, E2ECONFIGr, &val, 187 REMOTE_SRCMODIDf, rmod[0]); 188 189 /* 190 * Turn on e2e IBP only (no HOL) 191 */ 192 soc_reg_field_set(unit, E2ECONFIGr, &val, E2E_IBP_ENf, 1); 193 soc_reg_field_set(unit, E2ECONFIGr, &val, E2E_HOL_ENf, 1); 194 soc_reg_field_set(unit, E2ECONFIGr, &val, E2E_MAXTIMER_SELf, 195 E2E_MAXTIMER_DEFSEL); 196 soc_reg_field_set(unit, E2ECONFIGr, &val, E2E_MINTIMER_SELf, 197 E2E_MINTIMER_DEFSEL); 198 SOC_IF_ERROR_RETURN(WRITE_E2ECONFIGr(unit, val)); 199 200 /* define packet higig header */ 201 sal_memset(&hg, 0, sizeof(hg)); 202 soc_higig_field_set(unit, &hg, HG_start, SOC_HIGIG_START); 203 soc_higig_field_set(unit, &hg, HG_hgi, SOC_HIGIG_HGI); 204 soc_higig_field_set(unit, &hg, HG_vlan_id, vlan); 205 soc_higig_field_set(unit, &hg, HG_src_mod, lmod); 206 soc_higig_field_set(unit, &hg, HG_opcode, SOC_HIGIG_OP_UC); 207 soc_higig_field_set(unit, &hg, HG_src_port, port); 208 soc_higig_field_set(unit, &hg, HG_dst_port, port); 209 soc_higig_field_set(unit, &hg, HG_cos, cos); 210 sal_memcpy(hgwords, &hg, sizeof(hgwords)); 211 212 /* define packet data header (da, sa, len/type, opcode) */ 213 val0 = (mac[0] << 24) | (mac[1] << 16) | (mac[2] << 8) | mac[3]; 214 val1 = (mac[4] << 24) | (mac[5] << 16) | (mac[0] << 8) | mac[1]; 215 val2 = (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5]; 216 val3 = (E2E_ETHERTYPE << 16) | E2E_OPCODE_IBP; 217 218 for (idx = 0; idx < member_count; idx++) { 219 220 BCM_IF_ERROR_RETURN 221 (bcm_port_local_get(unit, member_array[idx].gport, &port)); 222 if (!IS_HG_PORT(unit, port)) { 223 continue; 224 } 225 226 val = 0; 227 SOC_IF_ERROR_RETURN(READ_E2ECONFIGr(unit, &val)); 228 switch(port) { 229 case 24: 230 soc_reg_field_set(unit, E2ECONFIGr, &val, XPORT24_SEND_E2E_IBPf, 1); 231 break; 232 233 case 25: 234 soc_reg_field_set(unit, E2ECONFIGr, &val, XPORT25_SEND_E2E_IBPf, 1); 235 break; 236 237 case 26: 238 soc_reg_field_set(unit, E2ECONFIGr, &val, XPORT26_SEND_E2E_IBPf, 1); 239 break; 240 241 case 27: 242 soc_reg_field_set(unit, E2ECONFIGr, &val, XPORT27_SEND_E2E_IBPf, 1); 243 break; 244 245 default: 246 break; 247 } 248 SOC_IF_ERROR_RETURN(WRITE_E2ECONFIGr(unit, val)); 249 250 SOC_IF_ERROR_RETURN(WRITE_XIBP_MH0r(unit, port, hgwords[0])); 251 SOC_IF_ERROR_RETURN(WRITE_XIBP_MH1r(unit, port, hgwords[1])); 252 SOC_IF_ERROR_RETURN(WRITE_XIBP_MH2r(unit, port, hgwords[2])); 253 254 SOC_IF_ERROR_RETURN(WRITE_XIBP_D0r(unit, port, val0)); 255 SOC_IF_ERROR_RETURN(WRITE_XIBP_D1r(unit, port, val1)); 256 SOC_IF_ERROR_RETURN(WRITE_XIBP_D2r(unit, port, val2)); 257 SOC_IF_ERROR_RETURN(WRITE_XIBP_D3r(unit, port, val3)); 258 259 val = 0; 260 SOC_IF_ERROR_RETURN(READ_IE2E_CONTROLr(unit, port, &val)); 261 soc_reg_field_set(unit, IE2E_CONTROLr, &val, IBP_ENABLEf, 1); 262 SOC_IF_ERROR_RETURN(WRITE_IE2E_CONTROLr(unit, port, val)); 263 264 val = 0; 265 SOC_IF_ERROR_RETURN(READ_XPORT_CONFIGr(unit, port, &val)); 266 soc_reg_field_set(unit, XPORT_CONFIGr, &val, E2E_IBP_ENf, 1); 267 SOC_IF_ERROR_RETURN(WRITE_XPORT_CONFIGr(unit, port, val)); 268 269 /* 270 * Setup pkt and cell limits for ibp 271 */ 272 cell_limit = E2E_FB_CELL_LIMIT; 273 pkt_limit = E2E_FB_PKT_LIMIT; 274 275 val = 0; 276 soc_reg_field_set(unit, E2EIBPCELLSETLIMITr, &val, CELLSETLIMITf, 277 cell_limit); 278 soc_reg_field_set(unit, E2EIBPCELLSETLIMITr, &val, RESETLIMITSELf, 279 E2E_PKTCELL_RESET_LIMIT); 280 SOC_IF_ERROR_RETURN(WRITE_E2EIBPCELLSETLIMITr(unit, port, val)); 281 282 val = 0; 283 soc_reg_field_set(unit, E2EIBPPKTSETLIMITr, &val, PKTSETLIMITf, 284 pkt_limit); 285 soc_reg_field_set(unit, E2EIBPPKTSETLIMITr, &val, RESETLIMITSELf, 286 E2E_PKTCELL_RESET_LIMIT); 287 SOC_IF_ERROR_RETURN(WRITE_E2EIBPPKTSETLIMITr(unit, port, val)); 288 289 SOC_IF_ERROR_RETURN 290 (WRITE_E2EIBPDISCARDSETLIMITr(unit, port, 291 E2E_CELL_DISCARD_LIMIT)); 292 } 293 294 /* 295 * define packet recognition criteria for IBP 296 */ 297 val = (mac[0] << 8) | mac[1]; 298 SOC_IF_ERROR_RETURN(WRITE_E2E_IBP_RX_DA_MSr(unit, val)); 299 val = (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5]; 300 SOC_IF_ERROR_RETURN(WRITE_E2E_IBP_RX_DA_LSr(unit, val)); 301 SOC_IF_ERROR_RETURN(WRITE_E2E_IBP_RX_LENGTH_TYPEr(unit, E2E_ETHERTYPE)); 302 SOC_IF_ERROR_RETURN(WRITE_E2E_IBP_RX_OPCODEr(unit, E2E_OPCODE_IBP)); 303 304 return BCM_E_NONE; 305 } 306 #endif /* BCM_FIREBOLT_SUPPORT */ 307 308 STATIC int 309 _bcm_board_e2e_unit(int unit, 310 int lmod, 311 int cos, 312 int vlan, 313 bcm_mac_t mac, 314 int *rmod, 315 int **rpstate) 316 { 317 int rv = BCM_E_NONE; 318 319 #ifdef BCM_FIREBOLT_SUPPORT 320 if (SOC_IS_FIREBOLT(unit)) { 321 rv = _bcm_board_e2e_fbx_unit(unit, lmod, cos, vlan, mac, 322 rmod, rpstate); 323 } 324 #endif 325 326 return rv; 327 } 328 329 330 int 331 bcm_board_e2e_set(void) 332 { 333 int unit, neunits, i, cos, vlan; 334 int eunits[E2E_MAXUNIT]; 335 int emods[E2E_MAXUNIT]; 336 bcm_mac_t mac; 337 int lmod, nr, j, max_e2e_units; 338 int pstate[E2E_MAXUNIT][SOC_MAX_NUM_PORTS]; 339 int rmod[E2E_MAXUNIT-1], *rpstate[E2E_MAXUNIT-1]; 340 bcm_port_t port; 341 int pause_tx, pause_rx, link_up; 342 343 /* find e2e capable units */ 344 neunits = 0; 345 max_e2e_units = E2E_MAXUNIT; 346 347 #ifdef BCM_XGS3_SWITCH_SUPPORT 348 for (unit = 0; unit < soc_ndev; unit++) { 349 if (SOC_IS_FB_FX_HX(SOC_NDEV_IDX2DEV(unit))) { 350 neunits++; 351 if (max_e2e_units != E2E_MAXUNIT_FB) { 352 max_e2e_units = E2E_MAXUNIT_FB; 353 } 354 } 355 } 356 357 if (max_e2e_units == E2E_MAXUNIT_FB) { 358 /* 359 * We've established there is a FB in the system; 360 * Allow E2E in a stacked system with only 2 FBs 361 */ 362 if (neunits != max_e2e_units) { 363 return BCM_E_UNAVAIL; 364 } 365 } 366 #endif 367 368 neunits = 0; 369 for (unit = 0; unit < soc_ndev; unit++) { 370 if (E2E_CAPABLE(SOC_NDEV_IDX2DEV(unit))) { 371 eunits[neunits] = SOC_NDEV_IDX2DEV(unit); 372 BCM_IF_ERROR_RETURN(bcm_stk_modid_get(SOC_NDEV_IDX2DEV(unit), &emods[neunits])); 373 neunits += 1; 374 if (neunits == max_e2e_units) { 375 break; 376 } 377 } 378 } 379 380 if (neunits < 2) { /* need at least two devices */ 381 return BCM_E_NONE; 382 } 383 384 /* use nexthop cos, vlan, mac for E2E packets */ 385 if (next_hop_cos_get(&cos) < 0) { 386 cos = 0; 387 } 388 389 if (next_hop_vlan_get(&vlan) < 0) { 390 vlan = 1; 391 } 392 (void)nh_tx_local_mac_get(&mac); 393 394 /* get link/pause state */ 395 sal_memset(pstate, 0, sizeof(pstate)); 396 for (i = 0; i < neunits; i++) { 397 unit = eunits[i]; 398 PBMP_E_ITER(unit, port) { 399 if (bcm_port_pause_get(unit, port, &pause_tx, &pause_rx) < 0) { 400 continue; 401 } 402 if (!pause_tx) { 403 continue; 404 } 405 if (bcm_port_link_status_get(unit, port, &link_up) < 0) { 406 continue; 407 } 408 if (!link_up) { 409 continue; 410 } 411 pstate[i][port] = 1; 412 } 413 } 414 415 /* setup each unit for e2e */ 416 for (i = 0; i < neunits; i++) { 417 unit = eunits[i]; 418 lmod = emods[i]; 419 rmod[0] = rmod[1] = rmod[2] = -1; 420 nr = 0; 421 for (j = 0; j < neunits; j++) { 422 if (j == i) { 423 continue; 424 } 425 rmod[nr] = emods[j]; 426 rpstate[nr] = &pstate[j][0]; 427 nr += 1; 428 } 429 BCM_IF_ERROR_RETURN 430 (_bcm_board_e2e_unit(unit, lmod, cos, vlan, mac, 431 rmod, rpstate)); 432 } 433 434 return BCM_E_NONE; 435 } 436 437 /* 438 * E2E IBP programming for dual FB LMs 439 */ 440 int 441 _bcm_board_dual_xgs3_e2e_set(int unit0, bcm_module_t modid0, 442 int unit1, bcm_module_t modid1) 443 { 444 #ifdef BCM_FIREBOLT_SUPPORT 445 int unit, i, cos, vlan; 446 bcm_mac_t mac; 447 int lmod, nr, j; 448 int pstate[E2E_MAXUNIT_FB][SOC_MAX_NUM_PORTS]; 449 int rmod[E2E_MAXUNIT_FB], *rpstate[E2E_MAXUNIT_FB]; 450 bcm_port_t port; 451 int pause_tx, pause_rx, link_up; 452 xgs3devinfo_t dev[E2E_MAXUNIT_FB]; 453 454 dev[0].unit = unit0; 455 dev[0].modid = modid0; 456 dev[1].unit = unit1; 457 dev[1].modid = modid1; 458 459 /* use nexthop cos, vlan, mac for E2E packets */ 460 if (next_hop_cos_get(&cos) < 0) { 461 cos = 0; 462 } 463 464 if (next_hop_vlan_get(&vlan) < 0) { 465 vlan = 1; 466 } 467 (void)nh_tx_local_mac_get(&mac); 468 469 /* get link/pause state */ 470 sal_memset(pstate, 0, sizeof(pstate)); 471 for (i = 0; i < E2E_MAXUNIT_FB; i++) { 472 unit = dev[i].unit; 473 PBMP_E_ITER(unit, port) { 474 if (bcm_port_pause_get(unit, port, &pause_tx, &pause_rx) < 0) { 475 continue; 476 } 477 if (!pause_tx) { 478 continue; 479 } 480 if (bcm_port_link_status_get(unit, port, &link_up) < 0) { 481 continue; 482 } 483 if (!link_up) { 484 continue; 485 } 486 pstate[i][port] = 1; 487 } 488 } 489 490 /* setup each unit for e2e */ 491 for (i = 0; i < E2E_MAXUNIT_FB; i++) { 492 unit = dev[i].unit; 493 lmod = dev[i].modid; 494 rmod[0] = rmod[1] = -1; 495 nr = 0; 496 for (j = 0; j < E2E_MAXUNIT_FB; j++) { 497 if (j == i) { 498 continue; 499 } 500 rmod[nr] = dev[j].modid; 501 rpstate[nr] = &pstate[j][0]; 502 nr += 1; 503 } 504 505 BCM_IF_ERROR_RETURN 506 (_bcm_board_e2e_fbx_unit(unit, lmod, cos, vlan, mac, 507 rmod, rpstate)); 508 } 509 #endif /* BCM_FIREBOLT_SUPPORT */ 510 511 return BCM_E_NONE; 512 } 513 514