l2mcast.c (27107B)
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/common/multicast.h> 23 #if defined(BCM_TOMAHAWK3_SUPPORT) 24 #include <bcm_int/esw/tomahawk3.h> 25 #include <soc/tomahawk3.h> 26 27 typedef struct { 28 int size; 29 int *used; 30 soc_mem_t l2mem; 31 soc_mem_t mcmem; 32 } _bcm_th3_l2_mcast_t; 33 34 static _bcm_th3_l2_mcast_t th3_l2mc_info[BCM_MAX_NUM_UNITS]; 35 36 #define L2MC_INFO(unit) (&th3_l2mc_info[unit]) 37 #define L2MC_SIZE(unit) L2MC_INFO(unit)->size 38 #define L2MC_USED(unit) L2MC_INFO(unit)->used 39 #define L2MC_L2MEM(unit) L2MC_INFO(unit)->l2mem 40 #define L2MC_MCMEM(unit) L2MC_INFO(unit)->mcmem 41 #define L2MC_USED_SET(unit, n) L2MC_USED(unit)[n] += 1 42 #define L2MC_USED_CLR(unit, n) L2MC_USED(unit)[n] -= 1 43 #define L2MC_USED_ISSET(unit, n) (L2MC_USED(unit)[n] > 0) 44 45 #define L2MC_INIT(unit) \ 46 if (L2MC_USED(unit) == NULL) { return BCM_E_INIT; } 47 #define L2MC_ID(unit, id) \ 48 if (id < 0 || id >= L2MC_SIZE(unit)) { return BCM_E_PARAM; } 49 50 #define L2MC_LOCK(unit) do { \ 51 soc_mem_lock(unit, L2MC_MCMEM(unit)); \ 52 } while(0) 53 #define L2MC_UNLOCK(unit) do { \ 54 soc_mem_unlock(unit, L2MC_MCMEM(unit)); \ 55 } while(0) 56 #define L2MC_ID_GET(l2mc_index) \ 57 (_BCM_MULTICAST_IS_SET(l2mc_index) && \ 58 _BCM_MULTICAST_IS_L2(l2mc_index)) ? \ 59 _BCM_MULTICAST_ID_GET(l2mc_index) : l2mc_index 60 61 /* 62 * Function: 63 * _bcm_th3_l2_addr_delete_mcast 64 * Description 65 * Delete L2 multicast entries 66 * Parameters: 67 * unit - device unit 68 * flags - BCM_L2_DELETE_XXX 69 * Returns: 70 * BCM_E_XXX 71 */ 72 int 73 _bcm_th3_l2_addr_delete_mcast(int unit, uint32 flags) 74 { 75 l2x_entry_t *l2xe, *l2xep; 76 int rv, chunksize, chunk, chunk_max, i; 77 int dyn_only, chnk_end, mem_idx_max; 78 bcm_mac_t mac; 79 80 chunksize = soc_property_get(unit, spn_L2DELETE_CHUNKS, 81 L2_MEM_CHUNKS_DEFAULT); 82 83 l2xe = soc_cm_salloc(unit, chunksize * sizeof(*l2xe), "l2del_chunk"); 84 if (l2xe == NULL) { 85 return BCM_E_MEMORY; 86 } 87 88 rv = BCM_E_NONE; 89 90 dyn_only = !(flags & BCM_L2_DELETE_STATIC); 91 92 mem_idx_max = soc_mem_index_max(unit, L2Xm); 93 for (chunk = soc_mem_index_min(unit, L2Xm); chunk <= mem_idx_max; 94 chunk += chunksize) { 95 96 chunk_max = chunk + chunksize - 1; 97 if (chunk_max > mem_idx_max) { 98 chunk_max = mem_idx_max; 99 } 100 101 rv = soc_mem_read_range(unit, L2Xm, MEM_BLOCK_ANY, 102 chunk, chunk_max, l2xe); 103 if (rv < 0) { 104 break; 105 } 106 107 chnk_end = (chunk_max - chunk); 108 for (i = 0; i <= chnk_end; i++) { 109 110 l2xep = soc_mem_table_idx_to_pointer(unit, L2Xm, 111 l2x_entry_t *, l2xe, i); 112 113 if (!soc_L2Xm_field32_get(unit, l2xep, BASE_VALIDf)) { 114 continue; 115 } 116 117 soc_L2Xm_mac_addr_get(unit, l2xep, MAC_ADDRf, mac); 118 if (!BCM_MAC_IS_MCAST(mac)) { 119 continue; 120 } 121 122 if (dyn_only && 123 soc_L2Xm_field32_get(unit, l2xep, STATIC_BITf)) { 124 continue; 125 } 126 127 rv = soc_mem_delete(unit, L2Xm, MEM_BLOCK_ALL, l2xep); 128 if (rv < 0) { 129 break; 130 } 131 } 132 133 if (rv < 0) { 134 break; 135 } 136 } 137 138 soc_cm_sfree(unit, l2xe); 139 140 return rv; 141 } 142 143 /* 144 * Function: 145 * _bcm_th3_l2mc_size_get 146 * Description: 147 * Get number of L2MC groups. 148 */ 149 int 150 _bcm_th3_l2mc_size_get(int unit, int *size) 151 { 152 *size = L2MC_SIZE(unit); 153 return BCM_E_NONE; 154 } 155 156 /* 157 * Function: 158 * _bcm_th3_l2mc_index_is_set 159 * Description: 160 * Check whether and l2mc index is used. 161 */ 162 163 int 164 _bcm_th3_l2mc_index_is_set(int unit, int l2mc_id, int *is_set) 165 { 166 L2MC_ID(unit, l2mc_id); 167 168 *is_set = (0 != L2MC_USED_ISSET(unit, l2mc_id)); 169 170 return BCM_E_NONE; 171 } 172 173 /* 174 * Function: 175 * _bcm_th3_l2mc_free_index 176 * Description: 177 * Find an unused l2mc index and mark it used. 178 */ 179 180 int 181 _bcm_th3_l2mc_free_index(int unit, int *l2mc_id) 182 { 183 int i, rv; 184 185 rv = BCM_E_FULL; 186 for (i = 1; i < L2MC_SIZE(unit); i++) { 187 if (!L2MC_USED_ISSET(unit, i)) { 188 L2MC_USED_SET(unit, i); 189 *l2mc_id = i; 190 rv = BCM_E_NONE; 191 break; 192 } 193 } 194 195 return rv; 196 } 197 198 /* 199 * Function: 200 * _bcm_th3_l2mc_id_alloc 201 * Description: 202 * allocate the given l2mc entry (increment use count) 203 */ 204 205 int 206 _bcm_th3_l2mc_id_alloc(int unit, int l2mc_id) 207 { 208 L2MC_ID(unit, l2mc_id); 209 210 L2MC_USED_SET(unit, l2mc_id); 211 212 return BCM_E_NONE; 213 } 214 215 /* 216 * Function: 217 * _bcm_th3_l2mc_id_free 218 * Description: 219 * Marks an l2mc index as free (decrements use count) 220 */ 221 222 int 223 _bcm_th3_l2mc_id_free(int unit, int l2mc_id) 224 { 225 L2MC_ID(unit, l2mc_id); 226 227 L2MC_USED_CLR(unit, l2mc_id); 228 229 return BCM_E_NONE; 230 } 231 232 /* 233 * Function: 234 * _bcm_th3_mcast_from_l2 235 * Description: 236 * Fill in fields of bcm_mcast_addr_t from bcm_l2_addr_t 237 * Parameters: 238 * unit - (IN) device 239 * mcaddr - (OUT) mcast addr struct 240 * l2addr - (IN) l2 addr struct 241 */ 242 243 STATIC void 244 _bcm_th3_mcast_from_l2(int unit, 245 bcm_mcast_addr_t *mcaddr, 246 bcm_l2_addr_t *l2addr) 247 { 248 int rv; 249 vlan_tab_entry_t vte; 250 soc_mem_t vlan_mem; 251 252 sal_memcpy(mcaddr->mac, l2addr->mac, sizeof(bcm_mac_t)); 253 mcaddr->vid = l2addr->vid; 254 mcaddr->cos_dst = l2addr->cos_dst; 255 mcaddr->l2mc_index = l2addr->l2mc_group; 256 257 /* Need to fill in the untagged port bitmap from the VLAN table */ 258 SOC_PBMP_CLEAR(mcaddr->ubmp); 259 vlan_mem = EGR_VLANm; 260 rv = soc_mem_read(unit, vlan_mem, MEM_BLOCK_ANY, mcaddr->vid, &vte); 261 if (rv < 0) { 262 return; 263 } 264 265 soc_mem_pbmp_field_get(unit, vlan_mem, &vte, UT_BITMAPf, &mcaddr->ubmp); 266 } 267 268 /* 269 * Function: 270 * _bcm_th3_l2_mcast_to_l2 271 * Description: 272 * Fill in fields of bcm_l2_addr_t from bcm_mcast_addr_t 273 * Parameters: 274 * unit - (IN) device 275 * l2addr - (OUT) Pointer to bcm_l2_addr_t 276 * mcaddr - (IN) Pointer to bcm_mcast_addr_t 277 */ 278 279 STATIC void 280 _bcm_th3_l2_mcast_to_l2(int unit, 281 bcm_l2_addr_t *l2addr, 282 bcm_mcast_addr_t *mcaddr) 283 { 284 sal_memset(l2addr, 0, sizeof(*l2addr)); 285 l2addr->flags = BCM_L2_STATIC | BCM_L2_MCAST | BCM_L2_REPLACE_DYNAMIC; 286 l2addr->cos_dst = mcaddr->cos_dst; 287 l2addr->vid = mcaddr->vid; 288 sal_memcpy(l2addr->mac, mcaddr->mac, sizeof(bcm_mac_t)); 289 l2addr->l2mc_group = mcaddr->l2mc_index; 290 } 291 292 /* 293 * Function: 294 * _bcm_th3_mcast_create 295 * Description: 296 * Create a muticast entry 297 * Parameters: 298 * unit - (IN) device 299 * mcaddr - (IN) Pointer to bcm_mcast_addr_t 300 * mcindex - (IN) mcast index to use (-1 lets routine choose) 301 * Returns: 302 * BCM_E_XXX 303 */ 304 305 STATIC int 306 _bcm_th3_mcast_create(int unit, bcm_mcast_addr_t *mcaddr, 307 int mcindex) 308 { 309 l2mc_entry_t l2mc, rl2mc; 310 bcm_l2_addr_t l2addr, rl2addr; 311 bcm_pbmp_t pbm, rpbm; 312 int rv; 313 314 bcm_l2_addr_t_init (&l2addr, mcaddr->mac, mcaddr->vid); 315 rv = bcm_tomahawk3_l2_addr_get(unit, mcaddr->mac, mcaddr->vid, &l2addr); 316 if (rv >= 0) { 317 if (!(l2addr.flags & BCM_L2_MCAST)) { 318 return BCM_E_EXISTS; 319 } 320 l2addr.l2mc_group = L2MC_ID_GET(l2addr.l2mc_group); 321 if (mcindex >= 0 && mcindex == l2addr.l2mc_group) { 322 return BCM_E_NONE; 323 } 324 BCM_IF_ERROR_RETURN(_bcm_th3_l2mc_id_free(unit, l2addr.l2mc_group)); 325 } 326 327 /* Before getting free MC index, make sure this is a valid Port */ 328 rv = soc_mem_field_pbmp_fit(unit, L2MC_MCMEM(unit), PORT_BITMAPf, 329 (uint32 *)&mcaddr->pbmp); 330 if (rv != SOC_E_NONE) { 331 return rv; 332 } 333 334 if (mcindex < 0) { 335 BCM_IF_ERROR_RETURN(_bcm_th3_l2mc_free_index(unit, &mcindex)); 336 } else { 337 BCM_IF_ERROR_RETURN(_bcm_th3_l2mc_id_alloc(unit, mcindex)); 338 } 339 340 sal_memset(&l2mc, 0, sizeof(l2mc)); 341 soc_mem_field32_set(unit, L2MC_MCMEM(unit), &l2mc, VALIDf, 1); 342 soc_mem_pbmp_field_set(unit, L2MC_MCMEM(unit), &l2mc, PORT_BITMAPf, 343 &mcaddr->pbmp); 344 _bcm_th3_l2_mcast_to_l2(unit, &l2addr, mcaddr); 345 l2addr.l2mc_group = mcindex; 346 347 if (SOC_MCAST_ADD_ALL_ROUTER_PORTS(unit)) { 348 sal_memset(&rl2addr, 0, sizeof(bcm_l2_addr_t)); 349 rv = bcm_tomahawk3_l2_addr_get(unit, (uint8 *)_soc_mac_all_routers, 350 mcaddr->vid, &rl2addr); 351 if (rv >= 0) { 352 rl2addr.l2mc_group = L2MC_ID_GET(rl2addr.l2mc_group); 353 SOC_IF_ERROR_RETURN 354 (soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY, 355 rl2addr.l2mc_group, &rl2mc)); 356 soc_mem_pbmp_field_get(unit, L2MC_MCMEM(unit), &rl2mc, 357 PORT_BITMAPf, &rpbm); 358 soc_mem_pbmp_field_get(unit, L2MC_MCMEM(unit), &l2mc, PORT_BITMAPf, 359 &pbm); 360 BCM_PBMP_OR(pbm, rpbm); 361 soc_mem_pbmp_field_set(unit, L2MC_MCMEM(unit), &l2mc, PORT_BITMAPf, 362 &pbm); 363 } 364 } 365 366 /* add l2mc entry */ 367 SOC_IF_ERROR_RETURN 368 (soc_mem_write(unit, L2MC_MCMEM(unit), MEM_BLOCK_ALL, mcindex, &l2mc)); 369 370 /* add l2 entry */ 371 rv = bcm_tomahawk3_l2_addr_add(unit, &l2addr); 372 if (BCM_FAILURE(rv)) { 373 _bcm_th3_l2mc_id_free(unit, l2addr.l2mc_group); 374 if (!L2MC_USED_ISSET(unit, l2addr.l2mc_group)) { 375 soc_mem_write(unit, L2MC_MCMEM(unit), MEM_BLOCK_ALL, 376 l2addr.l2mc_group, 377 soc_mem_entry_null(unit, L2MC_MCMEM(unit))); 378 } 379 } 380 381 return rv; 382 } 383 384 /* 385 * Function: 386 * _bcm_th3_mcast_port_add 387 * Purpose: 388 * Add new ports to a multicast entry 389 * Parameters: 390 * unit - device 391 * mcaddr - mcast addr struct with new ports 392 * Returns: 393 * BCM_E_XXX 394 */ 395 396 STATIC int 397 _bcm_th3_mcast_port_add(int unit, bcm_mcast_addr_t *mcaddr) 398 { 399 bcm_l2_addr_t l2addr; 400 l2mc_entry_t l2mc_entry; 401 bcm_pbmp_t pbmp; 402 403 bcm_l2_addr_t_init(&l2addr, mcaddr->mac, mcaddr->vid); 404 BCM_IF_ERROR_RETURN(bcm_tomahawk3_l2_addr_get(unit, mcaddr->mac, 405 mcaddr->vid, &l2addr)); 406 if (!(l2addr.flags & BCM_L2_MCAST)) { 407 return BCM_E_NOT_FOUND; 408 } 409 410 l2addr.l2mc_group = L2MC_ID_GET(l2addr.l2mc_group); 411 412 SOC_IF_ERROR_RETURN(soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY, 413 l2addr.l2mc_group, &l2mc_entry)); 414 415 soc_mem_pbmp_field_get(unit, L2MC_MCMEM(unit), &l2mc_entry, PORT_BITMAPf, 416 &pbmp); 417 BCM_PBMP_OR(pbmp, mcaddr->pbmp); 418 soc_mem_pbmp_field_set(unit, L2MC_MCMEM(unit), &l2mc_entry, PORT_BITMAPf, 419 &pbmp); 420 421 SOC_IF_ERROR_RETURN(soc_mem_write(unit, L2MC_MCMEM(unit), MEM_BLOCK_ALL, 422 l2addr.l2mc_group, &l2mc_entry)); 423 424 return BCM_E_NONE; 425 } 426 427 /* 428 * Function: 429 * _bcm_th3_mcast_port_delete 430 * Purpose: 431 * Remove ports from a multicast entry 432 * Parameters: 433 * unit - device 434 * mcaddr - mcast addr struct with ports to delete 435 * Returns: 436 * BCM_E_XXX 437 */ 438 439 STATIC int 440 _bcm_th3_mcast_port_delete(int unit, 441 bcm_mcast_addr_t *mcaddr) 442 { 443 bcm_l2_addr_t l2addr; 444 l2mc_entry_t l2mc_entry; 445 bcm_pbmp_t pbmp; 446 447 bcm_l2_addr_t_init (&l2addr, mcaddr->mac, mcaddr->vid); 448 BCM_IF_ERROR_RETURN(bcm_tomahawk3_l2_addr_get(unit, mcaddr->mac, 449 mcaddr->vid, &l2addr)); 450 451 if (!(l2addr.flags & BCM_L2_MCAST)) { 452 return BCM_E_NOT_FOUND; 453 } 454 455 l2addr.l2mc_group = L2MC_ID_GET(l2addr.l2mc_group); 456 457 SOC_IF_ERROR_RETURN(soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY, 458 l2addr.l2mc_group, &l2mc_entry)); 459 460 soc_mem_pbmp_field_get(unit, L2MC_MCMEM(unit), &l2mc_entry, PORT_BITMAPf, 461 &pbmp); 462 BCM_PBMP_REMOVE(pbmp, mcaddr->pbmp); 463 soc_mem_pbmp_field_set(unit, L2MC_MCMEM(unit), &l2mc_entry, PORT_BITMAPf, 464 &pbmp); 465 466 SOC_IF_ERROR_RETURN(soc_mem_write(unit, L2MC_MCMEM(unit), MEM_BLOCK_ALL, 467 l2addr.l2mc_group, &l2mc_entry)); 468 469 return BCM_E_NONE; 470 } 471 472 /* 473 * Function: 474 * bcm_th3_mcast_port_remove 475 * Purpose: 476 * Remove ports from existing MC entry. 477 * Returns: 478 * BCM_E_XXX 479 */ 480 481 int 482 bcm_th3_mcast_port_remove(int unit, bcm_mcast_addr_t *mcaddr) 483 { 484 int rv; 485 486 L2MC_INIT(unit); 487 L2MC_LOCK(unit); 488 rv = _bcm_th3_mcast_port_delete(unit, mcaddr); 489 L2MC_UNLOCK(unit); 490 return rv; 491 } 492 493 /* 494 * Function: 495 * bcm_th3_mcast_port_add 496 * Purpose: 497 * Add ports to existing MC entry. 498 * Returns: 499 * BCM_E_XXX 500 */ 501 502 int 503 bcm_th3_mcast_port_add(int unit, bcm_mcast_addr_t *mcaddr) 504 { 505 int rv; 506 507 L2MC_INIT(unit); 508 L2MC_LOCK(unit); 509 rv = _bcm_th3_mcast_port_add(unit, mcaddr); 510 L2MC_UNLOCK(unit); 511 return rv; 512 } 513 514 /* 515 * Function: 516 * bcm_th3_mcast_addr_add_w_l2mcindex 517 * Purpose: 518 * Add a new MC entry to the L2 and L2MC tables, with given MC index. 519 * Returns: 520 * BCM_E_XXX 521 */ 522 523 int 524 bcm_th3_mcast_addr_add_w_l2mcindex(int unit, bcm_mcast_addr_t *mcaddr) 525 { 526 int rv; 527 528 L2MC_INIT(unit); 529 L2MC_LOCK(unit); 530 rv = _bcm_th3_mcast_create(unit, mcaddr, mcaddr->l2mc_index); 531 L2MC_UNLOCK(unit); 532 return rv; 533 } 534 535 /* 536 * Function: 537 * bcm_th3_mcast_addr_add 538 * Purpose: 539 * Add new L2 multicast entry 540 * Returns: 541 * BCM_E_XXX 542 */ 543 544 int 545 bcm_th3_mcast_addr_add(int unit, bcm_mcast_addr_t *mcaddr) 546 { 547 int rv; 548 549 L2MC_INIT(unit); 550 L2MC_LOCK(unit); 551 /* coverity[negative_returns : FALSE] */ 552 rv = _bcm_th3_mcast_create(unit, mcaddr, -1); 553 L2MC_UNLOCK(unit); 554 return rv; 555 } 556 557 /* 558 * Function: 559 * bcm_th3_mcast_addr_remove 560 * Purpose: 561 * Remove a multicast entry 562 * Returns: 563 * BCM_E_XXX 564 */ 565 566 int 567 bcm_th3_mcast_addr_remove(int unit, sal_mac_addr_t mac, bcm_vlan_t vid) 568 { 569 int rv; 570 bcm_l2_addr_t l2addr; 571 572 L2MC_INIT(unit); 573 L2MC_LOCK(unit); 574 575 bcm_l2_addr_t_init (&l2addr, mac, vid); 576 rv = bcm_tomahawk3_l2_addr_get(unit, mac, vid, &l2addr); 577 if (rv < 0) { 578 L2MC_UNLOCK(unit); 579 return rv; 580 } 581 582 if (!(l2addr.flags & BCM_L2_MCAST)) { 583 L2MC_UNLOCK(unit); 584 return BCM_E_NOT_FOUND; 585 } 586 587 rv = bcm_tomahawk3_l2_addr_delete(unit, mac, vid); 588 if (rv < 0) { 589 L2MC_UNLOCK(unit); 590 return rv; 591 } 592 593 /* Check added to avoid Segmentation fault in regression tests */ 594 /* Sometimes l2mc_index may not have a multicast type set when 595 * switchcontrol L2McIdxRetType is set to 0 596 */ 597 if (_BCM_MULTICAST_IS_L2(l2addr.l2mc_group) || 598 !_BCM_MULTICAST_IS_SET(l2addr.l2mc_group)) { 599 l2addr.l2mc_group = L2MC_ID_GET(l2addr.l2mc_group); 600 _bcm_th3_l2mc_id_free(unit, l2addr.l2mc_group); 601 602 if (!L2MC_USED_ISSET(unit, l2addr.l2mc_group)) { 603 rv = soc_mem_write(unit, L2MC_MCMEM(unit), MEM_BLOCK_ALL, 604 l2addr.l2mc_group, 605 soc_mem_entry_null(unit, L2MC_MCMEM(unit))); 606 } 607 } 608 609 L2MC_UNLOCK(unit); 610 return rv; 611 } 612 613 /* 614 * Function: 615 * bcm_th3_mcast_addr_remove_w_l2mcindex 616 * Purpose: 617 * Remove a multicast entry with l2mc index provided 618 * Returns: 619 * BCM_E_XXX 620 */ 621 622 int 623 bcm_th3_mcast_addr_remove_w_l2mcindex(int unit, 624 bcm_mcast_addr_t *mcaddr) 625 { 626 return bcm_th3_mcast_addr_remove(unit, mcaddr->mac, mcaddr->vid); 627 } 628 629 /* 630 * Function: 631 * _bcm_th3_mcast_index_port_get 632 * Purpose: 633 * Get port bit maps for a multicast group by index. 634 * Returns: 635 * BCM_E_XXX 636 */ 637 638 int 639 _bcm_th3_mcast_index_port_get(int unit, int l2mc_index, 640 bcm_mcast_addr_t *mcaddr) 641 { 642 l2mc_entry_t l2mc_entry; 643 644 L2MC_INIT(unit); 645 646 SOC_IF_ERROR_RETURN(soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY, 647 L2MC_ID_GET(l2mc_index), &l2mc_entry)); 648 649 soc_mem_pbmp_field_get(unit, L2MC_MCMEM(unit), &l2mc_entry, PORT_BITMAPf, 650 &mcaddr->pbmp); 651 652 return BCM_E_NONE; 653 } 654 655 /* 656 * Function: 657 * bcm_th3_mcast_port_get 658 * Purpose: 659 * Get port bit maps for a multicast group. 660 * Returns: 661 * BCM_E_XXX 662 */ 663 664 int 665 bcm_th3_mcast_port_get(int unit, 666 sal_mac_addr_t mac, bcm_vlan_t vid, 667 bcm_mcast_addr_t *mcaddr) 668 { 669 l2mc_entry_t l2mc_entry; 670 bcm_l2_addr_t l2addr; 671 672 L2MC_INIT(unit); 673 674 bcm_l2_addr_t_init (&l2addr, mac, vid); 675 BCM_IF_ERROR_RETURN(bcm_tomahawk3_l2_addr_get(unit, mac, vid, &l2addr)); 676 677 l2addr.l2mc_group = L2MC_ID_GET(l2addr.l2mc_group); 678 SOC_IF_ERROR_RETURN 679 (soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY, 680 l2addr.l2mc_group, &l2mc_entry)); 681 682 _bcm_th3_mcast_from_l2(unit, mcaddr, &l2addr); 683 soc_mem_pbmp_field_get(unit, L2MC_MCMEM(unit), &l2mc_entry, PORT_BITMAPf, 684 &mcaddr->pbmp); 685 686 return BCM_E_NONE; 687 } 688 689 /* 690 * Function: 691 * _bcm_th3_mcast_detach 692 * Purpose: 693 * De-initialize multicast api components 694 * Returns: 695 * BCM_E_XXX 696 */ 697 int 698 _bcm_th3_mcast_detach(int unit) 699 { 700 if (L2MC_USED(unit) != NULL) { 701 sal_free(L2MC_USED(unit)); 702 L2MC_USED(unit) = NULL; 703 } 704 L2MC_SIZE(unit) = 0; 705 L2MC_L2MEM(unit) = INVALIDm; 706 L2MC_MCMEM(unit) = INVALIDm; 707 708 return (BCM_E_NONE); 709 } 710 711 /* 712 * Function: 713 * bcm_th3_l2_addr_mcast_delete_all 714 * Purpose: 715 * Delete multicast address entries in l2 table 716 * Returns: 717 * BCM_E_XXX 718 */ 719 int 720 bcm_th3_l2_addr_mcast_delete_all(int unit) 721 { 722 /* Delete all multicast entries from L2 */ 723 if (!SAL_BOOT_QUICKTURN && !SAL_BOOT_BCMSIM && !SAL_BOOT_XGSSIM) { 724 if (!SAL_BOOT_BCMSIM) { 725 BCM_IF_ERROR_RETURN(_bcm_th3_l2_addr_delete_mcast(unit, 726 BCM_L2_DELETE_STATIC)); 727 } 728 } 729 730 return BCM_E_NONE; 731 } 732 733 /* 734 * Function: 735 * bcm_th3_mcast_init 736 * Purpose: 737 * Initialize multicast api components 738 * Returns: 739 * BCM_E_XXX on error 740 * number of mcast entries supported on success 741 */ 742 743 int 744 bcm_th3_mcast_init(int unit) 745 { 746 if (L2MC_USED(unit) != NULL) { 747 sal_free(L2MC_USED(unit)); 748 } 749 L2MC_SIZE(unit) = 0; 750 751 L2MC_L2MEM(unit) = L2Xm; 752 L2MC_MCMEM(unit) = L2MCm; 753 #if defined(BCM_BRADLEY_SUPPORT) || defined(BCM_TRX_SUPPORT) 754 if (SOC_IS_HBX(unit) || SOC_IS_TRX(unit)) { 755 int mc_base, mc_size; 756 757 #ifdef BCM_WARM_BOOT_SUPPORT 758 if (SOC_WARM_BOOT(unit)) { 759 uint32 mc_ctrl; 760 soc_control_t *soc = SOC_CONTROL(unit); 761 762 /* Recover the mcast size settings */ 763 if (SOC_REG_FIELD_VALID(unit, MC_CONTROL_5r, 764 SHARED_TABLE_L2MC_SIZEf) && 765 SOC_REG_FIELD_VALID(unit, MC_CONTROL_5r, 766 SHARED_TABLE_IPMC_SIZEf)) { 767 SOC_IF_ERROR_RETURN(READ_MC_CONTROL_5r(unit, &mc_ctrl)); 768 soc->mcast_size = 769 soc_reg_field_get(unit, MC_CONTROL_5r, mc_ctrl, 770 SHARED_TABLE_L2MC_SIZEf); 771 soc->ipmc_size = 772 soc_reg_field_get(unit, MC_CONTROL_5r, mc_ctrl, 773 SHARED_TABLE_IPMC_SIZEf); 774 } 775 776 } 777 #endif /* BCM_WARM_BOOT_SUPPORT */ 778 779 /* We will keep the hbx calls for now */ 780 SOC_IF_ERROR_RETURN 781 (soc_hbx_mcast_size_get(unit, &mc_base, &mc_size)); 782 783 L2MC_SIZE(unit) = mc_size; 784 } 785 #endif 786 787 if (L2MC_SIZE(unit) <= 0) { 788 L2MC_SIZE(unit) = soc_mem_index_count(unit, L2MC_MCMEM(unit)); 789 } 790 791 L2MC_USED(unit) = sal_alloc(sizeof(int) * L2MC_SIZE(unit), "L2MC"); 792 if (L2MC_USED(unit) == NULL) { 793 return BCM_E_MEMORY; 794 } 795 sal_memset(L2MC_USED(unit), 0, sizeof(int) * L2MC_SIZE(unit)); 796 797 #ifdef BCM_WARM_BOOT_SUPPORT 798 if (SOC_WARM_BOOT(unit)) { 799 l2x_entry_t *l2_entry, *l2_table; 800 l2mc_entry_t *l2mc_entry, *l2mc_table; 801 int index, index_min, index_max, l2mc_tbl_sz, l2_tbl_sz; 802 sal_mac_addr_t mcmac; 803 int iter, dma_iter = 1; 804 805 /* 806 * Go through L2 table to get MC use counts 807 */ 808 809 index_min = soc_mem_index_min(unit, L2MC_L2MEM(unit)); 810 index_max = soc_mem_index_max(unit, L2MC_L2MEM(unit)); 811 l2_tbl_sz = sizeof(l2x_entry_t) * (index_max - index_min + 1); 812 813 for (iter = 0; iter < dma_iter; iter++) { 814 l2_table = soc_cm_salloc(unit, l2_tbl_sz, "l2 tbl dma"); 815 if (l2_table == NULL) { 816 sal_free(L2MC_USED(unit)); 817 return BCM_E_MEMORY; 818 } 819 820 memset((void *)l2_table, 0, l2_tbl_sz); 821 if (soc_mem_read_range(unit, L2MC_L2MEM(unit), MEM_BLOCK_ANY, 822 index_min, index_max, l2_table) < 0) { 823 sal_free(L2MC_USED(unit)); 824 soc_cm_sfree(unit, l2_table); 825 return BCM_E_INTERNAL; 826 } 827 for (index = index_min; index <= index_max; index++) { 828 int l2mc_idx; 829 l2mc_entry_t mc_entry; 830 soc_field_t field_valid; 831 832 l2_entry = 833 soc_mem_table_idx_to_pointer(unit, L2MC_L2MEM(unit), 834 l2x_entry_t *, l2_table, 835 index - index_min); 836 field_valid = BASE_VALIDf; 837 if (!soc_mem_field32_get(unit, L2MC_L2MEM(unit), l2_entry, 838 field_valid)) { 839 continue; 840 } 841 842 if (soc_mem_field_valid(unit, L2MC_L2MEM(unit), KEY_TYPEf) 843 && (soc_mem_field32_get(unit, L2MC_L2MEM(unit), 844 l2_entry, KEY_TYPEf) != 845 TH3_L2_HASH_KEY_TYPE_BRIDGE)) { 846 847 /* Field L2MC_PTRf is only valid for key type BRIDGE */ 848 continue; 849 } 850 851 soc_L2Xm_mac_addr_get(unit, l2_entry, MAC_ADDRf, mcmac); 852 if (!BCM_MAC_IS_MCAST(mcmac)) { 853 continue; 854 } 855 856 l2mc_idx = soc_mem_field32_get(unit, L2MC_L2MEM(unit), 857 l2_entry, L2MC_PTRf); 858 sal_memset(&mc_entry, 0, sizeof(l2mc_entry_t)); 859 if (soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY, 860 l2mc_idx, &mc_entry) < 0) { 861 sal_free(L2MC_USED(unit)); 862 soc_cm_sfree(unit, l2_table); 863 return BCM_E_INTERNAL; 864 } 865 866 if (!soc_mem_field32_get(unit, L2MC_MCMEM(unit), &mc_entry, 867 VALIDf)) { 868 continue; 869 } 870 871 L2MC_USED_SET(unit, l2mc_idx); 872 } 873 soc_cm_sfree(unit, l2_table); 874 } 875 876 /* 877 * But then L2 table may not have indices populated for 878 * all valid L2MC entries. 879 * Go through L2MC table to search for existing entries 880 */ 881 index_min = soc_mem_index_min(unit, L2MC_MCMEM(unit)); 882 index_max = index_min + L2MC_SIZE(unit) - 1; 883 884 l2mc_tbl_sz = sizeof(l2mc_entry_t) * L2MC_SIZE(unit); 885 l2mc_table = soc_cm_salloc(unit, l2mc_tbl_sz, "l2mc tbl dma"); 886 if (l2mc_table == NULL) { 887 sal_free(L2MC_USED(unit)); 888 return BCM_E_MEMORY; 889 } 890 891 memset((void *)l2mc_table, 0, l2mc_tbl_sz); 892 if (soc_mem_read_range(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY, 893 index_min, index_max, l2mc_table) < 0) { 894 sal_free(L2MC_USED(unit)); 895 soc_cm_sfree(unit, l2mc_table); 896 return BCM_E_INTERNAL; 897 } 898 899 for (index = index_min; index <= index_max; index++) { 900 901 l2mc_entry = soc_mem_table_idx_to_pointer(unit, L2MC_MCMEM(unit), 902 l2mc_entry_t *, 903 l2mc_table, index); 904 905 if (!soc_mem_field32_get(unit, L2MC_MCMEM(unit), 906 l2mc_entry, VALIDf)) { 907 continue; 908 } 909 910 if (!L2MC_USED_ISSET(unit, index)) { 911 L2MC_USED_SET(unit, index); 912 } 913 } 914 915 soc_cm_sfree(unit, l2mc_table); 916 917 return L2MC_SIZE(unit); 918 } 919 #endif /* BCM_WARM_BOOT_SUPPORT */ 920 921 if (!SAL_BOOT_BCMSIM && !SAL_BOOT_QUICKTURN && !SAL_BOOT_XGSSIM) { 922 SOC_IF_ERROR_RETURN 923 (soc_mem_clear(unit, L2MC_MCMEM(unit), MEM_BLOCK_ALL, FALSE)); 924 } 925 926 BCM_IF_ERROR_RETURN(bcm_th3_l2_addr_mcast_delete_all(unit)); 927 928 return L2MC_SIZE(unit); 929 } 930 931 #ifndef BCM_SW_STATE_DUMP_DISABLE 932 /* 933 * Function: 934 * _bcm_th3_l2_mcast_sw_dump 935 * Purpose: 936 * Displays TH3 mcast information maintained by software. 937 * Parameters: 938 * unit - Device unit number 939 * Returns: 940 * None 941 */ 942 void 943 _bcm_th3_l2_mcast_sw_dump(int unit) 944 { 945 _bcm_th3_l2_mcast_t *info; 946 int *used; 947 int i, j; 948 949 info = &th3_l2mc_info[unit]; 950 951 LOG_CLI((BSL_META_U(unit, 952 "\n L2 MCAST -\n"))); 953 LOG_CLI((BSL_META_U(unit, 954 " Size : %d\n"), info->size)); 955 LOG_CLI((BSL_META_U(unit, 956 " L2 Mem : %d\n"), info->l2mem)); 957 LOG_CLI((BSL_META_U(unit, 958 " MC Mem : %d\n"), info->mcmem)); 959 960 LOG_CLI((BSL_META_U(unit, 961 " Used (index:value) :"))); 962 used = info->used; 963 if (used != NULL) { 964 for (i = 0, j = 0; i < info->size; i++) { 965 /* If zero, skip print */ 966 if (used[i] == 0) { 967 continue; 968 } 969 if (!(j % 4)) { 970 LOG_CLI((BSL_META_U(unit, 971 "\n "))); 972 } 973 LOG_CLI((BSL_META_U(unit, 974 " %4d:%-5d"), i, used[i])); 975 j++; 976 } 977 } 978 LOG_CLI((BSL_META_U(unit, 979 "\n"))); 980 981 return; 982 } 983 #endif /* BCM_SW_STATE_DUMP_DISABLE */ 984 #endif /* BCM_TOMAHAWK3_SUPPORT */