multicast.c (23240B)
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: multicast.c 8 * Purpose: Trident2Plus multicast functions 9 */ 10 11 #include <soc/defs.h> 12 #include <sal/core/libc.h> 13 #include <shared/bsl.h> 14 #if defined(BCM_TRIDENT2PLUS_SUPPORT) && defined(INCLUDE_L3) 15 #include <soc/drv.h> 16 #include <soc/scache_dictionary.h> 17 #include <bcm/error.h> 18 #include <bcm/types.h> 19 #include <bcm_int/esw/trident2plus.h> 20 #define _TD2P_NUM_TRUNKS 1024 21 22 23 #define _TD2P_NUM_AGGID_PER_PIPE(unit) \ 24 (soc_mem_field_length(unit, MMU_REPL_GROUP_INFO0m, PIPE_MEMBER_BMPf)) 25 26 typedef struct _bcm_td2p_aggid_used_bmp_per_pipe_s { 27 SHR_BITDCL* pipe_aggid_bmp; 28 } _bcm_td2p_aggid_used_bmp_per_pipe_t; 29 30 STATIC _bcm_td2p_aggid_used_bmp_per_pipe_t *td2p_aggid_used_bmp[BCM_MAX_NUM_UNITS]; 31 32 typedef struct _bcm_td2p_trunk_aggid_info_s { 33 int agg_id; 34 int ref_cnt; 35 } _bcm_td2p_trunk_aggid_info_t; 36 37 typedef struct _bcm_td2p_trunk_aggid_per_pipe_info_s { 38 _bcm_td2p_trunk_aggid_info_t trunk_aggid_info[_TD2P_NUM_TRUNKS]; 39 } _bcm_td2p_trunk_aggid_per_pipe_info_t; 40 41 typedef struct _bcm_td2p_port_aggid_info_s { 42 int agg_id; 43 int ref_cnt; /* The number of the pair <mc group, nexthop> pointing to it. */ 44 int trunk_id; 45 } _bcm_td2p_port_aggid_info_t; 46 47 STATIC _bcm_td2p_trunk_aggid_per_pipe_info_t *td2p_trunk_aggid[BCM_MAX_NUM_UNITS]; 48 49 STATIC _bcm_td2p_port_aggid_info_t *td2p_port_aggid[BCM_MAX_NUM_UNITS]; 50 51 /* 52 * Function: 53 * bcm_td2p_aggid_info_detach 54 * Purpose: 55 * Free aggregation ID list. 56 * Parameters: 57 * unit - (IN) Unit number. 58 * Returns: 59 * BCM_E_XXX 60 */ 61 int 62 bcm_td2p_aggid_info_detach(int unit) 63 { 64 int num_pipes; 65 int i; 66 SHR_BITDCL *pipe_aggid_bmp; 67 68 num_pipes = NUM_PIPE(unit); 69 70 if (td2p_aggid_used_bmp[unit] != NULL) { 71 for (i = 0; i < num_pipes; i++) { 72 pipe_aggid_bmp = td2p_aggid_used_bmp[unit][i].pipe_aggid_bmp; 73 if (pipe_aggid_bmp != NULL) { 74 sal_free(pipe_aggid_bmp); 75 pipe_aggid_bmp = NULL; 76 } 77 } 78 sal_free(td2p_aggid_used_bmp[unit]); 79 td2p_aggid_used_bmp[unit] = NULL; 80 } 81 82 if (td2p_trunk_aggid[unit] != NULL) { 83 sal_free(td2p_trunk_aggid[unit]); 84 td2p_trunk_aggid[unit] = NULL; 85 } 86 87 if (td2p_port_aggid[unit] != NULL) { 88 sal_free(td2p_port_aggid[unit]); 89 td2p_port_aggid[unit] = NULL; 90 } 91 92 return BCM_E_NONE; 93 } 94 95 /* 96 * Function: 97 * bcm_td2p_aggid_info_init 98 * Purpose: 99 * Initialize aggregation ID to trunk map array. 100 * Parameters: 101 * unit - (IN) Unit number. 102 * Returns: 103 * BCM_E_XXX 104 */ 105 int 106 bcm_td2p_aggid_info_init(int unit) 107 { 108 int num_pipes; 109 int i, j; 110 _bcm_td2p_trunk_aggid_info_t *trunk_aggid_info; 111 _bcm_td2p_port_aggid_info_t *port_aggid_info; 112 113 114 if (!SOC_UNIT_VALID(unit)) { 115 return BCM_E_UNIT; 116 } 117 118 num_pipes = NUM_PIPE(unit); 119 120 bcm_td2p_aggid_info_detach(unit); 121 122 123 td2p_aggid_used_bmp[unit] = 124 sal_alloc((num_pipes * sizeof(_bcm_td2p_aggid_used_bmp_per_pipe_t)), 125 "aggid_used_bmp_info"); 126 if (td2p_aggid_used_bmp[unit] == NULL) { 127 return BCM_E_MEMORY; 128 } 129 for (i = 0; i < num_pipes; i++) { 130 td2p_aggid_used_bmp[unit][i].pipe_aggid_bmp = 131 sal_alloc(SHR_BITALLOCSIZE(_TD2P_NUM_AGGID_PER_PIPE(unit)), 132 "aggid_used_bmp_per_piep_info"); 133 if (td2p_aggid_used_bmp[unit][i].pipe_aggid_bmp == NULL) { 134 bcm_td2p_aggid_info_detach(unit); 135 return BCM_E_MEMORY; 136 } 137 sal_memset(td2p_aggid_used_bmp[unit][i].pipe_aggid_bmp, 0, 138 SHR_BITALLOCSIZE(_TD2P_NUM_AGGID_PER_PIPE(unit))); 139 } 140 141 /* Init trunk aggid info. */ 142 td2p_trunk_aggid[unit] = 143 sal_alloc((num_pipes * sizeof(_bcm_td2p_trunk_aggid_per_pipe_info_t)), 144 "trunk_aggid_info"); 145 if (td2p_trunk_aggid[unit] == NULL) { 146 bcm_td2p_aggid_info_detach(unit); 147 return BCM_E_MEMORY; 148 } 149 for (i = 0; i < num_pipes; i++) { 150 for (j = 0; j < _TD2P_NUM_TRUNKS; j++) { 151 trunk_aggid_info = &(td2p_trunk_aggid[unit][i].trunk_aggid_info[j]); 152 trunk_aggid_info->agg_id = TD2P_AGG_ID_INVALID; 153 trunk_aggid_info->ref_cnt = 0; 154 } 155 } 156 157 /* Init port aggid info. */ 158 td2p_port_aggid[unit] = 159 sal_alloc((SOC_MAX_NUM_PORTS * sizeof(_bcm_td2p_port_aggid_info_t)), 160 "port_aggid_info"); 161 if (td2p_port_aggid[unit] == NULL) { 162 bcm_td2p_aggid_info_detach(unit); 163 return BCM_E_MEMORY; 164 } 165 for (i = 0; i < SOC_MAX_NUM_PORTS; i++) { 166 port_aggid_info = &td2p_port_aggid[unit][i]; 167 port_aggid_info->agg_id = TD2P_AGG_ID_INVALID; 168 port_aggid_info->ref_cnt = 0; 169 port_aggid_info->trunk_id = BCM_TRUNK_INVALID; 170 } 171 172 return BCM_E_NONE; 173 } 174 175 /* 176 * Function: 177 * bcm_td2p_get_free_aggid 178 * Purpose: 179 * Get a free aggid for given pipe. 180 * Parameters: 181 * unit - (IN) Unit number. 182 * pipe - (IN) Pipe id. 183 * aggid - (OUT) Returned aggid. 184 * Returns: 185 * BCM_E_XXX 186 */ 187 STATIC int 188 bcm_td2p_get_free_aggid(int unit, int pipe, int *aggid) 189 { 190 SHR_BITDCL *aggid_bmp; 191 int i; 192 193 aggid_bmp = td2p_aggid_used_bmp[unit][pipe].pipe_aggid_bmp; 194 for (i = 0; i < _TD2P_NUM_AGGID_PER_PIPE(unit); i++) { 195 if (!SHR_BITGET(aggid_bmp, i)) { 196 *aggid = i; 197 SHR_BITSET(aggid_bmp, i); 198 return BCM_E_NONE; 199 } 200 } 201 202 if (i == _TD2P_NUM_AGGID_PER_PIPE(unit)) { 203 return BCM_E_FULL; 204 } 205 206 return BCM_E_NONE; 207 208 } 209 210 /* 211 * Function: 212 * bcm_td2p_set_free_aggid 213 * Purpose: 214 * Free aggid for given pipe. 215 * Parameters: 216 * unit - (IN) Unit number. 217 * pipe - (IN) Pipe id. 218 * aggid - (IN) Aggregation ID. 219 * Returns: 220 * BCM_E_XXX 221 */ 222 STATIC int 223 bcm_td2p_set_free_aggid(int unit, int pipe, int aggid) 224 { 225 SHR_BITDCL *aggid_bmp; 226 227 aggid_bmp = td2p_aggid_used_bmp[unit][pipe].pipe_aggid_bmp; 228 if (aggid >= _TD2P_NUM_AGGID_PER_PIPE(unit)) { 229 return BCM_E_PARAM; 230 } 231 SHR_BITCLR(aggid_bmp, aggid); 232 233 return BCM_E_NONE; 234 } 235 236 /* 237 * Function: 238 * bcm_td2p_set_port_hw_agg_map 239 * Purpose: 240 * Set HW aggid map register for a port. 241 * Since L3MC-Port-Agg-ID is used per egress pipe, the maximum L3MC-Port-Agg-IDs 242 * needs to match the maximum number of ports per pipe, which is 53. 243 * Therefore, only the lower six bits are needed for L3MC-Port-Agg-ID by the hardware. 244 * But for the ENQ stage regregiter used in cut-through mode, 245 * PIPE_NUM field must be programmed because L3MC-Port-Agg-ID is used per chip. 246 * Parameters: 247 * unit - (IN) Unit number. 248 * port - (IN) Logical Port. 249 * aggid - (IN) Aggregation ID. 250 * Returns: 251 * BCM_E_XXX 252 */ 253 int 254 bcm_td2p_set_port_hw_agg_map(int unit, bcm_port_t port, int aggid) 255 { 256 uint32 regval; 257 int pipe_num = SOC_INFO(unit).port_pipe[port]; 258 259 BCM_IF_ERROR_RETURN(READ_MMU_TOQ_REPL_PORT_AGG_MAPr(unit, port, ®val)); 260 soc_reg_field_set(unit, MMU_TOQ_REPL_PORT_AGG_MAPr, ®val, 261 L3MC_PORT_AGG_IDf, aggid); 262 SOC_IF_ERROR_RETURN( 263 soc_reg32_set(unit, MMU_TOQ_REPL_PORT_AGG_MAPr, port, 0, regval)); 264 265 soc_reg_field_set(unit, MMU_ENQ_REPL_PORT_AGG_MAPr, ®val, 266 L3MC_PORT_AGG_IDf, aggid); 267 soc_reg_field_set(unit, MMU_ENQ_REPL_PORT_AGG_MAPr, ®val, 268 PIPE_NUMf, pipe_num); 269 SOC_IF_ERROR_RETURN( 270 soc_reg32_set(unit, MMU_ENQ_REPL_PORT_AGG_MAPr, port, 0, regval)); 271 272 soc_reg_field_set(unit, MMU_ENQ_LOGICAL_PORT_TO_PORT_AGG_MAPr, ®val, 273 L3MC_PORT_AGG_IDf, aggid); 274 soc_reg_field_set(unit, MMU_ENQ_REPL_PORT_AGG_MAPr, ®val, 275 PIPE_NUMf, pipe_num); 276 SOC_IF_ERROR_RETURN(WRITE_MMU_ENQ_LOGICAL_PORT_TO_PORT_AGG_MAPr(unit, 277 port, regval)); 278 279 return BCM_E_NONE; 280 } 281 282 /* 283 * Function: 284 * bcm_td2p_aggid_add 285 * Purpose: 286 * Increase aggid refcnt of a independ port or trunk. 287 * Parameters: 288 * unit - (IN) Unit number. 289 * port - (IN) Logical Port. 290 * tgid - (IN) Trunk id. 291 * aggid - (OUT) Returned aggid. 292 * Returns: 293 * BCM_E_XXX 294 */ 295 STATIC int 296 bcm_td2p_aggid_add(int unit, bcm_port_t port, bcm_trunk_t tgid, int *aggid) 297 { 298 int rv = BCM_E_NONE; 299 int pipe; 300 _bcm_td2p_trunk_aggid_info_t *trunk_aggid_info; 301 _bcm_td2p_port_aggid_info_t *port_aggid_info; 302 303 if (((tgid != BCM_TRUNK_INVALID) && (tgid < 0 || tgid >= _TD2P_NUM_TRUNKS)) || 304 (port < 0 || port >= SOC_MAX_NUM_PORTS) || 305 (aggid == NULL)) { 306 return BCM_E_PARAM; 307 } 308 309 pipe = SOC_INFO(unit).port_pipe[port]; 310 if (tgid != BCM_TRUNK_INVALID) { 311 trunk_aggid_info = &(td2p_trunk_aggid[unit][pipe].trunk_aggid_info[tgid]); 312 if (trunk_aggid_info->agg_id == TD2P_AGG_ID_INVALID) { 313 BCM_IF_ERROR_RETURN(bcm_td2p_get_free_aggid(unit, pipe, aggid)); 314 trunk_aggid_info->agg_id = *aggid; 315 trunk_aggid_info->ref_cnt = 1; 316 } else { 317 *aggid = trunk_aggid_info->agg_id; 318 trunk_aggid_info->ref_cnt++; 319 } 320 } else { 321 port_aggid_info = &(td2p_port_aggid[unit][port]); 322 if (port_aggid_info->agg_id == TD2P_AGG_ID_INVALID) { 323 BCM_IF_ERROR_RETURN(bcm_td2p_get_free_aggid(unit, pipe, aggid)); 324 rv = bcm_td2p_set_port_hw_agg_map(unit, port, *aggid); 325 if (BCM_FAILURE(rv)) { 326 bcm_td2p_set_free_aggid(unit, pipe, *aggid); 327 return rv; 328 } 329 port_aggid_info->agg_id = *aggid; 330 port_aggid_info->ref_cnt = 1; 331 port_aggid_info->trunk_id = BCM_TRUNK_INVALID; 332 } else { 333 *aggid = port_aggid_info->agg_id; 334 port_aggid_info->ref_cnt++; 335 } 336 } 337 338 return BCM_E_NONE; 339 } 340 341 /* 342 * Function: 343 * bcm_td2p_aggid_del 344 * Purpose: 345 * Decrease aggid refcnt of a independ port or trunk. 346 * Parameters: 347 * unit - (IN) Unit number. 348 * port - (IN) Logical Port. 349 * Returns: 350 * BCM_E_XXX 351 */ 352 STATIC int 353 bcm_td2p_aggid_del(int unit, bcm_port_t port) 354 { 355 int pipe; 356 bcm_trunk_t tgid; 357 int rv; 358 _bcm_td2p_trunk_aggid_info_t *trunk_aggid_info; 359 _bcm_td2p_port_aggid_info_t *port_aggid_info; 360 361 if ((port < 0) || (port >= SOC_MAX_NUM_PORTS)) { 362 return BCM_E_PARAM; 363 } 364 port_aggid_info = &(td2p_port_aggid[unit][port]); 365 tgid = port_aggid_info->trunk_id; 366 pipe = SOC_INFO(unit).port_pipe[port]; 367 if (tgid != BCM_TRUNK_INVALID) { 368 trunk_aggid_info = &(td2p_trunk_aggid[unit][pipe].trunk_aggid_info[tgid]); 369 if (trunk_aggid_info->ref_cnt <= 0) { 370 return BCM_E_PARAM; 371 } 372 trunk_aggid_info->ref_cnt--; 373 if (trunk_aggid_info->ref_cnt == 0) { 374 bcm_td2p_set_free_aggid(unit, pipe, trunk_aggid_info->agg_id); 375 trunk_aggid_info->agg_id = TD2P_AGG_ID_INVALID; 376 } 377 if (port_aggid_info->ref_cnt == 0) { 378 port_aggid_info->trunk_id = BCM_TRUNK_INVALID; 379 } 380 } else { 381 if (port_aggid_info->ref_cnt <= 0) { 382 return BCM_E_PARAM; 383 } 384 port_aggid_info->ref_cnt--; 385 if (port_aggid_info->ref_cnt == 0) { 386 rv = bcm_td2p_set_port_hw_agg_map(unit, port, TD2P_AGG_ID_HW_INVALID); 387 if (BCM_FAILURE(rv)) { 388 port_aggid_info->ref_cnt++; 389 return rv; 390 } 391 bcm_td2p_set_free_aggid(unit, pipe, port_aggid_info->agg_id); 392 port_aggid_info->agg_id = TD2P_AGG_ID_INVALID; 393 } 394 } 395 396 return BCM_E_NONE; 397 } 398 399 400 /* 401 * Function: 402 * bcm_td2p_aggid_ref_inc_for_member 403 * Purpose: 404 * Increase aggid refcount for a trunk member port. 405 * Parameters: 406 * unit - (IN) Unit number. 407 * port - (IN) Logical Port. 408 * tgid - (IN) Trunk id. 409 * Returns: 410 * BCM_E_XXX 411 */ 412 STATIC int 413 bcm_td2p_aggid_ref_inc_for_member(int unit, bcm_port_t port, bcm_trunk_t tgid) 414 { 415 int aggid, pipe; 416 _bcm_td2p_port_aggid_info_t *port_aggid_info; 417 418 if (port < 0 || port >= SOC_MAX_NUM_PORTS) { 419 return BCM_E_PARAM; 420 } 421 422 port_aggid_info = &(td2p_port_aggid[unit][port]); 423 if (port_aggid_info->agg_id != TD2P_AGG_ID_INVALID) { 424 return BCM_E_PARAM; 425 } 426 427 if (port_aggid_info->trunk_id == BCM_TRUNK_INVALID) { 428 /* This is the first time that member port joined trunk tgid. 429 * For member port, it just uses trunk's agg_id not itself. 430 */ 431 if (port_aggid_info->ref_cnt != 0) { 432 return BCM_E_PARAM; 433 } 434 port_aggid_info->trunk_id = tgid; 435 port_aggid_info->ref_cnt = 1; 436 pipe = SOC_INFO(unit).port_pipe[port]; 437 aggid = td2p_trunk_aggid[unit][pipe].trunk_aggid_info[tgid].agg_id; 438 BCM_IF_ERROR_RETURN(bcm_td2p_set_port_hw_agg_map(unit, port, aggid)); 439 } else { 440 /* member port has joined one trunk. */ 441 if (port_aggid_info->trunk_id != tgid) { 442 return BCM_E_PARAM; 443 } 444 port_aggid_info->ref_cnt++; 445 } 446 447 return BCM_E_NONE; 448 } 449 450 /* 451 * Function: 452 * bcm_td2p_aggid_ref_dec_for_member 453 * Purpose: 454 * Decrease aggid refcount for a trunk member port. 455 * Parameters: 456 * unit - (IN) Unit number. 457 * port - (IN) Logical Port. 458 * Returns: 459 * BCM_E_XXX 460 */ 461 STATIC int 462 bcm_td2p_aggid_ref_dec_for_member(int unit, bcm_port_t port) 463 { 464 _bcm_td2p_port_aggid_info_t *port_aggid_info; 465 int rv; 466 467 if (port < 0 || port >= SOC_MAX_NUM_PORTS) { 468 return BCM_E_PARAM; 469 } 470 471 port_aggid_info = &(td2p_port_aggid[unit][port]); 472 if (port_aggid_info->trunk_id == BCM_TRUNK_INVALID) { 473 return BCM_E_PARAM; 474 } 475 476 if (port_aggid_info->ref_cnt <= 0) { 477 return BCM_E_PARAM; 478 } 479 480 port_aggid_info->ref_cnt--; 481 if (port_aggid_info->ref_cnt == 0) { 482 /* All (port, mc group) has can leave the trunk. 483 * Do not set port_aggid_info->trunk_id to BCM_TRUNK_INVALID here. 484 */ 485 rv = bcm_td2p_set_port_hw_agg_map(unit, port, TD2P_AGG_ID_HW_INVALID); 486 if (BCM_FAILURE(rv)) { 487 port_aggid_info->ref_cnt++; 488 return rv; 489 } 490 } 491 492 return BCM_E_NONE; 493 } 494 495 /* 496 * Function: 497 * bcm_td2p_port_aggid_add 498 * Purpose: 499 * Add a aggid for a logical port. 500 * If there is no aggid allocated for the logical port, a new aggid 501 * will be allocated for it. Otherwise, the reference count will be 502 * incremented. 503 * Parameters: 504 * unit - (IN) Unit number. 505 * port - (IN) Logical Port. 506 * tgid - (IN) Trunk id. 507 * aggid - (OUT) Aggid returned. 508 * Returns: 509 * BCM_E_XXX 510 */ 511 int 512 bcm_td2p_port_aggid_add(int unit, bcm_port_t port, bcm_trunk_t tgid, int *aggid) 513 { 514 int rv; 515 516 if (tgid != BCM_TRUNK_INVALID) { 517 rv = bcm_td2p_aggid_add(unit, port, tgid, aggid); 518 if (BCM_FAILURE(rv)) { 519 return rv; 520 } 521 rv = bcm_td2p_aggid_ref_inc_for_member(unit, port, tgid); 522 if (BCM_FAILURE(rv)) { 523 bcm_td2p_aggid_del(unit, port); 524 return rv; 525 } 526 } else { 527 rv = bcm_td2p_aggid_add(unit, port, tgid, aggid); 528 if (BCM_FAILURE(rv)) { 529 return rv; 530 } 531 } 532 533 return BCM_E_NONE; 534 } 535 536 /* 537 * Function: 538 * bcm_td2p_port_aggid_del 539 * Purpose: 540 * Del aggid of a logical port. 541 * If there is the reference count is greater than 1, the reference count 542 * will be decreased. Otherwise, the aggid will be freed. 543 * Parameters: 544 * unit - (IN) Unit number. 545 * port - (IN) Logical Port. 546 * Returns: 547 * BCM_E_XXX 548 */ 549 int 550 bcm_td2p_port_aggid_del(int unit, bcm_port_t port) 551 { 552 _bcm_td2p_port_aggid_info_t *port_aggid_info; 553 bcm_trunk_t tgid; 554 int rv; 555 556 if (port < 0 || port >= SOC_MAX_NUM_PORTS) { 557 return BCM_E_PARAM; 558 } 559 560 port_aggid_info = &(td2p_port_aggid[unit][port]); 561 tgid = port_aggid_info->trunk_id; 562 563 if (tgid != BCM_TRUNK_INVALID) { 564 rv = bcm_td2p_aggid_ref_dec_for_member(unit, port); 565 if (BCM_FAILURE(rv)) { 566 return rv; 567 } 568 rv = bcm_td2p_aggid_del(unit, port); 569 if (BCM_FAILURE(rv)) { 570 bcm_td2p_aggid_ref_inc_for_member(unit, port, tgid); 571 return rv; 572 } 573 } else { 574 rv = bcm_td2p_aggid_del(unit, port); 575 if (BCM_FAILURE(rv)) { 576 return rv; 577 } 578 } 579 580 return BCM_E_NONE; 581 } 582 583 /* 584 * Function: 585 * bcm_td2p_port_trunkid_get 586 * Purpose: 587 * When port has been removed from trunk in trunk module, 588 * we could only get trunkid of port from previous saved DB. 589 * Parameters: 590 * unit - (IN) Unit number. 591 * port - (IN) Logical Port 592 * tgid - (OUT) returned Trunk id. 593 * Returns: 594 * BCM_E_XXX 595 * Note: This function only can be used when deleting port from trunk. 596 */ 597 int 598 bcm_td2p_port_trunkid_get(int unit, bcm_port_t port, int *tgid) 599 { 600 _bcm_td2p_port_aggid_info_t *port_aggid_info; 601 602 if ((port < 0 || port >= SOC_MAX_NUM_PORTS) || 603 (tgid == NULL)) { 604 return BCM_E_PARAM; 605 } 606 607 port_aggid_info = &(td2p_port_aggid[unit][port]); 608 *tgid = port_aggid_info->trunk_id; 609 610 return BCM_E_NONE; 611 } 612 613 /* 614 * Function: 615 * bcm_td2p_port_last_member_check 616 * Purpose: 617 * Check whether a member port is the last member of its trunk. 618 * Parameters: 619 * unit - (IN) Unit number. 620 * port - (IN) Logical Port 621 * val - (OUT) returned val. 622 * Returns: 623 * BCM_E_XXX 624 */ 625 int 626 bcm_td2p_port_last_member_check(int unit, bcm_port_t port, int *val) 627 { 628 int pipe; 629 bcm_trunk_t tgid; 630 _bcm_td2p_port_aggid_info_t *port_aggid_info; 631 int i; 632 int member_cnt = 0; 633 634 if (port < 0 || port >= SOC_MAX_NUM_PORTS) { 635 return BCM_E_PARAM; 636 } 637 638 pipe = SOC_INFO(unit).port_pipe[port]; 639 port_aggid_info = &(td2p_port_aggid[unit][port]); 640 tgid = port_aggid_info->trunk_id; 641 if (tgid == BCM_TRUNK_INVALID) { 642 return BCM_E_PARAM; 643 } 644 645 for (i = 0; i < SOC_MAX_NUM_PORTS; i++) { 646 if (member_cnt > 1) { 647 *val = FALSE; 648 return BCM_E_NONE; 649 } 650 port_aggid_info = &(td2p_port_aggid[unit][i]); 651 if ((port_aggid_info->trunk_id == tgid) && 652 (SOC_INFO(unit).port_pipe[i] == pipe)) { 653 member_cnt++; 654 } 655 } 656 657 if (member_cnt > 1) { 658 *val = FALSE; 659 } else { 660 *val = TRUE; 661 } 662 663 return BCM_E_NONE; 664 } 665 666 /* 667 * Function: 668 * bcm_td2p_port_to_aggid 669 * Purpose: 670 * Get aggid value for a logical port. 671 * Parameters: 672 * unit - (IN) Unit number. 673 * aggid - (OUT) Returned aggid. 674 * Returns: 675 * BCM_E_XXX 676 */ 677 int 678 bcm_td2p_port_to_aggid(int unit, bcm_port_t port, int *aggid) 679 { 680 int pipe; 681 bcm_trunk_t tgid; 682 _bcm_td2p_port_aggid_info_t *port_aggid_info; 683 _bcm_td2p_trunk_aggid_info_t *trunk_aggid_info; 684 685 if (port < 0 || port >= SOC_MAX_NUM_PORTS) { 686 return BCM_E_PARAM; 687 } 688 689 pipe = SOC_INFO(unit).port_pipe[port]; 690 port_aggid_info = &(td2p_port_aggid[unit][port]); 691 tgid = port_aggid_info->trunk_id; 692 if (tgid == BCM_TRUNK_INVALID) { 693 *aggid = port_aggid_info->agg_id; 694 } else { 695 trunk_aggid_info = &(td2p_trunk_aggid[unit][pipe].trunk_aggid_info[tgid]); 696 *aggid = trunk_aggid_info->agg_id; 697 } 698 if (*aggid == TD2P_AGG_ID_INVALID) { 699 return BCM_E_INTERNAL; 700 } 701 702 return BCM_E_NONE; 703 } 704 705 706 #ifdef BCM_WARM_BOOT_SUPPORT 707 /* 708 * Function: 709 * bcm_td2p_ipmc_aggid_info_scache_size_get 710 * Purpose: 711 * Get the required scache size for storing aggid info. 712 * Parameters: 713 * unit - (IN) StrataSwitch unit # 714 * size - (OUT) Number of bytes 715 * Returns: 716 * BCM_E_xxx 717 */ 718 int 719 bcm_td2p_ipmc_aggid_info_scache_size_get( 720 int unit, uint32 *size) 721 { 722 int num_pipes; 723 int aggid_used_bmp_size, trunk_aggid_size, port_aggid_size; 724 725 *size = 0; 726 727 num_pipes = NUM_PIPE(unit); 728 729 aggid_used_bmp_size = 730 num_pipes * SHR_BITALLOCSIZE(_TD2P_NUM_AGGID_PER_PIPE(unit)); 731 *size += aggid_used_bmp_size; 732 733 trunk_aggid_size = 734 num_pipes * sizeof(_bcm_td2p_trunk_aggid_per_pipe_info_t); 735 *size += trunk_aggid_size; 736 737 port_aggid_size = SOC_MAX_NUM_PORTS * sizeof(_bcm_td2p_port_aggid_info_t); 738 *size += port_aggid_size; 739 740 return BCM_E_NONE; 741 } 742 743 /* 744 * Function: 745 * bcm_td2p_ipmc_aggid_info_sync 746 * Purpose: 747 * Sync aggid info to scache. 748 * Parameters: 749 * unit - (IN) StrataSwitch unit # 750 * scache_ptr - (IN/OUT) Scache pointer 751 * Returns: 752 * BCM_E_xxx 753 */ 754 int bcm_td2p_ipmc_aggid_info_sync(int unit, uint8 **scache_ptr) 755 { 756 int num_pipes; 757 int aggid_used_bmp_size, trunk_aggid_size, port_aggid_size; 758 int i; 759 760 num_pipes = NUM_PIPE(unit); 761 762 aggid_used_bmp_size = SHR_BITALLOCSIZE(_TD2P_NUM_AGGID_PER_PIPE(unit)); 763 for (i = 0; i < num_pipes; i++) { 764 sal_memcpy((*scache_ptr), td2p_aggid_used_bmp[unit][i].pipe_aggid_bmp, 765 aggid_used_bmp_size); 766 (*scache_ptr) += aggid_used_bmp_size; 767 } 768 769 trunk_aggid_size = sizeof(_bcm_td2p_trunk_aggid_per_pipe_info_t); 770 for (i = 0; i < num_pipes; i++) { 771 sal_memcpy((*scache_ptr), td2p_trunk_aggid[unit] + i, trunk_aggid_size); 772 (*scache_ptr) += trunk_aggid_size; 773 } 774 775 port_aggid_size = SOC_MAX_NUM_PORTS * sizeof(_bcm_td2p_port_aggid_info_t); 776 sal_memcpy((*scache_ptr), td2p_port_aggid[unit], port_aggid_size); 777 (*scache_ptr) += port_aggid_size; 778 779 return BCM_E_NONE; 780 } 781 782 783 /* 784 * Function: 785 * bcm_td2p_ipmc_aggid_info_recover 786 * Purpose: 787 * Recover aggid info from scache. 788 * Parameters: 789 * unit - (IN) StrataSwitch unit # 790 * scache_ptr - (IN/OUT) Scache pointer 791 * Returns: 792 * BCM_E_xxx 793 */ 794 int 795 bcm_td2p_ipmc_aggid_info_recover(int unit, uint8 **scache_ptr) 796 { 797 int num_pipes; 798 int aggid_used_bmp_size, trunk_aggid_size, port_aggid_size; 799 int i; 800 int max_num_ports, scache_sz; 801 802 max_num_ports = soc_scache_dictionary_entry_get(unit, 803 ssden_SOC_MAX_NUM_PORTS, 804 SOC_MAX_NUM_PORTS); 805 num_pipes = NUM_PIPE(unit); 806 807 aggid_used_bmp_size = SHR_BITALLOCSIZE(_TD2P_NUM_AGGID_PER_PIPE(unit)); 808 for (i = 0; i < num_pipes; i++) { 809 sal_memcpy(td2p_aggid_used_bmp[unit][i].pipe_aggid_bmp, 810 (*scache_ptr), aggid_used_bmp_size); 811 (*scache_ptr) += aggid_used_bmp_size; 812 } 813 814 trunk_aggid_size = sizeof(_bcm_td2p_trunk_aggid_per_pipe_info_t); 815 for (i = 0; i < num_pipes; i++) { 816 sal_memcpy(td2p_trunk_aggid[unit] + i, (*scache_ptr), trunk_aggid_size); 817 (*scache_ptr) += trunk_aggid_size; 818 } 819 820 port_aggid_size = SOC_MAX_NUM_PORTS * sizeof(_bcm_td2p_port_aggid_info_t); 821 scache_sz = max_num_ports * sizeof(_bcm_td2p_port_aggid_info_t); 822 823 SOC_SCACHE_SIZE_MIN_RECOVER(*scache_ptr, td2p_port_aggid[unit], 824 scache_sz, port_aggid_size); 825 826 return BCM_E_NONE; 827 } 828 829 #endif /* BCM_WARM_BOOT_SUPPORT */ 830 831 #endif 832