mcast.c (45087B)
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: mcast.c 8 * Purpose: Tracks and manages L2 Multicast tables. 9 */ 10 11 #include <shared/bsl.h> 12 #include <soc/drv.h> 13 #include <soc/mem.h> 14 #include <soc/l2x.h> 15 #if defined(BCM_BRADLEY_SUPPORT) 16 #include <soc/bradley.h> 17 #endif /* BCM_BRADLEY_SUPPORT */ 18 19 #include <bcm/error.h> 20 #include <bcm/l2.h> 21 22 #include <bcm_int/esw/firebolt.h> 23 #include <bcm_int/esw_dispatch.h> 24 #include <bcm_int/esw/triumph3.h> 25 #if defined(BCM_TRIDENT3_SUPPORT) 26 #include <bcm_int/esw/trident3.h> 27 #endif 28 #include <bcm_int/common/multicast.h> 29 30 typedef struct { 31 int size; 32 int *used; 33 soc_mem_t l2mem; 34 soc_mem_t mcmem; 35 } _bcm_xgs3_mcast_t; 36 37 static _bcm_xgs3_mcast_t xgs3_l2mc_info[BCM_MAX_NUM_UNITS]; 38 39 #define L2MC_INFO(unit) (&xgs3_l2mc_info[unit]) 40 #define L2MC_SIZE(unit) L2MC_INFO(unit)->size 41 #define L2MC_USED(unit) L2MC_INFO(unit)->used 42 #define L2MC_L2MEM(unit) L2MC_INFO(unit)->l2mem 43 #define L2MC_MCMEM(unit) L2MC_INFO(unit)->mcmem 44 #define L2MC_USED_SET(unit, n) L2MC_USED(unit)[n] += 1 45 #define L2MC_USED_CLR(unit, n) L2MC_USED(unit)[n] -= 1 46 #define L2MC_USED_ISSET(unit, n) (L2MC_USED(unit)[n] > 0) 47 48 #define L2MC_INIT(unit) \ 49 if (L2MC_USED(unit) == NULL) { return BCM_E_INIT; } 50 #define L2MC_ID(unit, id) \ 51 if (id < 0 || id >= L2MC_SIZE(unit)) { return BCM_E_PARAM; } 52 53 #define L2MC_LOCK(unit) do { \ 54 soc_mem_lock(unit, L2MC_MCMEM(unit)); \ 55 } while(0) 56 #define L2MC_UNLOCK(unit) do { \ 57 soc_mem_unlock(unit, L2MC_MCMEM(unit)); \ 58 } while(0) 59 #define L2MC_ID_GET(l2mc_index) \ 60 (_BCM_MULTICAST_IS_SET(l2mc_index) && \ 61 _BCM_MULTICAST_IS_L2(l2mc_index)) ? \ 62 _BCM_MULTICAST_ID_GET(l2mc_index) : l2mc_index 63 64 /* 65 * Function: 66 * _bcm_xgs3_l2_addr_delete_mcast 67 * Description 68 * Delete L2 multicast entries 69 * Parameters: 70 * unit - device unit 71 * flags - BCM_L2_DELETE_XXX 72 * Returns: 73 * BCM_E_XXX 74 */ 75 int 76 _bcm_xgs3_l2_addr_delete_mcast(int unit, uint32 flags) 77 { 78 l2x_entry_t *l2xe, *l2xep; 79 int rv, chunksize, chunk, chunk_max, i; 80 int dyn_only, chnk_end, mem_idx_max; 81 bcm_mac_t mac; 82 uint32 field_valid = INVALIDf; 83 84 chunksize = soc_property_get(unit, spn_L2DELETE_CHUNKS, 85 L2_MEM_CHUNKS_DEFAULT); 86 87 l2xe = soc_cm_salloc(unit, chunksize * sizeof(*l2xe), "l2del_chunk"); 88 if (l2xe == NULL) { 89 return BCM_E_MEMORY; 90 } 91 92 rv = BCM_E_NONE; 93 94 dyn_only = !(flags & BCM_L2_DELETE_STATIC); 95 96 mem_idx_max = soc_mem_index_max(unit, L2Xm); 97 for (chunk = soc_mem_index_min(unit, L2Xm); chunk <= mem_idx_max; 98 chunk += chunksize) { 99 100 chunk_max = chunk + chunksize - 1; 101 if (chunk_max > mem_idx_max) { 102 chunk_max = mem_idx_max; 103 } 104 105 rv = soc_mem_read_range(unit, L2Xm, MEM_BLOCK_ANY, 106 chunk, chunk_max, l2xe); 107 if (rv < 0) { 108 break; 109 } 110 chnk_end = (chunk_max - chunk); 111 for (i = 0; i <= chnk_end; i++) { 112 113 l2xep = soc_mem_table_idx_to_pointer(unit, L2Xm, 114 l2x_entry_t *, l2xe, i); 115 116 117 field_valid = VALIDf; 118 if (soc_feature(unit, soc_feature_base_valid)) { 119 field_valid = BASE_VALIDf; 120 } 121 if(!soc_L2Xm_field32_get(unit, l2xep, field_valid)) { 122 continue; 123 } 124 125 soc_L2Xm_mac_addr_get(unit, l2xep, MAC_ADDRf, mac); 126 if (!BCM_MAC_IS_MCAST(mac)) { 127 continue; 128 } 129 130 if (dyn_only && 131 soc_L2Xm_field32_get(unit, l2xep, STATIC_BITf)) { 132 continue; 133 } 134 rv = soc_mem_delete(unit, L2Xm, MEM_BLOCK_ALL, l2xep); 135 if (rv < 0) { 136 break; 137 } 138 } 139 140 if (rv < 0) { 141 break; 142 } 143 } 144 145 soc_cm_sfree(unit, l2xe); 146 147 return rv; 148 } 149 150 /* 151 * Function: 152 * _bcm_xgs3_l2mc_size_get 153 * Description: 154 * Get number of L2MC groups. 155 */ 156 157 int 158 _bcm_xgs3_l2mc_size_get(int unit, int *size) 159 { 160 *size = L2MC_SIZE(unit); 161 return BCM_E_NONE; 162 } 163 164 /* 165 * Function: 166 * _bcm_xgs3_l2mc_index_is_set 167 * Description: 168 * Check whether and l2mc index is used. 169 */ 170 171 int 172 _bcm_xgs3_l2mc_index_is_set(int unit, int l2mc_id, int *is_set) 173 { 174 L2MC_ID(unit, l2mc_id); 175 176 *is_set = (0 != L2MC_USED_ISSET(unit, l2mc_id)); 177 178 return BCM_E_NONE; 179 } 180 181 /* 182 * Function: 183 * _bcm_xgs3_l2mc_free_index 184 * Description: 185 * Find an unused l2mc index and mark it used. 186 */ 187 188 int 189 _bcm_xgs3_l2mc_free_index(int unit, int *l2mc_id) 190 { 191 int i, rv; 192 193 rv = BCM_E_FULL; 194 for (i = 1; i < L2MC_SIZE(unit); i++) { 195 if (!L2MC_USED_ISSET(unit, i)) { 196 L2MC_USED_SET(unit, i); 197 *l2mc_id = i; 198 rv = BCM_E_NONE; 199 break; 200 } 201 } 202 203 return rv; 204 } 205 206 /* 207 * Function: 208 * _bcm_xgs3_l2mc_id_alloc 209 * Description: 210 * allocate the given l2mc entry (increment use count) 211 */ 212 213 int 214 _bcm_xgs3_l2mc_id_alloc(int unit, int l2mc_id) 215 { 216 L2MC_ID(unit, l2mc_id); 217 218 L2MC_USED_SET(unit, l2mc_id); 219 220 return BCM_E_NONE; 221 } 222 223 /* 224 * Function: 225 * _bcm_xgs3_l2mc_id_free 226 * Description: 227 * Marks an l2mc index as free (decrements use count) 228 */ 229 230 int 231 _bcm_xgs3_l2mc_id_free(int unit, int l2mc_id) 232 { 233 L2MC_ID(unit, l2mc_id); 234 235 L2MC_USED_CLR(unit, l2mc_id); 236 237 return BCM_E_NONE; 238 } 239 240 /* 241 * Function: 242 * _bcm_xgs3_mcast_from_l2 243 * Description: 244 * Fill in fields of bcm_mcast_addr_t from bcm_l2_addr_t 245 * Parameters: 246 * unit - (IN) device 247 * mcaddr - (OUT) mcast addr struct 248 * l2addr - (IN) l2 addr struct 249 */ 250 251 STATIC void 252 _bcm_xgs3_mcast_from_l2(int unit, 253 bcm_mcast_addr_t *mcaddr, 254 bcm_l2_addr_t *l2addr) 255 { 256 int rv; 257 vlan_tab_entry_t vte; 258 soc_mem_t vlan_mem; 259 260 sal_memcpy(mcaddr->mac, l2addr->mac, sizeof(bcm_mac_t)); 261 mcaddr->vid = l2addr->vid; 262 mcaddr->cos_dst = l2addr->cos_dst; 263 mcaddr->l2mc_index = l2addr->l2mc_group; 264 265 /* Need to fill in the untagged port bitmap from the VLAN table */ 266 SOC_PBMP_CLEAR(mcaddr->ubmp); 267 vlan_mem = SOC_IS_FBX(unit) ? EGR_VLANm : VLAN_TABm; 268 rv = soc_mem_read(unit, vlan_mem, MEM_BLOCK_ANY, mcaddr->vid, &vte); 269 if (rv < 0) { 270 return; 271 } 272 #if defined (BCM_TRIDENT3_SUPPORT) 273 if (SOC_IS_TRIDENT3X(unit)) { 274 (void)bcm_td3_vlan_table_ut_port_get(unit, mcaddr->vid, &mcaddr->ubmp); 275 } else 276 #endif 277 { 278 soc_mem_pbmp_field_get(unit, vlan_mem, &vte, UT_BITMAPf, &mcaddr->ubmp); 279 } 280 } 281 282 /* 283 * Function: 284 * _bcm_xgs3_mcast_to_l2 285 * Description: 286 * Fill in fields of bcm_l2_addr_t from bcm_mcast_addr_t 287 * Parameters: 288 * unit - (IN) device 289 * l2addr - (OUT) Pointer to bcm_l2_addr_t 290 * mcaddr - (IN) Pointer to bcm_mcast_addr_t 291 */ 292 293 STATIC void 294 _bcm_xgs3_mcast_to_l2(int unit, 295 bcm_l2_addr_t *l2addr, 296 bcm_mcast_addr_t *mcaddr) 297 { 298 bcm_l2_addr_t_init(l2addr, mcaddr->mac, mcaddr->vid); 299 l2addr->flags = BCM_L2_STATIC | BCM_L2_MCAST | BCM_L2_REPLACE_DYNAMIC; 300 l2addr->cos_dst = mcaddr->cos_dst; 301 l2addr->l2mc_group = mcaddr->l2mc_index; 302 303 } 304 305 /* 306 * Function: 307 * _bcm_xgs3_mcast_create 308 * Description: 309 * Create a muticast entry 310 * Parameters: 311 * unit - (IN) device 312 * mcaddr - (IN) Pointer to bcm_mcast_addr_t 313 * mcindex - (IN) mcast index to use (-1 lets routine choose) 314 * Returns: 315 * BCM_E_XXX 316 */ 317 318 STATIC int 319 _bcm_xgs3_mcast_create(int unit, bcm_mcast_addr_t *mcaddr, 320 int mcindex) 321 { 322 l2mc_entry_t l2mc, rl2mc; 323 bcm_l2_addr_t l2addr, rl2addr; 324 bcm_pbmp_t pbm, rpbm; 325 int rv; 326 327 bcm_l2_addr_t_init (&l2addr, mcaddr->mac, mcaddr->vid); 328 rv = bcm_esw_l2_addr_get(unit, mcaddr->mac, mcaddr->vid, &l2addr); 329 if (rv >= 0) { 330 if (!(l2addr.flags & BCM_L2_MCAST)) { 331 return BCM_E_EXISTS; 332 } 333 l2addr.l2mc_group = L2MC_ID_GET(l2addr.l2mc_group); 334 if (mcindex >= 0 && mcindex == l2addr.l2mc_group) { 335 return BCM_E_NONE; 336 } 337 BCM_IF_ERROR_RETURN(_bcm_xgs3_l2mc_id_free(unit, l2addr.l2mc_group)); 338 339 } 340 341 /* Before getting free MC index, make sure this is a valid Port */ 342 rv = soc_mem_field_pbmp_fit(unit, L2MC_MCMEM(unit), PORT_BITMAPf, 343 (uint32 *)&mcaddr->pbmp); 344 if (rv != SOC_E_NONE) { 345 return rv; 346 } 347 348 if (mcindex < 0) { 349 BCM_IF_ERROR_RETURN(_bcm_xgs3_l2mc_free_index(unit, &mcindex)); 350 } else { 351 BCM_IF_ERROR_RETURN(_bcm_xgs3_l2mc_id_alloc(unit, mcindex)); 352 } 353 354 sal_memset(&l2mc, 0, sizeof(l2mc)); 355 soc_mem_field32_set(unit, L2MC_MCMEM(unit), &l2mc, VALIDf, 1); 356 soc_mem_pbmp_field_set(unit, L2MC_MCMEM(unit), &l2mc, PORT_BITMAPf, 357 &mcaddr->pbmp); 358 _bcm_xgs3_mcast_to_l2(unit, &l2addr, mcaddr); 359 l2addr.l2mc_group = mcindex; 360 361 if (SOC_MCAST_ADD_ALL_ROUTER_PORTS(unit)) { 362 sal_memset(&rl2addr, 0, sizeof(bcm_l2_addr_t)); 363 rv = bcm_esw_l2_addr_get(unit, (uint8 *)_soc_mac_all_routers, 364 mcaddr->vid, &rl2addr); 365 if (rv >= 0) { 366 rl2addr.l2mc_group = L2MC_ID_GET(rl2addr.l2mc_group); 367 SOC_IF_ERROR_RETURN 368 (soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY, 369 rl2addr.l2mc_group, &rl2mc)); 370 soc_mem_pbmp_field_get(unit, L2MC_MCMEM(unit), &rl2mc, 371 PORT_BITMAPf, &rpbm); 372 soc_mem_pbmp_field_get(unit, L2MC_MCMEM(unit), &l2mc, PORT_BITMAPf, 373 &pbm); 374 BCM_PBMP_OR(pbm, rpbm); 375 soc_mem_pbmp_field_set(unit, L2MC_MCMEM(unit), &l2mc, PORT_BITMAPf, 376 &pbm); 377 } 378 } 379 380 /* add l2mc entry */ 381 SOC_IF_ERROR_RETURN 382 (soc_mem_write(unit, L2MC_MCMEM(unit), MEM_BLOCK_ALL, mcindex, &l2mc)); 383 384 /* add l2 entry */ 385 rv = bcm_esw_l2_addr_add(unit, &l2addr); 386 if (BCM_FAILURE(rv)) { 387 _bcm_xgs3_l2mc_id_free(unit, l2addr.l2mc_group); 388 if (!L2MC_USED_ISSET(unit, l2addr.l2mc_group)) { 389 soc_mem_write(unit, L2MC_MCMEM(unit), MEM_BLOCK_ALL, 390 l2addr.l2mc_group, 391 soc_mem_entry_null(unit, L2MC_MCMEM(unit))); 392 } 393 } 394 395 return rv; 396 } 397 398 /* 399 * Function: 400 * _bcm_xgs3_mcast_port_add 401 * Purpose: 402 * Add new ports to a multicast entry 403 * Parameters: 404 * unit - device 405 * mcaddr - mcast addr struct with new ports 406 * Returns: 407 * BCM_E_XXX 408 */ 409 410 STATIC int 411 _bcm_xgs3_mcast_port_add(int unit, bcm_mcast_addr_t *mcaddr) 412 { 413 bcm_l2_addr_t l2addr; 414 l2mc_entry_t l2mc_entry; 415 bcm_pbmp_t pbmp; 416 417 bcm_l2_addr_t_init(&l2addr, mcaddr->mac, mcaddr->vid); 418 BCM_IF_ERROR_RETURN 419 (bcm_esw_l2_addr_get(unit, mcaddr->mac, mcaddr->vid, &l2addr)); 420 421 if (!(l2addr.flags & BCM_L2_MCAST)) { 422 return BCM_E_NOT_FOUND; 423 } 424 425 l2addr.l2mc_group = L2MC_ID_GET(l2addr.l2mc_group); 426 427 SOC_IF_ERROR_RETURN 428 (soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY, 429 l2addr.l2mc_group, &l2mc_entry)); 430 431 soc_mem_pbmp_field_get(unit, L2MC_MCMEM(unit), &l2mc_entry, PORT_BITMAPf, 432 &pbmp); 433 BCM_PBMP_OR(pbmp, mcaddr->pbmp); 434 soc_mem_pbmp_field_set(unit, L2MC_MCMEM(unit), &l2mc_entry, PORT_BITMAPf, 435 &pbmp); 436 437 SOC_IF_ERROR_RETURN 438 (soc_mem_write(unit, L2MC_MCMEM(unit), MEM_BLOCK_ALL, 439 l2addr.l2mc_group, &l2mc_entry)); 440 441 return BCM_E_NONE; 442 } 443 444 /* 445 * Function: 446 * _bcm_xgs3_mcast_port_delete 447 * Purpose: 448 * Remove ports from a multicast entry 449 * Parameters: 450 * unit - device 451 * mcaddr - mcast addr struct with ports to delete 452 * Returns: 453 * BCM_E_XXX 454 */ 455 456 STATIC int 457 _bcm_xgs3_mcast_port_delete(int unit, 458 bcm_mcast_addr_t *mcaddr) 459 { 460 bcm_l2_addr_t l2addr; 461 l2mc_entry_t l2mc_entry; 462 bcm_pbmp_t pbmp; 463 464 bcm_l2_addr_t_init (&l2addr, mcaddr->mac, mcaddr->vid); 465 BCM_IF_ERROR_RETURN 466 (bcm_esw_l2_addr_get(unit, mcaddr->mac, mcaddr->vid, &l2addr)); 467 468 if (!(l2addr.flags & BCM_L2_MCAST)) { 469 return BCM_E_NOT_FOUND; 470 } 471 472 l2addr.l2mc_group = L2MC_ID_GET(l2addr.l2mc_group); 473 474 SOC_IF_ERROR_RETURN 475 (soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY, 476 l2addr.l2mc_group, &l2mc_entry)); 477 478 soc_mem_pbmp_field_get(unit, L2MC_MCMEM(unit), &l2mc_entry, PORT_BITMAPf, 479 &pbmp); 480 BCM_PBMP_REMOVE(pbmp, mcaddr->pbmp); 481 soc_mem_pbmp_field_set(unit, L2MC_MCMEM(unit), &l2mc_entry, PORT_BITMAPf, 482 &pbmp); 483 484 SOC_IF_ERROR_RETURN 485 (soc_mem_write(unit, L2MC_MCMEM(unit), MEM_BLOCK_ALL, 486 l2addr.l2mc_group, &l2mc_entry)); 487 488 return BCM_E_NONE; 489 } 490 491 /* 492 * Function: 493 * bcm_xgs3_mcast_port_remove 494 * Purpose: 495 * Remove ports from existing MC entry. 496 * Returns: 497 * BCM_E_XXX 498 */ 499 500 int 501 bcm_xgs3_mcast_port_remove(int unit, bcm_mcast_addr_t *mcaddr) 502 { 503 int rv; 504 505 L2MC_INIT(unit); 506 L2MC_LOCK(unit); 507 rv = _bcm_xgs3_mcast_port_delete(unit, mcaddr); 508 L2MC_UNLOCK(unit); 509 return rv; 510 } 511 512 /* 513 * Function: 514 * bcm_xgs3_mcast_port_add 515 * Purpose: 516 * Add ports to existing MC entry. 517 * Returns: 518 * BCM_E_XXX 519 */ 520 521 int 522 bcm_xgs3_mcast_port_add(int unit, bcm_mcast_addr_t *mcaddr) 523 { 524 int rv; 525 526 L2MC_INIT(unit); 527 L2MC_LOCK(unit); 528 rv = _bcm_xgs3_mcast_port_add(unit, mcaddr); 529 L2MC_UNLOCK(unit); 530 return rv; 531 } 532 533 /* 534 * Function: 535 * bcm_xgs3_mcast_addr_add_w_l2mcindex 536 * Purpose: 537 * Add a new MC entry to the L2 and L2MC tables, with given MC index. 538 * Returns: 539 * BCM_E_XXX 540 */ 541 542 int 543 bcm_xgs3_mcast_addr_add_w_l2mcindex(int unit, bcm_mcast_addr_t *mcaddr) 544 { 545 int rv; 546 547 L2MC_INIT(unit); 548 L2MC_LOCK(unit); 549 rv = _bcm_xgs3_mcast_create(unit, mcaddr, mcaddr->l2mc_index); 550 L2MC_UNLOCK(unit); 551 return rv; 552 } 553 554 /* 555 * Function: 556 * bcm_xgs3_mcast_addr_add 557 * Purpose: 558 * Add new L2 multicast entry 559 * Returns: 560 * BCM_E_XXX 561 */ 562 563 int 564 bcm_xgs3_mcast_addr_add(int unit, bcm_mcast_addr_t *mcaddr) 565 { 566 int rv; 567 568 L2MC_INIT(unit); 569 L2MC_LOCK(unit); 570 /* coverity[negative_returns : FALSE] */ 571 rv = _bcm_xgs3_mcast_create(unit, mcaddr, -1); 572 L2MC_UNLOCK(unit); 573 return rv; 574 } 575 576 /* 577 * Function: 578 * bcm_xgs3_mcast_addr_remove 579 * Purpose: 580 * Remove a multicast entry 581 * Returns: 582 * BCM_E_XXX 583 */ 584 585 int 586 bcm_xgs3_mcast_addr_remove(int unit, sal_mac_addr_t mac, bcm_vlan_t vid) 587 { 588 int rv; 589 bcm_l2_addr_t l2addr; 590 591 L2MC_INIT(unit); 592 L2MC_LOCK(unit); 593 594 bcm_l2_addr_t_init (&l2addr, mac, vid); 595 rv = bcm_esw_l2_addr_get(unit, mac, vid, &l2addr); 596 if (rv < 0) { 597 L2MC_UNLOCK(unit); 598 return rv; 599 } 600 601 if (!(l2addr.flags & BCM_L2_MCAST)) { 602 L2MC_UNLOCK(unit); 603 return BCM_E_NOT_FOUND; 604 } 605 606 rv = bcm_esw_l2_addr_delete(unit, mac, vid); 607 if (rv < 0) { 608 L2MC_UNLOCK(unit); 609 return rv; 610 } 611 612 /* Check added to avoid Segmentation fault in regression tests */ 613 /* Sometimes l2mc_index may not have a multicast type set when switchcontrol L2McIdxRetType is set to 0*/ 614 if (_BCM_MULTICAST_IS_L2(l2addr.l2mc_group) || 615 !_BCM_MULTICAST_IS_SET(l2addr.l2mc_group)) { 616 l2addr.l2mc_group = L2MC_ID_GET(l2addr.l2mc_group); 617 _bcm_xgs3_l2mc_id_free(unit, l2addr.l2mc_group); 618 619 if (!L2MC_USED_ISSET(unit, l2addr.l2mc_group)) { 620 rv = soc_mem_write(unit, L2MC_MCMEM(unit), MEM_BLOCK_ALL, 621 l2addr.l2mc_group, 622 soc_mem_entry_null(unit, L2MC_MCMEM(unit))); 623 } 624 } 625 626 L2MC_UNLOCK(unit); 627 return rv; 628 } 629 630 /* 631 * Function: 632 * bcm_fb_mcast_addr_remove_w_l2mcindex 633 * Purpose: 634 * Remove a multicast entry with l2mc index provided 635 * Returns: 636 * BCM_E_XXX 637 */ 638 639 int 640 bcm_xgs3_mcast_addr_remove_w_l2mcindex(int unit, 641 bcm_mcast_addr_t *mcaddr) 642 { 643 return bcm_xgs3_mcast_addr_remove(unit, mcaddr->mac, mcaddr->vid); 644 } 645 646 /* 647 * Function: 648 * _bcm_xgs3_mcast_index_port_get 649 * Purpose: 650 * Get port bit maps for a multicast group by index. 651 * Returns: 652 * BCM_E_XXX 653 */ 654 655 int 656 _bcm_xgs3_mcast_index_port_get(int unit, int l2mc_index, 657 bcm_mcast_addr_t *mcaddr) 658 { 659 l2mc_entry_t l2mc_entry; 660 661 L2MC_INIT(unit); 662 663 SOC_IF_ERROR_RETURN 664 (soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY, 665 L2MC_ID_GET(l2mc_index), &l2mc_entry)); 666 667 soc_mem_pbmp_field_get(unit, L2MC_MCMEM(unit), &l2mc_entry, PORT_BITMAPf, 668 &mcaddr->pbmp); 669 670 return BCM_E_NONE; 671 } 672 673 674 /* 675 * Function: 676 * bcm_xgs3_mcast_port_get 677 * Purpose: 678 * Get port bit maps for a multicast group. 679 * Returns: 680 * BCM_E_XXX 681 */ 682 683 int 684 bcm_xgs3_mcast_port_get(int unit, 685 sal_mac_addr_t mac, bcm_vlan_t vid, 686 bcm_mcast_addr_t *mcaddr) 687 { 688 l2mc_entry_t l2mc_entry; 689 bcm_l2_addr_t l2addr; 690 691 L2MC_INIT(unit); 692 693 bcm_l2_addr_t_init (&l2addr, mac, vid); 694 BCM_IF_ERROR_RETURN(bcm_esw_l2_addr_get(unit, mac, vid, &l2addr)); 695 696 l2addr.l2mc_group = L2MC_ID_GET(l2addr.l2mc_group); 697 SOC_IF_ERROR_RETURN 698 (soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY, 699 l2addr.l2mc_group, &l2mc_entry)); 700 701 _bcm_xgs3_mcast_from_l2(unit, mcaddr, &l2addr); 702 soc_mem_pbmp_field_get(unit, L2MC_MCMEM(unit), &l2mc_entry, PORT_BITMAPf, 703 &mcaddr->pbmp); 704 705 return BCM_E_NONE; 706 } 707 708 #ifdef BCM_WARM_BOOT_SUPPORT 709 #ifdef BCM_TRIUMPH3_SUPPORT 710 /* 711 * Function: 712 * _bcm_tr3_mcast_l2_table_recover 713 * Purpose: 714 * Recover L2MC group usage from L2 table. 715 * Returns: 716 * BCM_E_XXX 717 */ 718 STATIC int 719 _bcm_tr3_mcast_l2_table_recover(int unit) 720 { 721 int rv = BCM_E_NONE; 722 int buf_size, chunksize; 723 uint32 *l2_tbl_chnk; 724 soc_mem_t mem; 725 int chnk_idx, chnk_idx_max, mem_idx_max; 726 int chnk_end, ent_idx; 727 uint32 *l2_entry; 728 int key_type; 729 bcm_mac_t mac_addr; 730 int l2mc_idx; 731 l2mc_entry_t mc_entry; 732 733 chunksize = soc_property_get(unit, spn_L2DELETE_CHUNKS, 734 L2_MEM_CHUNKS_DEFAULT); 735 buf_size = 4 * SOC_MAX_MEM_FIELD_WORDS * chunksize; 736 l2_tbl_chnk = soc_cm_salloc(unit, buf_size, "l2 mcast delete"); 737 if (NULL == l2_tbl_chnk) { 738 return BCM_E_MEMORY; 739 } 740 741 /* First work on L2_ENTRY_1 */ 742 743 mem = L2_ENTRY_1m; 744 mem_idx_max = soc_mem_index_max(unit, mem); 745 for (chnk_idx = soc_mem_index_min(unit, mem); 746 chnk_idx <= mem_idx_max; 747 chnk_idx += chunksize) { 748 749 sal_memset((void *)l2_tbl_chnk, 0, buf_size); 750 chnk_idx_max = ((chnk_idx + chunksize) <= mem_idx_max) ? 751 (chnk_idx + chunksize - 1) : mem_idx_max; 752 rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, 753 chnk_idx, chnk_idx_max, l2_tbl_chnk); 754 if (BCM_FAILURE(rv)) { 755 break; 756 } 757 758 chnk_end = (chnk_idx_max - chnk_idx); 759 for (ent_idx = 0 ; ent_idx <= chnk_end; ent_idx++) { 760 l2_entry = soc_mem_table_idx_to_pointer(unit, mem, uint32 *, 761 l2_tbl_chnk, ent_idx); 762 763 if (!soc_mem_field32_get(unit, mem, l2_entry, VALIDf)) { 764 continue; 765 } 766 767 key_type = soc_mem_field32_get(unit, mem, l2_entry, KEY_TYPEf); 768 if (SOC_MEM_KEY_L2_ENTRY_1_L2_BRIDGE != key_type) { 769 continue; 770 } 771 772 soc_mem_mac_addr_get(unit, mem, l2_entry, L2__MAC_ADDRf, mac_addr); 773 if (!BCM_MAC_IS_MCAST(mac_addr)) { 774 continue; 775 } 776 777 l2mc_idx = soc_mem_field32_get(unit, mem, l2_entry, L2__L2MC_PTRf); 778 rv = soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY, l2mc_idx, 779 &mc_entry); 780 if (BCM_FAILURE(rv)) { 781 break; 782 } 783 if (soc_mem_field32_get(unit, L2MC_MCMEM(unit), &mc_entry, 784 VALIDf)) { 785 L2MC_USED_SET(unit, l2mc_idx); 786 } 787 } 788 } 789 790 if (BCM_FAILURE(rv)) { 791 sal_free(L2MC_USED(unit)); 792 soc_cm_sfree(unit, l2_tbl_chnk); 793 return rv; 794 } 795 796 /* Then work on L2_ENTRY_2 */ 797 798 mem = L2_ENTRY_2m; 799 mem_idx_max = soc_mem_index_max(unit, mem); 800 for (chnk_idx = soc_mem_index_min(unit, mem); 801 chnk_idx <= mem_idx_max; 802 chnk_idx += chunksize) { 803 804 sal_memset((void *)l2_tbl_chnk, 0, buf_size); 805 chnk_idx_max = ((chnk_idx + chunksize) <= mem_idx_max) ? 806 (chnk_idx + chunksize - 1) : mem_idx_max; 807 rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, 808 chnk_idx, chnk_idx_max, l2_tbl_chnk); 809 if (BCM_FAILURE(rv)) { 810 break; 811 } 812 813 chnk_end = (chnk_idx_max - chnk_idx); 814 for (ent_idx = 0 ; ent_idx <= chnk_end; ent_idx++) { 815 l2_entry = soc_mem_table_idx_to_pointer(unit, mem, uint32 *, 816 l2_tbl_chnk, ent_idx); 817 818 if (!soc_mem_field32_get(unit, mem, l2_entry, VALID_0f)) { 819 continue; 820 } 821 if (!soc_mem_field32_get(unit, mem, l2_entry, VALID_1f)) { 822 continue; 823 } 824 825 key_type = soc_mem_field32_get(unit, mem, l2_entry, 826 KEY_TYPE_0f); 827 if (SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE != key_type) { 828 continue; 829 } 830 831 soc_mem_mac_addr_get(unit, mem, l2_entry, L2__MAC_ADDRf, mac_addr); 832 if (!BCM_MAC_IS_MCAST(mac_addr)) { 833 continue; 834 } 835 836 l2mc_idx = soc_mem_field32_get(unit, mem, l2_entry, L2__L2MC_PTRf); 837 rv = soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY, l2mc_idx, 838 &mc_entry); 839 if (BCM_FAILURE(rv)) { 840 break; 841 } 842 if (soc_mem_field32_get(unit, L2MC_MCMEM(unit), &mc_entry, 843 VALIDf)) { 844 L2MC_USED_SET(unit, l2mc_idx); 845 } 846 } 847 } 848 849 if (BCM_FAILURE(rv)) { 850 sal_free(L2MC_USED(unit)); 851 soc_cm_sfree(unit, l2_tbl_chnk); 852 return rv; 853 } 854 855 /* Next work on EXT_L2_ENTRY_1 */ 856 857 if (!soc_feature(unit, soc_feature_esm_support)) { 858 return BCM_E_NONE; 859 } 860 861 mem = EXT_L2_ENTRY_1m; 862 mem_idx_max = soc_mem_index_max(unit, mem); 863 for (chnk_idx = soc_mem_index_min(unit, mem); 864 chnk_idx <= mem_idx_max; 865 chnk_idx += chunksize) { 866 867 sal_memset((void *)l2_tbl_chnk, 0, buf_size); 868 chnk_idx_max = ((chnk_idx + chunksize) <= mem_idx_max) ? 869 (chnk_idx + chunksize - 1) : mem_idx_max; 870 rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, 871 chnk_idx, chnk_idx_max, l2_tbl_chnk); 872 if (BCM_FAILURE(rv)) { 873 break; 874 } 875 876 chnk_end = (chnk_idx_max - chnk_idx); 877 for (ent_idx = 0 ; ent_idx <= chnk_end; ent_idx++) { 878 l2_entry = soc_mem_table_idx_to_pointer(unit, mem, uint32 *, 879 l2_tbl_chnk, ent_idx); 880 881 if (soc_mem_field32_get(unit, mem, l2_entry, FREEf)) { 882 continue; 883 } 884 885 key_type = soc_mem_field32_get(unit, mem, l2_entry, 886 KEY_TYPEf); 887 if (0 != key_type) { 888 continue; 889 } 890 891 soc_mem_mac_addr_get(unit, mem, l2_entry, MAC_ADDRf, mac_addr); 892 if (!BCM_MAC_IS_MCAST(mac_addr)) { 893 continue; 894 } 895 896 l2mc_idx = soc_mem_field32_get(unit, mem, l2_entry, DESTINATIONf); 897 rv = soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY, l2mc_idx, 898 &mc_entry); 899 if (BCM_FAILURE(rv)) { 900 break; 901 } 902 if (soc_mem_field32_get(unit, L2MC_MCMEM(unit), &mc_entry, 903 VALIDf)) { 904 L2MC_USED_SET(unit, l2mc_idx); 905 } 906 } 907 } 908 909 if (BCM_FAILURE(rv)) { 910 sal_free(L2MC_USED(unit)); 911 soc_cm_sfree(unit, l2_tbl_chnk); 912 return rv; 913 } 914 915 /* Finally work on EXT_L2_ENTRY_2 */ 916 917 mem = EXT_L2_ENTRY_2m; 918 mem_idx_max = soc_mem_index_max(unit, mem); 919 for (chnk_idx = soc_mem_index_min(unit, mem); 920 chnk_idx <= mem_idx_max; 921 chnk_idx += chunksize) { 922 923 sal_memset((void *)l2_tbl_chnk, 0, buf_size); 924 chnk_idx_max = ((chnk_idx + chunksize) <= mem_idx_max) ? 925 (chnk_idx + chunksize - 1) : mem_idx_max; 926 rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, 927 chnk_idx, chnk_idx_max, l2_tbl_chnk); 928 if (BCM_FAILURE(rv)) { 929 break; 930 } 931 932 chnk_end = (chnk_idx_max - chnk_idx); 933 for (ent_idx = 0 ; ent_idx <= chnk_end; ent_idx++) { 934 l2_entry = soc_mem_table_idx_to_pointer(unit, mem, uint32 *, 935 l2_tbl_chnk, ent_idx); 936 937 if (soc_mem_field32_get(unit, mem, l2_entry, FREEf)) { 938 continue; 939 } 940 941 key_type = soc_mem_field32_get(unit, mem, l2_entry, 942 KEY_TYPEf); 943 if (0 != key_type) { 944 continue; 945 } 946 947 soc_mem_mac_addr_get(unit, mem, l2_entry, MAC_ADDRf, mac_addr); 948 if (!BCM_MAC_IS_MCAST(mac_addr)) { 949 continue; 950 } 951 952 l2mc_idx = soc_mem_field32_get(unit, mem, l2_entry, DESTINATIONf); 953 rv = soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY, l2mc_idx, 954 &mc_entry); 955 if (BCM_FAILURE(rv)) { 956 break; 957 } 958 if (soc_mem_field32_get(unit, L2MC_MCMEM(unit), &mc_entry, 959 VALIDf)) { 960 L2MC_USED_SET(unit, l2mc_idx); 961 } 962 } 963 } 964 965 if (BCM_FAILURE(rv)) { 966 sal_free(L2MC_USED(unit)); 967 } 968 969 soc_cm_sfree(unit, l2_tbl_chnk); 970 return rv; 971 } 972 #endif /* BCM_TRIUMPH3_SUPPORT */ 973 #endif /* BCM_WARM_BOOT_SUPPORT */ 974 975 /* 976 * Function: 977 * _bcm_xgs3_mcast_detach 978 * Purpose: 979 * De-initialize multicast api components 980 * Returns: 981 * BCM_E_XXX 982 */ 983 int 984 _bcm_xgs3_mcast_detach(int unit) 985 { 986 if (L2MC_USED(unit) != NULL) { 987 sal_free(L2MC_USED(unit)); 988 L2MC_USED(unit) = NULL; 989 } 990 L2MC_SIZE(unit) = 0; 991 L2MC_L2MEM(unit) = INVALIDm; 992 L2MC_MCMEM(unit) = INVALIDm; 993 994 return (BCM_E_NONE); 995 } 996 997 /* 998 * Function: 999 * bcm_xgs3_l2_addr_mcast_delete_all 1000 * Purpose: 1001 * Delete multicast address entries in l2 table 1002 * Returns: 1003 * BCM_E_XXX 1004 */ 1005 int 1006 bcm_xgs3_l2_addr_mcast_delete_all(int unit) 1007 { 1008 /* Delete all multicast entries from L2 */ 1009 if (!SAL_BOOT_QUICKTURN && !SAL_BOOT_BCMSIM && !SAL_BOOT_XGSSIM) { 1010 #ifdef BCM_TRIDENT_SUPPORT 1011 if (soc_feature(unit, soc_feature_l2_bulk_control) && 1012 !SAL_BOOT_PLISIM) { 1013 #ifdef BCM_TRIUMPH3_SUPPORT 1014 if (soc_feature(unit, soc_feature_ism_memory)) { 1015 BCM_IF_ERROR_RETURN 1016 (bcm_tr3_l2_addr_delete_mcast(unit, TRUE)); 1017 } else 1018 #endif /* BCM_TRIUMPH3_SUPPORT */ 1019 #ifdef BCM_TOMAHAWK_SUPPORT 1020 if (soc_feature(unit, soc_feature_l2_bulk_unified_table)) { 1021 l2_bulk_entry_t match_mask; 1022 l2_bulk_entry_t match_data; 1023 bcm_mac_t mac_mask; 1024 int field_len; 1025 1026 BCM_IF_ERROR_RETURN 1027 (soc_reg_field32_modify(unit, L2_BULK_CONTROLr, 1028 REG_PORT_ANY, ACTIONf, 1)); 1029 BCM_IF_ERROR_RETURN 1030 (soc_reg_field32_modify(unit, L2_BULK_CONTROLr, 1031 REG_PORT_ANY, NUM_ENTRIESf, 1032 soc_mem_index_count(unit, L2Xm))); 1033 1034 sal_memset(&match_mask, 0, sizeof(match_mask)); 1035 sal_memset(&match_data, 0, sizeof(match_data)); 1036 1037 if (soc_feature(unit, soc_feature_base_valid)) { 1038 soc_mem_field32_set(unit, L2_BULKm, &match_mask, 1039 BASE_VALIDf, 1); 1040 soc_mem_field32_set(unit, L2_BULKm, &match_data, 1041 BASE_VALIDf, 1); 1042 } else { 1043 soc_mem_field32_set(unit, L2_BULKm, &match_mask, 1044 VALIDf, 1); 1045 soc_mem_field32_set(unit, L2_BULKm, &match_data, 1046 VALIDf, 1); 1047 } 1048 1049 field_len = soc_mem_field_length(unit, L2_BULKm, 1050 KEY_TYPEf); 1051 soc_mem_field32_set(unit, L2_BULKm, &match_mask, 1052 KEY_TYPEf, (1 << field_len) - 1); 1053 /* KEY_TYPE field in data is 0 */ 1054 1055 sal_memset(&mac_mask, 0, sizeof(mac_mask)); 1056 mac_mask[0] = 1; /* bit 40 */ 1057 soc_mem_mac_addr_set(unit, L2_BULKm, &match_mask, 1058 MAC_ADDRf, mac_mask); 1059 soc_mem_mac_addr_set(unit, L2_BULKm, &match_data, 1060 MAC_ADDRf, mac_mask); 1061 1062 BCM_IF_ERROR_RETURN 1063 (WRITE_L2_BULKm(unit, MEM_BLOCK_ALL, 1, 1064 &match_mask)); 1065 BCM_IF_ERROR_RETURN 1066 (WRITE_L2_BULKm(unit, MEM_BLOCK_ALL, 0, 1067 &match_data)); 1068 if (!SAL_BOOT_BCMSIM) { 1069 BCM_IF_ERROR_RETURN 1070 (soc_l2x_port_age(unit, L2_BULK_CONTROLr, INVALIDr)); 1071 } 1072 } else 1073 #endif /* BCM_TOMAHAWK_SUPPORT */ 1074 { 1075 l2_bulk_match_mask_entry_t match_mask; 1076 l2_bulk_match_data_entry_t match_data; 1077 bcm_mac_t mac_mask; 1078 int field_len; 1079 1080 BCM_IF_ERROR_RETURN 1081 (soc_reg_field32_modify(unit, L2_BULK_CONTROLr, 1082 REG_PORT_ANY, ACTIONf, 1)); 1083 1084 sal_memset(&match_mask, 0, sizeof(match_mask)); 1085 sal_memset(&match_data, 0, sizeof(match_data)); 1086 1087 soc_mem_field32_set(unit, L2_BULK_MATCH_MASKm, &match_mask, 1088 VALIDf, 1); 1089 soc_mem_field32_set(unit, L2_BULK_MATCH_DATAm, &match_data, 1090 VALIDf, 1); 1091 1092 field_len = soc_mem_field_length(unit, L2_BULK_MATCH_MASKm, 1093 KEY_TYPEf); 1094 soc_mem_field32_set(unit, L2_BULK_MATCH_MASKm, &match_mask, 1095 KEY_TYPEf, (1 << field_len) - 1); 1096 /* KEY_TYPE field in data is 0 */ 1097 1098 sal_memset(&mac_mask, 0, sizeof(mac_mask)); 1099 mac_mask[0] = 1; /* bit 40 */ 1100 soc_mem_mac_addr_set(unit, L2_BULK_MATCH_MASKm, &match_mask, 1101 MAC_ADDRf, mac_mask); 1102 soc_mem_mac_addr_set(unit, L2_BULK_MATCH_DATAm, &match_data, 1103 MAC_ADDRf, mac_mask); 1104 1105 BCM_IF_ERROR_RETURN 1106 (WRITE_L2_BULK_MATCH_MASKm(unit, MEM_BLOCK_ALL, 0, 1107 &match_mask)); 1108 BCM_IF_ERROR_RETURN 1109 (WRITE_L2_BULK_MATCH_DATAm(unit, MEM_BLOCK_ALL, 0, 1110 &match_data)); 1111 if (!SAL_BOOT_BCMSIM) { 1112 BCM_IF_ERROR_RETURN 1113 (soc_l2x_port_age(unit, L2_BULK_CONTROLr, INVALIDr)); 1114 } 1115 } 1116 } else 1117 #endif /* BCM_TRIDENT_SUPPORT */ 1118 { 1119 #ifdef BCM_TRIUMPH3_SUPPORT 1120 if (soc_feature(unit, soc_feature_ism_memory)) { 1121 if (!SAL_BOOT_PLISIM) { 1122 BCM_IF_ERROR_RETURN 1123 (bcm_tr3_l2_addr_delete_mcast(unit, FALSE)); 1124 } 1125 } else 1126 #endif /* BCM_TRIUMPH3_SUPPORT */ 1127 { 1128 if (!SAL_BOOT_BCMSIM) { 1129 BCM_IF_ERROR_RETURN 1130 (_bcm_xgs3_l2_addr_delete_mcast(unit, BCM_L2_DELETE_STATIC)); 1131 } 1132 } 1133 } 1134 } 1135 1136 return BCM_E_NONE; 1137 } 1138 1139 /* 1140 * Function: 1141 * bcm_xgs3_mcast_init 1142 * Purpose: 1143 * Initialize multicast api components 1144 * Returns: 1145 * BCM_E_XXX on error 1146 * number of mcast entries supported on success 1147 */ 1148 1149 int 1150 bcm_xgs3_mcast_init(int unit) 1151 { 1152 if (L2MC_USED(unit) != NULL) { 1153 sal_free(L2MC_USED(unit)); 1154 } 1155 L2MC_SIZE(unit) = 0; 1156 1157 L2MC_L2MEM(unit) = soc_feature(unit, soc_feature_ism_memory) ? 1158 L2_ENTRY_1m: L2Xm; 1159 L2MC_MCMEM(unit) = L2MCm; 1160 #if defined(BCM_BRADLEY_SUPPORT) || defined(BCM_TRX_SUPPORT) 1161 if (SOC_IS_HBX(unit) || SOC_IS_TRX(unit)) { 1162 int mc_base, mc_size; 1163 1164 #ifdef BCM_WARM_BOOT_SUPPORT 1165 if (SOC_WARM_BOOT(unit)) { 1166 uint32 mc_ctrl; 1167 soc_control_t *soc = SOC_CONTROL(unit); 1168 1169 /* Recover the mcast size settings */ 1170 if (soc_feature(unit, soc_feature_higig2)) { 1171 SOC_IF_ERROR_RETURN 1172 (READ_MC_CONTROL_1r(unit, &mc_ctrl)); 1173 soc->higig2_bcast_size = 1174 soc_reg_field_get(unit, MC_CONTROL_1r, mc_ctrl, 1175 HIGIG2_BC_SIZEf); 1176 1177 SOC_IF_ERROR_RETURN 1178 (READ_MC_CONTROL_2r(unit, &mc_ctrl)); 1179 soc->higig2_mcast_size = 1180 soc_reg_field_get(unit, MC_CONTROL_2r, mc_ctrl, 1181 HIGIG2_L2MC_SIZEf); 1182 1183 SOC_IF_ERROR_RETURN 1184 (READ_MC_CONTROL_3r(unit, &mc_ctrl)); 1185 soc->higig2_ipmc_size = 1186 soc_reg_field_get(unit, MC_CONTROL_3r, mc_ctrl, 1187 HIGIG2_IPMC_SIZEf); 1188 } 1189 1190 if (!SOC_IS_MONTEREY(unit)) { 1191 if (SOC_REG_FIELD_VALID(unit, MC_CONTROL_5r, 1192 SHARED_TABLE_L2MC_SIZEf) && 1193 SOC_REG_FIELD_VALID(unit, MC_CONTROL_5r, 1194 SHARED_TABLE_IPMC_SIZEf)) { 1195 SOC_IF_ERROR_RETURN 1196 (READ_MC_CONTROL_5r(unit, &mc_ctrl)); 1197 soc->mcast_size = 1198 soc_reg_field_get(unit, MC_CONTROL_5r, mc_ctrl, 1199 SHARED_TABLE_L2MC_SIZEf); 1200 soc->ipmc_size = 1201 soc_reg_field_get(unit, MC_CONTROL_5r, mc_ctrl, 1202 SHARED_TABLE_IPMC_SIZEf); 1203 } 1204 } 1205 1206 } 1207 #endif /* BCM_WARM_BOOT_SUPPORT */ 1208 1209 SOC_IF_ERROR_RETURN 1210 (soc_hbx_mcast_size_get(unit, &mc_base, &mc_size)); 1211 1212 L2MC_SIZE(unit) = mc_size; 1213 } 1214 #endif 1215 1216 if (L2MC_SIZE(unit) <= 0) { 1217 L2MC_SIZE(unit) = soc_mem_index_count(unit, L2MC_MCMEM(unit)); 1218 } 1219 1220 L2MC_USED(unit) = sal_alloc(sizeof(int) * L2MC_SIZE(unit), "L2MC"); 1221 if (L2MC_USED(unit) == NULL) { 1222 return BCM_E_MEMORY; 1223 } 1224 sal_memset(L2MC_USED(unit), 0, sizeof(int) * L2MC_SIZE(unit)); 1225 1226 #ifdef BCM_WARM_BOOT_SUPPORT 1227 if (SOC_WARM_BOOT(unit)) { 1228 l2x_entry_t *l2_entry, *l2_table; 1229 l2mc_entry_t *l2mc_entry, *l2mc_table; 1230 int index, index_min, index_max, l2mc_tbl_sz, l2_tbl_sz; 1231 sal_mac_addr_t mcmac; 1232 1233 /* 1234 * Go through L2 table to get MC use counts 1235 */ 1236 #ifdef BCM_TRIUMPH3_SUPPORT 1237 if (soc_feature(unit, soc_feature_ism_memory)) { 1238 _bcm_tr3_mcast_l2_table_recover(unit); 1239 } else 1240 #endif /* BCM_TRIUMPH3_SUPPORT */ 1241 { 1242 int iter, dma_iter = 1; 1243 #ifdef BCM_TRIDENT2PLUS_SUPPORT 1244 int index_half = 0; 1245 #endif /* BCM_TRIDENT2PLUS_SUPPORT */ 1246 index_min = soc_mem_index_min(unit, L2MC_L2MEM(unit)); 1247 index_max = soc_mem_index_max(unit, L2MC_L2MEM(unit)); 1248 l2_tbl_sz = sizeof(l2x_entry_t) * (index_max - index_min + 1); 1249 1250 #ifdef BCM_TRIDENT2PLUS_SUPPORT 1251 if (SOC_IS_TRIDENT2PLUS(unit)) { 1252 /* Trident2 has a Max L2_ENTRY Table Size of 294911 and TD2Plus 1253 * has double the entries, So for the DMA allocation to succeed 1254 * we are reading the L2_Entries in 2 chuncks for TD2Plus. 1255 */ 1256 if ((index_max - index_min) > 294911) { 1257 dma_iter = 2; 1258 index_half = (index_max - index_min) / 2; 1259 l2_tbl_sz = sizeof(l2x_entry_t) * (index_half + 1); 1260 } 1261 } 1262 #endif /* BCM_TRIDENT2PLUS_SUPPORT */ 1263 1264 for (iter = 0; iter < dma_iter; iter++) { 1265 #ifdef BCM_TRIDENT2PLUS_SUPPORT 1266 if (SOC_IS_TRIDENT2PLUS(unit)) { 1267 if (dma_iter == 2) { 1268 if(iter == 0) { 1269 index_max = index_half; 1270 } else if (iter == 1) { 1271 index_min = index_half + 1; 1272 index_max = soc_mem_index_max(unit, 1273 L2MC_L2MEM(unit)); 1274 } 1275 } 1276 } 1277 #endif /* BCM_TRIDENT2PLUS_SUPPORT */ 1278 l2_table = soc_cm_salloc(unit, l2_tbl_sz, "l2 tbl dma"); 1279 if (l2_table == NULL) { 1280 sal_free(L2MC_USED(unit)); 1281 return BCM_E_MEMORY; 1282 } 1283 1284 memset((void *)l2_table, 0, l2_tbl_sz); 1285 if (soc_mem_read_range(unit, L2MC_L2MEM(unit), MEM_BLOCK_ANY, 1286 index_min, index_max, l2_table) < 0) { 1287 sal_free(L2MC_USED(unit)); 1288 soc_cm_sfree(unit, l2_table); 1289 return SOC_E_INTERNAL; 1290 } 1291 for (index = index_min; index <= index_max; index++) { 1292 int l2mc_idx; 1293 l2mc_entry_t mc_entry; 1294 soc_field_t field_valid; 1295 1296 l2_entry = 1297 soc_mem_table_idx_to_pointer(unit, L2MC_L2MEM(unit), 1298 l2x_entry_t *, l2_table, 1299 index - index_min); 1300 field_valid = VALIDf; 1301 if (soc_feature(unit, soc_feature_base_valid)) { 1302 field_valid = BASE_VALIDf; 1303 } 1304 if (!soc_mem_field32_get(unit, L2MC_L2MEM(unit), 1305 l2_entry, field_valid)) { 1306 continue; 1307 } 1308 1309 #ifdef BCM_TRX_SUPPORT 1310 /* We're already traversing the L2 memory here, so 1311 * check for non-bridge items */ 1312 if ((FALSE == SOC_CONTROL(unit)->l2x_ppa_bypass) && 1313 soc_feature(unit, soc_feature_ppa_bypass) && 1314 (soc_mem_field32_get(unit, L2MC_L2MEM(unit), 1315 l2_entry, KEY_TYPEf) != 1316 TR_L2_HASH_KEY_TYPE_BRIDGE)) { 1317 SOC_CONTROL(unit)->l2x_ppa_bypass = TRUE; 1318 } 1319 1320 if (soc_mem_field_valid(unit, 1321 L2MC_L2MEM(unit), KEY_TYPEf) && 1322 (soc_mem_field32_get(unit, L2MC_L2MEM(unit), 1323 l2_entry, KEY_TYPEf) != 1324 TR_L2_HASH_KEY_TYPE_BRIDGE)) { 1325 /* The field L2MC_PTRf is only valid for key 1326 * type BRIDGE */ 1327 continue; 1328 } 1329 #endif /* BCM_TRX_SUPPORT */ 1330 1331 soc_L2Xm_mac_addr_get(unit, l2_entry, MAC_ADDRf, mcmac); 1332 if (!BCM_MAC_IS_MCAST(mcmac)) { 1333 continue; 1334 } 1335 1336 if (soc_feature(unit, soc_feature_generic_dest)) { 1337 uint32 dest_type; 1338 l2mc_idx = soc_mem_field32_dest_get(unit, 1339 L2MC_L2MEM(unit), l2_entry, 1340 DESTINATIONf, &dest_type); 1341 if (dest_type != SOC_MEM_FIF_DEST_L2MC) { 1342 l2mc_idx = 0; 1343 } 1344 } else { 1345 l2mc_idx = soc_mem_field32_get(unit, L2MC_L2MEM(unit), 1346 l2_entry, L2MC_PTRf); 1347 } 1348 sal_memset(&mc_entry, 0, sizeof(l2mc_entry_t)); 1349 if (soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY, 1350 l2mc_idx, &mc_entry) < 0) { 1351 sal_free(L2MC_USED(unit)); 1352 soc_cm_sfree(unit, l2_table); 1353 return SOC_E_INTERNAL; 1354 } 1355 1356 if (!soc_mem_field32_get(unit, L2MC_MCMEM(unit), 1357 &mc_entry, VALIDf)) { 1358 continue; 1359 } 1360 L2MC_USED_SET(unit, l2mc_idx); 1361 } 1362 soc_cm_sfree(unit, l2_table); 1363 } 1364 } 1365 1366 /* 1367 * But then L2 table may not have indices populated for 1368 * all valid L2MC entries.. 1369 * Go through L2MC table to search for existing entries 1370 */ 1371 index_min = soc_mem_index_min(unit, L2MC_MCMEM(unit)); 1372 index_max = index_min + L2MC_SIZE(unit) - 1; 1373 1374 l2mc_tbl_sz = sizeof(l2mc_entry_t) * L2MC_SIZE(unit); 1375 l2mc_table = soc_cm_salloc(unit, l2mc_tbl_sz, "l2mc tbl dma"); 1376 if (l2mc_table == NULL) { 1377 sal_free(L2MC_USED(unit)); 1378 return BCM_E_MEMORY; 1379 } 1380 1381 memset((void *)l2mc_table, 0, l2mc_tbl_sz); 1382 if (soc_mem_read_range(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY, 1383 index_min, index_max, l2mc_table) < 0) { 1384 sal_free(L2MC_USED(unit)); 1385 soc_cm_sfree(unit, l2mc_table); 1386 return SOC_E_INTERNAL; 1387 } 1388 1389 for (index = index_min; index <= index_max; index++) { 1390 1391 l2mc_entry = soc_mem_table_idx_to_pointer(unit, L2MC_MCMEM(unit), 1392 l2mc_entry_t *, l2mc_table, index); 1393 1394 if (!soc_mem_field32_get(unit, L2MC_MCMEM(unit), 1395 l2mc_entry, VALIDf)) { 1396 continue; 1397 } 1398 1399 if (!L2MC_USED_ISSET(unit, index)) { 1400 L2MC_USED_SET(unit, index); 1401 } 1402 } 1403 1404 soc_cm_sfree(unit, l2mc_table); 1405 1406 return L2MC_SIZE(unit); 1407 } 1408 #endif /* BCM_WARM_BOOT_SUPPORT */ 1409 1410 if (!SAL_BOOT_BCMSIM && !SAL_BOOT_QUICKTURN && !SAL_BOOT_XGSSIM) { 1411 SOC_IF_ERROR_RETURN 1412 (soc_mem_clear(unit, L2MC_MCMEM(unit), MEM_BLOCK_ALL, FALSE)); 1413 } 1414 1415 BCM_IF_ERROR_RETURN(bcm_xgs3_l2_addr_mcast_delete_all(unit)); 1416 1417 return L2MC_SIZE(unit); 1418 } 1419 1420 #ifndef BCM_SW_STATE_DUMP_DISABLE 1421 /* 1422 * Function: 1423 * _bcm_xgs3_mcast_sw_dump 1424 * Purpose: 1425 * Displays XGS3 mcast information maintained by software. 1426 * Parameters: 1427 * unit - Device unit number 1428 * Returns: 1429 * None 1430 */ 1431 void 1432 _bcm_xgs3_mcast_sw_dump(int unit) 1433 { 1434 _bcm_xgs3_mcast_t *info; 1435 int *used; 1436 int i, j; 1437 1438 info = &xgs3_l2mc_info[unit]; 1439 1440 LOG_CLI((BSL_META_U(unit, 1441 "\n XGS3 MCAST -\n"))); 1442 LOG_CLI((BSL_META_U(unit, 1443 " Size : %d\n"), info->size)); 1444 LOG_CLI((BSL_META_U(unit, 1445 " L2 Mem : %d\n"), info->l2mem)); 1446 LOG_CLI((BSL_META_U(unit, 1447 " MC Mem : %d\n"), info->mcmem)); 1448 1449 LOG_CLI((BSL_META_U(unit, 1450 " Used (index:value) :"))); 1451 used = info->used; 1452 if (used != NULL) { 1453 for (i = 0, j = 0; i < info->size; i++) { 1454 /* If zero, skip print */ 1455 if (used[i] == 0) { 1456 continue; 1457 } 1458 if (!(j % 4)) { 1459 LOG_CLI((BSL_META_U(unit, 1460 "\n "))); 1461 } 1462 LOG_CLI((BSL_META_U(unit, 1463 " %4d:%-5d"), i, used[i])); 1464 j++; 1465 } 1466 } 1467 LOG_CLI((BSL_META_U(unit, 1468 "\n"))); 1469 1470 return; 1471 } 1472 #endif /* BCM_SW_STATE_DUMP_DISABLE */