ipmc.c (120246B)
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: ipmc.c 8 * Purpose: Tracks and manages IPMC tables. 9 */ 10 11 #ifdef INCLUDE_L3 12 #include <shared/bsl.h> 13 #include <shared/l3.h> 14 #include <soc/l3x.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/ipmc.h> 21 22 #include <bcm_int/esw/ipmc.h> 23 #include <bcm_int/esw/mbcm.h> 24 #include <bcm_int/esw/firebolt.h> 25 #include <bcm_int/esw/trx.h> 26 #include <bcm_int/esw/stack.h> 27 #include <bcm_int/esw/bradley.h> 28 #include <bcm_int/esw/triumph.h> 29 #include <bcm_int/common/multicast.h> 30 #include <bcm_int/esw/multicast.h> 31 32 #ifdef BCM_TRIUMPH2_SUPPORT 33 #include <bcm_int/esw/triumph2.h> 34 #endif /* BCM_TRIUMPH2_SUPPORT */ 35 #if defined(BCM_TRIUMPH3_SUPPORT) || defined(BCM_KATANA2_SUPPORT) 36 #include <bcm_int/esw/triumph3.h> 37 #endif /* BCM_TRIUMPH3_SUPPORT */ 38 #ifdef BCM_TRIDENT2_SUPPORT 39 #include <soc/trident2.h> 40 #include <bcm_int/esw/trident2.h> 41 #endif /* BCM_TRIDENT2_SUPPORT */ 42 #ifdef BCM_TRIDENT2PLUS_SUPPORT 43 #include <bcm_int/esw/trident2plus.h> 44 #endif /* BCM_TRIDENT2PLUS_SUPPORT */ 45 46 #ifdef BCM_KATANA2_SUPPORT 47 #include <bcm_int/esw/katana2.h> 48 #endif /* BCM_KATANA2_SUPPORT */ 49 #ifdef BCM_TOMAHAWK_SUPPORT 50 #include <bcm_int/esw/tomahawk.h> 51 #endif /* BCM_TOMAHAWK_SUPPORT */ 52 53 #ifdef BCM_SABER2_SUPPORT 54 #include <bcm_int/esw/saber2.h> 55 #endif /* BCM_SABER2_SUPPORT */ 56 #include <bcm_int/esw_dispatch.h> 57 58 /* 59 * to define the no_src_check_port_id chip specific value : 60 * - GREYHOUND : 0x1f 61 * - HURRICANE3 : 0x3f 62 * - GREYHOUND2 : 0x7f 63 */ 64 #define TR_IPMC_NO_SRC_CHECK_PORT_DEFAULT (0x3f) 65 #define TR_IPMC_NO_SRC_CHECK_PORT(unit) ((SOC_IS_TD_TT(unit) || \ 66 SOC_IS_TRIUMPH3(unit) || \ 67 SOC_IS_KATANAX(unit) || \ 68 SOC_IS_GREYHOUND2(unit)) ? 0x7f : \ 69 ((SOC_IS_ENDURO(unit) || \ 70 SOC_IS_HURRICANE(unit) || \ 71 SOC_IS_HURRICANE2(unit) || \ 72 SOC_IS_GREYHOUND(unit)) ? 0x1f : \ 73 SOC_IS_HURRICANE3(unit) ? 0x3f : \ 74 TR_IPMC_NO_SRC_CHECK_PORT_DEFAULT)) 75 76 /* 77 * Function: 78 * _bcm_tr_ipmc_l3entry_list_add 79 * Purpose: 80 * Add a L3 entry to IPMC group's linked list of L3 entries 81 * Parameters: 82 * unit - (IN) BCM device number. 83 * ipmc_index - (IN) IPMC group ID. 84 * _bcm_l3_cfg_t - (IN) l3 config structure 85 * Returns: 86 * BCM_E_XXX 87 */ 88 STATIC int 89 _bcm_tr_ipmc_l3entry_list_add(int unit, int ipmc_index, 90 _bcm_l3_cfg_t *l3cfg) 91 { 92 _bcm_esw_ipmc_l3entry_t *ipmc_l3entry; 93 94 ipmc_l3entry = sal_alloc(sizeof(_bcm_esw_ipmc_l3entry_t), "IPMC L3 entry"); 95 sal_memset(ipmc_l3entry, 0, sizeof(_bcm_esw_ipmc_l3entry_t)); 96 if (ipmc_l3entry == NULL) { 97 return BCM_E_MEMORY; 98 } 99 ipmc_l3entry->ip6 = (l3cfg->l3c_flags & BCM_L3_IP6) ? 1 : 0; 100 ipmc_l3entry->l3info.flags = l3cfg->l3c_flags; 101 ipmc_l3entry->l3info.vrf = l3cfg->l3c_vrf; 102 ipmc_l3entry->l3info.ip_addr = l3cfg->l3c_ipmc_group; 103 ipmc_l3entry->l3info.src_ip_addr = l3cfg->l3c_src_ip_addr; 104 sal_memcpy(ipmc_l3entry->l3info.ip6, l3cfg->l3c_ip6, BCM_IP6_ADDRLEN); 105 sal_memcpy(ipmc_l3entry->l3info.sip6, l3cfg->l3c_sip6, BCM_IP6_ADDRLEN); 106 ipmc_l3entry->l3info.vid = l3cfg->l3c_vid; 107 ipmc_l3entry->l3info.ing_intf = l3cfg->l3c_ing_intf; 108 ipmc_l3entry->l3info.prio = l3cfg->l3c_prio; 109 ipmc_l3entry->l3info.ipmc_ptr = l3cfg->l3c_ipmc_ptr; 110 ipmc_l3entry->l3info.ipmc_ptr_l2 = l3cfg->l3c_ipmc_ptr_l2; 111 ipmc_l3entry->l3info.lookup_class = l3cfg->l3c_lookup_class; 112 ipmc_l3entry->l3info.rp_id = l3cfg->l3c_rp_id; 113 #ifdef BCM_TRIDENT3_SUPPORT 114 if (soc_feature(unit, soc_feature_flex_flow)) { 115 ipmc_l3entry->l3info.flow_handle = l3cfg->l3c_flow_handle; 116 ipmc_l3entry->l3info.flow_option_handle = l3cfg->l3c_flow_option_handle; 117 ipmc_l3entry->l3info.num_logical_fields = l3cfg->l3c_num_of_fields; 118 sal_memcpy(ipmc_l3entry->l3info.logical_fields, l3cfg->l3c_logical_fields, 119 l3cfg->l3c_num_of_fields*sizeof(bcm_flow_logical_field_t)); 120 } 121 #endif /* BCM_TRIDENT3_SUPPORT */ 122 ipmc_l3entry->next = IPMC_GROUP_INFO(unit, ipmc_index)->l3entry_list; 123 IPMC_GROUP_INFO(unit, ipmc_index)->l3entry_list = ipmc_l3entry; 124 125 return BCM_E_NONE; 126 } 127 128 /* 129 * Function: 130 * _bcm_tr_ipmc_l3entry_list_del 131 * Purpose: 132 * Delete a L3 entry from IPMC group's linked list of L3 entries 133 * Parameters: 134 * unit - (IN) BCM device number. 135 * ipmc_index - (IN) IPMC group ID. 136 * _bcm_l3_cfg_t - (IN) l3 config structure 137 * Returns: 138 * BCM_E_XXX 139 */ 140 STATIC int 141 _bcm_tr_ipmc_l3entry_list_del(int unit, int ipmc_index, 142 _bcm_l3_cfg_t *l3cfg) 143 { 144 _bcm_esw_ipmc_l3entry_t *ipmc_l3entry; 145 _bcm_esw_ipmc_l3entry_t *prev_ipmc_l3entry = NULL; 146 uint8 matched=0; 147 148 ipmc_l3entry = IPMC_GROUP_INFO(unit, ipmc_index)->l3entry_list; 149 while (ipmc_l3entry != NULL) { 150 if ((ipmc_l3entry->l3info.ip_addr == l3cfg->l3c_ip_addr) && 151 (ipmc_l3entry->l3info.src_ip_addr == l3cfg->l3c_src_ip_addr) && 152 (!_shr_ip6_addr_compare(ipmc_l3entry->l3info.ip6, l3cfg->l3c_ip6)) && 153 (!_shr_ip6_addr_compare(ipmc_l3entry->l3info.sip6, l3cfg->l3c_sip6)) && 154 (ipmc_l3entry->l3info.vrf == l3cfg->l3c_vrf)) { 155 156 if((ipmc_l3entry->l3info.flags & BCM_L3_L2ONLY) || 157 (ipmc_l3entry->l3info.ing_intf == BCM_IF_INVALID)) { 158 matched = (ipmc_l3entry->l3info.vid == l3cfg->l3c_vid) ? 1 : 0; 159 } else { 160 matched = (ipmc_l3entry->l3info.ing_intf == l3cfg->l3c_ing_intf) ? 1 : 0; 161 } 162 if(matched) { 163 if (ipmc_l3entry == IPMC_GROUP_INFO(unit, ipmc_index)->l3entry_list) { 164 IPMC_GROUP_INFO(unit, ipmc_index)->l3entry_list = ipmc_l3entry->next; 165 } else { 166 /* 167 * In the following line of code, Coverity thinks the 168 * prev_ipmc_l3entry pointer may still be NULL when 169 * dereferenced. This situation will never occur because 170 * if ipmc_l3entry is not pointing to the head of the 171 * linked list, prev_ipmc_l3entry would not be NULL. 172 */ 173 /* coverity[var_deref_op : FALSE] */ 174 prev_ipmc_l3entry->next = ipmc_l3entry->next; 175 } 176 sal_free(ipmc_l3entry); 177 break; 178 } 179 } 180 prev_ipmc_l3entry = ipmc_l3entry; 181 ipmc_l3entry = ipmc_l3entry->next; 182 } 183 184 if (ipmc_l3entry == NULL) { 185 return BCM_E_NOT_FOUND; 186 } 187 188 return BCM_E_NONE; 189 } 190 191 STATIC int 192 _bcm_tr_ipmc_l3entry_list_update(int unit, int ipmc_index, 193 _bcm_l3_cfg_t *l3cfg) 194 { 195 _bcm_esw_ipmc_l3entry_t *ipmc_l3entry; 196 uint8 matched; 197 198 ipmc_l3entry = IPMC_GROUP_INFO(unit, ipmc_index)->l3entry_list; 199 while (ipmc_l3entry != NULL) { 200 if ((ipmc_l3entry->l3info.ip_addr == l3cfg->l3c_ip_addr) && 201 (ipmc_l3entry->l3info.src_ip_addr == l3cfg->l3c_src_ip_addr) && 202 (!sal_memcmp(ipmc_l3entry->l3info.ip6, l3cfg->l3c_ip6, BCM_IP6_ADDRLEN)) && 203 (!sal_memcmp(ipmc_l3entry->l3info.sip6, l3cfg->l3c_sip6, BCM_IP6_ADDRLEN)) && 204 (ipmc_l3entry->l3info.ing_intf == l3cfg->l3c_ing_intf) && 205 (ipmc_l3entry->l3info.vid == l3cfg->l3c_vid) && 206 (ipmc_l3entry->l3info.vrf == l3cfg->l3c_vrf)) { 207 208 if((ipmc_l3entry->l3info.flags & BCM_L3_L2ONLY) || 209 (ipmc_l3entry->l3info.ing_intf == BCM_IF_INVALID)) { 210 matched = (ipmc_l3entry->l3info.vid == l3cfg->l3c_vid) ? 1 : 0; 211 } else { 212 matched = (ipmc_l3entry->l3info.ing_intf == l3cfg->l3c_ing_intf) ? 1 : 0; 213 } 214 215 if(matched) { 216 /* set new values */ 217 ipmc_l3entry->l3info.flags = l3cfg->l3c_flags; 218 ipmc_l3entry->l3info.vrf = l3cfg->l3c_vrf; 219 ipmc_l3entry->l3info.prio = l3cfg->l3c_prio; 220 ipmc_l3entry->l3info.ipmc_ptr = l3cfg->l3c_ipmc_ptr; 221 ipmc_l3entry->l3info.ipmc_ptr_l2 = l3cfg->l3c_ipmc_ptr_l2; 222 ipmc_l3entry->l3info.lookup_class = l3cfg->l3c_lookup_class; 223 ipmc_l3entry->l3info.rp_id = l3cfg->l3c_rp_id; 224 ipmc_l3entry->l3info.vid = l3cfg->l3c_vid; 225 ipmc_l3entry->l3info.ing_intf = l3cfg->l3c_ing_intf; 226 } 227 break; 228 } 229 ipmc_l3entry = ipmc_l3entry->next; 230 } 231 232 if (ipmc_l3entry == NULL) { 233 return BCM_E_NOT_FOUND; 234 } 235 236 return BCM_E_NONE; 237 } 238 239 /* 240 * Function: 241 * _bcm_tr_ipmc_l3entry_list_size_get 242 * Purpose: 243 * Get the number of L3 entries in IPMC group's linked list. 244 * Parameters: 245 * unit - (IN) BCM device number. 246 * ipmc_index - (IN) IPMC group ID. 247 * size - (OUT) Number of L3 entries. 248 * Returns: 249 * BCM_E_XXX 250 */ 251 STATIC int 252 _bcm_tr_ipmc_l3entry_list_size_get(int unit, int ipmc_index, 253 int *size) 254 { 255 if (IPMC_USED_ISSET(unit, ipmc_index)) { 256 *size = IPMC_GROUP_INFO(unit, ipmc_index)->ref_count - 1; 257 } else { 258 *size = 0; 259 } 260 261 return BCM_E_NONE; 262 } 263 264 #ifdef BCM_TRIUMPH2_SUPPORT 265 /* 266 * Function: 267 * _tr2_ipmc_glp_get 268 * Purpose: 269 * Fill source information to bcm_ipmc_addr_t struct. 270 */ 271 int 272 _tr2_ipmc_glp_get(int unit, bcm_ipmc_addr_t *ipmc, ipmc_1_entry_t *entry) 273 274 { 275 int mod, port_tgid, is_trunk, rv = BCM_E_NONE; 276 int no_src_check = FALSE; 277 int modid_max = 0; 278 279 is_trunk = soc_L3_IPMC_1m_field32_get(unit, entry, Tf); 280 mod = soc_L3_IPMC_1m_field32_get(unit, entry, MODULE_IDf); 281 port_tgid = soc_L3_IPMC_1m_field32_get(unit, entry, PORT_NUMf); 282 #ifdef BCM_METROLITE_SUPPORT 283 if (SOC_IS_METROLITE(unit)) { 284 modid_max = SOC_MEM_FIELD32_VALUE_MAX( 285 unit, L3_IPMC_1m, MODULE_IDf); 286 }else 287 #endif 288 { 289 modid_max = SOC_MODID_MAX(unit); 290 } 291 if (is_trunk) { 292 if ((port_tgid == TR_IPMC_NO_SRC_CHECK_PORT(unit)) && 293 (mod == modid_max)) { 294 no_src_check = TRUE; 295 } else { 296 mod = 0; 297 port_tgid = soc_L3_IPMC_1m_field32_get(unit, entry, TGIDf); 298 } 299 } 300 if (no_src_check) { 301 ipmc->ts = 0; 302 ipmc->mod_id = -1; 303 ipmc->port_tgid = -1; 304 ipmc->flags |= BCM_IPMC_SOURCE_PORT_NOCHECK; 305 } else if (is_trunk) { 306 ipmc->ts = 1; 307 ipmc->mod_id = 0; 308 ipmc->port_tgid = port_tgid; 309 } else { 310 bcm_module_t mod_in, mod_out; 311 bcm_port_t port_in, port_out; 312 313 mod_in = mod; 314 port_in = port_tgid; 315 BCM_IF_ERROR_RETURN 316 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET, 317 mod_in, port_in, 318 &mod_out, &port_out)); 319 ipmc->ts = 0; 320 ipmc->mod_id = mod_out; 321 ipmc->port_tgid = port_out; 322 } 323 return rv; 324 } 325 #endif 326 327 /* 328 * Function: 329 * _tr_ipmc_info_get 330 * Purpose: 331 * Fill information in bcm_ipmc_addr_t struct. 332 */ 333 334 STATIC int 335 _tr_ipmc_info_get(int unit, int ipmc_index, bcm_ipmc_addr_t *ipmc, 336 ipmc_entry_t *entry, uint8 do_l3_lkup, 337 _bcm_esw_ipmc_l3entry_t *use_ipmc_l3entry) 338 { 339 int mod = -1, port_tgid = -1, is_trunk = 0; 340 int no_src_check = FALSE; 341 int modid_max = 0; 342 343 ipmc->v = soc_L3_IPMCm_field32_get(unit, entry, VALIDf); 344 #ifdef BCM_METROLITE_SUPPORT 345 if (SOC_IS_METROLITE(unit)) { 346 modid_max = SOC_MEM_FIELD32_VALUE_MAX( 347 unit, L3_IPMC_1m, MODULE_IDf); 348 }else 349 #endif 350 { 351 modid_max = SOC_MODID_MAX(unit); 352 } 353 354 if (soc_mem_field_valid(unit, L3_IPMCm, PORT_NUMf)) { 355 is_trunk = soc_L3_IPMCm_field32_get(unit, entry, Tf); 356 mod = soc_L3_IPMCm_field32_get(unit, entry, MODULE_IDf); 357 port_tgid = soc_L3_IPMCm_field32_get(unit, entry, PORT_NUMf); 358 if (is_trunk) { 359 if ((port_tgid == TR_IPMC_NO_SRC_CHECK_PORT(unit)) && 360 (mod == modid_max)) { 361 no_src_check = TRUE; 362 } else { 363 mod = 0; 364 port_tgid = soc_L3_IPMCm_field32_get(unit, entry, TGIDf); 365 } 366 } 367 if (no_src_check) { 368 ipmc->ts = 0; 369 ipmc->mod_id = -1; 370 ipmc->port_tgid = -1; 371 ipmc->flags |= BCM_IPMC_SOURCE_PORT_NOCHECK; 372 } else if (is_trunk) { 373 ipmc->ts = 1; 374 ipmc->mod_id = 0; 375 ipmc->port_tgid = port_tgid; 376 } else { 377 bcm_module_t mod_in, mod_out; 378 bcm_port_t port_in, port_out; 379 380 mod_in = mod; 381 port_in = port_tgid; 382 BCM_IF_ERROR_RETURN 383 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET, 384 mod_in, port_in, 385 &mod_out, &port_out)); 386 ipmc->ts = 0; 387 ipmc->mod_id = mod_out; 388 ipmc->port_tgid = port_out; 389 } 390 } 391 392 if ((ipmc->v) && (do_l3_lkup)) { 393 _bcm_l3_cfg_t l3cfg; 394 _bcm_esw_ipmc_l3entry_t *ipmc_l3entry; 395 396 if (use_ipmc_l3entry) { 397 /* use the passed in l3 info */ 398 ipmc_l3entry = use_ipmc_l3entry; 399 } else { 400 /* Note: this simply picks up the first l3 info */ 401 ipmc_l3entry = IPMC_GROUP_INFO(unit, ipmc_index)->l3entry_list; 402 if (NULL == ipmc_l3entry) { 403 /* No entries in Multicast host table */ 404 return BCM_E_EMPTY; 405 } 406 } 407 sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t)); 408 l3cfg.l3c_flags = BCM_L3_IPMC; 409 l3cfg.l3c_vrf = ipmc_l3entry->l3info.vrf; 410 l3cfg.l3c_vid = ipmc_l3entry->l3info.vid; 411 l3cfg.l3c_ing_intf = ipmc_l3entry->l3info.ing_intf; 412 413 if (ipmc_l3entry->l3info.flags & BCM_L3_L2ONLY) { 414 l3cfg.l3c_flags |= BCM_L3_L2ONLY; 415 ipmc->flags |= BCM_IPMC_L2; 416 } 417 if (ipmc_l3entry->ip6) { 418 ipmc->flags |= BCM_IPMC_IP6; 419 } else { 420 ipmc->flags &= ~BCM_IPMC_IP6; 421 } 422 if (ipmc->flags & BCM_IPMC_HIT_CLEAR) { 423 l3cfg.l3c_flags |= BCM_L3_HIT_CLEAR; 424 } 425 426 /* need to get current l3 info from h/w like hit bits */ 427 if (ipmc->flags & BCM_IPMC_IP6) { 428 sal_memcpy(ipmc->s_ip6_addr, &ipmc_l3entry->l3info.sip6, BCM_IP6_ADDRLEN); 429 sal_memcpy(ipmc->mc_ip6_addr, &ipmc_l3entry->l3info.ip6, BCM_IP6_ADDRLEN); 430 sal_memcpy(l3cfg.l3c_sip6, &ipmc_l3entry->l3info.sip6, BCM_IP6_ADDRLEN); 431 sal_memcpy(l3cfg.l3c_ip6, &ipmc_l3entry->l3info.ip6, BCM_IP6_ADDRLEN); 432 l3cfg.l3c_flags |= BCM_L3_IP6; 433 BCM_IF_ERROR_RETURN(mbcm_driver[unit]->mbcm_l3_ip6_get(unit, &l3cfg)); 434 } else { 435 ipmc->s_ip_addr = ipmc_l3entry->l3info.src_ip_addr; 436 ipmc->mc_ip_addr = ipmc_l3entry->l3info.ipmc_group; 437 l3cfg.l3c_src_ip_addr = ipmc_l3entry->l3info.src_ip_addr; 438 l3cfg.l3c_ipmc_group = ipmc_l3entry->l3info.ipmc_group; 439 BCM_IF_ERROR_RETURN(mbcm_driver[unit]->mbcm_l3_ip4_get(unit, &l3cfg)); 440 } 441 442 if (l3cfg.l3c_flags & BCM_L3_HIT) { 443 ipmc->flags |= BCM_IPMC_HIT; 444 } 445 446 if (l3cfg.l3c_flags & BCM_IPMC_POST_LOOKUP_RPF_CHECK) { 447 ipmc->flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK; 448 ipmc->l3a_intf = l3cfg.l3c_intf; 449 if (l3cfg.l3c_flags & BCM_IPMC_RPF_FAIL_DROP) { 450 ipmc->flags |= BCM_IPMC_RPF_FAIL_DROP; 451 } 452 if (l3cfg.l3c_flags & BCM_IPMC_RPF_FAIL_TOCPU) { 453 ipmc->flags |= BCM_IPMC_RPF_FAIL_TOCPU; 454 } 455 } 456 457 #ifdef BCM_MONTEREY_SUPPORT 458 if (l3cfg.l3c_flags2 & BCM_L3_FLAGS2_DECAP_ROE_HEADER) { 459 ipmc->flags |= BCM_IPMC_DECAP_ROE_HEADER; 460 } 461 #endif 462 463 if (ipmc_l3entry->l3info.flags & BCM_L3_RPE) { 464 ipmc->cos = ipmc_l3entry->l3info.prio; 465 ipmc->flags |= BCM_IPMC_SETPRI; 466 } else { 467 ipmc->cos = -1; 468 ipmc->flags &= ~BCM_IPMC_SETPRI; 469 } 470 ipmc->group = ipmc_index; 471 ipmc->lookup_class = ipmc_l3entry->l3info.lookup_class; 472 ipmc->vrf = ipmc_l3entry->l3info.vrf; 473 ipmc->vid = ipmc_l3entry->l3info.vid; 474 ipmc->ing_intf = ipmc_l3entry->l3info.ing_intf; 475 ipmc->rp_id = ipmc_l3entry->l3info.rp_id; 476 } 477 478 return BCM_E_NONE; 479 } 480 481 /* 482 * Function: 483 * _tr_ipmc_write 484 * Purpose: 485 * Write an ipmc entry from bcm_ipmc_addr_t struct. 486 */ 487 488 STATIC int 489 _tr_ipmc_write(int unit, int ipmc_id, bcm_ipmc_addr_t *ipmc) 490 { 491 int rv = BCM_E_NONE; 492 ipmc_entry_t entry; 493 int mod, port_tgid, is_trunk, no_src_check = FALSE; 494 int valid_chg = FALSE; 495 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT) 496 ipmc_1_entry_t entry_1; 497 sal_memset(&entry_1, 0, sizeof(ipmc_1_entry_t)); 498 #endif 499 500 BCM_IF_ERROR_RETURN 501 (soc_mem_read(unit, L3_IPMCm, MEM_BLOCK_ANY, ipmc_id, &entry)); 502 503 if (ipmc->v != soc_L3_IPMCm_field32_get(unit, &entry, VALIDf)) { 504 valid_chg = TRUE; 505 soc_L3_IPMCm_field32_set(unit, &entry, VALIDf, ipmc->v); 506 } 507 508 if (soc_feature(unit, soc_feature_src_port_consistency_check_skip)) { 509 /* Source port check for L3 Multicast has been moved in lookup table in Tomahawk, 510 * hence no need to write in replication table for Tomahawk 511 */ 512 if (valid_chg) { 513 rv = soc_mem_write(unit, L3_IPMCm, MEM_BLOCK_ALL, ipmc_id, &entry); 514 } 515 return rv; 516 } 517 518 if ((ipmc->flags & BCM_IPMC_SOURCE_PORT_NOCHECK) || 519 (ipmc->port_tgid < 0)) { /* no source port */ 520 no_src_check = TRUE; 521 is_trunk = 0; 522 #ifdef BCM_METROLITE_SUPPORT 523 if (SOC_IS_METROLITE(unit)) { 524 mod = SOC_MEM_FIELD32_VALUE_MAX(unit, L3_IPMC_1m, MODULE_IDf); 525 } else 526 #endif 527 { 528 mod = SOC_MODID_MAX(unit); 529 } 530 port_tgid = TR_IPMC_NO_SRC_CHECK_PORT(unit); 531 } else if (ipmc->ts) { /* trunk source port */ 532 is_trunk = 1; 533 mod = 0; 534 port_tgid = ipmc->port_tgid; 535 } else { /* source port */ 536 bcm_module_t mod_in, mod_out; 537 bcm_port_t port_in, port_out; 538 539 mod_in = ipmc->mod_id; 540 port_in = ipmc->port_tgid; 541 BCM_IF_ERROR_RETURN 542 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET, 543 mod_in, port_in, 544 &mod_out, &port_out)); 545 /* Check parameters, since above is an application callback */ 546 if (!SOC_MODID_ADDRESSABLE(unit, mod_out)) { 547 return BCM_E_BADID; 548 } 549 if (!SOC_PORT_ADDRESSABLE(unit, port_out)) { 550 return BCM_E_PORT; 551 } 552 is_trunk = 0; 553 mod = mod_out; 554 port_tgid = port_out; 555 } 556 557 if (is_trunk) { 558 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT) 559 if (SOC_MEM_IS_VALID(unit, L3_IPMC_1m)) { 560 soc_L3_IPMC_1m_field32_set(unit, &entry_1, Tf, 1); 561 soc_L3_IPMC_1m_field32_set(unit, &entry_1, TGIDf, port_tgid); 562 } else 563 #endif 564 { 565 if (soc_mem_field_valid(unit, L3_IPMCm, Tf)) { 566 soc_L3_IPMCm_field32_set(unit, &entry, Tf, 1); 567 } 568 if (soc_mem_field_valid(unit, L3_IPMCm, TGIDf)) { 569 soc_L3_IPMCm_field32_set(unit, &entry, TGIDf, port_tgid); 570 } 571 } 572 } else { 573 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT) 574 if (SOC_MEM_IS_VALID(unit, L3_IPMC_1m)) { 575 soc_L3_IPMC_1m_field32_set(unit, &entry_1, MODULE_IDf, mod); 576 soc_L3_IPMC_1m_field32_set(unit, &entry_1, PORT_NUMf, port_tgid); 577 if (no_src_check) { 578 soc_L3_IPMC_1m_field32_set(unit, &entry_1, Tf, 1); 579 } else { 580 soc_L3_IPMC_1m_field32_set(unit, &entry_1, Tf, 0); 581 } 582 } else 583 #endif 584 { 585 if (soc_mem_field_valid(unit, L3_IPMCm, MODULE_IDf)) { 586 soc_L3_IPMCm_field32_set(unit, &entry, MODULE_IDf, mod); 587 } 588 589 if (soc_mem_field_valid(unit, L3_IPMCm, PORT_NUMf)) { 590 soc_L3_IPMCm_field32_set(unit, &entry, PORT_NUMf, port_tgid); 591 } 592 593 if (soc_mem_field_valid(unit, L3_IPMCm, Tf)) { 594 if (no_src_check) { 595 soc_L3_IPMCm_field32_set(unit, &entry, Tf, 1); 596 } else { 597 soc_L3_IPMCm_field32_set(unit, &entry, Tf, 0); 598 } 599 } 600 } 601 } 602 603 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT) 604 if (SOC_MEM_IS_VALID(unit, L3_IPMC_1m)) { 605 if (valid_chg) { 606 BCM_IF_ERROR_RETURN( 607 soc_mem_write(unit, L3_IPMCm, MEM_BLOCK_ALL, ipmc_id, &entry)); 608 } 609 rv = soc_mem_write(unit, L3_IPMC_1m, MEM_BLOCK_ALL, ipmc_id, &entry_1); 610 return (rv); 611 } else 612 #endif 613 { 614 rv = soc_mem_write(unit, L3_IPMCm, MEM_BLOCK_ALL, ipmc_id, &entry); 615 } 616 617 return (rv); 618 } 619 620 /* 621 * Function: 622 * _tr_ipmc_enable 623 * Purpose: 624 * Enable/disable IPMC support. 625 * Parameters: 626 * unit - StrataSwitch PCI device unit number (driver internal). 627 * enable - TRUE: enable IPMC support. 628 * FALSE: disable IPMC support. 629 * Returns: 630 * BCM_E_XXX 631 */ 632 633 STATIC int 634 _tr_ipmc_enable(int unit, int enable) 635 { 636 int port, do_vlan; 637 bcm_pbmp_t port_pbmp; 638 soc_field_t flds[3] = {V4IPMC_ENABLEf, V6IPMC_ENABLEf, IPMC_DO_VLANf}; 639 uint32 vals[3]; 640 641 enable = enable ? 1 : 0; 642 do_vlan = soc_property_get(unit, spn_IPMC_DO_VLAN, 1); 643 644 BCM_PBMP_CLEAR(port_pbmp); 645 BCM_PBMP_ASSIGN(port_pbmp, PBMP_PORT_ALL(unit)); 646 647 #ifdef BCM_KATANA2_SUPPORT 648 if (SOC_IS_KATANA2(unit) && soc_feature(unit, soc_feature_flex_port)) { 649 BCM_IF_ERROR_RETURN(_bcm_kt2_flexio_pbmp_update(unit, &port_pbmp)); 650 } 651 if (soc_feature(unit, soc_feature_linkphy_coe) || 652 soc_feature(unit, soc_feature_subtag_coe)) { 653 _bcm_kt2_subport_pbmp_update(unit, &port_pbmp); 654 } 655 #endif 656 657 vals[0] = vals[1] = enable; 658 vals[2] = (enable && do_vlan) ? 1 : 0; 659 660 PBMP_ITER(port_pbmp, port) { 661 int rv = BCM_E_NONE; 662 PORT_LOCK(unit); 663 rv = _bcm_esw_port_tab_multi_set(unit, port, _BCM_CPU_TABS_BOTH, 3, 664 flds, vals); 665 PORT_UNLOCK(unit); 666 if (BCM_FAILURE(rv)) { 667 return rv; 668 } 669 } 670 671 #if defined(BCM_TRX_SUPPORT) 672 if (soc_feature(unit, soc_feature_lport_tab_profile)) { 673 /* Update LPORT Profile Table */ 674 BCM_IF_ERROR_RETURN( 675 _bcm_lport_profile_fields32_modify(unit, LPORT_PROFILE_LPORT_TAB, 676 3, flds, vals)); 677 } 678 #endif /* BCM_TRX_SUPPORT */ 679 680 return BCM_E_NONE; 681 } 682 683 /* 684 * Function: 685 * bcm_tr_ipmc_init 686 * Purpose: 687 * Initialize the IPMC module and enable IPMC support. 688 * Parameters: 689 * unit - StrataSwitch PCI device unit number (driver internal). 690 * Returns: 691 * BCM_E_XXX 692 * Notes: 693 * This function has to be called before any other IPMC functions. 694 */ 695 696 int 697 bcm_tr_ipmc_init(int unit) 698 { 699 _bcm_esw_ipmc_t *info = IPMC_INFO(unit); 700 int rv = BCM_E_NONE; 701 #if defined(BCM_TRIUMPH2_SUPPORT) 702 int i; 703 #endif /*BCM_TRIUMPH2_SUPPORT*/ 704 705 BCM_IF_ERROR_RETURN(bcm_tr_ipmc_detach(unit)); 706 BCM_IF_ERROR_RETURN(_tr_ipmc_enable(unit, TRUE)); 707 708 IPMC_GROUP_NUM(unit) = soc_mem_index_count(unit, L3_IPMCm); 709 #if defined(BCM_TRIUMPH3_SUPPORT) 710 if (soc_feature(unit, soc_feature_static_repl_head_alloc)) { 711 soc_info_t *si; 712 int member_count; 713 int port, phy_port, mmu_port; 714 715 /* Each replication group is statically allocated a region 716 * in REPL_HEAD table. The size of the region depends on the 717 * maximum number of valid ports. Thus, the max number of 718 * replication groups is limited to number of REPL_HEAD entries 719 * divided by the max number of valid ports. 720 */ 721 si = &SOC_INFO(unit); 722 member_count = 0; 723 PBMP_ITER(SOC_CONTROL(unit)->repl_eligible_pbmp, port) { 724 phy_port = si->port_l2p_mapping[port]; 725 mmu_port = si->port_p2m_mapping[phy_port]; 726 if ((mmu_port == 57) || (mmu_port == 59) || (mmu_port == 61) || (mmu_port == 62)) { 727 /* No replication on MMU ports 57, 59, 61 and 62 */ 728 continue; 729 } 730 member_count++; 731 } 732 if (member_count > 0) { 733 IPMC_GROUP_NUM(unit) = 734 soc_mem_index_count(unit, MMU_REPL_HEAD_TBLm) / member_count; 735 if (IPMC_GROUP_NUM(unit) > soc_mem_index_count(unit, L3_IPMCm)) { 736 IPMC_GROUP_NUM(unit) = soc_mem_index_count(unit, L3_IPMCm); 737 } 738 } 739 } 740 #endif /* BCM_TRIUMPH3_SUPPORT */ 741 742 #ifdef BCM_BRADLEY_SUPPORT 743 if(!SOC_IS_MONTEREY(unit)) { 744 if (SOC_REG_FIELD_VALID(unit, MC_CONTROL_5r, SHARED_TABLE_IPMC_SIZEf)) { 745 int ipmc_base, ipmc_size; 746 747 SOC_IF_ERROR_RETURN 748 (soc_hbx_ipmc_size_get(unit, &ipmc_base, &ipmc_size)); 749 750 if (IPMC_GROUP_NUM(unit) > ipmc_size) { 751 /* Reduce to fix allocated table space */ 752 IPMC_GROUP_NUM(unit) = ipmc_size; 753 } 754 } 755 } 756 #endif 757 758 info->ipmc_count = 0; 759 760 info->ipmc_group_info = 761 sal_alloc(IPMC_GROUP_NUM(unit) * sizeof(_bcm_esw_ipmc_group_info_t), 762 "IPMC group info"); 763 if (info->ipmc_group_info == NULL) { 764 return (BCM_E_MEMORY); 765 } 766 sal_memset(info->ipmc_group_info, 0, 767 IPMC_GROUP_NUM(unit) * sizeof(_bcm_esw_ipmc_group_info_t)); 768 769 #ifdef BCM_TRIDENT2_SUPPORT 770 if(soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn) && 771 soc_property_get(unit, spn_IPMC_L2_USE_VLAN_VPN, 0)) { 772 773 rv = soc_reg_field32_modify(unit, ING_CONFIG_64r, 774 REG_PORT_ANY, L2MC_LOOKUP_USE_BROADCAST_DOMAINf, 1); 775 if (BCM_FAILURE(rv)) { 776 sal_free(info->ipmc_group_info); 777 info->ipmc_group_info = NULL; 778 return rv; 779 } 780 } 781 if (soc_feature(unit, soc_feature_pim_bidir)) { 782 rv = bcm_td2_ipmc_pim_bidir_init(unit); 783 if (BCM_FAILURE(rv)) { 784 sal_free(info->ipmc_group_info); 785 info->ipmc_group_info = NULL; 786 return rv; 787 } 788 } 789 #endif /* BCM_TRIDENT2_SUPPORT */ 790 791 /* Program the table IPMC_GROUP_NUM = index_count(L3_IPMCm) 792 * index_count of L3_IPMCm, L3_IPMC_REMAPm, EGR_IPMCm are the same 793 */ 794 #if defined(BCM_TRIUMPH2_SUPPORT) 795 if (SOC_MEM_IS_VALID(unit, L3_IPMC_REMAPm)) { 796 int size; 797 ipmc_remap_entry_t *ipmc_remap_entry; 798 uint8 *mbuf; 799 800 size = SOC_MEM_TABLE_BYTES(unit, L3_IPMC_REMAPm); 801 mbuf = soc_cm_salloc(unit, size, "L3_IPMC_REMAP"); 802 if (NULL == mbuf) { 803 return BCM_E_MEMORY; 804 } 805 sal_memset(mbuf, 0, size); 806 for (i = 0; i < IPMC_GROUP_NUM(unit); i++) { 807 ipmc_remap_entry = soc_mem_table_idx_to_pointer(unit, L3_IPMC_REMAPm, 808 ipmc_remap_entry_t *, mbuf, i); 809 soc_L3_IPMC_REMAPm_field32_set(unit, ipmc_remap_entry, L3MC_INDEXf, i); 810 } 811 rv = soc_mem_write_range(unit, L3_IPMC_REMAPm, MEM_BLOCK_ANY, 812 soc_mem_index_min(unit, L3_IPMC_REMAPm), 813 soc_mem_index_max(unit, L3_IPMC_REMAPm), 814 mbuf); 815 soc_cm_sfree(unit, mbuf); 816 if (rv < 0) { 817 sal_free(info->ipmc_group_info); 818 info->ipmc_group_info = NULL; 819 return rv; 820 } 821 } 822 #endif 823 if (SOC_MEM_IS_VALID(unit, EGR_IPMCm)) { 824 /* Initialize EGR_IPMC entries need to have: 825 * { L3_PAYLOAD == 0, REPLICATION_TYPE == 0, DONT_PRUNE_VLAN == 0 } 826 * Just same to clear it. 827 */ 828 rv = soc_mem_clear(unit, EGR_IPMCm, MEM_BLOCK_ANY, TRUE); 829 if (rv < 0) { 830 sal_free(info->ipmc_group_info); 831 info->ipmc_group_info = NULL; 832 return rv; 833 } 834 } 835 836 info->ipmc_initialized = TRUE; 837 return BCM_E_NONE; 838 } 839 840 /* 841 * Function: 842 * bcm_tr_ipmc_detach 843 * Purpose: 844 * Detach the IPMC module. 845 * Parameters: 846 * unit - StrataSwitch PCI device unit number (driver internal). 847 * Returns: 848 * BCM_E_XXX 849 */ 850 851 int 852 bcm_tr_ipmc_detach(int unit) 853 { 854 _bcm_esw_ipmc_t *info = IPMC_INFO(unit); 855 _bcm_esw_ipmc_l3entry_t *ipmc_l3entry; 856 int i, rv; 857 858 if (info->ipmc_initialized) { 859 /* Delete all IPMC entries. BCM_E_NOT_FOUND may be 860 * returned by bcm_tr_ipmc_delete_all since L3 module 861 * clears L3 tables during initialization. 862 */ 863 rv = bcm_tr_ipmc_delete_all(unit); 864 if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) { 865 return rv; 866 } 867 868 if (!SOC_WARM_BOOT(unit)) { 869 BCM_IF_ERROR_RETURN(_tr_ipmc_enable(unit, FALSE)); 870 } 871 872 if (info->ipmc_group_info != NULL) { 873 for (i = 0; i < IPMC_GROUP_NUM(unit); i++) { 874 ipmc_l3entry = IPMC_GROUP_INFO(unit, i)->l3entry_list; 875 while (ipmc_l3entry != NULL) { 876 IPMC_GROUP_INFO(unit, i)->l3entry_list = ipmc_l3entry->next; 877 sal_free(ipmc_l3entry); 878 ipmc_l3entry = IPMC_GROUP_INFO(unit, i)->l3entry_list; 879 } 880 } 881 sal_free(info->ipmc_group_info); 882 info->ipmc_group_info = NULL; 883 } 884 885 #ifdef BCM_TRIDENT2_SUPPORT 886 if (soc_feature(unit, soc_feature_pim_bidir)) { 887 BCM_IF_ERROR_RETURN(bcm_td2_ipmc_pim_bidir_detach(unit)); 888 } 889 #endif /* BCM_TRIDENT2_SUPPORT */ 890 891 info->ipmc_initialized = FALSE; 892 } 893 894 return BCM_E_NONE; 895 } 896 897 /* 898 * Function: 899 * bcm_tr_ipmc_get 900 * Purpose: 901 * Get an IPMC entry by index. 902 * Parameters: 903 * unit - StrataSwitch PCI device unit number (driver internal). 904 * index - The index number. 905 * ipmc - (OUT) IPMC entry information. 906 * Returns: 907 * BCM_E_XXX 908 */ 909 910 int 911 bcm_tr_ipmc_get(int unit, int index, bcm_ipmc_addr_t *ipmc) 912 { 913 ipmc_entry_t ipmc_entry; 914 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT) 915 ipmc_1_entry_t ipmc_1_entry; 916 #endif 917 918 IPMC_INIT(unit); 919 IPMC_ID(unit, index); 920 921 if (IPMC_USED_ISSET(unit, index)) { 922 BCM_IF_ERROR_RETURN 923 (soc_mem_read(unit, L3_IPMCm, MEM_BLOCK_ANY, index, &ipmc_entry)); 924 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT) 925 if (SOC_MEM_IS_VALID(unit, L3_IPMC_1m)) { 926 BCM_IF_ERROR_RETURN 927 (soc_mem_read(unit, L3_IPMC_1m, MEM_BLOCK_ANY, index, 928 &ipmc_1_entry)); 929 BCM_IF_ERROR_RETURN 930 (_tr2_ipmc_glp_get(unit, ipmc, &ipmc_1_entry)); 931 } 932 #endif 933 #ifdef BCM_TOMAHAWK_SUPPORT 934 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 935 BCM_IF_ERROR_RETURN 936 (_th_ipmc_info_get(unit, index, ipmc, &ipmc_entry, NULL)); 937 } else 938 #endif /* BCM_TOMAHAWK_SUPPORT */ 939 { 940 BCM_IF_ERROR_RETURN 941 (_tr_ipmc_info_get(unit, index, ipmc, &ipmc_entry, 1, NULL)); 942 } 943 944 ipmc->group = index; 945 946 return BCM_E_NONE; 947 } 948 949 return BCM_E_NOT_FOUND; 950 } 951 952 /* 953 * Function: 954 * _bcm_tr_ipmc_find 955 * Purpose: 956 * Search an IPMC entry by sip, mcip and vid 957 * Parameters: 958 * unit - StrataSwitch PCI device unit number (driver internal). 959 * ipmc - (IN) IPMC entry information. 960 * l3cfg - (OUT) L3 entry information.. 961 * Returns: 962 * BCM_E_XXX 963 */ 964 965 STATIC int 966 _bcm_tr_ipmc_find(int unit, bcm_ipmc_addr_t *ipmc, _bcm_l3_cfg_t *l3cfg) 967 { 968 sal_memset(l3cfg, 0, sizeof(_bcm_l3_cfg_t)); 969 970 l3cfg->l3c_vid = ipmc->vid; 971 l3cfg->l3c_flags = BCM_L3_IPMC; 972 l3cfg->l3c_vrf = ipmc->vrf; 973 l3cfg->l3c_ing_intf = ipmc->ing_intf; 974 if (ipmc->flags & BCM_IPMC_HIT_CLEAR) { 975 l3cfg->l3c_flags |= BCM_L3_HIT_CLEAR; 976 } 977 if (ipmc->flags & BCM_IPMC_L2) { 978 l3cfg->l3c_flags |= BCM_L3_L2ONLY; 979 } 980 #ifdef BCM_TRIDENT3_SUPPORT 981 if (soc_feature(unit, soc_feature_flex_flow)) { 982 l3cfg->l3c_rp_id = BCM_IPMC_RP_ID_INVALID; 983 l3cfg->l3c_flow_handle = ipmc->flow_handle; 984 l3cfg->l3c_flow_option_handle = ipmc->flow_option_handle; 985 l3cfg->l3c_num_of_fields = ipmc->num_logical_fields; 986 sal_memcpy(l3cfg->l3c_logical_fields, ipmc->logical_fields, 987 ipmc->num_logical_fields*sizeof(bcm_flow_logical_field_t)); 988 } 989 #endif /* BCM_TRIDENT3_SUPPORT */ 990 if (ipmc->flags & BCM_IPMC_IP6) { 991 sal_memcpy(l3cfg->l3c_sip6, ipmc->s_ip6_addr, BCM_IP6_ADDRLEN); 992 sal_memcpy(l3cfg->l3c_ip6, ipmc->mc_ip6_addr, BCM_IP6_ADDRLEN); 993 l3cfg->l3c_flags |= BCM_L3_IP6; 994 BCM_IF_ERROR_RETURN( 995 mbcm_driver[unit]->mbcm_l3_ip6_get(unit, l3cfg)); 996 } else { 997 l3cfg->l3c_src_ip_addr = ipmc->s_ip_addr; 998 l3cfg->l3c_ipmc_group = ipmc->mc_ip_addr; 999 BCM_IF_ERROR_RETURN( 1000 mbcm_driver[unit]->mbcm_l3_ip4_get(unit, l3cfg)); 1001 } 1002 1003 return BCM_E_NONE; 1004 } 1005 1006 /* 1007 * Function: 1008 * bcm_tr_ipmc_lookup 1009 * Purpose: 1010 * Look up an IPMC entry by sip, mcip and vid 1011 * Parameters: 1012 * unit - StrataSwitch PCI device unit number (driver internal). 1013 * index - (OUT) The index number. 1014 * ipmc - (IN, OUT) IPMC entry information. 1015 * Returns: 1016 * BCM_E_XXX 1017 */ 1018 1019 int 1020 bcm_tr_ipmc_lookup(int unit, int *index, bcm_ipmc_addr_t *ipmc) 1021 { 1022 ipmc_entry_t ipmc_entry; 1023 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT) 1024 ipmc_1_entry_t ipmc_1_entry; 1025 #endif 1026 _bcm_l3_cfg_t l3cfg; 1027 int ipmc_id; 1028 1029 IPMC_INIT(unit); 1030 1031 BCM_IF_ERROR_RETURN( 1032 _bcm_tr_ipmc_find(unit, ipmc, &l3cfg)); 1033 1034 ipmc_id = l3cfg.l3c_ipmc_ptr; 1035 BCM_IF_ERROR_RETURN 1036 (soc_mem_read(unit, L3_IPMCm, MEM_BLOCK_ANY, ipmc_id, &ipmc_entry)); 1037 1038 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT) 1039 if (SOC_MEM_IS_VALID(unit, L3_IPMC_1m)) { 1040 BCM_IF_ERROR_RETURN 1041 (soc_mem_read(unit, L3_IPMC_1m, MEM_BLOCK_ANY, ipmc_id, 1042 &ipmc_1_entry)); 1043 BCM_IF_ERROR_RETURN 1044 (_tr2_ipmc_glp_get(unit, ipmc, &ipmc_1_entry)); 1045 } 1046 #endif 1047 1048 #ifdef BCM_TOMAHAWK_SUPPORT 1049 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 1050 ipmc->v = soc_L3_IPMCm_field32_get(unit, &ipmc_entry, VALIDf); 1051 BCM_IF_ERROR_RETURN 1052 (_th_ipmc_glp_get(unit, ipmc, &l3cfg)); 1053 } else 1054 #endif /* BCM_TOMAHAWK_SUPPORT */ 1055 { 1056 BCM_IF_ERROR_RETURN 1057 (_tr_ipmc_info_get(unit, ipmc_id, ipmc, &ipmc_entry, 0, NULL)); 1058 } 1059 1060 if (ipmc->v) { 1061 ipmc->group = ipmc_id; 1062 ipmc->group_l2 = l3cfg.l3c_ipmc_ptr_l2; 1063 ipmc->lookup_class = l3cfg.l3c_lookup_class; 1064 ipmc->rp_id = l3cfg.l3c_rp_id; 1065 ipmc->ing_intf = l3cfg.l3c_ing_intf; 1066 ipmc->vid = l3cfg.l3c_vid; 1067 if (l3cfg.l3c_flags & BCM_L3_HIT) { 1068 ipmc->flags |= BCM_IPMC_HIT; 1069 } 1070 if (l3cfg.l3c_flags & BCM_L3_RPE) { 1071 ipmc->cos = l3cfg.l3c_prio; 1072 ipmc->flags |= BCM_IPMC_SETPRI; 1073 } else { 1074 ipmc->cos = -1; 1075 ipmc->flags &= ~BCM_IPMC_SETPRI; 1076 } 1077 if (l3cfg.l3c_flags & BCM_IPMC_POST_LOOKUP_RPF_CHECK) { 1078 ipmc->flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK; 1079 ipmc->l3a_intf = l3cfg.l3c_intf; 1080 if (l3cfg.l3c_flags & BCM_IPMC_RPF_FAIL_DROP) { 1081 ipmc->flags |= BCM_IPMC_RPF_FAIL_DROP; 1082 } 1083 if (l3cfg.l3c_flags & BCM_IPMC_RPF_FAIL_DROP) { 1084 ipmc->flags |= BCM_IPMC_RPF_FAIL_TOCPU; 1085 } 1086 } 1087 #ifdef BCM_MONTEREY_SUPPORT 1088 if (l3cfg.l3c_flags2 & BCM_L3_FLAGS2_DECAP_ROE_HEADER) { 1089 ipmc->flags |= BCM_IPMC_DECAP_ROE_HEADER; 1090 } 1091 #endif 1092 } 1093 if (index != NULL) { 1094 *index = ipmc_id; 1095 } 1096 1097 return BCM_E_NONE; 1098 } 1099 1100 /* 1101 * Function: 1102 * _bcm_tr_ipmc_add 1103 * Purpose: 1104 * Add a new entry to the L3 table. 1105 * Parameters: 1106 * unit - (IN) BCM device number. 1107 * ipmc - (IN) IPMC entry information. 1108 * Returns: 1109 * BCM_E_XXX 1110 */ 1111 1112 STATIC int 1113 _bcm_tr_ipmc_add(int unit, bcm_ipmc_addr_t *ipmc) 1114 { 1115 _bcm_l3_cfg_t l3cfg; /* L3 ipmc entry. */ 1116 int rv; /* Operation return status. */ 1117 1118 sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t)); 1119 1120 l3cfg.l3c_vid = ipmc->vid; 1121 l3cfg.l3c_flags = BCM_L3_IPMC; 1122 l3cfg.l3c_vrf = ipmc->vrf; 1123 l3cfg.l3c_lookup_class = ipmc->lookup_class; 1124 l3cfg.l3c_modid = ipmc->mod_id; 1125 l3cfg.l3c_port_tgid = ipmc->port_tgid; 1126 l3cfg.l3c_tunnel = ipmc->ts; 1127 1128 if (ipmc->flags & BCM_IPMC_SETPRI) { 1129 l3cfg.l3c_flags |= BCM_L3_RPE; 1130 l3cfg.l3c_prio = ipmc->cos; 1131 } 1132 /* Dont set hit bits if user says so */ 1133 if (ipmc->flags & BCM_IPMC_HIT_CLEAR) { 1134 l3cfg.l3c_flags |= BCM_L3_HIT_CLEAR; 1135 } else { 1136 l3cfg.l3c_flags |= BCM_L3_HIT; 1137 } 1138 if (ipmc->flags & BCM_IPMC_IP6) { 1139 if (!BCM_IP6_MULTICAST(ipmc->mc_ip6_addr)) { 1140 return BCM_E_PARAM; 1141 } 1142 sal_memcpy(l3cfg.l3c_sip6, ipmc->s_ip6_addr, BCM_IP6_ADDRLEN); 1143 sal_memcpy(l3cfg.l3c_ip6, ipmc->mc_ip6_addr, BCM_IP6_ADDRLEN); 1144 l3cfg.l3c_flags |= BCM_L3_IP6; 1145 } else { 1146 if (!BCM_IP4_MULTICAST(ipmc->mc_ip_addr)) { 1147 return BCM_E_PARAM; 1148 } 1149 l3cfg.l3c_src_ip_addr = ipmc->s_ip_addr; 1150 l3cfg.l3c_ipmc_group = ipmc->mc_ip_addr; 1151 } 1152 1153 l3cfg.l3c_ipmc_ptr = ipmc->group; 1154 l3cfg.l3c_ipmc_ptr_l2 = ipmc->group_l2; 1155 l3cfg.l3c_vid = ipmc->vid; 1156 l3cfg.l3c_rp_id = ipmc->rp_id; 1157 l3cfg.l3c_ing_intf = ipmc->ing_intf; 1158 if (ipmc->flags & BCM_IPMC_L2) { 1159 l3cfg.l3c_flags |= BCM_L3_L2ONLY; 1160 } 1161 if (ipmc->flags & BCM_IPMC_REPLACE) { 1162 l3cfg.l3c_flags |= BCM_L3_REPLACE; 1163 } 1164 1165 if (ipmc->flags & BCM_IPMC_POST_LOOKUP_RPF_CHECK) { 1166 l3cfg.l3c_intf = ipmc->l3a_intf; 1167 l3cfg.l3c_flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK; 1168 if (ipmc->flags & BCM_IPMC_RPF_FAIL_DROP) { 1169 l3cfg.l3c_flags |= BCM_IPMC_RPF_FAIL_DROP; 1170 } 1171 if (ipmc->flags & BCM_IPMC_RPF_FAIL_TOCPU) { 1172 l3cfg.l3c_flags |= BCM_IPMC_RPF_FAIL_TOCPU; 1173 } 1174 } 1175 1176 if (ipmc->flags & BCM_IPMC_SOURCE_PORT_NOCHECK) { 1177 l3cfg.l3c_flags |= BCM_IPMC_SOURCE_PORT_NOCHECK; 1178 } 1179 1180 #ifdef BCM_TOMAHAWK_SUPPORT 1181 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 1182 BCM_IF_ERROR_RETURN 1183 (_th_ipmc_glp_set(unit, ipmc, &l3cfg)); 1184 } 1185 #endif 1186 /* Write mcast entry to hw. */ 1187 l3cfg.l3c_hw_index = BCM_XGS3_L3_INVALID_INDEX;/* Add /No overrite. */ 1188 1189 #ifdef BCM_MONTEREY_SUPPORT 1190 if (ipmc->flags & BCM_IPMC_DECAP_ROE_HEADER) { 1191 l3cfg.l3c_flags2 |= BCM_L3_FLAGS2_DECAP_ROE_HEADER; 1192 } 1193 #endif 1194 1195 #ifdef BCM_TRIDENT3_SUPPORT 1196 if (soc_feature(unit, soc_feature_flex_flow)) { 1197 l3cfg.l3c_flow_handle = ipmc->flow_handle; 1198 l3cfg.l3c_flow_option_handle = ipmc->flow_option_handle; 1199 l3cfg.l3c_num_of_fields = ipmc->num_logical_fields; 1200 sal_memcpy(l3cfg.l3c_logical_fields, ipmc->logical_fields, 1201 ipmc->num_logical_fields*sizeof(bcm_flow_logical_field_t)); 1202 } 1203 #endif /* BCM_TRIDENT3_SUPPORT */ 1204 1205 if (ipmc->flags & BCM_IPMC_IP6) { 1206 rv = mbcm_driver[unit]->mbcm_l3_ip6_add(unit, &l3cfg); 1207 } else { 1208 rv = mbcm_driver[unit]->mbcm_l3_ip4_add(unit, &l3cfg); 1209 } 1210 1211 if (BCM_SUCCESS(rv)) { 1212 rv = _bcm_tr_ipmc_l3entry_list_add(unit, ipmc->group, 1213 &l3cfg); 1214 } 1215 1216 return (rv); 1217 } 1218 1219 /* 1220 * Function: 1221 * _bcm_tr_ipmc_del 1222 * Purpose: 1223 * Remove an entry from the L3 table. 1224 * Parameters: 1225 * unit - (IN) BCM device number. 1226 * ipmc - (IN)IPMC entry information. 1227 * modify_l3entry_list - (IN) Controls whether to modify IPMC group's 1228 * L3 entry list. 1229 * Returns: 1230 * BCM_E_XXX 1231 */ 1232 1233 STATIC int 1234 _bcm_tr_ipmc_del(int unit, bcm_ipmc_addr_t *ipmc, int modify_l3entry_list) 1235 { 1236 _bcm_l3_cfg_t l3cfg; /* L3 ipmc entry. */ 1237 int rv; /* Operation return status. */ 1238 int ipmc_index = 0; 1239 1240 sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t)); 1241 1242 l3cfg.l3c_vid = ipmc->vid; 1243 l3cfg.l3c_flags = BCM_L3_IPMC; 1244 l3cfg.l3c_vrf = ipmc->vrf; 1245 l3cfg.l3c_vid = ipmc->vid; 1246 l3cfg.l3c_ing_intf = ipmc->ing_intf; 1247 if (ipmc->flags & BCM_IPMC_L2) { 1248 l3cfg.l3c_flags |= BCM_L3_L2ONLY; 1249 } 1250 if (ipmc->flags & BCM_IPMC_IP6) { 1251 if (!BCM_IP6_MULTICAST(ipmc->mc_ip6_addr)) { 1252 return BCM_E_PARAM; 1253 } 1254 sal_memcpy(l3cfg.l3c_sip6, ipmc->s_ip6_addr, BCM_IP6_ADDRLEN); 1255 sal_memcpy(l3cfg.l3c_ip6, ipmc->mc_ip6_addr, BCM_IP6_ADDRLEN); 1256 l3cfg.l3c_flags |= BCM_L3_IP6; 1257 } else { 1258 if (!BCM_IP4_MULTICAST(ipmc->mc_ip_addr)) { 1259 return BCM_E_PARAM; 1260 } 1261 l3cfg.l3c_src_ip_addr = ipmc->s_ip_addr; 1262 l3cfg.l3c_ipmc_group = ipmc->mc_ip_addr; 1263 } 1264 #ifdef BCM_TRIDENT3_SUPPORT 1265 if (soc_feature(unit, soc_feature_flex_flow)) { 1266 l3cfg.l3c_rp_id = BCM_IPMC_RP_ID_INVALID; 1267 l3cfg.l3c_flow_handle = ipmc->flow_handle; 1268 l3cfg.l3c_flow_option_handle = ipmc->flow_option_handle; 1269 l3cfg.l3c_num_of_fields = ipmc->num_logical_fields; 1270 sal_memcpy(l3cfg.l3c_logical_fields, ipmc->logical_fields, 1271 ipmc->num_logical_fields*sizeof(bcm_flow_logical_field_t)); 1272 } 1273 #endif /* BCM_TRIDENT3_SUPPORT */ 1274 if (ipmc->flags & BCM_IPMC_IP6) { 1275 rv = mbcm_driver[unit]->mbcm_l3_ip6_get(unit, &l3cfg); 1276 if (BCM_SUCCESS(rv)) { 1277 ipmc_index = l3cfg.l3c_ipmc_ptr; 1278 rv = mbcm_driver[unit]->mbcm_l3_ip6_delete(unit, &l3cfg); 1279 } 1280 } else { 1281 rv = mbcm_driver[unit]->mbcm_l3_ip4_get(unit, &l3cfg); 1282 if (BCM_SUCCESS(rv)) { 1283 ipmc_index = l3cfg.l3c_ipmc_ptr; 1284 rv = mbcm_driver[unit]->mbcm_l3_ip4_delete(unit, &l3cfg); 1285 } 1286 } 1287 1288 if (BCM_SUCCESS(rv) && modify_l3entry_list) { 1289 rv = _bcm_tr_ipmc_l3entry_list_del(unit, ipmc_index, &l3cfg); 1290 } 1291 1292 return (rv); 1293 } 1294 1295 /* 1296 * Function: 1297 * _bcm_tr_ipmc_replace 1298 * Purpose: 1299 * Overwrite an entry in the IPMC table. 1300 * Parameters: 1301 * unit - StrataSwitch PCI device unit number (driver internal). 1302 * ipmc - New IPMC entry information. 1303 * old_l3cfg - Old IPMC configuration information. 1304 * Returns: 1305 * BCM_E_XXX 1306 */ 1307 STATIC int 1308 _bcm_tr_ipmc_replace(int unit, bcm_ipmc_addr_t *ipmc, _bcm_l3_cfg_t *old_l3cfg) 1309 { 1310 _bcm_l3_cfg_t l3cfg; 1311 int old_ipmc_index; 1312 int rv = BCM_E_NONE; 1313 int flex_fields_replace = 0; 1314 1315 l3cfg = *old_l3cfg; 1316 old_ipmc_index = l3cfg.l3c_ipmc_ptr; 1317 1318 if (!(ipmc->flags & BCM_IPMC_SETPRI)) { 1319 l3cfg.l3c_flags &= ~BCM_L3_RPE; 1320 l3cfg.l3c_prio = 0; 1321 } else { 1322 l3cfg.l3c_flags |= BCM_L3_RPE; 1323 l3cfg.l3c_prio = ipmc->cos; 1324 } 1325 if (ipmc->flags & BCM_IPMC_HIT_CLEAR) { 1326 l3cfg.l3c_flags &= ~BCM_L3_HIT; 1327 } 1328 l3cfg.l3c_lookup_class = ipmc->lookup_class; 1329 l3cfg.l3c_ipmc_ptr = ipmc->group; 1330 l3cfg.l3c_ipmc_ptr_l2 = ipmc->group_l2; 1331 l3cfg.l3c_rp_id = ipmc->rp_id; 1332 1333 if (ipmc->flags & BCM_IPMC_POST_LOOKUP_RPF_CHECK) { 1334 l3cfg.l3c_intf = ipmc->l3a_intf; 1335 l3cfg.l3c_flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK; 1336 if (ipmc->flags & BCM_IPMC_RPF_FAIL_DROP) { 1337 l3cfg.l3c_flags |= BCM_IPMC_RPF_FAIL_DROP; 1338 } 1339 if (ipmc->flags & BCM_IPMC_RPF_FAIL_TOCPU) { 1340 l3cfg.l3c_flags |= BCM_IPMC_RPF_FAIL_TOCPU; 1341 } 1342 } 1343 1344 #ifdef BCM_TOMAHAWK_SUPPORT 1345 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 1346 if (!(ipmc->flags & BCM_IPMC_SOURCE_PORT_NOCHECK)) { 1347 l3cfg.l3c_flags &= ~BCM_IPMC_SOURCE_PORT_NOCHECK; 1348 } 1349 BCM_IF_ERROR_RETURN 1350 (_th_ipmc_glp_set(unit, ipmc, &l3cfg)); 1351 } 1352 #endif 1353 1354 #ifdef BCM_TRIDENT3_SUPPORT 1355 if (soc_feature(unit, soc_feature_flex_flow) && 1356 (ipmc->flow_handle != 0)) { 1357 if (ipmc->flags & BCM_IPMC_REPLACE) { 1358 l3cfg.l3c_flags |= BCM_L3_REPLACE; 1359 } 1360 if ((l3cfg.l3c_flow_handle != ipmc->flow_handle) || 1361 (l3cfg.l3c_flow_option_handle != ipmc->flow_option_handle) || 1362 (l3cfg.l3c_num_of_fields != ipmc->num_logical_fields) || 1363 (!sal_memcmp(l3cfg.l3c_logical_fields, ipmc->logical_fields, 1364 ipmc->num_logical_fields*sizeof(bcm_flow_logical_field_t)))) { 1365 flex_fields_replace = 1; 1366 } 1367 } 1368 #endif 1369 BCM_IF_ERROR_RETURN 1370 (bcm_xgs3_l3_replace(unit, &l3cfg)); 1371 1372 if ((old_ipmc_index != ipmc->group) || flex_fields_replace) { 1373 rv = _bcm_tr_ipmc_l3entry_list_del(unit, old_ipmc_index, &l3cfg); 1374 if (rv == BCM_E_NOT_FOUND) { 1375 rv = _bcm_tr_ipmc_l3entry_list_add(unit, ipmc->group, &l3cfg); 1376 return rv; 1377 } else if (BCM_FAILURE(rv)) { 1378 return rv; 1379 } 1380 rv = _bcm_tr_ipmc_l3entry_list_add(unit, ipmc->group, &l3cfg); 1381 if (BCM_FAILURE(rv)) { 1382 (void) _bcm_tr_ipmc_l3entry_list_add(unit, old_ipmc_index, &l3cfg); 1383 return rv; 1384 } 1385 } else { 1386 BCM_IF_ERROR_RETURN 1387 (_bcm_tr_ipmc_l3entry_list_update(unit, old_ipmc_index, &l3cfg)); 1388 } 1389 1390 return BCM_E_NONE; 1391 } 1392 1393 /* 1394 * Function: 1395 * _bcm_tr_ipmc_src_port_compare 1396 * Purpose: 1397 * Compare the IPMC source port parameters. 1398 * Parameters: 1399 * unit - StrataSwitch PCI device unit number (driver internal). 1400 * ipmc_index - IPMC index to be shared. 1401 * ipmc - IPMC address entry info. 1402 * match - (OUT) Match indication. 1403 * Returns: 1404 * BCM_E_XXX 1405 */ 1406 STATIC int 1407 _bcm_tr_ipmc_src_port_compare(int unit, int ipmc_index, 1408 bcm_ipmc_addr_t *ipmc, int *match) 1409 { 1410 ipmc_entry_t entry; 1411 ipmc_1_entry_t entry_1; 1412 int no_src_check, is_trunk, tgid, mod, port; 1413 int t_f, tgid_f, mod_f, port_f; 1414 int modid_max = 0; 1415 1416 if (SOC_MEM_IS_VALID(unit, L3_IPMC_1m)) { 1417 BCM_IF_ERROR_RETURN 1418 (soc_mem_read(unit, L3_IPMC_1m, MEM_BLOCK_ANY, ipmc_index, 1419 &entry_1)); 1420 } else { 1421 BCM_IF_ERROR_RETURN 1422 (soc_mem_read(unit, L3_IPMCm, MEM_BLOCK_ANY, ipmc_index, 1423 &entry)); 1424 } 1425 1426 no_src_check = FALSE; 1427 is_trunk = 0; 1428 tgid = -1; 1429 mod = -1; 1430 port = -1; 1431 if (SOC_MEM_IS_VALID(unit, L3_IPMC_1m)) { 1432 t_f = soc_L3_IPMC_1m_field32_get(unit, &entry_1, Tf); 1433 tgid_f = soc_L3_IPMC_1m_field32_get(unit, &entry_1, TGIDf); 1434 mod_f = soc_L3_IPMC_1m_field32_get(unit, &entry_1, MODULE_IDf); 1435 port_f = soc_L3_IPMC_1m_field32_get(unit, &entry_1, PORT_NUMf); 1436 } else { 1437 t_f = soc_L3_IPMCm_field32_get(unit, &entry, Tf); 1438 tgid_f = soc_L3_IPMCm_field32_get(unit, &entry, TGIDf); 1439 mod_f = soc_L3_IPMCm_field32_get(unit, &entry, MODULE_IDf); 1440 port_f = soc_L3_IPMCm_field32_get(unit, &entry, PORT_NUMf); 1441 } 1442 #ifdef BCM_METROLITE_SUPPORT 1443 if (SOC_IS_METROLITE(unit)) { 1444 modid_max = SOC_MEM_FIELD32_VALUE_MAX( 1445 unit, L3_IPMC_1m, MODULE_IDf); 1446 }else 1447 #endif 1448 { 1449 modid_max = SOC_MODID_MAX(unit); 1450 } 1451 1452 if ((t_f == 1) && (mod_f == modid_max) && 1453 (port_f == TR_IPMC_NO_SRC_CHECK_PORT(unit))) { 1454 no_src_check = TRUE; 1455 } else if (t_f == 1) { 1456 is_trunk = 1; 1457 tgid = tgid_f; 1458 } else { 1459 mod = mod_f; 1460 port = port_f; 1461 } 1462 1463 *match = FALSE; 1464 if ((ipmc->flags & BCM_IPMC_SOURCE_PORT_NOCHECK) || 1465 (ipmc->port_tgid < 0)) { /* no source port */ 1466 if (no_src_check) { 1467 *match = TRUE; 1468 } 1469 } else if (ipmc->ts) { /* trunk source port */ 1470 if (is_trunk && (tgid == ipmc->port_tgid)) { 1471 *match = TRUE; 1472 } 1473 } else { /* source port */ 1474 bcm_module_t mod_in, mod_out; 1475 bcm_port_t port_in, port_out; 1476 1477 mod_in = ipmc->mod_id; 1478 port_in = ipmc->port_tgid; 1479 BCM_IF_ERROR_RETURN 1480 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET, 1481 mod_in, port_in, 1482 &mod_out, &port_out)); 1483 /* Check parameters, since above is an application callback */ 1484 if (!SOC_MODID_ADDRESSABLE(unit, mod_out)) { 1485 return BCM_E_BADID; 1486 } 1487 if (!SOC_PORT_ADDRESSABLE(unit, port_out)) { 1488 return BCM_E_PORT; 1489 } 1490 1491 if ((mod == mod_out) && (port == port_out)) { 1492 *match = TRUE; 1493 } 1494 } 1495 1496 return BCM_E_NONE; 1497 } 1498 1499 /* 1500 * Function: 1501 * _bcm_tr_ipmc_src_port_consistency_check 1502 * Purpose: 1503 * When multiple IPMC address entries share the same IPMC 1504 * index, they must also have the same port parameter 1505 * for the purpose of IPMC source port checking. This 1506 * procedure makes sure this is the case. 1507 * Parameters: 1508 * unit - StrataSwitch PCI device unit number (driver internal). 1509 * ipmc_index - IPMC index to be shared. 1510 * ipmc - IPMC address entry info. 1511 * already_used - Indicates if the given IPMC address entry is 1512 * already using the ipmc index to be shared. 1513 * need_write - Indicates whether the the ipmc index to be shared 1514 * should be writen or not. 1515 * Returns: 1516 * BCM_E_XXX 1517 */ 1518 int 1519 _bcm_tr_ipmc_src_port_consistency_check(int unit, int ipmc_index, 1520 bcm_ipmc_addr_t *ipmc, int already_used, int *need_write) 1521 { 1522 int l3entry_list_size; 1523 int match = 0; 1524 int defip_ref_count; 1525 1526 *need_write = TRUE; 1527 1528 if (soc_feature(unit, soc_feature_src_port_consistency_check_skip)) { 1529 /* Source port check for L3 Multicast has been moved in lookup table in Tomahawk, 1530 * hence src port consistency check is not required as the device allows sharing an 1531 * ipmc index without doing src port check. 1532 */ 1533 return BCM_E_NONE; 1534 } 1535 1536 BCM_IF_ERROR_RETURN(_bcm_tr_ipmc_l3entry_list_size_get(unit, 1537 ipmc_index, &l3entry_list_size)); 1538 defip_ref_count = IPMC_GROUP_INFO(unit, ipmc_index)->defip_ref_count; 1539 if ((already_used && (l3entry_list_size > 1)) || 1540 (!already_used && (l3entry_list_size > 0)) || 1541 (defip_ref_count > 0)) { 1542 /* If there are IPMC address entries other than the given IPMC address 1543 * entry that are pointing the given ipmc index, verify that the IPMC 1544 * source port check parameters are the same. If not, the ipmc index 1545 * cannot be shared. 1546 */ 1547 1548 BCM_IF_ERROR_RETURN(_bcm_tr_ipmc_src_port_compare(unit, 1549 ipmc_index, ipmc, &match)); 1550 1551 if (!match) { 1552 return BCM_E_PARAM; 1553 } 1554 1555 *need_write = FALSE; 1556 } 1557 1558 return BCM_E_NONE; 1559 } 1560 1561 /* 1562 * Function: 1563 * bcm_tr_ipmc_add 1564 * Purpose: 1565 * Add a new entry to the IPMC table. 1566 * Parameters: 1567 * unit - StrataSwitch PCI device unit number (driver internal). 1568 * ipmc - IPMC entry information. 1569 * Returns: 1570 * BCM_E_XXX 1571 */ 1572 1573 int 1574 bcm_tr_ipmc_add(int unit, bcm_ipmc_addr_t *ipmc) 1575 { 1576 _bcm_l3_cfg_t l3cfg; 1577 int old_ipmc_index; 1578 int new_entry, rv, need_write; 1579 #ifdef BCM_TRIDENT2_SUPPORT 1580 int old_rp_id; 1581 #endif /* BCM_TRIDENT2_SUPPORT */ 1582 1583 IPMC_INIT(unit); 1584 IPMC_ID(unit, ipmc->group); 1585 1586 /* To keep logic simple, group_l2 won't be validated here, user needs to 1587 * maintain the consistency of group_l2 and IPMC table */ 1588 if (!IPMC_USED_ISSET(unit, ipmc->group)) { 1589 return BCM_E_PARAM; 1590 } 1591 1592 /* Check if IPMC entry already exists. 1593 * In case of BCM_IPMC_REPLACE flag being set, 1594 * if entry is already present, old entry will be replaced, 1595 * else new entry will be created. This is the expected behaviour 1596 */ 1597 rv = _bcm_tr_ipmc_find(unit, ipmc, &l3cfg); 1598 old_ipmc_index = l3cfg.l3c_ipmc_ptr; 1599 #ifdef BCM_TRIDENT2_SUPPORT 1600 old_rp_id = l3cfg.l3c_rp_id; 1601 #endif /* BCM_TRIDENT2_SUPPORT */ 1602 if (BCM_SUCCESS(rv)) { 1603 if (!(ipmc->flags & BCM_IPMC_REPLACE)) { 1604 return (BCM_E_EXISTS); 1605 } else { 1606 new_entry = FALSE; 1607 } 1608 } else { 1609 /* Return if error occured. */ 1610 if (rv != BCM_E_NOT_FOUND) { 1611 return (rv); 1612 } 1613 new_entry = TRUE; 1614 } 1615 1616 if (new_entry) { 1617 BCM_IF_ERROR_RETURN(_bcm_tr_ipmc_src_port_consistency_check(unit, 1618 ipmc->group, ipmc, 0, &need_write)); 1619 1620 /* Increment the reference count of the given ipmc_index. */ 1621 BCM_IF_ERROR_RETURN(bcm_xgs3_ipmc_id_alloc(unit, ipmc->group)); 1622 } else { 1623 if (ipmc->group != old_ipmc_index) { 1624 BCM_IF_ERROR_RETURN 1625 (_bcm_tr_ipmc_src_port_consistency_check(unit, 1626 ipmc->group, 1627 ipmc, 0, &need_write)); 1628 /* Increment the reference count of the given ipmc_index. */ 1629 BCM_IF_ERROR_RETURN(bcm_xgs3_ipmc_id_alloc(unit, ipmc->group)); 1630 1631 /* Decrement the reference count of the old ipmc_index. */ 1632 BCM_IF_ERROR_RETURN(bcm_xgs3_ipmc_id_free(unit, old_ipmc_index)); 1633 if (!IPMC_USED_ISSET(unit, old_ipmc_index)) { 1634 /* Reference count should not be zero yet. */ 1635 (void) bcm_xgs3_ipmc_id_free(unit, ipmc->group); 1636 (void) bcm_xgs3_ipmc_id_alloc(unit, old_ipmc_index); 1637 return BCM_E_INTERNAL; 1638 } 1639 } else { 1640 BCM_IF_ERROR_RETURN 1641 (_bcm_tr_ipmc_src_port_consistency_check(unit, 1642 ipmc->group, 1643 ipmc, 1, &need_write)); 1644 } 1645 } 1646 1647 ipmc->v = (ipmc->flags & BCM_IPMC_ADD_DISABLED) ? 0 : 1; 1648 1649 if (new_entry) { 1650 if (need_write) { 1651 /* Write L3_IPMC table entry. */ 1652 rv = _tr_ipmc_write(unit, ipmc->group, ipmc); 1653 if (BCM_FAILURE(rv)) { 1654 bcm_xgs3_ipmc_id_free(unit, ipmc->group); 1655 return (rv); 1656 } 1657 } 1658 1659 /* Add new L3 table entry */ 1660 rv = _bcm_tr_ipmc_add(unit, ipmc); 1661 if (BCM_FAILURE(rv)) { 1662 bcm_xgs3_ipmc_id_free(unit, ipmc->group); 1663 if (!IPMC_USED_ISSET(unit, ipmc->group)) { 1664 /* Reference count should not be zero yet. */ 1665 return BCM_E_INTERNAL; 1666 } 1667 return (rv); 1668 } 1669 } else { 1670 if (need_write) { 1671 /* Write L3_IPMC table entry. */ 1672 rv = _tr_ipmc_write(unit, ipmc->group, ipmc); 1673 if (BCM_FAILURE(rv)) { 1674 if (ipmc->group != old_ipmc_index) { 1675 (void) bcm_xgs3_ipmc_id_free(unit, ipmc->group); 1676 (void) bcm_xgs3_ipmc_id_alloc(unit, old_ipmc_index); 1677 } 1678 return (rv); 1679 } 1680 } 1681 /* Update existing IPMC entry */ 1682 rv = _bcm_tr_ipmc_replace(unit, ipmc, &l3cfg); 1683 if (BCM_FAILURE(rv)) { 1684 if (ipmc->group != old_ipmc_index) { 1685 (void) bcm_xgs3_ipmc_id_free(unit, ipmc->group); 1686 (void) bcm_xgs3_ipmc_id_alloc(unit, old_ipmc_index); 1687 } 1688 return rv; 1689 } 1690 } 1691 1692 #ifdef BCM_TRIDENT2_SUPPORT 1693 /* Update reference count of rendezvous point */ 1694 if (soc_feature(unit, soc_feature_pim_bidir)) { 1695 if (new_entry) { 1696 if (ipmc->rp_id != BCM_IPMC_RP_ID_INVALID) { 1697 BCM_IF_ERROR_RETURN 1698 (bcm_td2_ipmc_rp_ref_count_incr(unit, ipmc->rp_id)); 1699 } 1700 } else { 1701 if (old_rp_id != ipmc->rp_id) { 1702 if (ipmc->rp_id != BCM_IPMC_RP_ID_INVALID) { 1703 BCM_IF_ERROR_RETURN 1704 (bcm_td2_ipmc_rp_ref_count_incr(unit, ipmc->rp_id)); 1705 } 1706 if (old_rp_id != BCM_IPMC_RP_ID_INVALID) { 1707 BCM_IF_ERROR_RETURN 1708 (bcm_td2_ipmc_rp_ref_count_decr(unit, old_rp_id)); 1709 } 1710 } 1711 } 1712 } 1713 #endif /* BCM_TRIDENT2_SUPPORT */ 1714 1715 return BCM_E_NONE; 1716 } 1717 1718 /* 1719 * Function: 1720 * bcm_tr_ipmc_put 1721 * Purpose: 1722 * Overwrite an entry in the IPMC table. 1723 * Parameters: 1724 * unit - StrataSwitch PCI device unit number (driver internal). 1725 * index - Table index to overwrite. 1726 * data - IPMC entry information. 1727 * Returns: 1728 * BCM_E_XXX 1729 */ 1730 1731 int 1732 bcm_tr_ipmc_put(int unit, int index, bcm_ipmc_addr_t *ipmc) 1733 { 1734 _bcm_l3_cfg_t l3cfg; 1735 1736 IPMC_INIT(unit); 1737 IPMC_ID(unit, index); 1738 1739 BCM_IF_ERROR_RETURN(_tr_ipmc_write(unit, index, ipmc)); 1740 1741 sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t)); 1742 1743 l3cfg.l3c_vid = ipmc->vid; 1744 l3cfg.l3c_flags = BCM_L3_IPMC; 1745 l3cfg.l3c_vrf = ipmc->vrf; 1746 l3cfg.l3c_ing_intf = ipmc->ing_intf; 1747 if (ipmc->flags & BCM_IPMC_L2) { 1748 l3cfg.l3c_flags |= BCM_L3_L2ONLY; 1749 } 1750 if (ipmc->flags & BCM_IPMC_IP6) { 1751 sal_memcpy(l3cfg.l3c_sip6, ipmc->s_ip6_addr, BCM_IP6_ADDRLEN); 1752 sal_memcpy(l3cfg.l3c_ip6, ipmc->mc_ip6_addr, BCM_IP6_ADDRLEN); 1753 l3cfg.l3c_flags |= BCM_L3_IP6; 1754 BCM_IF_ERROR_RETURN 1755 (mbcm_driver[unit]->mbcm_l3_ip6_get(unit, &l3cfg)); 1756 } else { 1757 l3cfg.l3c_src_ip_addr = ipmc->s_ip_addr; 1758 l3cfg.l3c_ipmc_group = ipmc->mc_ip_addr; 1759 BCM_IF_ERROR_RETURN 1760 (mbcm_driver[unit]->mbcm_l3_ip4_get(unit, &l3cfg)); 1761 } 1762 1763 return _bcm_tr_ipmc_replace(unit, ipmc, &l3cfg); 1764 } 1765 1766 /* 1767 * Function: 1768 * bcm_tr_ipmc_write 1769 * Purpose: 1770 * Overwrite an entry in the IPMC table. 1771 * Parameters: 1772 * unit - StrataSwitch PCI device unit number (driver internal). 1773 * index - Table index to overwrite. 1774 * data - IPMC entry information. 1775 * Returns: 1776 * BCM_E_XXX 1777 */ 1778 int 1779 bcm_tr_ipmc_write (int unit, int ipmc_id, bcm_ipmc_addr_t *ipmc) 1780 { 1781 1782 return (_tr_ipmc_write(unit, ipmc_id, ipmc)); 1783 } 1784 1785 /* 1786 * Function: 1787 * _bcm_tr_ipmc_delete 1788 * Purpose: 1789 * Delete an entry from the IPMC table. 1790 * Parameters: 1791 * unit - StrataSwitch PCI device unit number (driver internal). 1792 * data - IPMC entry information. 1793 * modify_l3entry_list - Control whether to modify IPMC group's linked 1794 * list of L3 entries. 1795 * Returns: 1796 * BCM_E_XXX 1797 * Notes: 1798 * If BCM_IPMC_KEEP_ENTRY is true, the entry valid bit is cleared 1799 * but the entry is not deleted from the table. 1800 */ 1801 1802 STATIC int 1803 _bcm_tr_ipmc_delete(int unit, bcm_ipmc_addr_t *ipmc, int modify_l3entry_list) 1804 { 1805 _bcm_l3_cfg_t l3cfg; 1806 int ipmc_id; 1807 #ifdef BCM_TRIDENT2_SUPPORT 1808 int rp_id; 1809 #endif /* BCM_TRIDENT2_SUPPORT */ 1810 1811 IPMC_INIT(unit); 1812 1813 sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t)); 1814 l3cfg.l3c_vid = ipmc->vid; 1815 l3cfg.l3c_flags = BCM_L3_IPMC; 1816 l3cfg.l3c_vrf = ipmc->vrf; 1817 l3cfg.l3c_ing_intf = ipmc->ing_intf; 1818 if (ipmc->flags & BCM_IPMC_L2) { 1819 l3cfg.l3c_flags |= BCM_L3_L2ONLY; 1820 } 1821 #ifdef BCM_TRIDENT3_SUPPORT 1822 if (soc_feature(unit, soc_feature_flex_flow)) { 1823 l3cfg.l3c_rp_id = BCM_IPMC_RP_ID_INVALID; 1824 l3cfg.l3c_flow_handle = ipmc->flow_handle; 1825 l3cfg.l3c_flow_option_handle = ipmc->flow_option_handle; 1826 l3cfg.l3c_num_of_fields = ipmc->num_logical_fields; 1827 sal_memcpy(l3cfg.l3c_logical_fields, ipmc->logical_fields, 1828 ipmc->num_logical_fields*sizeof(bcm_flow_logical_field_t)); 1829 } 1830 #endif /* BCM_TRIDENT3_SUPPORT */ 1831 if (ipmc->flags & BCM_IPMC_IP6) { 1832 sal_memcpy(l3cfg.l3c_sip6, ipmc->s_ip6_addr, BCM_IP6_ADDRLEN); 1833 sal_memcpy(l3cfg.l3c_ip6, ipmc->mc_ip6_addr, BCM_IP6_ADDRLEN); 1834 l3cfg.l3c_flags |= BCM_L3_IP6; 1835 BCM_IF_ERROR_RETURN( 1836 mbcm_driver[unit]->mbcm_l3_ip6_get(unit, &l3cfg)); 1837 } else { 1838 l3cfg.l3c_src_ip_addr = ipmc->s_ip_addr; 1839 l3cfg.l3c_ipmc_group = ipmc->mc_ip_addr; 1840 BCM_IF_ERROR_RETURN( 1841 mbcm_driver[unit]->mbcm_l3_ip4_get(unit, &l3cfg)); 1842 } 1843 ipmc_id = l3cfg.l3c_ipmc_ptr; 1844 #ifdef BCM_TRIDENT2_SUPPORT 1845 rp_id = l3cfg.l3c_rp_id; 1846 #endif /* BCM_TRIDENT2_SUPPORT */ 1847 1848 if (!(ipmc->flags & BCM_IPMC_KEEP_ENTRY)) { 1849 BCM_IF_ERROR_RETURN 1850 (_bcm_tr_ipmc_del(unit, ipmc, modify_l3entry_list)); 1851 1852 bcm_xgs3_ipmc_id_free(unit, ipmc_id); 1853 if (!IPMC_USED_ISSET(unit, ipmc_id)) { 1854 /* Reference count should not be zero yet. */ 1855 return BCM_E_INTERNAL; 1856 } 1857 1858 #ifdef BCM_TRIDENT2_SUPPORT 1859 if (soc_feature(unit, soc_feature_pim_bidir)) { 1860 if (rp_id != BCM_IPMC_RP_ID_INVALID) { 1861 BCM_IF_ERROR_RETURN 1862 (bcm_td2_ipmc_rp_ref_count_decr(unit, rp_id)); 1863 } 1864 } 1865 #endif /* BCM_TRIDENT2_SUPPORT */ 1866 } 1867 1868 return BCM_E_NONE; 1869 } 1870 1871 /* 1872 * Function: 1873 * bcm_tr_ipmc_delete 1874 * Purpose: 1875 * Delete an entry from the IPMC table. 1876 * Parameters: 1877 * unit - StrataSwitch PCI device unit number (driver internal). 1878 * data - IPMC entry information. 1879 * Returns: 1880 * BCM_E_XXX 1881 * Notes: 1882 * If BCM_IPMC_KEEP_ENTRY is true, the entry valid bit is cleared 1883 * but the entry is not deleted from the table. 1884 */ 1885 1886 int 1887 bcm_tr_ipmc_delete(int unit, bcm_ipmc_addr_t *ipmc) 1888 { 1889 return _bcm_tr_ipmc_delete(unit, ipmc, TRUE); 1890 } 1891 1892 /* 1893 * Function: 1894 * bcm_tr_ipmc_delete_all 1895 * Purpose: 1896 * Delete all entries from the IPMC table. 1897 * Parameters: 1898 * unit - StrataSwitch PCI device unit number (driver internal). 1899 * Returns: 1900 * BCM_E_XXX 1901 */ 1902 1903 int 1904 bcm_tr_ipmc_delete_all(int unit) 1905 { 1906 int i, rv = BCM_E_NONE; 1907 _bcm_esw_ipmc_l3entry_t *ipmc_l3entry; 1908 _bcm_l3_cfg_t l3cfg; 1909 1910 IPMC_INIT(unit); 1911 1912 IPMC_LOCK(unit); 1913 for (i = 0; i < IPMC_GROUP_NUM(unit); i++) { 1914 if (IPMC_USED_ISSET(unit, i)) { 1915 ipmc_l3entry = IPMC_GROUP_INFO(unit, i)->l3entry_list; 1916 while (ipmc_l3entry != NULL) { 1917 sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t)); 1918 1919 #ifdef BCM_TRIDENT3_SUPPORT 1920 if (soc_feature(unit, soc_feature_flex_flow)) { 1921 l3cfg.l3c_flow_handle = ipmc_l3entry->l3info.flow_handle; 1922 l3cfg.l3c_flow_option_handle = ipmc_l3entry->l3info.flow_option_handle; 1923 l3cfg.l3c_num_of_fields = ipmc_l3entry->l3info.num_logical_fields; 1924 sal_memcpy(l3cfg.l3c_logical_fields, ipmc_l3entry->l3info.logical_fields, 1925 ipmc_l3entry->l3info.num_logical_fields*sizeof(bcm_flow_logical_field_t)); 1926 } 1927 #endif 1928 l3cfg.l3c_vid = ipmc_l3entry->l3info.vid; 1929 l3cfg.l3c_flags = BCM_L3_IPMC; 1930 l3cfg.l3c_vrf = ipmc_l3entry->l3info.vrf; 1931 l3cfg.l3c_ing_intf = ipmc_l3entry->l3info.ing_intf; 1932 if(ipmc_l3entry->l3info.flags & BCM_L3_L2ONLY) { 1933 l3cfg.l3c_flags |= BCM_L3_L2ONLY; 1934 } 1935 if (ipmc_l3entry->l3info.flags & BCM_L3_IP6) { 1936 sal_memcpy(l3cfg.l3c_sip6, ipmc_l3entry->l3info.sip6, BCM_IP6_ADDRLEN); 1937 sal_memcpy(l3cfg.l3c_ip6, ipmc_l3entry->l3info.ip6, BCM_IP6_ADDRLEN); 1938 l3cfg.l3c_flags |= BCM_L3_IP6; 1939 } else { 1940 l3cfg.l3c_src_ip_addr = ipmc_l3entry->l3info.src_ip_addr; 1941 l3cfg.l3c_ipmc_group = ipmc_l3entry->l3info.ip_addr; 1942 } 1943 rv = bcm_xgs3_l3_del(unit, &l3cfg); 1944 if (rv < 0) { 1945 IPMC_UNLOCK(unit); 1946 return rv; 1947 } 1948 #ifdef BCM_TRIDENT2_SUPPORT 1949 if (soc_feature(unit, soc_feature_pim_bidir)) { 1950 if (ipmc_l3entry->l3info.rp_id != BCM_IPMC_RP_ID_INVALID) { 1951 rv = bcm_td2_ipmc_rp_ref_count_decr(unit, 1952 ipmc_l3entry->l3info.rp_id); 1953 if (rv < 0) { 1954 IPMC_UNLOCK(unit); 1955 return rv; 1956 } 1957 } 1958 } 1959 #endif /* BCM_TRIDENT2_SUPPORT */ 1960 IPMC_GROUP_INFO(unit, i)->l3entry_list = ipmc_l3entry->next; 1961 sal_free(ipmc_l3entry); 1962 ipmc_l3entry = IPMC_GROUP_INFO(unit, i)->l3entry_list; 1963 } 1964 1965 /* For IPMC groups that have non-zero reference counts, 1966 * decrease reference count to 1, meaning the IPMC group 1967 * is only referenced by bcm_multicast_egress APIs. 1968 */ 1969 IPMC_USED_ONE(unit, i); 1970 } 1971 } 1972 1973 IPMC_UNLOCK(unit); 1974 1975 return rv; 1976 } 1977 1978 /* 1979 * Function: 1980 * bcm_tr_ipmc_age 1981 * Purpose: 1982 * Age out the ipmc entry by clearing the HIT bit when appropriate, 1983 * the ipmc entry itself is removed if HIT bit is not set. 1984 * Parameters: 1985 * unit - (IN) BCM device number. 1986 * flags - (IN) The criteria used to age out ipmc table. 1987 * IPv6/IPv4 1988 * age_cb - (IN) Call back routine. 1989 * user_data - (IN) User provided cookie for callback. 1990 * Returns: 1991 * BCM_E_XXX 1992 */ 1993 int 1994 bcm_tr_ipmc_age(int unit, uint32 flags, bcm_ipmc_traverse_cb age_cb, 1995 void *user_data) 1996 { 1997 int idx; /* Ipmc table iteration index. */ 1998 bcm_ipmc_addr_t entry; /* Ipmc entry iterator. */ 1999 int rv = BCM_E_NONE; /* Operation return status. */ 2000 2001 ipmc_entry_t ipmc_entry; 2002 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT) 2003 ipmc_1_entry_t ipmc_1_entry; 2004 #endif 2005 _bcm_esw_ipmc_l3entry_t *ipmc_l3entry; 2006 _bcm_esw_ipmc_l3entry_t *prev_ipmc_l3entry = NULL; 2007 2008 IPMC_INIT(unit); 2009 IPMC_LOCK(unit); 2010 2011 for (idx = 0; idx < IPMC_GROUP_NUM(unit); idx++) { 2012 if (IPMC_USED_ISSET(unit, idx)) { 2013 2014 rv = soc_mem_read(unit, L3_IPMCm, MEM_BLOCK_ANY, idx, &ipmc_entry); 2015 if (BCM_FAILURE(rv)) { 2016 goto age_done; 2017 } 2018 2019 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT) 2020 if (SOC_MEM_IS_VALID(unit, L3_IPMC_1m)) { 2021 rv = soc_mem_read(unit, L3_IPMC_1m, MEM_BLOCK_ANY, idx, 2022 &ipmc_1_entry); 2023 if (BCM_FAILURE(rv)) { 2024 goto age_done; 2025 } 2026 } 2027 #endif /* BCM_TRIUMPH2_SUPPORT */ 2028 2029 ipmc_l3entry = IPMC_GROUP_INFO(unit, idx)->l3entry_list; 2030 while (ipmc_l3entry != NULL) { 2031 sal_memset(&entry, 0, sizeof(bcm_ipmc_addr_t)); 2032 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT) 2033 if (SOC_MEM_IS_VALID(unit, L3_IPMC_1m)) { 2034 rv = _tr2_ipmc_glp_get(unit, &entry, &ipmc_1_entry); 2035 if (BCM_FAILURE(rv)) { 2036 goto age_done; 2037 } 2038 } 2039 #endif /* BCM_TRIUMPH2_SUPPORT */ 2040 #ifdef BCM_TOMAHAWK_SUPPORT 2041 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 2042 rv = _th_ipmc_info_get(unit, idx, &entry, &ipmc_entry, 2043 ipmc_l3entry); 2044 } else 2045 #endif /* BCM_TOMAHAWK_SUPPORT */ 2046 { 2047 rv = _tr_ipmc_info_get(unit, idx, &entry, &ipmc_entry, 2048 1, ipmc_l3entry); 2049 } 2050 2051 if (BCM_FAILURE(rv)) { 2052 goto age_done; 2053 } 2054 2055 /* Make sure update only ipv4 or ipv6 entries. */ 2056 if ((flags & BCM_IPMC_IP6) != (entry.flags & BCM_IPMC_IP6)) { 2057 prev_ipmc_l3entry = ipmc_l3entry; 2058 ipmc_l3entry = ipmc_l3entry->next; 2059 continue; 2060 } 2061 2062 if (entry.flags & BCM_IPMC_HIT) { 2063 _bcm_l3_cfg_t l3cfg; 2064 /* Clear hit bit on used entry (by doing a lookup !!) */ 2065 sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t)); 2066 l3cfg.l3c_flags |= BCM_L3_HIT_CLEAR; 2067 l3cfg.l3c_vid = ipmc_l3entry->l3info.vid; 2068 l3cfg.l3c_flags |= BCM_L3_IPMC; 2069 l3cfg.l3c_vrf = ipmc_l3entry->l3info.vrf; 2070 l3cfg.l3c_vid = ipmc_l3entry->l3info.vid; 2071 l3cfg.l3c_ing_intf = ipmc_l3entry->l3info.ing_intf; 2072 if(ipmc_l3entry->l3info.flags & BCM_L3_L2ONLY) { 2073 l3cfg.l3c_flags |= BCM_L3_L2ONLY; 2074 } 2075 if (ipmc_l3entry->ip6) { 2076 sal_memcpy(l3cfg.l3c_sip6, &ipmc_l3entry->l3info.sip6, 2077 BCM_IP6_ADDRLEN); 2078 sal_memcpy(l3cfg.l3c_ip6, &ipmc_l3entry->l3info.ip6, 2079 BCM_IP6_ADDRLEN); 2080 l3cfg.l3c_flags |= BCM_L3_IP6; 2081 rv = (mbcm_driver[unit]->mbcm_l3_ip6_get(unit, &l3cfg)); 2082 } else { 2083 l3cfg.l3c_src_ip_addr = ipmc_l3entry->l3info.src_ip_addr; 2084 l3cfg.l3c_ipmc_group = ipmc_l3entry->l3info.ipmc_group; 2085 rv = (mbcm_driver[unit]->mbcm_l3_ip4_get(unit, &l3cfg)); 2086 } 2087 if (BCM_FAILURE(rv)) { 2088 goto age_done; 2089 } 2090 prev_ipmc_l3entry = ipmc_l3entry; 2091 ipmc_l3entry = ipmc_l3entry->next; 2092 } else { 2093 /* Delete IPMC L3 entry. Inhibit modification of IPMC group's 2094 * l3entry_list by _bcm_tr_ipmc_delete. 2095 */ 2096 rv = _bcm_tr_ipmc_delete(unit, &entry, FALSE); 2097 if (BCM_FAILURE(rv)) { 2098 goto age_done; 2099 } 2100 2101 /* Delete from IPMC group's l3entry_list */ 2102 if (ipmc_l3entry == IPMC_GROUP_INFO(unit, idx)->l3entry_list) { 2103 IPMC_GROUP_INFO(unit, idx)->l3entry_list = ipmc_l3entry->next; 2104 sal_free(ipmc_l3entry); 2105 ipmc_l3entry = IPMC_GROUP_INFO(unit, idx)->l3entry_list; 2106 } else { 2107 /* 2108 * In the following line of code, Coverity thinks the 2109 * prev_ipmc_l3entry pointer may still be NULL when 2110 * dereferenced. This situation will never occur because 2111 * if ipmc_l3entry is not pointing to the head of the 2112 * linked list, prev_ipmc_l3entry would not be NULL. 2113 */ 2114 /* coverity[var_deref_op : FALSE] */ 2115 prev_ipmc_l3entry->next = ipmc_l3entry->next; 2116 sal_free(ipmc_l3entry); 2117 ipmc_l3entry = prev_ipmc_l3entry->next; 2118 } 2119 2120 /* Invoke user callback. */ 2121 if (NULL != age_cb) { 2122 _BCM_MULTICAST_GROUP_SET(entry.group, 2123 _BCM_MULTICAST_TYPE_L3, entry.group); 2124 _BCM_MULTICAST_GROUP_SET(entry.group_l2, 2125 _BCM_MULTICAST_TYPE_L3, entry.group_l2); 2126 rv = (*age_cb)(unit, &entry, user_data); 2127 #ifdef BCM_CB_ABORT_ON_ERR 2128 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 2129 goto age_done; 2130 } 2131 #endif 2132 } 2133 } 2134 } 2135 } 2136 } 2137 2138 age_done: 2139 IPMC_UNLOCK(unit); 2140 return (rv); 2141 } 2142 2143 /* 2144 * Function: 2145 * bcm_tr_ipmc_traverse 2146 * Purpose: 2147 * Go through all valid ipmc entries, and call the callback function 2148 * at each entry 2149 * Parameters: 2150 * unit - (IN) BCM device number. 2151 * flags - (IN) The criteria used to age out ipmc table. 2152 * cb - (IN) User supplied callback function. 2153 * user_data - (IN) User supplied cookie used in parameter 2154 * in callback function. 2155 * Returns: 2156 * BCM_E_XXX 2157 */ 2158 int 2159 bcm_tr_ipmc_traverse(int unit, uint32 flags, bcm_ipmc_traverse_cb cb, 2160 void *user_data) 2161 { 2162 int idx; /* Ipmc table iteration index. */ 2163 bcm_ipmc_addr_t entry; /* Ipmc entry iterator. */ 2164 int rv = BCM_E_NONE; /* Operation return status. */ 2165 2166 ipmc_entry_t ipmc_entry; 2167 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT) 2168 ipmc_1_entry_t ipmc_1_entry; 2169 #endif 2170 _bcm_esw_ipmc_l3entry_t *ipmc_l3entry; 2171 2172 IPMC_INIT(unit); 2173 IPMC_LOCK(unit); 2174 2175 for (idx = 0; idx < IPMC_GROUP_NUM(unit); idx++) { 2176 if (IPMC_USED_ISSET(unit, idx)) { 2177 2178 rv = soc_mem_read(unit, L3_IPMCm, MEM_BLOCK_ANY, idx, &ipmc_entry); 2179 if (BCM_FAILURE(rv)) { 2180 goto traverse_done; 2181 } 2182 2183 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT) 2184 if (SOC_MEM_IS_VALID(unit, L3_IPMC_1m)) { 2185 rv = soc_mem_read(unit, L3_IPMC_1m, MEM_BLOCK_ANY, idx, 2186 &ipmc_1_entry); 2187 if (BCM_FAILURE(rv)) { 2188 goto traverse_done; 2189 } 2190 } 2191 #endif /* BCM_TRIUMPH2_SUPPORT */ 2192 2193 ipmc_l3entry = IPMC_GROUP_INFO(unit, idx)->l3entry_list; 2194 while (ipmc_l3entry != NULL) { 2195 sal_memset(&entry, 0, sizeof(bcm_ipmc_addr_t)); 2196 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT) 2197 if (SOC_MEM_IS_VALID(unit, L3_IPMC_1m)) { 2198 rv = _tr2_ipmc_glp_get(unit, &entry, &ipmc_1_entry); 2199 if (BCM_FAILURE(rv)) { 2200 goto traverse_done; 2201 } 2202 } 2203 #endif /* BCM_TRIUMPH2_SUPPORT */ 2204 #ifdef BCM_TOMAHAWK_SUPPORT 2205 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 2206 rv = _th_ipmc_info_get(unit, idx, &entry, &ipmc_entry, 2207 ipmc_l3entry); 2208 } else 2209 #endif /* BCM_TOMAHAWK_SUPPORT */ 2210 { 2211 rv = _tr_ipmc_info_get(unit, idx, &entry, &ipmc_entry, 2212 1, ipmc_l3entry); 2213 } 2214 2215 if (BCM_FAILURE(rv)) { 2216 goto traverse_done; 2217 } 2218 2219 /* Make sure update only ipv4 or ipv6 entries. */ 2220 if ((flags & BCM_IPMC_IP6) != (entry.flags & BCM_IPMC_IP6)) { 2221 ipmc_l3entry = ipmc_l3entry->next; 2222 continue; 2223 } 2224 2225 /* Get the pointer to next ipmc_l3entry before callback, 2226 * since callback may delete the current ipmc_l3entry. 2227 */ 2228 ipmc_l3entry = ipmc_l3entry->next; 2229 2230 /* Invoke user callback. */ 2231 _BCM_MULTICAST_GROUP_SET(entry.group, 2232 _BCM_MULTICAST_TYPE_L3, entry.group); 2233 _BCM_MULTICAST_GROUP_SET(entry.group_l2, 2234 _BCM_MULTICAST_TYPE_L3, entry.group_l2); 2235 rv = (*cb)(unit, &entry, user_data); 2236 #ifdef BCM_CB_ABORT_ON_ERR 2237 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 2238 goto traverse_done; 2239 } 2240 #endif 2241 } 2242 } 2243 } 2244 2245 traverse_done: 2246 IPMC_UNLOCK(unit); 2247 return (rv); 2248 } 2249 2250 /* 2251 * Function: 2252 * bcm_tr_ipmc_enable 2253 * Purpose: 2254 * Enable or disable IPMC chip functions. 2255 * Parameters: 2256 * unit - Unit number 2257 * enable - TRUE to enable; FALSE to disable 2258 * Returns: 2259 * BCM_E_XXX 2260 */ 2261 2262 int 2263 bcm_tr_ipmc_enable(int unit, int enable) 2264 { 2265 IPMC_INIT(unit); 2266 2267 return _tr_ipmc_enable(unit, enable); 2268 } 2269 2270 2271 /* 2272 * Function: 2273 * bcm_tr_ipmc_src_port_check 2274 * Purpose: 2275 * Enable or disable Source Port checking in IPMC lookups. 2276 * Parameters: 2277 * unit - Unit number 2278 * enable - TRUE to enable; FALSE to disable 2279 * Returns: 2280 * BCM_E_XXX 2281 */ 2282 2283 int 2284 bcm_tr_ipmc_src_port_check(int unit, int enable) 2285 { 2286 IPMC_INIT(unit); 2287 2288 return BCM_E_UNAVAIL; 2289 } 2290 2291 /* 2292 * Function: 2293 * bcm_tr_ipmc_src_ip_search 2294 * Purpose: 2295 * Enable or disable Source IP significance in IPMC lookups. 2296 * Parameters: 2297 * unit - Unit number 2298 * enable - TRUE to enable; FALSE to disable 2299 * Returns: 2300 * BCM_E_XXX 2301 */ 2302 2303 int 2304 bcm_tr_ipmc_src_ip_search(int unit, int enable) 2305 { 2306 IPMC_INIT(unit); 2307 2308 if (enable) { 2309 return BCM_E_NONE; /* always on */ 2310 } else { 2311 return BCM_E_FAIL; /* cannot be disabled */ 2312 } 2313 } 2314 2315 /* 2316 * Function: 2317 * bcm_tr_ipmc_egress_port_set 2318 * Purpose: 2319 * Configure the IP Multicast egress properties 2320 * Parameters: 2321 * unit - StrataSwitch PCI device unit number (driver internal). 2322 * port - port to config. 2323 * mac - MAC address. 2324 * untag - 1: The IP multicast packet is transmitted as untagged packet. 2325 * 0: The IP multicast packet is transmitted as tagged packet 2326 * with VLAN tag vid. 2327 * vid - VLAN ID. 2328 * ttl - 1 to disable the TTL decrement, 0 otherwise. 2329 * Returns: 2330 * BCM_E_XXX 2331 */ 2332 2333 int 2334 bcm_tr_ipmc_egress_port_set(int unit, bcm_port_t port, 2335 const bcm_mac_t mac, int untag, 2336 bcm_vlan_t vid, int ttl) 2337 { 2338 uint32 cfg2; 2339 2340 if (soc_feature(unit, soc_feature_no_egr_ipmc_cfg)) { 2341 return BCM_E_UNAVAIL; 2342 } 2343 2344 #if defined(BCM_KATANA2_SUPPORT) 2345 if ((soc_feature(unit, soc_feature_linkphy_coe) && 2346 SOC_PBMP_MEMBER(SOC_INFO(unit).linkphy_pp_port_pbm, port)) || 2347 (soc_feature(unit, soc_feature_subtag_coe) && 2348 SOC_PBMP_MEMBER(SOC_INFO(unit).subtag_pp_port_pbm, port)) || 2349 (soc_feature(unit, soc_feature_general_cascade) && 2350 SOC_PBMP_MEMBER(SOC_INFO(unit).general_pp_port_pbm, port))) { 2351 } else 2352 #endif 2353 if (!IS_PORT(unit, port)) { 2354 return BCM_E_BADID; 2355 } 2356 2357 if (!SOC_PBMP_PORT_VALID(port)) { 2358 return BCM_E_BADID; 2359 } 2360 /* TD3TBD */ 2361 if (SOC_MEM_IS_VALID(unit, EGR_IPMC_CFG2m)) { 2362 SOC_IF_ERROR_RETURN(READ_EGR_IPMC_CFG2m(unit, MEM_BLOCK_ANY, port, &cfg2)); 2363 2364 soc_mem_field32_set(unit, EGR_IPMC_CFG2m, &cfg2, 2365 UNTAGf, untag ? 1 : 0); 2366 soc_mem_field32_set(unit, EGR_IPMC_CFG2m, &cfg2, 2367 VIDf, vid); 2368 2369 2370 SOC_IF_ERROR_RETURN(WRITE_EGR_IPMC_CFG2m(unit, MEM_BLOCK_ANY, port, &cfg2)); 2371 } else if (SOC_REG_IS_VALID(unit, EGR_IPMC_CFG2r)) { 2372 SOC_IF_ERROR_RETURN(READ_EGR_IPMC_CFG2r(unit, port, &cfg2)); 2373 2374 soc_reg_field_set(unit, EGR_IPMC_CFG2r, &cfg2, 2375 UNTAGf, untag ? 1 : 0); 2376 soc_reg_field_set(unit, EGR_IPMC_CFG2r, &cfg2, 2377 VIDf, vid); 2378 2379 2380 SOC_IF_ERROR_RETURN(WRITE_EGR_IPMC_CFG2r(unit, port, cfg2)); 2381 } 2382 2383 2384 return BCM_E_NONE; 2385 } 2386 2387 /* 2388 * Function: 2389 * bcm_tr_ipmc_egress_port_get 2390 * Purpose: 2391 * Return the IP Multicast egress properties 2392 * Parameters: 2393 * unit - StrataSwitch PCI device unit number (driver internal). 2394 * port - port to config. 2395 * mac - (OUT) MAC address. 2396 * untag - (OUT) 1: The IP multicast packet is transmitted as 2397 * untagged packet. 2398 * 0: The IP multicast packet is transmitted as tagged 2399 * packet with VLAN tag vid. 2400 * vid - (OUT) VLAN ID. 2401 * ttl_thresh - (OUT) Drop IPMC packets if TTL <= ttl_thresh. 2402 * Returns: 2403 * BCM_E_XXX 2404 */ 2405 2406 int 2407 bcm_tr_ipmc_egress_port_get(int unit, bcm_port_t port, sal_mac_addr_t mac, 2408 int *untag, bcm_vlan_t *vid, int *ttl_thresh) 2409 { 2410 uint32 cfg2; 2411 2412 if (soc_feature(unit, soc_feature_no_egr_ipmc_cfg)) { 2413 return BCM_E_UNAVAIL; 2414 } 2415 2416 #if defined(BCM_KATANA2_SUPPORT) 2417 if (IS_LP_PORT(unit, port) || IS_SUBTAG_PORT(unit, port)) { 2418 } else 2419 #endif 2420 if (!SOC_PBMP_PORT_VALID(port) || !IS_PORT(unit, port)) { 2421 return BCM_E_BADID; 2422 } 2423 2424 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 2425 if (soc_feature(unit, soc_feature_egr_ipmc_cfg2_is_memory)) { 2426 SOC_IF_ERROR_RETURN(READ_EGR_IPMC_CFG2m(unit, MEM_BLOCK_ANY, port, &cfg2)); 2427 2428 *untag = soc_mem_field32_get(unit, EGR_IPMC_CFG2m, &cfg2, 2429 UNTAGf); 2430 *vid = soc_mem_field32_get(unit, EGR_IPMC_CFG2m, &cfg2, 2431 VIDf); 2432 *ttl_thresh = -1; 2433 2434 } else 2435 #endif 2436 { 2437 SOC_IF_ERROR_RETURN(READ_EGR_IPMC_CFG2r(unit, port, &cfg2)); 2438 2439 *untag = soc_reg_field_get(unit, EGR_IPMC_CFG2r, cfg2, UNTAGf); 2440 *vid = soc_reg_field_get(unit, EGR_IPMC_CFG2r, cfg2, VIDf); 2441 *ttl_thresh = -1; 2442 } 2443 2444 return BCM_E_NONE; 2445 } 2446 2447 #ifdef BCM_WARM_BOOT_SUPPORT 2448 2449 /* 2450 * Recover IPMC group count, IPMC group info, and PIM-BIDIR 2451 * rendezvous point reference count by traversing IPMC address table 2452 */ 2453 STATIC int 2454 _bcm_tr_ipmc_table_recover(int unit) 2455 { 2456 int rv = BCM_E_NONE; 2457 soc_mem_t v4mc_mem, v6mc_mem; 2458 int v4mc_entry_size, v6mc_entry_size; 2459 int v4mc_key_type, v6mc_key_type; 2460 int key; 2461 soc_field_t l3mc_index_field, rpe_field, l3mc_index2 = INVALIDf; 2462 soc_field_t vrf_field, group_ip_field, source_ip_field; 2463 soc_field_t l3_iif_field, pri_field, class_id_field, rpa_id_field; 2464 soc_field_t source_ip_hi_field, source_ip_lo_field; 2465 soc_field_t group_ip_hi_field = INVALIDf; 2466 soc_field_t group_ip_lo_field = INVALIDf; 2467 #ifdef BCM_TRIDENT2_SUPPORT 2468 soc_field_t expect_l3_iif_field = INVALIDf; 2469 #endif 2470 int chunk_size, num_chunks, chunk_index; 2471 int entry_index_min, entry_index_max; 2472 uint8 *v4mc_buf = NULL; 2473 uint8 *v6mc_buf = NULL; 2474 int i; 2475 uint32 *v4mc_entry; 2476 uint32 *v6mc_entry; 2477 int ipmc_ptr; 2478 _bcm_l3_cfg_t l3cfg; 2479 soc_field_t key_type_field; 2480 2481 COMPILER_REFERENCE(rpa_id_field); 2482 2483 if (SOC_MEM_IS_VALID(unit, L3_ENTRY_2m)) { 2484 v4mc_mem = L3_ENTRY_2m; 2485 v4mc_entry_size = sizeof(l3_entry_2_entry_t); 2486 v4mc_key_type = 6; 2487 l3mc_index_field = IPV4MC__L3MC_INDEXf; 2488 rpe_field = IPV4MC__RPEf; 2489 vrf_field = IPV4MC__VRF_IDf; 2490 group_ip_field = IPV4MC__GROUP_IP_ADDRf; 2491 source_ip_field = IPV4MC__SOURCE_IP_ADDRf; 2492 l3_iif_field = IPV4MC__L3_IIFf; 2493 pri_field = IPV4MC__PRIf; 2494 class_id_field = IPV4MC__CLASS_IDf; 2495 rpa_id_field = INVALIDf; 2496 } else { 2497 if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) { 2498 v4mc_mem = L3_ENTRY_DOUBLEm; 2499 v4mc_entry_size = sizeof(l3_entry_double_entry_t); 2500 } else { 2501 v4mc_mem = L3_ENTRY_IPV4_MULTICASTm; 2502 v4mc_entry_size = sizeof(l3_entry_ipv4_multicast_entry_t); 2503 } 2504 #ifdef BCM_TRIDENT2_SUPPORT 2505 if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 2506 v4mc_key_type = TD2_L3_HASH_KEY_TYPE_V4MC; 2507 } else 2508 #endif /* BCM_TRIDENT2_SUPPORT */ 2509 { 2510 /* coverity[mixed_enums] */ 2511 v4mc_key_type = TR_L3_HASH_KEY_TYPE_V4MC; 2512 } 2513 2514 if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit) ) { 2515 v4mc_mem = L3_ENTRY_DOUBLEm; 2516 v4mc_entry_size = sizeof(l3_entry_double_entry_t); 2517 2518 if (SOC_IS_TRIDENT3X(unit)) { 2519 l3mc_index_field = IPV4MC__DESTINATIONf; 2520 } else { 2521 l3mc_index_field = IPV4MC__L3MC_INDEXf; 2522 } 2523 rpe_field = IPV4MC__RPEf; 2524 vrf_field = IPV4MC__VRF_IDf; 2525 group_ip_field = IPV4MC__GROUP_IP_ADDRf; 2526 source_ip_field = IPV4MC__SOURCE_IP_ADDRf; 2527 l3_iif_field = IPV4MC__L3_IIFf; 2528 pri_field = IPV4MC__PRIf; 2529 class_id_field = IPV4MC__CLASS_IDf; 2530 rpa_id_field = IPV4MC__RPA_IDf; 2531 } else { 2532 l3mc_index_field = L3MC_INDEXf; 2533 rpe_field = RPEf; 2534 vrf_field = VRF_IDf; 2535 group_ip_field = GROUP_IP_ADDRf; 2536 source_ip_field = SOURCE_IP_ADDRf; 2537 l3_iif_field = L3_IIFf; 2538 pri_field = PRIf; 2539 class_id_field = CLASS_IDf; 2540 rpa_id_field = RPA_IDf; 2541 } 2542 if (SOC_MEM_FIELD_VALID(unit, v4mc_mem, IPV4MC__L3MC_INDEX_FOR_L2_DISTRIBUTIONf)) { 2543 l3mc_index2 = IPV4MC__L3MC_INDEX_FOR_L2_DISTRIBUTIONf; 2544 } 2545 } 2546 2547 /* Traverse IPv4 multicast table in chunks to avoid BCM_E_MEMORY */ 2548 chunk_size = 1024; 2549 num_chunks = (soc_mem_index_count(unit, v4mc_mem) + chunk_size - 1) / 2550 chunk_size; 2551 v4mc_buf = soc_cm_salloc(unit, v4mc_entry_size * chunk_size, 2552 "v4mc buf dma"); 2553 if (v4mc_buf == NULL) { 2554 return BCM_E_MEMORY; 2555 } 2556 for (chunk_index = 0; chunk_index < num_chunks; chunk_index++) { 2557 /* Read a chunk of entries */ 2558 entry_index_min = chunk_index * chunk_size; 2559 entry_index_max = entry_index_min + chunk_size - 1; 2560 if (entry_index_max > soc_mem_index_max(unit, v4mc_mem)) { 2561 entry_index_max = soc_mem_index_max(unit, v4mc_mem); 2562 } 2563 rv = soc_mem_read_range(unit, v4mc_mem, MEM_BLOCK_ANY, 2564 entry_index_min, entry_index_max, v4mc_buf); 2565 if (SOC_FAILURE(rv)) { 2566 soc_cm_sfree(unit, v4mc_buf); 2567 return rv; 2568 } 2569 2570 /* Read each entry of the chunk */ 2571 for (i = 0; i < (entry_index_max - entry_index_min + 1); i++) { 2572 v4mc_entry = soc_mem_table_idx_to_pointer(unit, v4mc_mem, 2573 uint32 *, v4mc_buf, i); 2574 if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) { 2575 key_type_field = KEY_TYPEf; 2576 } else { 2577 key_type_field = KEY_TYPE_0f; 2578 } 2579 key = soc_mem_field32_get(unit, v4mc_mem, 2580 v4mc_entry, key_type_field); 2581 if (soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn) && 2582 soc_property_get(unit, spn_IPMC_L2_USE_VLAN_VPN, 0)) { 2583 if ((key != v4mc_key_type) 2584 #ifdef BCM_TRIDENT2_SUPPORT 2585 && (key != TD2_L3_HASH_KEY_TYPE_V4L2MC) 2586 && (key != TD2_L3_HASH_KEY_TYPE_V4L2VPMC) 2587 #endif 2588 ) { 2589 2590 continue; 2591 } 2592 } else if (key != v4mc_key_type) { 2593 continue; 2594 } 2595 if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) { 2596 key_type_field = KEY_TYPEf; 2597 } else { 2598 key_type_field = KEY_TYPE_1f; 2599 } 2600 key = soc_mem_field32_get(unit, v4mc_mem, 2601 v4mc_entry, key_type_field); 2602 if (soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn) && 2603 soc_property_get(unit, spn_IPMC_L2_USE_VLAN_VPN, 0)) { 2604 if ((key != v4mc_key_type) 2605 #ifdef BCM_TRIDENT2_SUPPORT 2606 && (key != TD2_L3_HASH_KEY_TYPE_V4L2MC) 2607 && (key != TD2_L3_HASH_KEY_TYPE_V4L2VPMC) 2608 #endif 2609 ) { 2610 2611 continue; 2612 } 2613 } else if (key != v4mc_key_type) { 2614 continue; 2615 } 2616 2617 /* Skip Invalid Entries */ 2618 if (SOC_IS_TRIDENT3X(unit)) { 2619 if ((soc_mem_field32_get(unit, v4mc_mem, v4mc_entry, BASE_VALID_0f) != 3) || 2620 (soc_mem_field32_get(unit, v4mc_mem, v4mc_entry, BASE_VALID_1f) != 4)) { 2621 continue; 2622 } 2623 } else if (SOC_IS_TOMAHAWK3(unit)) { 2624 if ((soc_mem_field32_get(unit, v4mc_mem, v4mc_entry, BASE_VALID_0f) != 1) || 2625 (soc_mem_field32_get(unit, v4mc_mem, v4mc_entry, BASE_VALID_1f) != 7)) { 2626 continue; 2627 } 2628 } else { 2629 if ((0 == soc_mem_field32_get(unit, v4mc_mem, v4mc_entry, VALID_0f)) || 2630 (0 == soc_mem_field32_get(unit, v4mc_mem, v4mc_entry, VALID_1f))) { 2631 continue; 2632 } 2633 } 2634 2635 /* Update IPMC group count and IPMC group reference count */ 2636 #ifdef BCM_TRIDENT3_SUPPORT 2637 if (SOC_IS_TRIDENT3X(unit)) { 2638 uint32 dtype; 2639 ipmc_ptr = soc_mem_field32_dest_get(unit, v4mc_mem, v4mc_entry, l3mc_index_field, &dtype); 2640 } else 2641 #endif 2642 { 2643 ipmc_ptr = soc_mem_field32_get(unit, v4mc_mem, v4mc_entry, 2644 l3mc_index_field); 2645 } 2646 IPMC_USED_SET(unit, ipmc_ptr); 2647 2648 /* Insert into IPMC group's linked list of L3 entries */ 2649 sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t)); 2650 l3cfg.l3c_ing_intf = BCM_IF_INVALID; 2651 l3cfg.l3c_flags |= BCM_L3_IPMC; 2652 l3cfg.l3c_flags |= BCM_L3_HIT; 2653 if (soc_mem_field32_get(unit, v4mc_mem, v4mc_entry, rpe_field)) { 2654 l3cfg.l3c_flags |= BCM_L3_RPE; 2655 } 2656 if (SOC_MEM_FIELD_VALID(unit, v4mc_mem, vrf_field)) { 2657 l3cfg.l3c_vrf = soc_mem_field32_get(unit, v4mc_mem, 2658 v4mc_entry, vrf_field); 2659 } 2660 l3cfg.l3c_ipmc_group = soc_mem_field32_get(unit, v4mc_mem, 2661 v4mc_entry, group_ip_field); 2662 l3cfg.l3c_src_ip_addr = soc_mem_field32_get(unit, v4mc_mem, 2663 v4mc_entry, source_ip_field); 2664 if (soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn)) { 2665 if (soc_property_get(unit, spn_IPMC_L2_USE_VLAN_VPN, 0)) { 2666 l3cfg.l3c_ing_intf = soc_mem_field32_get(unit, v4mc_mem, 2667 v4mc_entry, l3_iif_field); 2668 } else { 2669 l3cfg.l3c_vid = soc_mem_field32_get(unit, v4mc_mem, 2670 v4mc_entry, l3_iif_field); 2671 l3cfg.l3c_flags |= BCM_L3_L2ONLY; 2672 } 2673 } else { 2674 l3cfg.l3c_vid = soc_mem_field32_get(unit, v4mc_mem, 2675 v4mc_entry, l3_iif_field); 2676 } 2677 l3cfg.l3c_prio = soc_mem_field32_get(unit, v4mc_mem, 2678 v4mc_entry, pri_field); 2679 #ifdef BCM_TRIDENT3_SUPPORT 2680 if (SOC_IS_TRIDENT3X(unit)) { 2681 uint32 dtype; 2682 l3cfg.l3c_ipmc_ptr = soc_mem_field32_dest_get(unit, 2683 v4mc_mem, v4mc_entry, 2684 l3mc_index_field, &dtype); 2685 } else 2686 #endif 2687 { 2688 l3cfg.l3c_ipmc_ptr = soc_mem_field32_get(unit, v4mc_mem, 2689 v4mc_entry, l3mc_index_field); 2690 } 2691 if (l3mc_index2 != INVALIDf) { 2692 l3cfg.l3c_ipmc_ptr_l2 = soc_mem_field32_get(unit, v4mc_mem, 2693 v4mc_entry, l3mc_index2); 2694 } 2695 l3cfg.l3c_lookup_class = soc_mem_field32_get(unit, v4mc_mem, 2696 v4mc_entry, class_id_field); 2697 #ifdef BCM_TRIDENT2_SUPPORT 2698 if (soc_mem_field_valid(unit, L3_ENTRY_IPV4_MULTICASTm, RPA_IDf) || 2699 soc_mem_field_valid(unit, L3_ENTRY_DOUBLEm,rpa_id_field)) { 2700 int iif_fld = EXPECTED_L3_IIFf; 2701 2702 #ifdef BCM_TRIDENT3_SUPPORT 2703 if (SOC_IS_TRIDENT3X(unit)) { 2704 iif_fld = IPV4MC__EXPECTED_L3_IIFf; 2705 } 2706 #endif /* BCM_TRIDENT3_SUPPORT */ 2707 2708 l3cfg.l3c_rp_id = soc_mem_field32_get(unit, v4mc_mem, 2709 v4mc_entry, rpa_id_field); 2710 if (l3cfg.l3c_rp_id == 0 && (l3cfg.l3c_vid != 0 || 2711 soc_mem_field32_get(unit, v4mc_mem, v4mc_entry, 2712 iif_fld) != 0)) { 2713 /* If RPA_ID field value is 0, it could mean (1) this IPMC 2714 * entry is not a PIM-BIDIR entry, or (2) this entry is a 2715 * PIM-BIDIR entry and is associated with rendezvous point 2716 * 0. If either the L3 IIF in the key or the expected L3 2717 * IIF in the data is not zero, this entry is not a 2718 * PIM-BIDIR entry. 2719 */ 2720 l3cfg.l3c_rp_id = BCM_IPMC_RP_ID_INVALID; 2721 } else { 2722 /* Recover rendezvous point's reference count */ 2723 rv = bcm_td2_ipmc_rp_ref_count_recover(unit, 2724 l3cfg.l3c_rp_id); 2725 if (BCM_FAILURE(rv)) { 2726 soc_cm_sfree(unit, v4mc_buf); 2727 return rv; 2728 } 2729 } 2730 } 2731 #endif /* BCM_TRIDENT2_SUPPORT */ 2732 rv = _bcm_tr_ipmc_l3entry_list_add(unit, ipmc_ptr, &l3cfg); 2733 if (BCM_FAILURE(rv)) { 2734 soc_cm_sfree(unit, v4mc_buf); 2735 return rv; 2736 } 2737 } 2738 } 2739 soc_cm_sfree(unit, v4mc_buf); 2740 2741 /* 2742 * Deal with IPv6 multicast table now 2743 */ 2744 if (SOC_MEM_IS_VALID(unit, L3_ENTRY_4m)) { 2745 v6mc_mem = L3_ENTRY_4m; 2746 v6mc_entry_size = sizeof(l3_entry_4_entry_t); 2747 v6mc_key_type = 7; 2748 l3mc_index_field = IPV6MC__L3MC_INDEXf; 2749 rpe_field = IPV6MC__RPEf; 2750 vrf_field = IPV6MC__VRF_IDf; 2751 source_ip_hi_field = IPV6MC__SOURCE_IP_ADDR_UPR_64f; 2752 source_ip_lo_field = IPV6MC__SOURCE_IP_ADDR_LWR_64f; 2753 l3_iif_field = IPV6MC__L3_IIFf; 2754 pri_field = IPV6MC__PRIf; 2755 class_id_field = IPV6MC__CLASS_IDf; 2756 rpa_id_field = INVALIDf; 2757 } else { 2758 v6mc_mem = L3_ENTRY_IPV6_MULTICASTm; 2759 v6mc_entry_size = sizeof(l3_entry_ipv6_multicast_entry_t); 2760 #ifdef BCM_TRIDENT2_SUPPORT 2761 if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWKX(unit)) { 2762 v6mc_key_type = TD2_L3_HASH_KEY_TYPE_V6MC; 2763 } else 2764 #endif /* BCM_TRIDENT2_SUPPORT */ 2765 { 2766 /* coverity[mixed_enums] */ 2767 v6mc_key_type = TR_L3_HASH_KEY_TYPE_V6MC; 2768 } 2769 2770 if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) { 2771 v6mc_mem = L3_ENTRY_QUADm; 2772 v6mc_entry_size = sizeof(l3_entry_quad_entry_t); 2773 l3mc_index_field = IPV6MC__DESTINATIONf; 2774 rpe_field = IPV6MC__RPEf; 2775 vrf_field = IPV6MC__VRF_IDf; 2776 source_ip_hi_field = IPV6MC__SOURCE_IP_ADDR_UPR_64f; 2777 source_ip_lo_field = IPV6MC__SOURCE_IP_ADDR_LWR_64f; 2778 l3_iif_field = IPV6MC__L3_IIFf; 2779 pri_field = IPV6MC__PRIf; 2780 class_id_field = IPV6MC__CLASS_IDf; 2781 rpa_id_field = IPV6MC__RPA_IDf; 2782 group_ip_hi_field = IPV6MC__GROUP_IP_ADDR_UPR_56f; 2783 group_ip_lo_field = IPV6MC__GROUP_IP_ADDR_LWR_64f; 2784 #ifdef BCM_TRIDENT2_SUPPORT 2785 expect_l3_iif_field = IPV6MC__EXPECTED_L3_IIFf; 2786 #endif 2787 } else { 2788 l3mc_index_field = L3MC_INDEXf; 2789 rpe_field = RPEf; 2790 vrf_field = VRF_IDf; 2791 source_ip_hi_field = SOURCE_IP_ADDR_UPR_64f; 2792 source_ip_lo_field = SOURCE_IP_ADDR_LWR_64f; 2793 l3_iif_field = L3_IIFf; 2794 pri_field = PRIf; 2795 class_id_field = CLASS_IDf; 2796 rpa_id_field = RPA_IDf; 2797 group_ip_hi_field = GROUP_IP_ADDR_UPR_56f; 2798 group_ip_lo_field = GROUP_IP_ADDR_LWR_64f; 2799 #ifdef BCM_TRIDENT2_SUPPORT 2800 expect_l3_iif_field = EXPECTED_L3_IIFf; 2801 #endif 2802 } 2803 if (SOC_MEM_FIELD_VALID(unit, v6mc_mem, IPV6MC__L3MC_INDEX_FOR_L2_DISTRIBUTIONf)) { 2804 l3mc_index2 = IPV6MC__L3MC_INDEX_FOR_L2_DISTRIBUTIONf; 2805 } 2806 } 2807 2808 /* Traverse IPv6 multicast table in chunks to avoid BCM_E_MEMORY */ 2809 chunk_size = 1024; 2810 num_chunks = (soc_mem_index_count(unit, v6mc_mem) + chunk_size - 1) / 2811 chunk_size; 2812 v6mc_buf = soc_cm_salloc(unit, v6mc_entry_size * chunk_size, 2813 "v6mc buf dma"); 2814 if (v6mc_buf == NULL) { 2815 return BCM_E_MEMORY; 2816 } 2817 for (chunk_index = 0; chunk_index < num_chunks; chunk_index++) { 2818 /* Read a chunk of entries */ 2819 entry_index_min = chunk_index * chunk_size; 2820 entry_index_max = entry_index_min + chunk_size - 1; 2821 if (entry_index_max > soc_mem_index_max(unit, v6mc_mem)) { 2822 entry_index_max = soc_mem_index_max(unit, v6mc_mem); 2823 } 2824 rv = soc_mem_read_range(unit, v6mc_mem, MEM_BLOCK_ANY, 2825 entry_index_min, entry_index_max, v6mc_buf); 2826 if (SOC_FAILURE(rv)) { 2827 soc_cm_sfree(unit, v6mc_buf); 2828 return rv; 2829 } 2830 2831 /* Read each entry of the chunk */ 2832 for (i = 0; i < (entry_index_max - entry_index_min + 1); i++) { 2833 v6mc_entry = soc_mem_table_idx_to_pointer(unit, v6mc_mem, 2834 uint32 *, v6mc_buf, i); 2835 if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) { 2836 key_type_field = KEY_TYPEf; 2837 } else { 2838 key_type_field = KEY_TYPE_0f; 2839 } 2840 key = soc_mem_field32_get(unit, v6mc_mem, 2841 v6mc_entry, key_type_field); 2842 if (soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn) && 2843 soc_property_get(unit, spn_IPMC_L2_USE_VLAN_VPN, 0)) { 2844 if ((key != v6mc_key_type) 2845 #ifdef BCM_TRIDENT2_SUPPORT 2846 && (key != TD2_L3_HASH_KEY_TYPE_V6L2MC) 2847 && (key != TD2_L3_HASH_KEY_TYPE_V6L2VPMC) 2848 #endif 2849 ) { 2850 2851 continue; 2852 } 2853 } else if (key != v6mc_key_type) { 2854 continue; 2855 } 2856 2857 if (!SOC_IS_TRIDENT3X(unit)) { 2858 if (SOC_IS_TOMAHAWK3(unit)) { 2859 key = soc_mem_field32_get(unit, v6mc_mem, 2860 v6mc_entry, KEY_TYPEf); 2861 } else { 2862 key = soc_mem_field32_get(unit, v6mc_mem, 2863 v6mc_entry, KEY_TYPE_1f); 2864 } 2865 if (soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn) && 2866 soc_property_get(unit, spn_IPMC_L2_USE_VLAN_VPN, 0)) { 2867 if ((key != v6mc_key_type) 2868 #ifdef BCM_TRIDENT2_SUPPORT 2869 && (key != TD2_L3_HASH_KEY_TYPE_V6L2MC) 2870 && (key != TD2_L3_HASH_KEY_TYPE_V6L2VPMC) 2871 #endif 2872 ) { 2873 2874 continue; 2875 } 2876 } else if (key != v6mc_key_type) { 2877 continue; 2878 } 2879 2880 if (!SOC_IS_TOMAHAWK3(unit)) { 2881 key = soc_mem_field32_get(unit, v6mc_mem, 2882 v6mc_entry, KEY_TYPE_2f); 2883 } 2884 2885 if (soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn) && 2886 soc_property_get(unit, spn_IPMC_L2_USE_VLAN_VPN, 0)) { 2887 if ((key != v6mc_key_type) 2888 #ifdef BCM_TRIDENT2_SUPPORT 2889 && (key != TD2_L3_HASH_KEY_TYPE_V6L2MC) 2890 && (key != TD2_L3_HASH_KEY_TYPE_V6L2VPMC) 2891 #endif 2892 ) { 2893 2894 continue; 2895 } 2896 } else if (key != v6mc_key_type) { 2897 continue; 2898 } 2899 2900 if (!SOC_IS_TOMAHAWK3(unit)) { 2901 key = soc_mem_field32_get(unit, v6mc_mem, 2902 v6mc_entry, KEY_TYPE_3f); 2903 } 2904 if (soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn) && 2905 soc_property_get(unit, spn_IPMC_L2_USE_VLAN_VPN, 0)) { 2906 if ((key != v6mc_key_type) 2907 #ifdef BCM_TRIDENT2_SUPPORT 2908 && (key != TD2_L3_HASH_KEY_TYPE_V6L2MC) 2909 && (key != TD2_L3_HASH_KEY_TYPE_V6L2VPMC) 2910 #endif 2911 ) { 2912 2913 continue; 2914 } 2915 } else if (key != v6mc_key_type) { 2916 continue; 2917 } 2918 } 2919 2920 /* Skip Invalid Entries */ 2921 if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) { 2922 if ((soc_mem_field32_get(unit, v6mc_mem, v6mc_entry, BASE_VALID_0f) != 5) || 2923 (soc_mem_field32_get(unit, v6mc_mem, v6mc_entry, BASE_VALID_1f) != 6) || 2924 (soc_mem_field32_get(unit, v6mc_mem, v6mc_entry, BASE_VALID_2f) != 6) || 2925 (soc_mem_field32_get(unit, v6mc_mem, v6mc_entry, BASE_VALID_3f) != 7)) { 2926 continue; 2927 } 2928 } else { 2929 if ((0 == soc_mem_field32_get(unit, v6mc_mem, v6mc_entry, VALID_0f)) || 2930 (0 == soc_mem_field32_get(unit, v6mc_mem, v6mc_entry, VALID_1f)) || 2931 (0 == soc_mem_field32_get(unit, v6mc_mem, v6mc_entry, VALID_2f)) || 2932 (0 == soc_mem_field32_get(unit, v6mc_mem, v6mc_entry, VALID_3f))) { 2933 continue; 2934 } 2935 } 2936 2937 /* Update IPMC group count and IPMC group reference count */ 2938 #ifdef BCM_TRIDENT3_SUPPORT 2939 if (soc_feature(unit, soc_feature_generic_dest)) { 2940 uint32 dtype; 2941 ipmc_ptr = soc_mem_field32_dest_get(unit, v6mc_mem, v6mc_entry, 2942 l3mc_index_field, &dtype); 2943 } else 2944 #endif 2945 { 2946 ipmc_ptr = soc_mem_field32_get(unit, v6mc_mem, v6mc_entry, 2947 l3mc_index_field); 2948 } 2949 IPMC_USED_SET(unit, ipmc_ptr); 2950 2951 /* Insert into IPMC group's linked list of L3 entries */ 2952 sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t)); 2953 l3cfg.l3c_ing_intf = BCM_IF_INVALID; 2954 l3cfg.l3c_flags |= BCM_IPMC_IP6; 2955 l3cfg.l3c_flags |= BCM_L3_IPMC; 2956 l3cfg.l3c_flags |= BCM_L3_HIT; 2957 l3cfg.l3c_flags |= BCM_L3_IP6; 2958 2959 if (soc_mem_field32_get(unit, v6mc_mem, v6mc_entry, rpe_field)) { 2960 l3cfg.l3c_flags |= BCM_L3_RPE; 2961 } 2962 if (SOC_MEM_FIELD_VALID(unit, v6mc_mem, vrf_field)) { 2963 l3cfg.l3c_vrf = soc_mem_field32_get(unit, v6mc_mem, 2964 v6mc_entry, vrf_field); 2965 } 2966 if (SOC_MEM_IS_VALID(unit, L3_ENTRY_4m)) { 2967 soc_mem_ip6_addr_get(unit, v6mc_mem, v6mc_entry, 2968 IPV6MC__GROUP_IP_ADDR_LWR_96f, l3cfg.l3c_ip6, 2969 SOC_MEM_IP6_LOWER_96BIT); 2970 soc_mem_ip6_addr_get(unit, v6mc_mem, v6mc_entry, 2971 IPV6MC__GROUP_IP_ADDR_UPR_24f, l3cfg.l3c_ip6, 2972 SOC_MEM_IP6_BITS_119_96); 2973 } else { 2974 soc_mem_ip6_addr_get(unit, v6mc_mem, v6mc_entry, 2975 group_ip_lo_field, l3cfg.l3c_ip6, 2976 SOC_MEM_IP6_LOWER_ONLY); 2977 soc_mem_ip6_addr_get(unit, v6mc_mem, v6mc_entry, 2978 group_ip_hi_field, l3cfg.l3c_ip6, 2979 SOC_MEM_IP6_UPPER_ONLY); 2980 } 2981 l3cfg.l3c_ip6[0] = 0xff; /* Set entry to multicast*/ 2982 2983 if (SOC_MEM_IS_VALID(unit, L3_ENTRY_QUADm)) { 2984 soc_mem_ip6_addr_get(unit, v6mc_mem, v6mc_entry, 2985 IPV6MC__SOURCE_IP_ADDR_BITS_31_0f, l3cfg.l3c_sip6, 2986 SOC_MEM_IP6_BITS_31_0); 2987 soc_mem_ip6_addr_get(unit, v6mc_mem, v6mc_entry, 2988 IPV6MC__SOURCE_IP_ADDR_BITS_63_32f, l3cfg.l3c_sip6, 2989 SOC_MEM_IP6_BITS_63_32); 2990 } else { 2991 soc_mem_ip6_addr_get(unit, v6mc_mem, v6mc_entry, 2992 source_ip_lo_field, l3cfg.l3c_sip6, 2993 SOC_MEM_IP6_LOWER_ONLY); 2994 } 2995 soc_mem_ip6_addr_get(unit, v6mc_mem, v6mc_entry, 2996 source_ip_hi_field, l3cfg.l3c_sip6, 2997 SOC_MEM_IP6_UPPER_ONLY); 2998 2999 if (soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn)) { 3000 if (soc_property_get(unit, spn_IPMC_L2_USE_VLAN_VPN, 0)) { 3001 l3cfg.l3c_vid = soc_mem_field32_get(unit, v6mc_mem, 3002 v6mc_entry, l3_iif_field); 3003 l3cfg.l3c_flags |= BCM_L3_L2ONLY; 3004 } else { 3005 l3cfg.l3c_ing_intf = soc_mem_field32_get(unit, v6mc_mem, 3006 v6mc_entry, l3_iif_field); 3007 } 3008 } else { 3009 l3cfg.l3c_vid = soc_mem_field32_get(unit, v6mc_mem, 3010 v6mc_entry, l3_iif_field); 3011 } 3012 3013 l3cfg.l3c_prio = soc_mem_field32_get(unit, v6mc_mem, 3014 v6mc_entry, pri_field); 3015 l3cfg.l3c_ipmc_ptr = ipmc_ptr; 3016 if (l3mc_index2 != INVALIDf) { 3017 l3cfg.l3c_ipmc_ptr_l2 = soc_mem_field32_get(unit, v6mc_mem, 3018 v6mc_entry, l3mc_index2); 3019 } 3020 l3cfg.l3c_lookup_class = soc_mem_field32_get(unit, v6mc_mem, 3021 v6mc_entry, class_id_field); 3022 #ifdef BCM_TRIDENT2_SUPPORT 3023 if ((soc_mem_field_valid(unit, L3_ENTRY_IPV6_MULTICASTm, RPA_IDf)) || 3024 (soc_mem_field_valid(unit, L3_ENTRY_QUADm, rpa_id_field))) { 3025 l3cfg.l3c_rp_id = soc_mem_field32_get(unit, v6mc_mem, 3026 v6mc_entry, rpa_id_field); 3027 if (l3cfg.l3c_rp_id == 0 && (l3cfg.l3c_vid != 0 || 3028 soc_mem_field32_get(unit, v6mc_mem, v6mc_entry, 3029 expect_l3_iif_field) != 0)) { 3030 /* If RPA_ID field value is 0, it could mean (1) this IPMC 3031 * entry is not a PIM-BIDIR entry, or (2) this entry is a 3032 * PIM-BIDIR entry and is associated with rendezvous point 3033 * 0. If either the L3 IIF in the key or the expected L3 3034 * IIF in the data is not zero, this entry is not a 3035 * PIM-BIDIR entry. 3036 */ 3037 l3cfg.l3c_rp_id = BCM_IPMC_RP_ID_INVALID; 3038 } else { 3039 /* Update rendezvous point's reference count */ 3040 rv = bcm_td2_ipmc_rp_ref_count_recover(unit, 3041 l3cfg.l3c_rp_id); 3042 if (BCM_FAILURE(rv)) { 3043 soc_cm_sfree(unit, v6mc_buf); 3044 return rv; 3045 } 3046 } 3047 } 3048 #endif /* BCM_TRIDENT2_SUPPORT */ 3049 rv = _bcm_tr_ipmc_l3entry_list_add(unit, ipmc_ptr, &l3cfg); 3050 if (BCM_FAILURE(rv)) { 3051 soc_cm_sfree(unit, v6mc_buf); 3052 return rv; 3053 } 3054 } 3055 } 3056 soc_cm_sfree(unit, v6mc_buf); 3057 3058 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 3059 if (soc_feature(unit, soc_feature_ipmc_defip)) { 3060 BCM_IF_ERROR_RETURN(bcm_td2p_defip_ipmc_count_update(unit)); 3061 } 3062 #endif 3063 3064 return rv; 3065 } 3066 3067 /* 3068 * Reload IPMC state on TR class of devices 3069 */ 3070 int 3071 _bcm_tr_ipmc_reinit(int unit) 3072 { 3073 _bcm_esw_ipmc_t *info = IPMC_INFO(unit); 3074 int rv = BCM_E_NONE; 3075 int i; 3076 uint8 flags; 3077 int l3_min, l3_max, l3_ipmc_tbl_sz; 3078 uint8 *l3_ipmc_table = NULL; 3079 _bcm_esw_ipmc_l3entry_t *ipmc_l3entry; 3080 ipmc_entry_t *l3_ipmc_entry; 3081 3082 info->ipmc_group_info = NULL; 3083 3084 IPMC_GROUP_NUM(unit) = soc_mem_index_count(unit, L3_IPMCm); 3085 #if defined(BCM_TRIUMPH3_SUPPORT) 3086 if (soc_feature(unit, soc_feature_static_repl_head_alloc)) { 3087 soc_info_t *si; 3088 int member_count; 3089 int port, phy_port, mmu_port; 3090 3091 /* Each replication group is statically allocated a region 3092 * in REPL_HEAD table. The size of the region depends on the 3093 * maximum number of valid ports. Thus, the max number of 3094 * replication groups is limited to number of REPL_HEAD entries 3095 * divided by the max number of valid ports. 3096 */ 3097 si = &SOC_INFO(unit); 3098 member_count = 0; 3099 PBMP_ITER(SOC_CONTROL(unit)->repl_eligible_pbmp, port) { 3100 phy_port = si->port_l2p_mapping[port]; 3101 mmu_port = si->port_p2m_mapping[phy_port]; 3102 if ((mmu_port == 57) || (mmu_port == 59) || (mmu_port == 61) || (mmu_port == 62)) { 3103 /* No replication on MMU ports 57, 59, 61 and 62 */ 3104 continue; 3105 } 3106 member_count++; 3107 } 3108 if (member_count > 0) { 3109 IPMC_GROUP_NUM(unit) = 3110 soc_mem_index_count(unit, MMU_REPL_HEAD_TBLm) / member_count; 3111 if (IPMC_GROUP_NUM(unit) > soc_mem_index_count(unit, L3_IPMCm)) { 3112 IPMC_GROUP_NUM(unit) = soc_mem_index_count(unit, L3_IPMCm); 3113 } 3114 } 3115 } 3116 #endif /* BCM_TRIUMPH3_SUPPORT */ 3117 3118 #ifdef BCM_BRADLEY_SUPPORT 3119 if (!SOC_IS_MONTEREY(unit)) { 3120 if (SOC_REG_FIELD_VALID(unit, MC_CONTROL_5r, SHARED_TABLE_IPMC_SIZEf)) { 3121 int ipmc_base, ipmc_size; 3122 3123 SOC_IF_ERROR_RETURN 3124 (soc_hbx_ipmc_size_get(unit, &ipmc_base, &ipmc_size)); 3125 3126 if (IPMC_GROUP_NUM(unit) > ipmc_size) { 3127 /* Reduce to fix allocated table space */ 3128 IPMC_GROUP_NUM(unit) = ipmc_size; 3129 } 3130 } 3131 } 3132 #endif /* BCM_BRADLEY_SUPPORT */ 3133 3134 info->ipmc_count = 0; 3135 3136 info->ipmc_group_info = 3137 sal_alloc(IPMC_GROUP_NUM(unit) * sizeof(_bcm_esw_ipmc_group_info_t), 3138 "IPMC group info"); 3139 if (info->ipmc_group_info == NULL) { 3140 rv = BCM_E_MEMORY; 3141 goto ret_err; 3142 } 3143 sal_memset(info->ipmc_group_info, 0, 3144 IPMC_GROUP_NUM(unit) * sizeof(_bcm_esw_ipmc_group_info_t)); 3145 3146 #ifdef BCM_TRIDENT2_SUPPORT 3147 if (soc_feature(unit, soc_feature_pim_bidir)) { 3148 rv = bcm_td2_ipmc_pim_bidir_init(unit); 3149 if (BCM_FAILURE(rv)) { 3150 goto ret_err; 3151 } 3152 } 3153 #endif /* BCM_TRIDENT2_SUPPORT */ 3154 3155 /* Traverse IPMC address table to recover IPMC group count, 3156 * IPMC group info, and PIM-BIDIR rendezvous point reference count. 3157 */ 3158 rv = _bcm_tr_ipmc_table_recover(unit); 3159 if (BCM_FAILURE(rv)) { 3160 goto ret_err; 3161 } 3162 3163 /* Recover multicast mode from HW cache */ 3164 rv = _bcm_esw_ipmc_repl_wb_flags_get(unit, 3165 _BCM_IPMC_WB_MULTICAST_MODE, 3166 &flags); 3167 if (flags) { 3168 /* 3169 * Increase reference count for all defined mulitcast groups now 3170 */ 3171 l3_min = soc_mem_index_min(unit, L3_IPMCm); 3172 l3_max = soc_mem_index_max(unit, L3_IPMCm); 3173 l3_ipmc_tbl_sz = sizeof(ipmc_entry_t) * \ 3174 (l3_max - l3_min + 1); 3175 l3_ipmc_table = soc_cm_salloc(unit, l3_ipmc_tbl_sz, 3176 "L3 ipmc tbl dma"); 3177 if (l3_ipmc_table == NULL) { 3178 rv = BCM_E_MEMORY; 3179 goto ret_err; 3180 } 3181 if ((rv = soc_mem_read_range(unit, L3_IPMCm, 3182 MEM_BLOCK_ANY, 3183 l3_min, l3_max, l3_ipmc_table)) < 0) { 3184 soc_cm_sfree(unit, l3_ipmc_table); 3185 goto ret_err; 3186 } 3187 3188 for (i = l3_min; i <= l3_max; i++) { 3189 #if defined(BCM_XGS3_SWITCH_SUPPORT) && defined(INCLUDE_L3) 3190 if (SOC_IS_XGS3_SWITCH(unit) && !(SOC_IS_KATANAX(unit)) && i == 0) { 3191 /* reserve L3_IPMC entry 0 for default behavior */ 3192 /* for Katana and Katana2 0 and 1 get reserved from inside 3193 * bcm_tr2_ipmc_repl_init() and 3194 * bcm_kt2_ipmc_repl_init 3195 */ 3196 IPMC_USED_SET(unit, i); 3197 continue; 3198 } 3199 #endif 3200 l3_ipmc_entry = soc_mem_table_idx_to_pointer(unit, 3201 L3_IPMCm, 3202 ipmc_entry_t *, 3203 l3_ipmc_table, i); 3204 if (0 == soc_L3_IPMCm_field32_get(unit, l3_ipmc_entry, 3205 VALIDf)) { 3206 continue; 3207 } 3208 3209 /* It's a multicast group we need to note. */ 3210 IPMC_USED_SET(unit, i); 3211 } 3212 soc_cm_sfree(unit, l3_ipmc_table); 3213 } 3214 3215 /* 3216 * Recover replication state 3217 */ 3218 #if defined(BCM_TRIUMPH3_SUPPORT) 3219 if (SOC_IS_TRIUMPH3(unit) || SOC_IS_TRIDENT2X(unit)) { 3220 rv = _bcm_tr3_ipmc_repl_reload(unit); 3221 } else 3222 #if defined(BCM_TOMAHAWK_SUPPORT) 3223 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 3224 rv = _bcm_th_ipmc_repl_reload(unit); 3225 } else 3226 #endif /* BCM_TOMAHAWK_SUPPORT */ 3227 #endif /* BCM_TRIUMPH3_SUPPORT */ 3228 #ifdef BCM_SABER2_SUPPORT 3229 if (SOC_IS_SABER2(unit)) { 3230 rv = _bcm_sb2_ipmc_repl_reload(unit); 3231 } else 3232 #endif /* BCM_SABER2_SUPPORT */ 3233 3234 #ifdef BCM_KATANA2_SUPPORT 3235 if (SOC_IS_KATANA2(unit)) { 3236 rv = _bcm_kt2_ipmc_repl_reload(unit); 3237 } else 3238 #endif /* BCM_KATANA2_SUPPORT */ 3239 #ifdef BCM_TRIUMPH2_SUPPORT 3240 if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) || 3241 SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit) || 3242 SOC_IS_KATANA(unit)) { 3243 rv = _bcm_tr2_ipmc_repl_reload(unit); 3244 } else 3245 #endif /* BCM_TRIUMPH2_SUPPORT */ 3246 { 3247 rv = _bcm_xgs3_ipmc_repl_reload(unit); 3248 } 3249 3250 ret_err: 3251 if (BCM_FAILURE(rv)) { 3252 3253 if (info->ipmc_group_info != NULL) { 3254 for (i = 0; i < IPMC_GROUP_NUM(unit); i++) { 3255 ipmc_l3entry = IPMC_GROUP_INFO(unit, i)->l3entry_list; 3256 while (ipmc_l3entry != NULL) { 3257 IPMC_GROUP_INFO(unit, i)->l3entry_list = ipmc_l3entry->next; 3258 sal_free(ipmc_l3entry); 3259 ipmc_l3entry = IPMC_GROUP_INFO(unit, i)->l3entry_list; 3260 } 3261 } 3262 sal_free(info->ipmc_group_info); 3263 info->ipmc_group_info = NULL; 3264 } 3265 } else { 3266 info->ipmc_initialized = TRUE; 3267 } 3268 3269 return rv; 3270 } 3271 #endif /* BCM_WARM_BOOT_SUPPORT */ 3272 3273 #ifndef BCM_SW_STATE_DUMP_DISABLE 3274 /* 3275 * Function: 3276 * _bcm_tr_ipmc_sw_dump 3277 * Purpose: 3278 * Displays IPMC information maintained by software. 3279 * Parameters: 3280 * unit - Device unit number 3281 * Returns: 3282 * None 3283 */ 3284 void 3285 _bcm_tr_ipmc_sw_dump(int unit) 3286 { 3287 int i, j; 3288 _bcm_esw_ipmc_t *ipmc_info; 3289 _bcm_esw_ipmc_l3entry_t *ipmc_l3entry; 3290 3291 /* 3292 * xgs3_ipmc_info 3293 */ 3294 3295 ipmc_info = IPMC_INFO(unit); 3296 3297 LOG_CLI((BSL_META_U(unit, 3298 " XGS3 IPMC Info -\n"))); 3299 LOG_CLI((BSL_META_U(unit, 3300 " Init : %d\n"), ipmc_info->ipmc_initialized)); 3301 LOG_CLI((BSL_META_U(unit, 3302 " Size : %d\n"), IPMC_GROUP_NUM(unit))); 3303 LOG_CLI((BSL_META_U(unit, 3304 " Count : %d\n"), ipmc_info->ipmc_count)); 3305 3306 LOG_CLI((BSL_META_U(unit, 3307 " Alloc index :"))); 3308 if (ipmc_info->ipmc_group_info != NULL) { 3309 for (i = 0, j = 0; i < IPMC_GROUP_NUM(unit); i++) { 3310 /* If not set, skip print */ 3311 if (!IPMC_USED_ISSET(unit, i)) { 3312 continue; 3313 } 3314 if (!(j % 10)) { 3315 LOG_CLI((BSL_META_U(unit, 3316 "\n "))); 3317 } 3318 LOG_CLI((BSL_META_U(unit, 3319 " %5d"), i)); 3320 j++; 3321 } 3322 } 3323 LOG_CLI((BSL_META_U(unit, 3324 "\n"))); 3325 3326 LOG_CLI((BSL_META_U(unit, 3327 " Reference count (index:value) :"))); 3328 if (ipmc_info->ipmc_group_info != NULL) { 3329 for (i = 0, j = 0; i < IPMC_GROUP_NUM(unit); i++) { 3330 if (!IPMC_USED_ISSET(unit, i)) { 3331 continue; 3332 } 3333 if (!(j % 4)) { 3334 LOG_CLI((BSL_META_U(unit, 3335 "\n "))); 3336 } 3337 LOG_CLI((BSL_META_U(unit, 3338 " %5d:%-5d"), i, IPMC_GROUP_INFO(unit, i)->ref_count)); 3339 j++; 3340 } 3341 } 3342 LOG_CLI((BSL_META_U(unit, 3343 "\n"))); 3344 3345 LOG_CLI((BSL_META_U(unit, 3346 " IP6 (index:value) :"))); 3347 if (ipmc_info->ipmc_group_info != NULL) { 3348 for (i = 0, j = 0; i < IPMC_GROUP_NUM(unit); i++) { 3349 ipmc_l3entry = IPMC_GROUP_INFO(unit, i)->l3entry_list; 3350 while (ipmc_l3entry != NULL) { 3351 if (ipmc_l3entry->ip6 == 1) { 3352 if (!(j % 4)) { 3353 LOG_CLI((BSL_META_U(unit, 3354 "\n "))); 3355 } 3356 LOG_CLI((BSL_META_U(unit, 3357 " %5d:%-5d"), i, ipmc_l3entry->ip6)); 3358 j++; 3359 } 3360 ipmc_l3entry = ipmc_l3entry->next; 3361 } 3362 } 3363 } 3364 LOG_CLI((BSL_META_U(unit, 3365 "\n"))); 3366 LOG_CLI((BSL_META_U(unit, 3367 " Group (G1:G2) :"))); 3368 if (ipmc_info->ipmc_group_info != NULL) { 3369 for (i = 0, j = 0; i < IPMC_GROUP_NUM(unit); i++) { 3370 ipmc_l3entry = IPMC_GROUP_INFO(unit, i)->l3entry_list; 3371 while (ipmc_l3entry != NULL) { 3372 if (!(j % 4)) { 3373 LOG_CLI((BSL_META_U(unit, 3374 "\n "))); 3375 } 3376 LOG_CLI((BSL_META_U(unit, " %4d:%-4d"), 3377 ipmc_l3entry->l3info.ipmc_ptr, 3378 ipmc_l3entry->l3info.ipmc_ptr_l2)); 3379 j++; 3380 ipmc_l3entry = ipmc_l3entry->next; 3381 } 3382 } 3383 } 3384 LOG_CLI((BSL_META_U(unit, 3385 "\n"))); 3386 3387 3388 #ifdef BCM_TRIDENT2_SUPPORT 3389 if (soc_feature(unit, soc_feature_pim_bidir)) { 3390 _bcm_td2_ipmc_pim_bidir_sw_dump(unit); 3391 } 3392 #endif /* BCM_TRIDENT2_SUPPORT */ 3393 3394 /* IPMC replication info is elsewhere */ 3395 #if defined(BCM_TOMAHAWK_SUPPORT) 3396 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 3397 _bcm_th_ipmc_repl_sw_dump(unit); 3398 } else 3399 #endif /* BCM_TOMAHAWK_SUPPORT */ 3400 #if defined(BCM_TRIUMPH3_SUPPORT) || defined(BCM_KATANA2_SUPPORT) 3401 if (SOC_IS_TRIUMPH3(unit) || SOC_IS_TRIDENT2X(unit) || SOC_IS_KATANA2(unit)) { 3402 _bcm_tr3_ipmc_repl_sw_dump(unit); 3403 } else 3404 #endif /* BCM_TRIUMPH3_SUPPORT */ 3405 #ifdef BCM_TRIUMPH2_SUPPORT 3406 if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) || 3407 SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit) || 3408 SOC_IS_KATANA(unit)) { 3409 _bcm_tr2_ipmc_repl_sw_dump(unit); 3410 } else 3411 #endif /* BCM_TRIUMPH2_SUPPORT */ 3412 { 3413 _bcm_xgs3_ipmc_repl_sw_dump(unit); 3414 } 3415 3416 return; 3417 } 3418 #endif /* BCM_SW_STATE_DUMP_DISABLE */ 3419 3420 #endif /* INCLUDE_L3 */ 3421 3422 int _bcm_tr_firebolt_ipmc_not_empty;