connection.c (15706B)
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: connection.c 8 * Purpose: Board connection functions 9 */ 10 11 12 #include <shared/bsl.h> 13 14 #include <sal/core/alloc.h> 15 #include <sal/core/libc.h> 16 #include <bcm/init.h> 17 #include <bcm/error.h> 18 #include <bcm/types.h> 19 #include <bcm/port.h> 20 #include <bcm/trunk.h> 21 #include <bcm/stack.h> 22 #include <board/board.h> 23 #include <board/manager.h> 24 #include <board_int/support.h> 25 26 27 /* 28 * Function: 29 * board_connection_gport_stackable 30 * Purpose: 31 * Return true if the port is capable of being some sort of Higig 32 * port. 33 * Parameters: 34 * gport - (IN) stack port 35 * Returns: 36 * TRUE - port is stackable 37 * BCM_E_NONE - port is not stackable 38 * BCM_E_XXX - failure 39 * Notes: 40 * Not all Higig modes are usable for stacking purposes. 41 * 42 * This API is currently broken. See PR 36640 - 43 * bcm_port_ability_local_get only gets current encap of port 44 */ 45 int 46 board_connection_gport_stackable(bcm_gport_t gport) 47 { 48 bcm_port_ability_t ability; 49 int unit; 50 int rv = BCM_E_NONE; 51 52 unit = BCM_GPORT_DEVPORT_DEVID_GET(gport); 53 54 rv = bcm_port_ability_local_get(unit, gport, &ability); 55 if (BCM_SUCCESS(rv)) { 56 57 if ((ability.encap & BCM_PA_ENCAP_HIGIG) || 58 (ability.encap & BCM_PA_ENCAP_HIGIG2)) { 59 rv = TRUE; 60 } 61 } 62 63 return rv; 64 } 65 66 /* 67 * Function: 68 * board_connection_gport_stacking 69 * Purpose: 70 * Return TRUE if the stack port is currently in a stacking mode 71 * Parameters: 72 * gport - (IN) stack port 73 * Returns: 74 * TRUE - port is in a stacking mode 75 * BCM_E_NONE - port is not in a stacking mode 76 * BCM_E_XXX - failure 77 */ 78 int 79 board_connection_gport_stacking(bcm_gport_t gport) 80 { 81 int mode; 82 int unit; 83 int rv = BCM_E_NONE; 84 85 unit = BCM_GPORT_DEVPORT_DEVID_GET(gport); 86 87 rv = bcm_port_encap_get(unit, gport, &mode); 88 if (BCM_SUCCESS(rv)) { 89 if ((mode == BCM_PORT_ENCAP_HIGIG) || 90 (mode == BCM_PORT_ENCAP_HIGIG2) || 91 (mode == BCM_PORT_ENCAP_HIGIG2_LITE)) { 92 rv = TRUE; 93 } 94 } 95 96 return rv; 97 } 98 99 /* 100 * Function: 101 * board_connections_discover 102 * Purpose: 103 * Discovers internal connectivity between devices on a board. 104 * Discovery algorithm is guaranteed to disrupt traffic, 105 * and may be slow for large numbers of devices or internal ports. 106 * 107 * This function is provided for debugging and initial board 108 * implementation, and is not intended for production use. 109 * Parameters: 110 * max_num - (IN) maximum number of entries in connection array 111 * connection - (OUT) array of board_connection_t 112 * actual - (OUT) actual number of valid entries in connection array 113 * Returns: 114 * BCM_E_NONE - success 115 * BCM_E_XXX - failed 116 */ 117 int 118 board_connections_discover(int max_num, 119 board_connection_t *connection, 120 int *actual) 121 { 122 int u; 123 int unit = -1; 124 int num_units; 125 int count = 0; 126 int rv = BCM_E_NONE; 127 bcm_port_config_t port_info; 128 bcm_port_t port; 129 bcm_port_t gport; 130 131 for ( num_units=u=0; u<bcm_unit_max(); u++ ) { 132 if (bcm_unit_local(u)) { 133 if (unit < 0) { 134 unit = u; 135 num_units++; 136 } else { 137 138 return BCM_E_CONFIG; 139 } 140 } 141 } 142 143 if (unit >= 0) { 144 BCM_IF_ERROR_RETURN(bcm_port_config_get(unit, &port_info)); 145 BCM_PBMP_ITER(port_info.port, port) { 146 gport = BCM_GPORT_DEVPORT(unit, port); 147 rv = board_connection_gport_stackable(gport); 148 if (BCM_SUCCESS(rv) && rv > 0) { 149 if (count < max_num) { 150 connection[count].from = BCM_GPORT_DEVPORT(unit,port); 151 connection[count].to = BCM_GPORT_TYPE_NONE; 152 } 153 count++; 154 } else if (BCM_FAILURE(rv)) { 155 return rv; 156 } 157 } 158 } 159 160 if (max_num == 0) { 161 if (actual) { 162 *actual = count; 163 } else { 164 rv = BCM_E_PARAM; 165 } 166 } else { 167 if (actual) { 168 *actual = count; 169 } 170 } 171 172 return rv; 173 } 174 175 /* 176 * Function: 177 * board_connections_alloc 178 * Purpose: 179 * Allocate a worst case sized connection list for the current board. 180 * Parameters: 181 * driver - (IN) current board driver 182 * connection - (OUT) allocated connection array 183 * actual - (OUT) size of connection array 184 * Returns: 185 * BCM_E_NONE - success 186 * BCM_E_XXX - failed 187 */ 188 int 189 board_connections_alloc(board_driver_t *driver, 190 board_connection_t **connection, 191 int *actual) 192 { 193 int count; 194 int rv = BCM_E_MEMORY; 195 board_connection_t *conn; 196 197 if (driver == NULL || connection == NULL || actual == NULL) { 198 return BCM_E_PARAM; 199 } 200 201 count = board_num_devices() * BCM_PBMP_PORT_MAX; 202 conn = sal_alloc(count * sizeof(*conn), driver->name); 203 if (conn) { 204 sal_memset(conn, 0, count * sizeof(*conn)); 205 *connection = conn; 206 *actual = count; 207 rv = BCM_E_NONE; 208 } 209 210 return rv; 211 } 212 213 /* 214 * Function: 215 * board_connection_stack_ports 216 * Purpose: 217 * Returns all stack ports on all devices, without regard to internal 218 * connectivity. 219 * Parameters: 220 * max_num - (IN) maximum size of connection list 221 * connection - (INOUT) connection list 222 * actual - (OUT) actual size of connection list 223 * Returns: 224 * BCM_E_NONE - success 225 * BCM_E_XXX - failed 226 */ 227 int 228 board_connection_stack_ports(int max_num, 229 board_connection_t *connection, 230 int *actual) 231 { 232 int unit; 233 int count; 234 int rv = BCM_E_NONE; 235 bcm_port_config_t port_info; 236 bcm_port_t port; 237 bcm_port_t gport; 238 239 count = 0; 240 for ( unit=0; unit<bcm_unit_max(); unit++ ) { 241 if (bcm_unit_local(unit)) { 242 BCM_IF_ERROR_RETURN(bcm_port_config_get(unit, &port_info)); 243 BCM_PBMP_ITER(port_info.port, port) { 244 gport = BCM_GPORT_DEVPORT(unit, port); 245 rv = board_connection_gport_stackable(gport); 246 if (BCM_SUCCESS(rv) && rv > 0) { 247 if (count < max_num) { 248 connection[count].from = BCM_GPORT_DEVPORT(unit,port); 249 connection[count].to = BCM_GPORT_TYPE_NONE; 250 } 251 count++; 252 } else if (BCM_FAILURE(rv)) { 253 return rv; 254 } 255 } 256 } 257 } 258 259 if (actual) { 260 *actual = count; 261 } 262 263 return rv; 264 } 265 266 #define INT_STK_FLAGS (BCM_STK_ENABLE | BCM_STK_DUPLEX | BCM_STK_INTERNAL) 267 268 /* Traverse */ 269 270 /* 271 * Function: 272 * board_connection_connected_stack_port_traverse 273 * Purpose: 274 * Tranverses all connected stack ports in the list, ignoring 275 * external ports, and non-stack ports. 276 * Parameters: 277 * count - (IN) length of connection list 278 * connection - (IN) connection list 279 * func - (IN) callback function 280 * user_data - (IN) user data passed to callback 281 * Returns: 282 * BCM_E_NONE - success 283 * BCM_E_XXX - failed 284 */ 285 int 286 board_connection_connected_stack_port_traverse(int count, 287 board_connection_t *connection, 288 board_connection_sp_cb_t func, 289 void *user_data) 290 { 291 int i; 292 int rv = BCM_E_NONE; 293 294 for (i=0; i<count; i++) { 295 296 /* both have to be GPORTs */ 297 if (connection[i].from == BCM_GPORT_TYPE_NONE || 298 connection[i].to == BCM_GPORT_TYPE_NONE) { 299 continue; 300 } 301 302 /* both have to be stacking */ 303 rv = board_connection_gport_stacking(connection[i].from); 304 305 if (BCM_FAILURE(rv)) { 306 break; 307 } else if (rv != TRUE) { 308 continue; 309 } 310 311 rv = board_connection_gport_stacking(connection[i].to); 312 313 if (BCM_FAILURE(rv)) { 314 break; 315 } else if (rv != TRUE) { 316 continue; 317 } 318 319 /* Call the callback for each port */ 320 rv = func(&connection[i], user_data); 321 322 if (BCM_FAILURE(rv)) { 323 break; 324 } 325 326 } 327 328 return rv; 329 } 330 331 /* 332 * Function: 333 * 334 * Purpose: 335 * Mark the port as an internal stack port if the stack port 336 * is not yet enabled. 337 * Parameters: 338 * gport - (IN) stack port 339 * Returns: 340 * BCM_E_NONE - success 341 * BCM_E_XXX - failed 342 */ 343 STATIC int 344 _internal_stack_port_set(bcm_gport_t gport) 345 { 346 int unit; 347 uint32 flags; 348 349 unit = BCM_GPORT_DEVPORT_DEVID_GET(gport); 350 BCM_IF_ERROR_RETURN(bcm_stk_port_get(unit, gport, &flags)); 351 if (!(flags & BCM_STK_ENABLE)) { 352 /* add as a stack port */ 353 BCM_IF_ERROR_RETURN(bcm_stk_port_set(unit, gport, INT_STK_FLAGS)); 354 /* allow all modids */ 355 BCM_IF_ERROR_RETURN(bcm_port_modid_enable_set(unit, gport, 356 -1, TRUE)); 357 } 358 359 return BCM_E_NONE; 360 } 361 362 /* 363 * Function: 364 * _internal_stack_connection_set 365 * Purpose: 366 * Set the connection as internal stack ports 367 * Parameters: 368 * conn - (IN) internal stack port connection 369 * user_data - (IN) callback user data 370 * Returns: 371 * BCM_E_NONE - success 372 * BCM_E_XXX - failed 373 */ 374 STATIC int 375 _internal_stack_connection_set(board_connection_t *conn, void *user_data) 376 { 377 COMPILER_REFERENCE(user_data); 378 BCM_IF_ERROR_RETURN(_internal_stack_port_set(conn->from)); 379 BCM_IF_ERROR_RETURN(_internal_stack_port_set(conn->to)); 380 381 return BCM_E_NONE; 382 } 383 384 /* 385 * Function: 386 * board_connection_add_internal_stack_ports 387 * Purpose: 388 * Add all connection pairs in list as internal stack ports 389 * Parameters: 390 * count - (IN) length of connection list 391 * connection - (IN) connection list 392 * Returns: 393 * BCM_E_NONE - success 394 * BCM_E_XXX - failed 395 */ 396 int 397 board_connection_add_internal_stack_ports(int count, 398 board_connection_t *connection) 399 { 400 return 401 board_connection_connected_stack_port_traverse 402 (count, connection, _internal_stack_connection_set, NULL); 403 } 404 405 /* 406 * Function: 407 * _board_connection_info 408 * Purpose: 409 * Tree Programmer 'info' function. 410 * Local interdevice programming 411 * Sets modid/trunk info for given unit 412 * Parameters: 413 * unit - (IN) current unit 414 * modid - (OUT) modid for this unit 415 * ti - (OUT) trunk info for this unit 416 * user_data - (IN) user data registered 417 * Returns: 418 * BCM_E_NONE - success 419 * BCM_E_XXX - failed 420 */ 421 STATIC int 422 _board_connection_info(int unit, int *modid, bcm_trunk_chip_info_t *ti, 423 void *user_data) 424 { 425 int rv; 426 427 rv = bcm_trunk_chip_info_get(unit, ti); 428 if (BCM_SUCCESS(rv)) { 429 rv = bcm_stk_my_modid_get(unit, modid); 430 if (BCM_FAILURE(rv) && (rv == BCM_E_UNAVAIL)) { 431 /* Assume that this is a fabric */ 432 *modid = -1; 433 rv = BCM_E_NONE; 434 } 435 } 436 437 return rv; 438 } 439 440 /* 441 * Function: 442 * _board_connection_trunk 443 * Purpose: 444 * Tree Programmer 'edge' function. 445 * Program trunk if needed. 446 * Parameters: 447 * unit - (IN) current unit 448 * ti - (IN) trunk info for this unit 449 * ta - (OUT) trunk add info for this unit 450 * user_data - (IN) user data registered 451 * Returns: 452 * BCM_E_NONE - success 453 * BCM_E_XXX - failed 454 */ 455 STATIC int 456 _board_connection_trunk(int unit, bcm_trunk_chip_info_t *ti, 457 bcm_trunk_add_info_t *ta, void *user_data) 458 { 459 int rv, tid; 460 int i; 461 bcm_trunk_member_t *member_array = NULL; 462 bcm_trunk_info_t tinfo; 463 464 if (ta->num_ports < 2) { 465 /* Nothing to do */ 466 return BCM_E_NONE; 467 } 468 469 tid = ti->trunk_fabric_id_max; 470 if (tid >= ti->trunk_fabric_id_min) { 471 ta->psc = -1; /* Default hash algorithm */ 472 ta->dlf_index = -1; 473 ta->mc_index = -1; 474 ta->ipmc_index = -1; 475 rv = bcm_trunk_create(unit, BCM_TRUNK_FLAG_WITH_ID, &tid); 476 if (BCM_SUCCESS(rv)) { 477 LOG_VERBOSE(BSL_LS_BOARD_COMMON, 478 (BSL_META_U(unit, 479 "Board trunk u:%d tid:%d\n"), 480 unit, tid)); 481 member_array = sal_alloc(ta->num_ports * sizeof(bcm_trunk_member_t), 482 "trunk member array"); 483 if (NULL == member_array) { 484 return BCM_E_MEMORY; 485 } 486 for (i = 0; i < ta->num_ports; i++) { 487 bcm_trunk_member_t_init(&member_array[i]); 488 if (BCM_GPORT_IS_SET(ta->tp[i])) { 489 member_array[i].gport = ta->tp[i]; 490 } else { 491 BCM_GPORT_LOCAL_SET(member_array[i].gport, ta->tp[i]); 492 } 493 } 494 bcm_trunk_info_t_init(&tinfo); 495 tinfo.flags = ta->flags; 496 tinfo.psc = ta->psc; 497 tinfo.dlf_index = ta->dlf_index; 498 tinfo.mc_index = ta->mc_index; 499 tinfo.ipmc_index = ta->ipmc_index; 500 rv = bcm_trunk_set(unit, tid, &tinfo, ta->num_ports, member_array); 501 if (BCM_SUCCESS(rv)) { 502 ti->trunk_fabric_id_max--; 503 } 504 sal_free(member_array); 505 } 506 } else { 507 /* No more trunks */ 508 rv = BCM_E_FULL; 509 } 510 511 return rv; 512 } 513 514 /* 515 * Function: 516 * _board_connection_modmap 517 * Purpose: 518 * Tree Programmer 'vertex' function. 519 * Programs device modmap 520 * Parameters: 521 * unit - (IN) current unit 522 * modid - (IN) modid for this unit 523 * port - (IN) egressing stack port on this vertex 524 * user_data - (IN) user data registered 525 * Returns: 526 */ 527 528 STATIC int 529 _board_connection_modmap(int unit, int modid, bcm_gport_t port, 530 void *user_data) 531 { 532 int rv = BCM_E_NONE; 533 534 if (modid >= 0) { 535 LOG_VERBOSE(BSL_LS_BOARD_COMMON, 536 (BSL_META_U(unit, 537 "Board modmap mod=%d u:%d,%d\n"), 538 modid, unit, port)); 539 rv = bcm_stk_modport_set(unit, modid, port); 540 } 541 542 return rv; 543 } 544 545 546 /* 547 * Function: 548 * board_connection_setup 549 * Purpose: 550 * Sets up a board in a standard Ethernet switch configuration 551 * according to the board driver connection 552 * array. board_modid_set() must be called prior to calling this 553 * function. 554 * 555 * Multiple Higig links between devices will be trunked, and module 556 * mapping configured for multiple devices. 557 * 558 * Parameters: 559 * none 560 * Returns: 561 * BCM_E_NONE - success 562 * BCM_E_XXX - failed 563 */ 564 int 565 board_connection_setup(void) 566 { 567 int rv; 568 board_driver_t *driver; 569 board_tree_driver_t tree_driver; 570 571 driver = board_driver(); 572 573 if (!driver) { 574 rv = BCM_E_INIT; 575 } else if (driver->num_connection > 0) { 576 tree_driver.num_connection = driver->num_connection; 577 tree_driver.connection = driver->connection; 578 tree_driver.user_data = NULL; 579 tree_driver.info = _board_connection_info; 580 tree_driver.edge = _board_connection_trunk; 581 tree_driver.vertex = _board_connection_modmap; 582 rv = board_tree_connect(&tree_driver); 583 } else { 584 /* No connections, nothing to set up */ 585 rv = BCM_E_NONE; 586 } 587 588 return rv; 589 }